feat(contexts): add GuildMember
This commit is contained in:
@ -1,13 +1,7 @@
|
|||||||
import { useState, useEffect, useMemo } from 'react'
|
import { useState, useEffect, useMemo } from 'react'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import useTranslation from 'next-translate/useTranslation'
|
import useTranslation from 'next-translate/useTranslation'
|
||||||
import {
|
import { PlusIcon, MenuIcon, UsersIcon, XIcon } from '@heroicons/react/solid'
|
||||||
CogIcon,
|
|
||||||
PlusIcon,
|
|
||||||
MenuIcon,
|
|
||||||
UsersIcon,
|
|
||||||
XIcon
|
|
||||||
} from '@heroicons/react/solid'
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useMediaQuery } from 'react-responsive'
|
import { useMediaQuery } from 'react-responsive'
|
||||||
import { useSwipeable } from 'react-swipeable'
|
import { useSwipeable } from 'react-swipeable'
|
||||||
@ -15,7 +9,6 @@ import { useSwipeable } from 'react-swipeable'
|
|||||||
import { Sidebar, DirectionSidebar } from './Sidebar'
|
import { Sidebar, DirectionSidebar } from './Sidebar'
|
||||||
import { IconButton } from 'components/design/IconButton'
|
import { IconButton } from 'components/design/IconButton'
|
||||||
import { IconLink } from 'components/design/IconLink'
|
import { IconLink } from 'components/design/IconLink'
|
||||||
import { Channels } from './Channels'
|
|
||||||
import { Guilds } from './Guilds/Guilds'
|
import { Guilds } from './Guilds/Guilds'
|
||||||
import { Divider } from '../design/Divider'
|
import { Divider } from '../design/Divider'
|
||||||
import { Members } from './Members'
|
import { Members } from './Members'
|
||||||
@ -27,17 +20,20 @@ export interface GuildsChannelsPath {
|
|||||||
channelId: number
|
channelId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ApplicationPath =
|
||||||
|
| '/application'
|
||||||
|
| '/application/guilds/join'
|
||||||
|
| '/application/guilds/create'
|
||||||
|
| '/application/users/[userId]'
|
||||||
|
| GuildsChannelsPath
|
||||||
|
|
||||||
export interface ApplicationProps {
|
export interface ApplicationProps {
|
||||||
path:
|
path: ApplicationPath
|
||||||
| '/application'
|
guildLeftSidebar?: React.ReactNode
|
||||||
| '/application/guilds/join'
|
|
||||||
| '/application/guilds/create'
|
|
||||||
| '/application/users/[userId]'
|
|
||||||
| GuildsChannelsPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Application: React.FC<ApplicationProps> = (props) => {
|
export const Application: React.FC<ApplicationProps> = (props) => {
|
||||||
const { children, path } = props
|
const { children, path, guildLeftSidebar } = props
|
||||||
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { user } = useAuthentication()
|
const { user } = useAuthentication()
|
||||||
@ -217,26 +213,7 @@ export const Application: React.FC<ApplicationProps> = (props) => {
|
|||||||
<Guilds path={path} />
|
<Guilds path={path} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{typeof path !== 'string' && (
|
{guildLeftSidebar}
|
||||||
<div className='flex flex-col justify-between w-full mt-2'>
|
|
||||||
<div className='text-center p-2 mx-8 mt-2'>
|
|
||||||
<h2 className='text-xl'>Guild Name</h2>
|
|
||||||
</div>
|
|
||||||
<Divider />
|
|
||||||
<div className='scrollbar-firefox-support overflow-y-auto'>
|
|
||||||
<Channels path={path} />
|
|
||||||
</div>
|
|
||||||
<Divider />
|
|
||||||
<div className='flex justify-center items-center p-2 mb-1 space-x-6'>
|
|
||||||
<IconButton className='h-10 w-10' title='Add a Channel'>
|
|
||||||
<PlusIcon />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton className='h-7 w-7' title='Settings'>
|
|
||||||
<CogIcon />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
38
components/Application/GuildLeftSidebar/GuildLeftSidebar.tsx
Normal file
38
components/Application/GuildLeftSidebar/GuildLeftSidebar.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { CogIcon, PlusIcon } from '@heroicons/react/solid'
|
||||||
|
|
||||||
|
import { useGuildMember } from 'contexts/GuildMember'
|
||||||
|
import { Divider } from 'components/design/Divider'
|
||||||
|
import { Channels } from 'components/Application/Channels'
|
||||||
|
import { IconButton } from 'components/design/IconButton'
|
||||||
|
import { GuildsChannelsPath } from '..'
|
||||||
|
|
||||||
|
export interface GuildLeftSidebarProps {
|
||||||
|
path: GuildsChannelsPath
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GuildLeftSidebar: React.FC<GuildLeftSidebarProps> = (props) => {
|
||||||
|
const { path } = props
|
||||||
|
|
||||||
|
const { guild } = useGuildMember()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex flex-col justify-between w-full mt-2'>
|
||||||
|
<div className='text-center p-2 mx-8 mt-2'>
|
||||||
|
<h2 className='text-xl'>{guild.name}</h2>
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
|
<div className='scrollbar-firefox-support overflow-y-auto'>
|
||||||
|
<Channels path={path} />
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
|
<div className='flex justify-center items-center p-2 mb-1 space-x-6'>
|
||||||
|
<IconButton className='h-10 w-10' title='Add a Channel'>
|
||||||
|
<PlusIcon />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton className='h-7 w-7' title='Settings'>
|
||||||
|
<CogIcon />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
1
components/Application/GuildLeftSidebar/index.ts
Normal file
1
components/Application/GuildLeftSidebar/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './GuildLeftSidebar'
|
32
contexts/GuildMember.tsx
Normal file
32
contexts/GuildMember.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { createContext, useContext } from 'react'
|
||||||
|
|
||||||
|
import { Guild } from 'models/Guild'
|
||||||
|
import { Member } from 'models/Member'
|
||||||
|
|
||||||
|
export interface GuildMember {
|
||||||
|
guild: Guild
|
||||||
|
member: Member
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GuildMemberProps {
|
||||||
|
guildMember: GuildMember
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultGuildMemberContext = {} as any
|
||||||
|
const GuildMemberContext = createContext<GuildMember>(defaultGuildMemberContext)
|
||||||
|
|
||||||
|
export const GuildMemberProvider: React.FC<GuildMemberProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<GuildMemberContext.Provider value={props.guildMember}>
|
||||||
|
{props.children}
|
||||||
|
</GuildMemberContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGuildMember = (): GuildMember => {
|
||||||
|
const guildMember = useContext(GuildMemberContext)
|
||||||
|
if (guildMember === defaultGuildMemberContext) {
|
||||||
|
throw new Error('useGuildMember must be used within GuildMemberProvider')
|
||||||
|
}
|
||||||
|
return guildMember
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { Type } from '@sinclair/typebox'
|
import { Type, Static } from '@sinclair/typebox'
|
||||||
|
|
||||||
import { date, id } from './utils'
|
import { date, id } from './utils'
|
||||||
|
|
||||||
@ -10,3 +10,5 @@ export const memberSchema = {
|
|||||||
userId: id,
|
userId: id,
|
||||||
guildId: id
|
guildId: id
|
||||||
}
|
}
|
||||||
|
const memberObjectSchema = Type.Object(memberSchema)
|
||||||
|
export type Member = Static<typeof memberObjectSchema>
|
||||||
|
@ -8,33 +8,46 @@ import {
|
|||||||
AuthenticationProvider,
|
AuthenticationProvider,
|
||||||
PagePropsWithAuthentication
|
PagePropsWithAuthentication
|
||||||
} from 'utils/authentication'
|
} from 'utils/authentication'
|
||||||
|
import { GuildMember, GuildMemberProvider } from 'contexts/GuildMember'
|
||||||
|
import { GuildLeftSidebar } from 'components/Application/GuildLeftSidebar'
|
||||||
|
|
||||||
export interface ChannelPageProps extends PagePropsWithAuthentication {
|
export interface ChannelPageProps extends PagePropsWithAuthentication {
|
||||||
channelId: number
|
channelId: number
|
||||||
guildId: number
|
guildId: number
|
||||||
|
guildMember: GuildMember
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChannelPage: NextPage<ChannelPageProps> = (props) => {
|
const ChannelPage: NextPage<ChannelPageProps> = (props) => {
|
||||||
const { channelId, guildId, authentication } = props
|
const { channelId, guildId, authentication, guildMember } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthenticationProvider authentication={authentication}>
|
<AuthenticationProvider authentication={authentication}>
|
||||||
<Head title='Thream | Application' />
|
<GuildMemberProvider guildMember={guildMember}>
|
||||||
<Application
|
<Head title='Thream | Application' />
|
||||||
path={{
|
<Application
|
||||||
channelId,
|
path={{
|
||||||
guildId
|
channelId,
|
||||||
}}
|
guildId
|
||||||
>
|
}}
|
||||||
<Messages />
|
guildLeftSidebar={
|
||||||
</Application>
|
<GuildLeftSidebar
|
||||||
|
path={{
|
||||||
|
channelId,
|
||||||
|
guildId
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Messages />
|
||||||
|
</Application>
|
||||||
|
</GuildMemberProvider>
|
||||||
</AuthenticationProvider>
|
</AuthenticationProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getServerSideProps = authenticationFromServerSide({
|
export const getServerSideProps = authenticationFromServerSide({
|
||||||
shouldBeAuthenticated: true,
|
shouldBeAuthenticated: true,
|
||||||
fetchData: async (context) => {
|
fetchData: async (context, api) => {
|
||||||
const channelId = Number(context?.params?.channelId)
|
const channelId = Number(context?.params?.channelId)
|
||||||
const guildId = Number(context?.params?.guildId)
|
const guildId = Number(context?.params?.guildId)
|
||||||
if (isNaN(channelId) || isNaN(guildId)) {
|
if (isNaN(channelId) || isNaN(guildId)) {
|
||||||
@ -45,9 +58,11 @@ export const getServerSideProps = authenticationFromServerSide({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const { data: guildMember } = await api.get(`/guilds/${guildId}`)
|
||||||
return {
|
return {
|
||||||
channelId,
|
channelId,
|
||||||
guildId
|
guildId,
|
||||||
|
guildMember
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { AxiosInstance, AxiosResponse } from 'axios'
|
import { AxiosInstance, AxiosResponse } from 'axios'
|
||||||
import { GetServerSideProps, GetServerSidePropsContext, Redirect } from 'next'
|
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
|
||||||
|
|
||||||
import { api } from '../api'
|
import { api } from '../api'
|
||||||
import { Cookies } from '../cookies'
|
import { Cookies } from '../cookies'
|
||||||
@ -25,7 +25,7 @@ interface AuthenticationFromServerSideOptions {
|
|||||||
/** allows to fetch data server side with the authenticated user, the callback should returns the data that will be transfer to the component as props */
|
/** allows to fetch data server side with the authenticated user, the callback should returns the data that will be transfer to the component as props */
|
||||||
fetchData?: (
|
fetchData?: (
|
||||||
context: GetServerSidePropsContext,
|
context: GetServerSidePropsContext,
|
||||||
api?: AxiosInstance
|
api: AxiosInstance
|
||||||
) => Promise<{ [key: string]: any }>
|
) => Promise<{ [key: string]: any }>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,9 +56,9 @@ export const authenticationFromServerSide = (
|
|||||||
} else {
|
} else {
|
||||||
let data = {}
|
let data = {}
|
||||||
if (fetchData != null) {
|
if (fetchData != null) {
|
||||||
data = await fetchData(context)
|
data = await fetchData(context, api)
|
||||||
}
|
}
|
||||||
return { props: { ...data } }
|
return { props: data }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (tokens == null) {
|
if (tokens == null) {
|
||||||
@ -69,20 +69,26 @@ export const authenticationFromServerSide = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let data: Redirect | any = {}
|
try {
|
||||||
const authentication = new Authentication(tokens)
|
let data: any = {}
|
||||||
const { data: currentUser } = await authentication.api.get<
|
const authentication = new Authentication(tokens)
|
||||||
unknown,
|
const { data: currentUser } = await authentication.api.get<
|
||||||
AxiosResponse<UserCurrent>
|
unknown,
|
||||||
>('/users/current')
|
AxiosResponse<UserCurrent>
|
||||||
if (fetchData != null) {
|
>('/users/current')
|
||||||
data = await fetchData(context, authentication.api)
|
if (fetchData != null) {
|
||||||
}
|
data = await fetchData(context, authentication.api)
|
||||||
if (data.redirect != null) {
|
}
|
||||||
return data
|
return {
|
||||||
}
|
props: { authentication: { tokens, ...currentUser }, ...data }
|
||||||
return {
|
}
|
||||||
props: { authentication: { tokens, ...currentUser }, ...data }
|
} catch {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
destination: '/404',
|
||||||
|
permanent: false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user