diff --git a/frontend/src/apis/balanceContent.ts b/frontend/src/apis/balanceContent.ts index a494600ac..04c0c72c1 100644 --- a/frontend/src/apis/balanceContent.ts +++ b/frontend/src/apis/balanceContent.ts @@ -87,7 +87,7 @@ export const checkMyGameStatus = async ({ // 다음 라운드로 이동하기 export const moveNextRound = async (roomId: number) => { - const res = await fetcher.patch({ + await fetcher.patch({ url: API_URL.moveNextRound(roomId), headers: { 'Content-Type': `application/json`, diff --git a/frontend/src/apis/fetcher.ts b/frontend/src/apis/fetcher.ts index 1d5423b59..fea16a575 100644 --- a/frontend/src/apis/fetcher.ts +++ b/frontend/src/apis/fetcher.ts @@ -16,6 +16,7 @@ const fetcher = { method, body: body && JSON.stringify(body), headers: headers && headers, + credentials: 'include', }); if (!response.ok) { diff --git a/frontend/src/apis/room.ts b/frontend/src/apis/room.ts index 214c3621e..0a904770d 100644 --- a/frontend/src/apis/room.ts +++ b/frontend/src/apis/room.ts @@ -1,7 +1,13 @@ import fetcher from './fetcher'; import { API_URL } from '@/constants/url'; -import { RoomInfo, CreateOrEnterRoomResponse, Category, RoomSettingApply } from '@/types/room'; +import { + RoomInfo, + CreateOrEnterRoomResponse, + Category, + RoomSettingApply, + RoomAndMember, +} from '@/types/room'; interface CategoryResponse { categories: Category[]; @@ -136,3 +142,12 @@ export const isJoinableRoom = async (roomUuid: string): Promise<{ isJoinable: bo return data; }; + +// 사용자 정보 조회 +export const getUserInfo = async (): Promise => { + const res = await fetcher.get({ + url: API_URL.getUserInfo, + }); + const data = await res.json(); + return data; +}; diff --git a/frontend/src/components/GameResult/GameResult.hook.ts b/frontend/src/components/GameResult/GameResult.hook.ts index ca8f4a063..c702fe132 100644 --- a/frontend/src/components/GameResult/GameResult.hook.ts +++ b/frontend/src/components/GameResult/GameResult.hook.ts @@ -1,11 +1,10 @@ import { useMutation, useQuery, UseQueryResult } from '@tanstack/react-query'; import { useParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { fetchMatchingResult } from '@/apis/balanceContent'; import { resetRoom } from '@/apis/room'; import { QUERY_KEYS } from '@/constants/queryKeys'; -import { memberInfoState } from '@/recoil/atom'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; import { MatchingResult, MemberMatchingInfo } from '@/types/balanceContent'; type MatchingResultQueryResponse = UseQueryResult & { @@ -15,15 +14,17 @@ type MatchingResultQueryResponse = UseQueryResult & { export const useMatchingResultQuery = (): MatchingResultQueryResponse => { const { roomId } = useParams(); - const memberInfo = useRecoilValue(memberInfoState); + const { + member: { memberId }, + } = useGetUserInfo(); const matchingResultQuery = useQuery({ - queryKey: [QUERY_KEYS.matchingResult, roomId, memberInfo.memberId], + queryKey: [QUERY_KEYS.matchingResult, roomId, memberId], queryFn: async () => { - if (!memberInfo.memberId) { + if (!memberId) { throw new Error('Member ID is required'); } - return await fetchMatchingResult({ roomId: Number(roomId), memberId: memberInfo.memberId }); + return await fetchMatchingResult({ roomId: Number(roomId), memberId: memberId }); }, }); diff --git a/frontend/src/components/NicknameItem/NicknameItem.tsx b/frontend/src/components/NicknameItem/NicknameItem.tsx index a432afd66..6c90eeddb 100644 --- a/frontend/src/components/NicknameItem/NicknameItem.tsx +++ b/frontend/src/components/NicknameItem/NicknameItem.tsx @@ -1,17 +1,15 @@ -import { useRecoilValue } from 'recoil'; - import { nicknameItemLayout, nicknameText, profileImage } from './NicknameItem.styled'; import SillyDdangkongMedium from '@/assets/images/sillyDdangkongMedium.webp'; -import { memberInfoState } from '@/recoil/atom'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; interface NicknameItemProp { nickName: string; } const NicknameItem = ({ nickName }: NicknameItemProp) => { - const memberInfo = useRecoilValue(memberInfoState); - const isMyNickname = memberInfo.nickname === nickName; + const { member } = useGetUserInfo(); + const isMyNickname = member.nickname === nickName; return (
  • diff --git a/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx b/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx index 965f41eeb..efa9e4376 100644 --- a/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx +++ b/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx @@ -1,5 +1,5 @@ +import { useQueryClient } from '@tanstack/react-query'; import { useEffect, useRef } from 'react'; -import { useRecoilState } from 'recoil'; import { readyMembersContainerLayout, @@ -17,14 +17,14 @@ import A11yOnly from '../common/a11yOnly/A11yOnly'; import crownIcon from '@/assets/images/crownIcon.webp'; import SillyDdangkongMedium from '@/assets/images/sillyDdangkongMedium.webp'; import InviteModal from '@/components/common/InviteModal/InviteModal'; +import { QUERY_KEYS } from '@/constants/queryKeys'; import { useGetRoomInfo } from '@/hooks/useGetRoomInfo'; import useModal from '@/hooks/useModal'; -import { memberInfoState } from '@/recoil/atom'; const ReadyMembersContainer = () => { const { members, master } = useGetRoomInfo(); const { show } = useModal(); - const [memberInfo, setMemberInfo] = useRecoilState(memberInfoState); + const queryClient = useQueryClient(); const returnFocusRef = useRef(null); const memberCountMessage = `총 인원 ${members.length}명`; @@ -32,12 +32,9 @@ const ReadyMembersContainer = () => { show(InviteModal, { returnFocusRef }); }; - // 원래 방장이 아니다 + 방장의 memberId와 내 memberId가 같다 -> 방장으로 변경 useEffect(() => { - if (!memberInfo.isMaster && master.memberId === memberInfo.memberId) { - setMemberInfo({ ...memberInfo, isMaster: true }); - } - }, [master.memberId, memberInfo, setMemberInfo]); + queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.getUserInfo] }); + }, [master.memberId]); return (
    diff --git a/frontend/src/components/RoomSetting/RoomSetting.styled.ts b/frontend/src/components/RoomSetting/RoomSetting.styled.ts index 5260d5261..fc6e4744c 100644 --- a/frontend/src/components/RoomSetting/RoomSetting.styled.ts +++ b/frontend/src/components/RoomSetting/RoomSetting.styled.ts @@ -5,6 +5,7 @@ import getBorderRadius from '@/styles/utils/getBorderRadius'; export const roomSettingLayout = css` display: flex; + flex-direction: column; justify-content: space-evenly; align-items: center; width: 100%; @@ -16,22 +17,35 @@ export const roomSettingLayout = css` cursor: pointer; `; -export const roomSettingBox = css` - display: flex; - flex-direction: column; - gap: 1rem; -`; - export const bigTitle = css` + width: 10rem; + font-weight: 800; font-size: 2.8rem; `; export const smallTitle = css` + width: 10rem; + font-weight: 800; font-size: 2rem; `; -export const roomSettingLabel = css` +export const roomSettingKey = css` + width: 10rem; +`; + +export const roomSettingKeyBox = css` + display: flex; + justify-content: space-between; + width: 50rem; + font-weight: 600; `; + +export const roomSettingValueBox = css` + display: flex; + justify-content: space-between; + align-items: center; + width: 50rem; +`; diff --git a/frontend/src/components/RoomSetting/RoomSetting.test.tsx b/frontend/src/components/RoomSetting/RoomSetting.test.tsx index d687a7cb1..3d27f1fab 100644 --- a/frontend/src/components/RoomSetting/RoomSetting.test.tsx +++ b/frontend/src/components/RoomSetting/RoomSetting.test.tsx @@ -1,20 +1,18 @@ import { screen, waitFor } from '@testing-library/react'; import { userEvent } from '@testing-library/user-event'; -import type { MutableSnapshot } from 'recoil'; +import { http, HttpResponse } from 'msw'; import RoomSetting from './RoomSetting'; -import { memberInfoState } from '@/recoil/atom'; +import { MOCK_API_URL } from '@/constants/url'; +import { server } from '@/mocks/server'; import { customRender } from '@/utils/test-utils'; describe('RoomSetting 컴포넌트 테스트', () => { it('방장이 RoomSetting를 누르면 설정 modal이 뜬다', async () => { // Given - const initializeState = (snap: MutableSnapshot) => { - snap.set(memberInfoState, { memberId: 1, nickname: 'Test User', isMaster: true }); - }; const user = userEvent.setup(); - customRender(, { initializeState }); + customRender(); const settingButton = await screen.findByRole('button', { name: '방 설정' }); // When @@ -29,11 +27,20 @@ describe('RoomSetting 컴포넌트 테스트', () => { it('방장이 아닌 사람이 RoomSetting를 누르면 설정 modal이 뜨지 않는다', async () => { // Given - const initializeState = (snap: MutableSnapshot) => { - snap.set(memberInfoState, { memberId: 1, nickname: 'Test User', isMaster: false }); - }; + server.use( + http.get(MOCK_API_URL.getUserInfo, async () => { + return HttpResponse.json( + { + member: { + isMaster: false, + }, + }, + { status: 400 }, + ); + }), + ); const user = userEvent.setup(); - customRender(, { initializeState }); + customRender(); const optionButton = await screen.findByRole('button', { name: '방 설정' }); // When diff --git a/frontend/src/components/RoomSetting/RoomSetting.tsx b/frontend/src/components/RoomSetting/RoomSetting.tsx index 96419bda6..d6a5c91ab 100644 --- a/frontend/src/components/RoomSetting/RoomSetting.tsx +++ b/frontend/src/components/RoomSetting/RoomSetting.tsx @@ -1,24 +1,26 @@ import { useRef } from 'react'; -import { useRecoilValue } from 'recoil'; import { roomSettingLayout, bigTitle, smallTitle, - roomSettingLabel, - roomSettingBox, + roomSettingKeyBox, + roomSettingValueBox, + roomSettingKey, } from './RoomSetting.styled'; import A11yOnly from '@/components/common/a11yOnly/A11yOnly'; import RoomSettingModal from '@/components/common/RoomSettingModal/RoomSettingModal'; import { useGetRoomInfo } from '@/hooks/useGetRoomInfo'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; import useModal from '@/hooks/useModal'; -import { memberInfoState } from '@/recoil/atom'; const RoomSetting = () => { const returnFocusRef = useRef(null); const { roomSetting } = useGetRoomInfo(); - const { isMaster } = useRecoilValue(memberInfoState); + const { + member: { isMaster }, + } = useGetUserInfo(); const { show } = useModal(); const screenReaderRoomSetting = ` 방 정보. @@ -39,16 +41,14 @@ const RoomSetting = () => { onClick={isMaster ? handleClickCategory : () => {}} ref={returnFocusRef} > -
    - 라운드 -

    {roomSetting.totalRound}

    +
    + 라운드 + 카테고리 + 제한 시간
    -
    - 카테고리 +
    +

    {roomSetting.totalRound}

    {roomSetting.category.label}

    -
    -
    - 제한 시간

    {roomSetting.timeLimit / 1000}초

    diff --git a/frontend/src/components/StartButtonContainer/StartButton/StartButton.test.tsx b/frontend/src/components/StartButtonContainer/StartButton/StartButton.test.tsx index 723ca81c5..c0a008b20 100644 --- a/frontend/src/components/StartButtonContainer/StartButton/StartButton.test.tsx +++ b/frontend/src/components/StartButtonContainer/StartButton/StartButton.test.tsx @@ -7,7 +7,7 @@ import StartButton from './StartButton'; import { ERROR_MESSAGE } from '@/constants/message'; import { MOCK_API_URL } from '@/constants/url'; import { server } from '@/mocks/server'; -import { customRenderWithIsMaster } from '@/utils/test-utils'; +import { customRenderWithMaster } from '@/utils/test-utils'; describe('StartButton 테스트', () => { it('시작 버튼을 클릭했을 때, 게임 시작 API에서 에러가 발생하면 알림 모달이 뜬다.', async () => { @@ -24,7 +24,7 @@ describe('StartButton 테스트', () => { }), ); - customRenderWithIsMaster(, true); + customRenderWithMaster(); const startButton = await screen.findByRole('button', { name: '시작' }); await user.click(startButton); diff --git a/frontend/src/components/StartButtonContainer/StartButton/StartButton.tsx b/frontend/src/components/StartButtonContainer/StartButton/StartButton.tsx index 90f9a3bfb..8bb25ae35 100644 --- a/frontend/src/components/StartButtonContainer/StartButton/StartButton.tsx +++ b/frontend/src/components/StartButtonContainer/StartButton/StartButton.tsx @@ -4,12 +4,12 @@ import getStartButtonText from './StartButton.utils'; import Button from '@/components/common/Button/Button'; const StartButton = () => { - const { memberInfo, handleGameStart, isPending, isSuccess } = useGameStart(); + const { isMaster, handleGameStart, isPending, isSuccess } = useGameStart(); return (
    ); diff --git a/frontend/src/components/common/InviteModal/InviteModal.tsx b/frontend/src/components/common/InviteModal/InviteModal.tsx index 83ecb0ec0..881af1e2f 100644 --- a/frontend/src/components/common/InviteModal/InviteModal.tsx +++ b/frontend/src/components/common/InviteModal/InviteModal.tsx @@ -1,6 +1,5 @@ import { RefObject } from 'react'; import QRCode from 'react-qr-code'; -import { useRecoilValue } from 'recoil'; import { inviteModalLi, @@ -18,8 +17,8 @@ import Modal from '../Modal/Modal'; import CopyIcon from '@/assets/images/copyIcon.png'; import { INVITE_URL } from '@/constants/url'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; import useToast from '@/hooks/useToast'; -import { roomUuidState } from '@/recoil/atom'; interface InviteModalProps { isOpen: boolean; @@ -28,7 +27,7 @@ interface InviteModalProps { } const InviteModal = ({ isOpen, onClose, returnFocusRef }: InviteModalProps) => { - const roomUuid = useRecoilValue(roomUuidState); + const { roomUuid } = useGetUserInfo(); const inviteUrl = INVITE_URL(roomUuid); const { copyToClipboard } = useClipBoard(); diff --git a/frontend/src/components/common/NextRoundButton/NextRoundButton.test.tsx b/frontend/src/components/common/NextRoundButton/NextRoundButton.test.tsx index e095c1811..66cd78603 100644 --- a/frontend/src/components/common/NextRoundButton/NextRoundButton.test.tsx +++ b/frontend/src/components/common/NextRoundButton/NextRoundButton.test.tsx @@ -3,11 +3,11 @@ import { userEvent } from '@testing-library/user-event'; import NextRoundButton from './NextRoundButton'; -import { customRenderWithIsMaster } from '@/test-utils'; +import { customRenderWithMaster, customRenderWithNotMaster } from '@/test-utils'; describe('NextRoundButton 컴포넌트 테스트', () => { it('방장은 활성화 되어 있는 "다음" 버튼이 화면에 보인다.', async () => { - customRenderWithIsMaster(, true); + customRenderWithMaster(); const button = await screen.findByRole('button', { name: '다음' }); @@ -15,7 +15,7 @@ describe('NextRoundButton 컴포넌트 테스트', () => { }); it('방장이 아닌 참여자는 비활성화 되어 있는 "방장이 진행해 주세요" 버튼이 화면에 보인다.', async () => { - customRenderWithIsMaster(, false); + customRenderWithNotMaster(); const button = await screen.findByRole('button', { name: '방장이 진행해 주세요' }); @@ -23,7 +23,7 @@ describe('NextRoundButton 컴포넌트 테스트', () => { }); it('방장이 "다음" 버튼을 클릭하면 안내 모달이 열린다.', async () => { - customRenderWithIsMaster(, true); + customRenderWithMaster(); const button = await screen.findByRole('button', { name: '다음' }); await userEvent.click(button); diff --git a/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx b/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx index 852af2149..98f467b53 100644 --- a/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx +++ b/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx @@ -1,6 +1,5 @@ import { useRef } from 'react'; import { useParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import useMoveNextRoundMutation from './NextRoundButton.hook'; import { createRandomNextRoundMessage, getNextRoundButtonText } from './NextRoundButton.utils'; @@ -9,14 +8,16 @@ import Button from '../Button/Button'; import { bottomButtonLayout } from '../Button/Button.styled'; import useBalanceContentQuery from '@/hooks/useBalanceContentQuery'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; import useModal from '@/hooks/useModal'; -import { memberInfoState } from '@/recoil/atom'; const NextRoundButton = () => { const { roomId } = useParams(); const { balanceContent } = useBalanceContentQuery(Number(roomId)); const { mutate: moveNextRound, isPending, isSuccess } = useMoveNextRoundMutation(Number(roomId)); - const memberInfo = useRecoilValue(memberInfoState); + const { + member: { isMaster }, + } = useGetUserInfo(); const { show } = useModal(); const returnFocusRef = useRef(null); @@ -33,9 +34,9 @@ const NextRoundButton = () => {
    ); diff --git a/frontend/src/components/common/SelectButton/SelectButton.hook.ts b/frontend/src/components/common/SelectButton/SelectButton.hook.ts index fd56fae73..cb53e7149 100644 --- a/frontend/src/components/common/SelectButton/SelectButton.hook.ts +++ b/frontend/src/components/common/SelectButton/SelectButton.hook.ts @@ -1,9 +1,8 @@ import { useMutation } from '@tanstack/react-query'; import { useParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { voteBalanceContent } from '@/apis/balanceContent'; -import { memberInfoState } from '@/recoil/atom'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; interface UseSelectCompleteMutationProps { selectedId: number; @@ -17,19 +16,20 @@ const useCompleteSelectionMutation = ({ completeSelection, }: UseSelectCompleteMutationProps) => { const { roomId } = useParams(); - const memberInfo = useRecoilValue(memberInfoState); + const { + member: { memberId }, + } = useGetUserInfo(); return useMutation({ mutationFn: async () => { if (typeof contentId === 'undefined') { throw new Error('contentId 가 존재하지 않습니다.'); } - return await voteBalanceContent({ roomId: Number(roomId), optionId: selectedId, contentId, - memberId: Number(memberInfo.memberId), + memberId: Number(memberId), }); }, onSuccess: () => { diff --git a/frontend/src/components/common/Spinner/Spinner.styled.ts b/frontend/src/components/common/Spinner/Spinner.styled.ts index f0aa7f5d5..8a6bbdc62 100644 --- a/frontend/src/components/common/Spinner/Spinner.styled.ts +++ b/frontend/src/components/common/Spinner/Spinner.styled.ts @@ -11,7 +11,7 @@ export const spinnerWrapper = css` export const rotatingImage = (size: number) => css` width: ${size}rem; - height: 18rem; + height: ${size * 2}rem; animation: spin 2s linear infinite; /* 2초 동안 한 바퀴 회전하는 애니메이션 */ diff --git a/frontend/src/components/layout/Header/Header.test.tsx b/frontend/src/components/layout/Header/Header.test.tsx index 249f2c986..1035e7520 100644 --- a/frontend/src/components/layout/Header/Header.test.tsx +++ b/frontend/src/components/layout/Header/Header.test.tsx @@ -3,12 +3,12 @@ import { userEvent } from '@testing-library/user-event'; import { RoomSettingHeader } from './Header'; -import { customRenderWithIsMaster } from '@/utils/test-utils'; +import { customRenderWithMaster } from '@/utils/test-utils'; describe('Header 테스트', () => { - it('방 설정 버튼을 클릭했을 때, 방 설정 모달이 뜬다.', async () => { + it('방장이 방 설정 버튼을 클릭했을 때, 방 설정 모달이 뜬다.', async () => { const user = userEvent.setup(); - customRenderWithIsMaster(, true); + customRenderWithMaster(); const roomSettingButton = await screen.findByAltText('방 설정'); await user.click(roomSettingButton); diff --git a/frontend/src/components/layout/Header/Header.tsx b/frontend/src/components/layout/Header/Header.tsx index 5860374ac..288060272 100644 --- a/frontend/src/components/layout/Header/Header.tsx +++ b/frontend/src/components/layout/Header/Header.tsx @@ -1,7 +1,6 @@ /* eslint-disable jsx-a11y/no-noninteractive-tabindex */ import { useRef } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { buttonWrapper, @@ -26,8 +25,8 @@ import RoomSettingModal from '@/components/common/RoomSettingModal/RoomSettingMo import { convertMsecToSecond } from '@/components/SelectContainer/Timer/Timer.util'; import useBalanceContentQuery from '@/hooks/useBalanceContentQuery'; import useFocus from '@/hooks/useFocus'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; import useModal from '@/hooks/useModal'; -import { memberInfoState } from '@/recoil/atom'; interface HeaderProps { title: string; @@ -67,7 +66,10 @@ export const TitleHeader = ({ title }: HeaderProps) => ( // 3. 가운데 제목, 우측 상단 차지하는 헤더 : 게임 대기 화면 export const RoomSettingHeader = ({ title }: HeaderProps) => { const { show } = useModal(); - const { isMaster } = useRecoilValue(memberInfoState); + const { + member: { isMaster }, + } = useGetUserInfo(); + const { handleExit } = useExit(); const returnFocusRef = useRef(null); const focusRef = useFocus(); diff --git a/frontend/src/components/layout/Header/hooks/useExit.ts b/frontend/src/components/layout/Header/hooks/useExit.ts index 2f0e1e014..36d7fe1f2 100644 --- a/frontend/src/components/layout/Header/hooks/useExit.ts +++ b/frontend/src/components/layout/Header/hooks/useExit.ts @@ -1,18 +1,19 @@ import { useMutation } from '@tanstack/react-query'; import { useNavigate, useParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { exitRoom } from '@/apis/room'; -import { memberInfoState } from '@/recoil/atom'; +import useGetUserInfo from '@/hooks/useGetUserInfo'; +import { deleteAllCookies } from '@/utils/cookie'; export const useExit = () => { - const { memberId } = useRecoilValue(memberInfoState); + const { member: memberId } = useGetUserInfo(); const navigate = useNavigate(); const { roomId } = useParams(); const exitRoomMutation = useMutation({ mutationFn: ({ roomId, memberId }) => exitRoom(roomId, memberId), - onSuccess: () => { + onSettled: () => { + deleteAllCookies(); navigate('/'); }, }); diff --git a/frontend/src/constants/queryKeys.ts b/frontend/src/constants/queryKeys.ts index c496271ee..fe05a9204 100644 --- a/frontend/src/constants/queryKeys.ts +++ b/frontend/src/constants/queryKeys.ts @@ -7,4 +7,5 @@ export const QUERY_KEYS = { roomMembers: 'roomMembers', isRoomInitial: 'isRoomInitial', categoryList: 'categoryList', + getUserInfo: 'getUserInfo', } as const; diff --git a/frontend/src/constants/url.ts b/frontend/src/constants/url.ts index 6aa537e6d..6b7946020 100644 --- a/frontend/src/constants/url.ts +++ b/frontend/src/constants/url.ts @@ -1,3 +1,5 @@ +import { getUserInfo } from '@/apis/room'; + const BASE_URL = process.env.API_BASE_URL; export const API_URL = { @@ -25,11 +27,14 @@ export const API_URL = { deleteRoom: (roomId: number, memberId: number) => `${BASE_URL}/api/balances/rooms/${roomId}/members/${memberId}`, isJoinableRoom: (roomUuid: string) => `${BASE_URL}/api/balances/rooms/${roomUuid}/status`, + getUserInfo: `${BASE_URL}/api/balances/rooms/member`, }; type API_URL_KEYS = keyof typeof API_URL; export const MOCK_API_URL: Record = { + getUserInfo: `${BASE_URL}/api/balances/rooms/member`, + getRoomInfo: `${BASE_URL}/api/balances/rooms/:roomId`, balanceContent: `${BASE_URL}/api/balances/rooms/:roomId/content`, vote: `${BASE_URL}/api/balances/rooms/:roomId/contents/:contentId/votes`, roundVoteResult: `${BASE_URL}/api/balances/rooms/:roomId/contents/:contentId/vote-result`, @@ -38,7 +43,6 @@ export const MOCK_API_URL: Record = { matchingResult: `${BASE_URL}/api/balances/rooms/:roomId/members/:memberId/matching`, room: `${BASE_URL}/api/balances/rooms`, enterRoom: `${BASE_URL}/api/balances/rooms/:roomUuid/members`, - getRoomInfo: `${BASE_URL}/api/balances/rooms/:roomId`, startGame: `${BASE_URL}/api/balances/rooms/:roomId/start`, voteIsFinished: `${BASE_URL}/api/balances/rooms/:roomId/contents/:contentId/vote-finished`, resetRoom: `${BASE_URL}/api/balances/rooms/:roomId/reset`, diff --git a/frontend/src/hooks/useGetUserInfo.ts b/frontend/src/hooks/useGetUserInfo.ts new file mode 100644 index 000000000..ea21e3152 --- /dev/null +++ b/frontend/src/hooks/useGetUserInfo.ts @@ -0,0 +1,27 @@ +import { useQuery } from '@tanstack/react-query'; + +import { getUserInfo } from '@/apis/room'; +import { QUERY_KEYS } from '@/constants/queryKeys'; +import { RoomAndMember } from '@/types/room'; + +const USER_INFO_STALE_TIME = 2 * 60 * 60 * 1000; + +const useGetUserInfo = (): RoomAndMember => { + const { data } = useQuery({ + queryKey: [QUERY_KEYS.getUserInfo], + queryFn: getUserInfo, + staleTime: USER_INFO_STALE_TIME, + }); + + return { + roomId: data?.roomId || 0, + roomUuid: data?.roomUuid || '', + member: { + memberId: data?.member?.memberId || 0, + nickname: data?.member?.nickname || '', + isMaster: data?.member?.isMaster || false, + }, + }; +}; + +export default useGetUserInfo; diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 7ba7c7146..f0df24c56 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -38,7 +38,13 @@ enableMocking().then(() => { - +
    + +
    , diff --git a/frontend/src/mocks/data/roomAndMaster.json b/frontend/src/mocks/data/roomAndMaster.json new file mode 100644 index 000000000..e35156ed5 --- /dev/null +++ b/frontend/src/mocks/data/roomAndMaster.json @@ -0,0 +1,9 @@ +{ + "roomId": 142, + "roomUuid": "bc950f33f12f467da159a263a905bb40", + "member": { + "memberId": 217, + "nickname": "땅콩", + "isMaster": true + } +} diff --git a/frontend/src/mocks/data/roomAndNotMaster.json b/frontend/src/mocks/data/roomAndNotMaster.json new file mode 100644 index 000000000..b2746809c --- /dev/null +++ b/frontend/src/mocks/data/roomAndNotMaster.json @@ -0,0 +1,9 @@ +{ + "roomId": 142, + "roomUuid": "bc950f33f12f467da159a263a905bb40", + "member": { + "memberId": 217, + "nickname": "땅콩", + "isMaster": false + } +} diff --git a/frontend/src/mocks/handlers/roomHandler.ts b/frontend/src/mocks/handlers/roomHandler.ts index 40bf75fd4..65c2ba2d8 100644 --- a/frontend/src/mocks/handlers/roomHandler.ts +++ b/frontend/src/mocks/handlers/roomHandler.ts @@ -4,6 +4,7 @@ import CATEGORY_LIST from '../data/categoryList.json'; import CREATE_ROOM_RESPONSE from '../data/createRoomResponse.json'; import ENTER_ROOM_RESPONSE from '../data/enterRoomResponse.json'; import MASTER_AND_INITIAL from '../data/masterAndInitial.json'; +import ROOM_AND_MASTER from '../data/roomAndMaster.json'; import ROOM_INFO from '../data/roomInfo.json'; import { MOCK_API_URL } from '@/constants/url'; @@ -62,7 +63,12 @@ const isJoinableRoomHandler = () => { return HttpResponse.json({ isJoinable: false }, { status: 200 }); }; +const getUserInfoHandler = () => { + return HttpResponse.json(ROOM_AND_MASTER, { status: 200 }); +}; + export const roomHandler = [ + http.get(MOCK_API_URL.getUserInfo, getUserInfoHandler), http.get(MOCK_API_URL.getRoomInfo, getRoomInfoHandler), http.post(MOCK_API_URL.room, createRoomHandler), http.post(MOCK_API_URL.enterRoom, enterRoomHandler), diff --git a/frontend/src/pages/MainPage/MainPage.tsx b/frontend/src/pages/MainPage/MainPage.tsx index 0f39c0303..be1d92193 100644 --- a/frontend/src/pages/MainPage/MainPage.tsx +++ b/frontend/src/pages/MainPage/MainPage.tsx @@ -24,7 +24,7 @@ const MainPage = () => {

    땅콩

    어색한 분위기를 주도해봐요

    - +