Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 유저 정보 관리 cookie로 변경 #368

Merged
merged 25 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
aa638a9
feat: 방 재접속 API 함수 생성 #348
novice0840 Oct 18, 2024
a5e76ac
feat: 방 재접속 API mocking 함수 생성 #348
novice0840 Oct 18, 2024
702eadd
feat: rejoinRoom hook 구현 #348
novice0840 Oct 18, 2024
a190311
feat: 대기 페이지 쿠키 적용 #348
novice0840 Oct 18, 2024
94088a1
feat: 게임 시작 시 방장 판단 여부 recoil -> cookie 로 변경 #348
novice0840 Oct 18, 2024
ec120fc
refactor: button 태그 닫힌 태그로 변경 #348
novice0840 Oct 21, 2024
50de4c5
feat: API 함수 getMember로 변경 #348
novice0840 Oct 22, 2024
400fbee
feat: 멤버가 바뀔 경우 멤버 정보 초기화 #348
novice0840 Oct 22, 2024
4cea2b5
refactor: 방 시작 방장 판단 cookie로 변경 #348
novice0840 Oct 23, 2024
63119df
refactor: 다음 라운드로 넘어가기 기능 recoil -> cookie로 변경 #348
novice0840 Oct 23, 2024
275eda1
refactor: 게임 진행 시 유저정보조회 recoil -> cookie로 변경 #348
novice0840 Oct 23, 2024
7038f9b
refactor: 이미지 비율 깨짐 해결 #348
novice0840 Oct 23, 2024
443646c
fix: git conflict 해결 #348
novice0840 Oct 23, 2024
a0e75c7
fix: 땅콩이미지 비율 안 맞는 문제 해결 #348
novice0840 Oct 23, 2024
4327bbc
fix: git conflict 해결 #348
novice0840 Oct 23, 2024
3a8ed76
fix: 닉네임 페이지 isMaster 오류 해결 #348
novice0840 Oct 23, 2024
da1ff91
refactor: RoomSetting 텍스트 위아래 정렬 맞춤 #348
novice0840 Oct 23, 2024
7a4ae56
refactor: RoomSetting 글자 간격 넓힘 #348
novice0840 Oct 23, 2024
3028de5
refactor: 사용하지 않는 recoil 파일 제거 #348
novice0840 Oct 23, 2024
890335e
feat: getMember 함수 response 예제 json 생성 #348
novice0840 Oct 23, 2024
77b0cd1
refactor: queryKey, example JSON 적용 #348
novice0840 Oct 23, 2024
7532140
refactor: test 함수 변경 #348
novice0840 Oct 23, 2024
2c5b394
refactor: 함수 아래 줄바꿈 추가 #348
novice0840 Oct 24, 2024
0698012
fix: git conflict 해결 #348
novice0840 Oct 24, 2024
d86a41c
fix: RoomSetting test 함수명 에러 수정 #348
novice0840 Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/src/apis/balanceContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/apis/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const fetcher = {
method,
body: body && JSON.stringify(body),
headers: headers && headers,
credentials: 'include',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 질문 💭

오호 이 속성을 붙여야 쿠키를 주고받을 수 있는건가요??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네, 이 속성이 있어야 쿠키가 전송이 되더라고요!

});

if (!response.ok) {
Expand Down
17 changes: 16 additions & 1 deletion frontend/src/apis/room.ts
Original file line number Diff line number Diff line change
@@ -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[];
Expand Down Expand Up @@ -136,3 +142,12 @@ export const isJoinableRoom = async (roomUuid: string): Promise<{ isJoinable: bo

return data;
};

// 사용자 정보 조회
export const getMember = async (): Promise<RoomAndMember> => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 제안 🙏

getMember하면 뭔가 string 값이 반환될 것 같다고 느껴지는데 getUserInfo 이런 느낌은 어떤가요?? getMember는 객체로 반환하는데 객체 키값에 member가 있어서 어색하다고 느낀 것 같아요.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네, 그렇게 수정하겠습니다!

const res = await fetcher.get({
url: API_URL.getMember,
});
const data = await res.json();
return data;
};
13 changes: 7 additions & 6 deletions frontend/src/components/GameResult/GameResult.hook.ts
Original file line number Diff line number Diff line change
@@ -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 useGetmember from '@/hooks/useGetmember';
import { MatchingResult, MemberMatchingInfo } from '@/types/balanceContent';

