Skip to content

Commit

Permalink
Merge pull request #244 from kakao-tech-campus-2nd-step3/Week11
Browse files Browse the repository at this point in the history
Week11 3
  • Loading branch information
ppochaco authored Nov 13, 2024
2 parents eca3b5a + c7fa7dd commit e43870f
Show file tree
Hide file tree
Showing 25 changed files with 379 additions and 96 deletions.
6 changes: 5 additions & 1 deletion public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 22 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
import { ChakraProvider } from '@chakra-ui/react'
import { useEffect } from 'react'

import { ChakraProvider, useToast } from '@chakra-ui/react'
import { QueryClientProvider } from '@tanstack/react-query'

import { queryClient } from '@/api/instance'
import { Routes } from '@/routes'
import theme from '@/styles/theme'

import { CookieAlaram } from './components/CookieAlaram'
import { useSSEMessage } from './hooks/useSSEMessage'

function App() {
const { message } = useSSEMessage()
const toast = useToast()

useEffect(() => {
if (message) {
toast.closeAll()
toast({
position: 'top',
duration: 3000,
render: () => (
<CookieAlaram message={message} onClickCloseButton={toast.closeAll} />
),
})
}
}, [message, toast])

return (
<QueryClientProvider client={queryClient}>
<ChakraProvider theme={theme}>
Expand Down
32 changes: 32 additions & 0 deletions src/api/services/admin/admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { queryOptions } from '@tanstack/react-query'

import { authorizationInstance } from '@/api/instance'
import { appendParamsToUrl } from '@/api/utils/common/appendParamsToUrl'
import { AdminQuestion, PagingRequestParams } from '@/types'

type GetAdminQuestionsResponse = {
content: AdminQuestion[]
totalPages?: number
totalElements?: number
}

const getAdminQuestions = async (params: PagingRequestParams) => {
const response = await authorizationInstance.get<GetAdminQuestionsResponse>(
appendParamsToUrl('api/admin/question', params)
)

return {
questions: response.data.content,
totalPages: response.data.totalPages,
totalElements: response.data.totalElements,
}
}

export const getAdminQuestionsQuries = {
all: () => ['getAdminQuestions'],
adminQuestions: (page?: number, size?: number) =>
queryOptions({
queryKey: [...getAdminQuestionsQuries.all(), page, size],
queryFn: () => getAdminQuestions({ page: String(page), size: 8 }),
}),
}
22 changes: 22 additions & 0 deletions src/components/PageLayout/SideNavigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,31 @@ import { useUserInfoStore } from '@/stores/user-info'

export const SideNavigation = () => {
const clearAuthToken = useAuthTokenStore((state) => state.clearAuthToken)
const isLoggedIn = useAuthTokenStore((state) => state.isLoggedIn())

const clearUserInfo = useUserInfoStore((state) => state.clearUserInfo)
const userId = useUserInfoStore((state) => state.userInfo?.userId)

if (!isLoggedIn) {
return (
<Flex
background="brown.300"
width="40px"
height="full"
flexDirection="column"
alignItems="center"
justifyContent="end"
paddingY={6}
color="brown.400"
gap={2}
>
<BiLogOut size={26} />
<BiBell size={26} />
<BiUserCircle size={26} />
</Flex>
)
}

return (
<Flex
background="brown.300"
Expand Down
7 changes: 5 additions & 2 deletions src/hooks/useSEEMessage.ts → src/hooks/useSSEMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import { EventSourcePolyfill } from 'event-source-polyfill'
import { authorizationInstance } from '@/api/instance'
import { useAuthTokenStore } from '@/stores/auth-token'

export function useSEEMessage() {
export function useSSEMessage() {
const [message, setMessage] = useState('')
const { authToken } = useAuthTokenStore.getState()
const isLoggedIn = useAuthTokenStore.getState().isLoggedIn()

useEffect(() => {
if (!isLoggedIn) return () => {}

const eventSource = new EventSourcePolyfill(
`${import.meta.env.VITE_BASE_URL}/api/alarm`,
{
Expand All @@ -27,7 +30,7 @@ export function useSEEMessage() {
authorizationInstance.post('/api/alarm/disconnect', {})
eventSource.close()
}
}, [authToken])
}, [authToken, isLoggedIn])

return { message }
}
64 changes: 64 additions & 0 deletions src/pages/Admin/GetQuestionAdminPage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Box, Flex, Text } from '@chakra-ui/react'
import { useQuery } from '@tanstack/react-query'

import { getAdminQuestionsQuries } from '@/api/services/admin/admin'
import { Loading } from '@/components/Loading'
import ErrorPage from '@/pages/ErrorPage'

export default function GetQuestionAdminPage() {
const {
data: questions,
status,
isLoading,
isError,
} = useQuery(getAdminQuestionsQuries.adminQuestions(0, 10))

if (status === 'pending' || isLoading) return <Loading />
if (isError) return <ErrorPage />
if (!questions) return '질문 아무것도 없음'

const questionsList = questions.questions
const totalElements = questions?.totalElements
const totalPages = questions?.totalPages

return (
<Flex width="100%" justifyContent="center" margin="40px auto">
<Box textAlign="center" width="100%" padding="0 50px">
<Text fontWeight={600} fontSize="x-large" marginBottom={10}>
질문 리스트
</Text>
<Flex flexDirection="column" gap={2}>
<Flex
borderBottom="1px solid"
borderColor="brown.700"
paddingBottom={2}
>
<Box width="80px">questionId</Box>
<Box width="80px">groupId</Box>
<Box width={400}>questionContent</Box>
<Box width={200}>createdAt</Box>
<Box width={100} color="orange.700">
status
</Box>
</Flex>
{questionsList.map((question, idx) => (
<Flex
key={question.questionId}
borderBottom={idx === 7 ? '' : '1px solid'}
borderColor="brown.500"
paddingBottom={2}
>
<Box width="80px">{question.questionId}</Box>
<Box width="80px">{question.groupId}</Box>
<Box width={400}>{question.questionContent}</Box>
<Box width={200}>{question.createdAt}</Box>
<Box width={100} color="orange.700">
{question.status}
</Box>
</Flex>
))}
</Flex>
</Box>
</Flex>
)
}
59 changes: 59 additions & 0 deletions src/pages/Admin/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useNavigate } from 'react-router-dom'

import { Box, Button, Flex, Image, Text } from '@chakra-ui/react'
import { useQuery } from '@tanstack/react-query'

import { getAdminQuestionsQuries } from '@/api/services/admin/admin'
import cookies from '@/assets/cookies.svg'
import { Loading } from '@/components/Loading'

import ErrorPage from '../ErrorPage'

export default function Admin() {
const { data, status, isLoading, isError } = useQuery(
getAdminQuestionsQuries.adminQuestions(0, 10)
)

const navigate = useNavigate()

if (status === 'pending' || isLoading) return <Loading />
if (isError) return <ErrorPage />

console.log(data)

return (
<Flex
width="full"
margin="auto 30%"
flexDirection="column"
justifyContent="center"
alignContent="center"
>
<Image margin="20px 60px" src={cookies} />
<Box textAlign="center">
<Text fontWeight={700} fontSize="xx-large" marginBottom={18}>
Whokie 관리자 페이지
</Text>
</Box>
<Flex margin="0 20px" flexDirection="column" gap={3}>
<Button
bg="primary"
color="white"
_hover={{ bg: 'orange.500' }}
onClick={() => navigate('/admin/get/questions')}
>
질문 보기
</Button>
<Button bg="brown.500" color="white" _hover={{ bg: 'brown.600' }}>
질문 만들기
</Button>
<Button bg="primary" color="white" _hover={{ bg: 'orange.500' }}>
관리자 리스트
</Button>
<Button bg="brown.500" color="white" _hover={{ bg: 'brown.600' }}>
그룹 리스트
</Button>
</Flex>
</Flex>
)
}
2 changes: 2 additions & 0 deletions src/pages/GroupMembersPage/ExpelBtn/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export default function ExpelBtn({
mutationFn: () => expelMember({ groupId, userId }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['expelMember'] })
queryClient.invalidateQueries({ queryKey: ['group', 'member', groupId] })
queryClient.invalidateQueries({ queryKey: ['membersManage', groupId] })
window.location.reload()
},
onError: () => {
Expand Down
5 changes: 5 additions & 0 deletions src/pages/GroupPage/ExitGroupButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ConfirmModalButton,
} from '@/components/Modal/ConfirmModal'
import { useMembersLengthStore } from '@/stores/members-length'
import { useSelectedGroupStore } from '@/stores/selected-group'
import { GroupRole } from '@/types'

interface ExitGroupButtonProps {
Expand All @@ -28,11 +29,15 @@ export const ExitGroupButton = ({
const warningAlert = useDisclosure()
const errorAlert = useDisclosure()
const navigate = useNavigate()
const setSelectedGroup = useSelectedGroupStore(
(state) => state.setSelectedGroup
)

const { mutate: exitGroup } = useMutation({
mutationFn: () => exitGroupMember(groupId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['groups'] })
setSelectedGroup(undefined)
navigate('/')
},
})
Expand Down
22 changes: 20 additions & 2 deletions src/pages/GroupPage/GroupProfile/ImgModify/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeEvent, useState } from 'react'
import { ChangeEvent, useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { BiError } from 'react-icons/bi'

Expand Down Expand Up @@ -33,14 +33,32 @@ export default function ImgModify({ role, gprofile }: ImgModifyProps) {

const [errorMessage, setErrorMessage] = useState('')
const errorModal = useDisclosure()
const [timeoutId, setTimeoutId] = useState<number | null>(null)

const { mutate: uploadImage } = useMutation({
mutationFn: (data: ModifyGroupImgRequestBody) => modifyGroupImg(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['group', gprofile.groupId] })
if (timeoutId) {
clearTimeout(timeoutId)
}

const newTimeoutId = setTimeout(() => {
queryClient.invalidateQueries({ queryKey: ['group', gprofile.groupId] })
queryClient.invalidateQueries({ queryKey: ['groups'] })
}, 2000)

setTimeoutId(newTimeoutId)
},
})

useEffect(() => {
return () => {
if (timeoutId) {
clearTimeout(timeoutId)
}
}
}, [timeoutId])

const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files ? e.target.files[0] : null

Expand Down
5 changes: 5 additions & 0 deletions src/pages/GroupPage/Management/CreateQuestion/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Box, Flex, useDisclosure } from '@chakra-ui/react'
import { zodResolver } from '@hookform/resolvers/zod'
import { useMutation } from '@tanstack/react-query'

import { queryClient } from '@/api/instance'
import {
CreateGroupQuestionPayload,
createGroupQuestion,
Expand Down Expand Up @@ -44,6 +45,10 @@ export const GroupQuestionCreateModal = ({
createGroupQuestion(payload),
onSuccess: () => {
onClose()
form.reset({ groupId, content: '' })
queryClient.invalidateQueries({
queryKey: ['groupQuestions', groupId, 'pending'],
})
},
onError: () => {
setErrorMessage('질문 생성에 실패하였습니다')
Expand Down
9 changes: 7 additions & 2 deletions src/pages/GroupPage/Management/Questions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useParams } from 'react-router-dom'
import { Box, Text } from '@chakra-ui/react'
import { useMutation } from '@tanstack/react-query'

import { queryClient } from '@/api/instance'
import { approveGroupQuestion } from '@/api/services/group/group.api'
import { useGroupRole } from '@/api/services/group/member.api'
import { useGroupQuestion } from '@/api/services/question/group.api'
Expand All @@ -24,7 +25,6 @@ export const QuestionManagement = () => {
data: groupQuestions,
isLoading,
isError,
refetch,
} = useGroupQuestion({
groupId: groupId || '',
status,
Expand All @@ -37,7 +37,12 @@ export const QuestionManagement = () => {
return approveGroupQuestion(String(groupId), questionId, approve)
},
onSuccess: () => {
refetch()
queryClient.invalidateQueries({
queryKey: ['groupQuestions', groupId, status],
})
queryClient.invalidateQueries({
queryKey: ['question', 'common', 'random', 'group', groupId],
})
},
})

Expand Down
Loading

0 comments on commit e43870f

Please sign in to comment.