type MatchingResultQueryResponse = UseQueryResult<MatchingResult, Error> & {
Expand All @@ -15,15 +14,17 @@ type MatchingResultQueryResponse = UseQueryResult<MatchingResult, Error> & {

export const useMatchingResultQuery = (): MatchingResultQueryResponse => {
const { roomId } = useParams();
const memberInfo = useRecoilValue(memberInfoState);
const {
member: { memberId },
} = useGetmember();

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 });
},
});

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/GameResult/GameResult.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const noMatchingLayout = css`

export const noMatchingImg = css`
width: 18rem;
height: 30vh;
height: 18rem;
`;

export const noMatchingText = css`
Expand Down
9 changes: 4 additions & 5 deletions frontend/src/components/NicknameItem/NicknameItem.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +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 useGetmember from '@/hooks/useGetmember';

interface NicknameItemProp {
nickName: string;
}

const NicknameItem = ({ nickName }: NicknameItemProp) => {
const memberInfo = useRecoilValue(memberInfoState);
const isMyNickname = memberInfo.nickname === nickName;
const { member } = useGetmember();
const isMyNickname = member.nickname === nickName;

return (
<li css={nicknameItemLayout}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useQueryClient } from '@tanstack/react-query';
import { useEffect, useRef } from 'react';
import { useRecoilState } from 'recoil';

import {
readyMembersContainerLayout,
Expand All @@ -19,24 +19,20 @@ import SillyDdangkongMedium from '@/assets/images/sillyDdangkongMedium.webp';
import InviteModal from '@/components/common/InviteModal/InviteModal';
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<HTMLButtonElement>(null);

const handleClickInvite = () => {
show(InviteModal, { returnFocusRef });
};

// 원래 방장이 아니다 + 방장의 memberId와 내 memberId가 같다 -> 방장으로 변경
useEffect(() => {
if (!memberInfo.isMaster && master.memberId === memberInfo.memberId) {
setMemberInfo({ ...memberInfo, isMaster: true });
}
}, [master.memberId, memberInfo, setMemberInfo]);
queryClient.invalidateQueries({ queryKey: ['getMember'] });
}, [master.memberId]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌸 칭찬 🌸

오 유저정보를 서버에서 관리하니까 해당 처리가 가능하군요!!! 될 것 같긴 한데 잘 동작하는지 영상이 있으면 더 이해가 빠를 것 같아용


return (
<section css={readyMembersContainerLayout}>
Expand Down
28 changes: 21 additions & 7 deletions frontend/src/components/RoomSetting/RoomSetting.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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%;
Expand All @@ -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;
`;
27 changes: 17 additions & 10 deletions frontend/src/components/RoomSetting/RoomSetting.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<RoomSetting />, { initializeState });
customRender(<RoomSetting />);
const settingButton = await screen.findByRole('button', { name: '방 설정' });

// When
Expand All @@ -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.getMember, async () => {
return HttpResponse.json(
{
member: {
isMaster: false,
},
},
{ status: 400 },
);
}),
);
const user = userEvent.setup();
customRender(<RoomSetting />, { initializeState });
customRender(<RoomSetting />);
const optionButton = await screen.findByRole('button', { name: '방 설정' });

// When
Expand Down
26 changes: 13 additions & 13 deletions frontend/src/components/RoomSetting/RoomSetting.tsx
Original file line number Diff line number Diff line change
@@ -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 useGetmember from '@/hooks/useGetmember';
import { useGetRoomInfo } from '@/hooks/useGetRoomInfo';
import useModal from '@/hooks/useModal';
import { memberInfoState } from '@/recoil/atom';

const RoomSetting = () => {
const returnFocusRef = useRef<HTMLButtonElement>(null);
const { roomSetting } = useGetRoomInfo();
const { isMaster } = useRecoilValue(memberInfoState);
const {
member: { isMaster },
} = useGetmember();
const { show } = useModal();
const screenReaderRoomSetting = `
방 정보.
Expand All @@ -39,16 +41,14 @@ const RoomSetting = () => {
onClick={isMaster ? handleClickCategory : () => {}}
ref={returnFocusRef}
>
<div css={roomSettingBox}>
<span css={roomSettingLabel}>라운드</span>
<h2 css={smallTitle}>{roomSetting.totalRound}</h2>
<div css={roomSettingKeyBox}>
<span css={roomSettingKey}>라운드</span>
<span css={roomSettingKey}>카테고리</span>
<span css={roomSettingKey}>제한 시간</span>
</div>
<div css={roomSettingBox}>
<span css={roomSettingLabel}>카테고리</span>
<div css={roomSettingValueBox}>
<h2 css={smallTitle}>{roomSetting.totalRound}</h2>
<h2 css={bigTitle}>{roomSetting.category.label}</h2>
</div>
<div css={roomSettingBox}>
<span css={roomSettingLabel}>제한 시간</span>
<h2 css={smallTitle}>{roomSetting.timeLimit / 1000}초</h2>
</div>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -24,7 +24,7 @@ describe('StartButton 테스트', () => {
}),
);

customRenderWithIsMaster(<StartButton />, true);
customRenderWithMaster(<StartButton />);

const startButton = await screen.findByRole('button', { name: '시작' });
await user.click(startButton);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { useGameStart } from './hooks/useGameStart';
import Button from '@/components/common/Button/Button';

const StartButton = () => {
const { memberInfo, handleGameStart } = useGameStart();
const { isMaster, handleGameStart } = useGameStart();

return (
<Button
text={memberInfo.isMaster ? '시작' : '방장이 시작해 주세요'}
disabled={!memberInfo.isMaster}
text={isMaster ? '시작' : '방장이 시작해 주세요'}
disabled={!isMaster}
onClick={handleGameStart}
bottom
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { useMutation } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { useRecoilState } from 'recoil';

import { startGame } from '@/apis/room';
import { memberInfoState } from '@/recoil/atom';
import useGetmember from '@/hooks/useGetmember';

export const useGameStart = () => {
const [memberInfo, setMemberInfo] = useRecoilState(memberInfoState);
const {
member: { isMaster },
} = useGetmember();
const { roomId } = useParams();

const startGameMutation = useMutation({
mutationFn: () => startGame(Number(roomId)),
});

const handleGameStart = () => {
if (memberInfo.isMaster) {
if (isMaster) {
startGameMutation.mutate();
}
};

return { memberInfo, handleGameStart, setMemberInfo };
return { isMaster, handleGameStart };
};
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { screen, waitFor } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import type { MutableSnapshot } from 'recoil';

import StartButtonContainer from './StartButtonContainer';

import { memberInfoState } from '@/recoil/atom';
import { customRender } from '@/utils/test-utils';

describe('StartButtonContainer 테스트', () => {
it('게임 시작 버튼을 클릭하면 카운트 다운을 시작한다.', async () => {
const initializeIsMaster = (snap: MutableSnapshot) => {
snap.set(memberInfoState, { memberId: 1, nickname: 'Test User', isMaster: true });
};

const user = userEvent.setup();
customRender(<StartButtonContainer />, { initializeState: initializeIsMaster });
customRender(<StartButtonContainer />);
const COUNTDOWN_LABEL_TEXT = '게임 시작 3초 전';

const button = await screen.findByRole('button', { name: '시작' });
Expand Down
Loading
Loading