From 5afd2bea84d496dda970c39eb97c6d5d03167155 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Mon, 19 Aug 2024 17:49:16 +0900 Subject: [PATCH 01/36] =?UTF-8?q?chore:=20test=20API=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/features/Main/Headline.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/client/src/features/Main/Headline.tsx b/client/src/features/Main/Headline.tsx index 4f05c807..659e6b58 100644 --- a/client/src/features/Main/Headline.tsx +++ b/client/src/features/Main/Headline.tsx @@ -1,12 +1,10 @@ import { memo, useEffect } from "react"; import { motion } from "framer-motion"; -import { RushAPI } from "@/apis/rushAPI.ts"; import { TotalAPI } from "@/apis/totalAPI.ts"; import Keyword from "@/components/Keyword"; import Scroll from "@/components/Scroll"; import { ASCEND, ASCEND_DESCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { RushEventStatusCodeResponse } from "@/types/rushApi.ts"; import { SectionKeyProps } from "@/types/sections.ts"; import { GetTotalEventDateResponse } from "@/types/totalApi.ts"; import { formatEventDateRangeWithDot } from "@/utils/formatDate.ts"; @@ -16,11 +14,6 @@ interface HeadlineProps extends SectionKeyProps { } function Headline({ id, handleClickScroll }: HeadlineProps) { - // DATA RESET TEST API - const { fetchData: getRushTodayEventTest } = useFetch(() => - RushAPI.getRushTodayEventTest() - ); - const { data: totalData, isSuccess: isSuccessTotalData, @@ -28,7 +21,6 @@ function Headline({ id, handleClickScroll }: HeadlineProps) { } = useFetch(() => TotalAPI.getTotal()); useEffect(() => { - getRushTodayEventTest(); getTotal(); }, []); From bdf98fcf834fa6302f60f3fe18d154c2d9a937c8 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Mon, 19 Aug 2024 18:38:22 +0900 Subject: [PATCH 02/36] =?UTF-8?q?feat:=20=EC=84=A0=EC=B0=A9=EC=88=9C=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=EC=83=88=EB=A1=9C=EA=B3=A0=EC=B9=A8=20?= =?UTF-8?q?=EB=B0=8F=20=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B8=B0=20=EB=B0=A9?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/RushGame/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index f526004c..0531f14c 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -6,12 +6,16 @@ import CardOptions from "@/features/RushGame/RushGameSections/CardOptions.tsx"; import Countdown from "@/features/RushGame/RushGameSections/Countdown.tsx"; import FinalResult from "@/features/RushGame/RushGameSections/FinalResult.tsx"; import SelectedCard from "@/features/RushGame/RushGameSections/SelectedCard.tsx"; +import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToast from "@/hooks/useToast.tsx"; import { writeClipboard } from "@/utils/writeClipboard.ts"; -// TODO: 계속 카운트 다운에 맞춰 매초 렌더링 되는 문제 해결 export default function RushGame() { + useBlockNavigation( + "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" + ); + const { gameState } = useRushGameContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); From 47d5f69fe22b685a2f32fa15a33f48940084a332 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Mon, 19 Aug 2024 18:50:17 +0900 Subject: [PATCH 03/36] =?UTF-8?q?feat:=20FinalResult=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=97=90=EC=84=9C=20unblockNavigation=20=ED=98=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGame/RushGameSections/FinalResult.tsx | 12 +++++++++--- client/src/pages/RushGame/index.tsx | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 8d196f37..bd781b88 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -22,7 +22,11 @@ function getWinStatus(ratio: number, oppositeRatio: number): WinStatus { return ratio > oppositeRatio ? WIN_STATUS.WIN : WIN_STATUS.LOSE; } -export default function FinalResult() { +interface FinalResultProps { + unblockNavigation: () => void; +} + +export default function FinalResult({ unblockNavigation }: FinalResultProps) { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); const { gameState, getOptionRatio, getSelectedCardInfo, updateCardOptions } = useRushGameContext(); @@ -31,12 +35,14 @@ export default function FinalResult() { data: resultData, isSuccess: isSuccessRushResult, fetchData: getRushResult, - } = useFetch(() => - RushAPI.getRushResult(cookies[COOKIE_KEY.ACCESS_TOKEN]) + } = useFetch( + () => RushAPI.getRushResult(cookies[COOKIE_KEY.ACCESS_TOKEN]), + false ); useEffect(() => { getRushResult(); + unblockNavigation(); }, []); useEffect(() => { diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index 0531f14c..47586920 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -12,7 +12,7 @@ import useToast from "@/hooks/useToast.tsx"; import { writeClipboard } from "@/utils/writeClipboard.ts"; export default function RushGame() { - useBlockNavigation( + const { unblockNavigation } = useBlockNavigation( "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); @@ -34,7 +34,7 @@ export default function RushGame() { return ; } case CARD_PHASE.COMPLETED: - return ; + return ; default: return null; } From 974d8f29f40b1c58fc5f9188ac219ecf7f92d4f6 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Tue, 20 Aug 2024 11:12:22 +0900 Subject: [PATCH 04/36] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EC=9D=B4=EB=AF=B8=20=EC=98=B5=EC=85=98=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=ED=95=9C=20=ED=9B=84=EC=97=90=EB=8A=94=20=EC=83=88?= =?UTF-8?q?=EB=A1=9C=EA=B3=A0=EC=B9=A8/=EB=92=A4=EB=A1=9C=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=20=EB=B0=A9=EC=A7=80=20=ED=92=80=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGame/RushGameSections/SelectedCard.tsx | 13 +++++++++---- client/src/pages/RushGame/index.tsx | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx index ccd692b7..d81384aa 100644 --- a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx +++ b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx @@ -9,11 +9,11 @@ import useToggleContents from "@/hooks/useToggleContents.ts"; import ArrowLeftIcon from "/public/assets/icons/arrow-line-left.svg?react"; import ArrowRightIcon from "/public/assets/icons/arrow-line-right.svg?react"; -interface SelectedCardProps { +interface SelectedCardDetailsProps { onClick: () => void; } -function SelectedCardDescription({ onClick }: SelectedCardProps) { +function SelectedCardDescription({ onClick }: SelectedCardDetailsProps) { return ( @@ -32,7 +32,7 @@ function SelectedCardDescription({ onClick }: SelectedCardProps) { ); } -function SelectedCardCurrentRatio({ onClick }: SelectedCardProps) { +function SelectedCardCurrentRatio({ onClick }: SelectedCardDetailsProps) { return ( @@ -51,12 +51,17 @@ function SelectedCardCurrentRatio({ onClick }: SelectedCardProps) { ); } -export default function SelectedCard() { +interface SelectedCardProps { + unblockNavigation: () => void; +} + +export default function SelectedCard({ unblockNavigation }: SelectedCardProps) { const { toggleContents, toggle } = useToggleContents({ useDuration: false }); const { fetchRushBalance } = useRushGameContext(); useEffect(() => { fetchRushBalance(); + unblockNavigation(); }, []); return ( diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index 47586920..bf236939 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -31,7 +31,7 @@ export default function RushGame() { if (!gameState.userParticipatedStatus) { return ; } else { - return ; + return ; } case CARD_PHASE.COMPLETED: return ; From 1c0df684d32a47f3bb6d145e4e1bac9a5a1bdb4c Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Tue, 20 Aug 2024 11:27:49 +0900 Subject: [PATCH 05/36] =?UTF-8?q?chore:=20=ED=98=84=EC=9E=AC=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=EC=9D=84=20=EC=84=9C=EB=B2=84=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/features/Rush/Common/Headline.tsx | 2 +- client/src/pages/Lottery/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/features/Rush/Common/Headline.tsx b/client/src/features/Rush/Common/Headline.tsx index 379fb7cf..7a780002 100644 --- a/client/src/features/Rush/Common/Headline.tsx +++ b/client/src/features/Rush/Common/Headline.tsx @@ -33,7 +33,7 @@ export function Headline({ id, handleClickScroll }: HeadlineProps) { // TODO: 당일 이벤트 종료 시 참여 여부를 기준으로 분기 처리 (T: FinalResult() / F: 이벤트 참여 기간 아님) const startDate = getMsTime(rushData.eventStartDate); const endDate = getMsTime(rushData.eventEndDate); - const currentDate = new Date().getTime(); + const currentDate = getMsTime(rushData.serverTime); const isEventPeriod = currentDate >= startDate && currentDate <= endDate; diff --git a/client/src/pages/Lottery/index.tsx b/client/src/pages/Lottery/index.tsx index 9c6922bc..cca523f5 100644 --- a/client/src/pages/Lottery/index.tsx +++ b/client/src/pages/Lottery/index.tsx @@ -47,7 +47,7 @@ export default function Lottery() { const handleClickShortCut = useCallback(() => { const startDate = getMsTime(lotteryData.eventStartDate); const endDate = getMsTime(lotteryData.eventEndDate); - const currentDate = new Date().getTime(); + const currentDate = getMsTime(lotteryData.serverDateTime); const isEventPeriod = currentDate >= startDate && currentDate <= endDate; From 9ab86d241f4c7335a0973a0e844409219f3a3406 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Tue, 20 Aug 2024 13:44:16 +0900 Subject: [PATCH 06/36] =?UTF-8?q?feat:=200%=EC=9D=BC=20=EB=95=8C=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98=EC=8A=A4=EB=B0=94=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGame/RushGameComponents/RushBar.tsx | 13 +++++++++++-- .../RushGame/RushGameComponents/RushProgressBar.tsx | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/client/src/features/RushGame/RushGameComponents/RushBar.tsx b/client/src/features/RushGame/RushGameComponents/RushBar.tsx index ef9c8cae..aaa51c86 100644 --- a/client/src/features/RushGame/RushGameComponents/RushBar.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushBar.tsx @@ -7,6 +7,7 @@ const barVariants = cva(`flex items-center`, { red: "bg-gradient-red", blue: "bg-gradient-blue", yellow: "bg-gradient-yellow", + gray: "bg-n-neutral-100", }, status: { winning: "text-n-neutral-950", @@ -26,11 +27,19 @@ type BarVariantsProps = VariantProps; interface BarProps extends BarVariantsProps { ratio: number; + isAllZero: boolean; } -export default function RushBar({ ratio, color, status, textAlign }: BarProps) { +export default function RushBar({ ratio, color, status, textAlign, isAllZero }: BarProps) { + const barColor = isAllZero ? "gray" : color; + const barStatus = isAllZero ? "losing" : status; + const barWidth = isAllZero ? "50%" : `${ratio}%`; + return ( - +

{ratio}%

); diff --git a/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx b/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx index 0f7a35cb..7e34d907 100644 --- a/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx @@ -12,7 +12,10 @@ export default function RushProgressBar({ rightOptionRatio, }: RushProgressBarProps) { const { gameState } = useRushGameContext(); + const isCompleted = gameState.phase === CARD_PHASE.COMPLETED; + const isAllZero = leftOptionRatio === 0 && rightOptionRatio === 0; + const leftStatus = isCompleted && leftOptionRatio < rightOptionRatio ? "losing" : "winning"; const rightStatus = isCompleted && rightOptionRatio < leftOptionRatio ? "losing" : "winning"; @@ -23,12 +26,14 @@ export default function RushProgressBar({ color={CARD_COLOR.GREEN} status={leftStatus} textAlign="left" + isAllZero={isAllZero} /> ); From 36365dc7b6bdf7ad59cbd5f1c2de3b43740b4dd3 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Tue, 20 Aug 2024 13:47:03 +0900 Subject: [PATCH 07/36] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=EC=9D=91?= =?UTF-8?q?=EB=AA=A8=20=EC=97=AC=EB=B6=80=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?FinalResult=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushResultOptionDisplay.tsx | 6 ++++- .../RushGame/RushGameSections/FinalResult.tsx | 26 ++++++++++++------- client/src/types/rushGame.ts | 1 + 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/client/src/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx b/client/src/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx index b33c8aaf..850b1321 100644 --- a/client/src/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx @@ -5,12 +5,14 @@ interface RushResultOptionDisplayProps { mainText: string; winStatus: WinStatus; isUserSelected: boolean; + userParticipatedStatus: boolean; } export default function RushResultOptionDisplay({ mainText, winStatus, isUserSelected, + userParticipatedStatus, }: RushResultOptionDisplayProps) { const categoryType = winStatus === "Win" ? "limited" : "basic"; return ( @@ -21,7 +23,9 @@ export default function RushResultOptionDisplay({ {mainText}

{winStatus} - {isUserSelected && 당신의 선택} + {userParticipatedStatus && isUserSelected && ( + 당신의 선택 + )} ); } diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index bd781b88..1ddc0679 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -58,7 +58,9 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { } }, [resultData, isSuccessRushResult, updateCardOptions]); - const isWinner = resultData?.winner; + const userParticipatedStatus = gameState.userParticipatedStatus; + + const isWinner = resultData?.isWinner; const rank = resultData?.rank || 0; const totalParticipants = resultData?.totalParticipants || 0; @@ -84,16 +86,18 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) {

입력하신 전화번호로 경품 수령 관련 메시지가 전송될 예정이에요.

- -

나의 선착순 등수

- -

{rank}등

-

- / {totalParticipants.toLocaleString("en-US")}명 중 -

+ {userParticipatedStatus && ( + +

나의 선착순 등수

+ +

{rank}등

+

+ / {totalParticipants.toLocaleString("en-US")}명 중 +

+
-
-
+ )} +

최종 밸런스 게임 결과

) => void; + updateUserStatus: (token: string) => Promise; updateUserStatusAndSelectedOption: (token: string, selectedOption: CardOption) => Promise; getSelectedCardInfo: (option: CardOption) => CardOptionState; getOptionRatio: (option: CardOption) => number; From 107a778d8d437b1c31f032f814ef0560aac6956b Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Tue, 20 Aug 2024 13:52:41 +0900 Subject: [PATCH 08/36] =?UTF-8?q?fix:=20result=20API=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/types/rushApi.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/types/rushApi.ts b/client/src/types/rushApi.ts index bf87b6af..4d1c9429 100644 --- a/client/src/types/rushApi.ts +++ b/client/src/types/rushApi.ts @@ -40,9 +40,9 @@ export interface GetRushBalanceResponse { } export interface GetRushResultResponse { - winner: boolean; + isWinner?: boolean; leftOption: number; rightOption: number; - rank: number; - totalParticipants: number; + rank?: number; + totalParticipants?: number; } From c59978ef044e00b4948e32ffea89e19597cbf9c5 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Tue, 20 Aug 2024 14:27:00 +0900 Subject: [PATCH 09/36] =?UTF-8?q?chore:=20=ED=95=84=EC=9A=94=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20TODO=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/features/Rush/Common/Headline.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/features/Rush/Common/Headline.tsx b/client/src/features/Rush/Common/Headline.tsx index 7a780002..aad6d7ab 100644 --- a/client/src/features/Rush/Common/Headline.tsx +++ b/client/src/features/Rush/Common/Headline.tsx @@ -30,7 +30,6 @@ export function Headline({ id, handleClickScroll }: HeadlineProps) { const { showToast, ToastComponent } = useToast("이벤트 기간이 아닙니다"); const handleClickShortCut = useCallback(() => { - // TODO: 당일 이벤트 종료 시 참여 여부를 기준으로 분기 처리 (T: FinalResult() / F: 이벤트 참여 기간 아님) const startDate = getMsTime(rushData.eventStartDate); const endDate = getMsTime(rushData.eventEndDate); const currentDate = getMsTime(rushData.serverTime); From 07ce1ba1478a399ca068b503522e97122a032d4c Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Tue, 20 Aug 2024 19:38:26 +0900 Subject: [PATCH 10/36] =?UTF-8?q?feat:=20resultAPI=EC=9D=98=20optionId=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=ED=9B=84=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EC=84=A0=ED=83=9D=ED=95=9C=20optionId=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGame/RushGameSections/FinalResult.tsx | 13 ++++++++++--- client/src/types/rushApi.ts | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 1ddc0679..1b14ef71 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -28,8 +28,13 @@ interface FinalResultProps { export default function FinalResult({ unblockNavigation }: FinalResultProps) { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, getOptionRatio, getSelectedCardInfo, updateCardOptions } = - useRushGameContext(); + const { + gameState, + getOptionRatio, + getSelectedCardInfo, + updateCardOptions, + setUserSelectedOption, + } = useRushGameContext(); const { data: resultData, @@ -47,7 +52,9 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { useEffect(() => { if (resultData && isSuccessRushResult) { - const { leftOption, rightOption } = resultData; + const { optionId, leftOption, rightOption } = resultData; + + if (optionId) setUserSelectedOption(optionId); updateCardOptions(CARD_OPTION.LEFT_OPTIONS, { selectionCount: leftOption, diff --git a/client/src/types/rushApi.ts b/client/src/types/rushApi.ts index 4d1c9429..660cb652 100644 --- a/client/src/types/rushApi.ts +++ b/client/src/types/rushApi.ts @@ -1,3 +1,5 @@ +import { CardOption } from "@/types/rushGame.ts"; + interface RushEventType { rushEventId: number; startDateTime: string; @@ -34,12 +36,13 @@ export interface GetRushOptionResultResponse { } export interface GetRushBalanceResponse { - optionId: number; + optionId: CardOption; leftOption: number; rightOption: number; } export interface GetRushResultResponse { + optionId?: CardOption; isWinner?: boolean; leftOption: number; rightOption: number; From cd41ede310fe687e507d0b586a0fb5f05b60e7a8 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 00:18:42 +0900 Subject: [PATCH 11/36] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=A7=84?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=ED=98=84=EC=9E=AC=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=20=EC=A7=84=ED=96=89=20=EC=83=81=ED=83=9C=20=EB=B0=8F=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=B0=B8=EC=97=AC=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=20=EC=A0=80=EC=9E=A5=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20=EC=B9=B4=EC=9A=B4=ED=8A=B8=20=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 103 +++++------------- .../RushGameComponents/RushCountdown.tsx | 52 ++++++++- .../RushGame/RushGameSections/Countdown.tsx | 54 ++++++++- client/src/hooks/useCountdown.ts | 15 ++- client/src/pages/RushGame/index.tsx | 35 +++++- client/src/types/rushGame.ts | 6 +- 6 files changed, 177 insertions(+), 88 deletions(-) diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index 9718f103..e84e9ca7 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -4,7 +4,6 @@ import { useLoaderData } from "react-router-dom"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_COLOR, CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard"; import { COOKIE_KEY } from "@/constants/cookie.ts"; -import useCountdown from "@/hooks/useCountdown.ts"; import useFetch from "@/hooks/useFetch.ts"; import { GetRushBalanceResponse, @@ -17,11 +16,8 @@ import { getMsTime } from "@/utils/getMsTime.ts"; export const RushGameContext = createContext(undefined); export const RushGameProvider = ({ children }: { children: ReactNode }) => { - // const navigate = useNavigate(); const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); const rushData = useLoaderData() as GetTotalRushEventsResponse; - const [initialPreCountdown, setInitialPreCountdown] = useState(null); - const [initialRunCountdown, setInitialRunCountdown] = useState(null); const [gameState, setGameState] = useState({ phase: CARD_PHASE.NOT_STARTED, @@ -72,14 +68,13 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { [] ); - const { - data: userParticipatedStatus, - isSuccess: isSuccessUserParticipationStatus, - fetchData: getRushUserParticipationStatus, - } = useFetch((token) => - RushAPI.getRushUserParticipationStatus(token) - ); + const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< + GetRushUserParticipationStatusResponse, + string + >((token) => RushAPI.getRushUserParticipationStatus(token)); + // TODO: 상태 업데이트랑 옵션 업데이트 분리할까? 어차피 setUserSelectedOption이랑 setUserParticipationStatus 함수 다 내려줄건데 뭐하러 이렇게 하남..? + // TODO: 그냥 updateUserStatusAndSelectedOption 이 함수 호출해주는 곳에서 RushAPI.getRushUserParticipationStatus 이거 호출해주고, setUserSelectedOption 함수만 받아서 쓰면 될 것 같은데 const updateUserStatusAndSelectedOption = useCallback( async (token: string, selectedOption: CardOption) => { await getRushUserParticipationStatus(token); @@ -89,10 +84,10 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { ); useEffect(() => { - if (isSuccessUserParticipationStatus && userParticipatedStatus) { + if (userParticipatedStatus !== null) { setUserParticipationStatus(userParticipatedStatus); } - }, [isSuccessUserParticipationStatus, userParticipatedStatus]); + }, [userParticipatedStatus]); const getSelectedCardInfo = useCallback( (option: CardOption) => { @@ -145,79 +140,39 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { ); useEffect(() => { - const currentEvent = rushData.events.find( - (event) => event.rushEventId === rushData.todayEventId - ); - if (currentEvent) { - const serverTime = getMsTime(rushData.serverTime); - const startTime = getMsTime(currentEvent.startDateTime); - const endTime = getMsTime(currentEvent.endDateTime); - - if ( - gameState.phase === CARD_PHASE.NOT_STARTED && - rushData.serverTime && - currentEvent?.startDateTime - ) { - const preCountdown = Math.max(0, Math.floor((startTime - serverTime) / 1000)); - setInitialPreCountdown(preCountdown); - } else if ( - gameState.phase === CARD_PHASE.IN_PROGRESS && - rushData.serverTime && - currentEvent?.endDateTime - ) { - const runCountdown = Math.max(0, Math.floor((endTime - serverTime) / 1000)); - setInitialRunCountdown(runCountdown); + if (rushData) { + const currentEvent = rushData.events.find( + (event) => event.rushEventId === rushData.todayEventId + ); + + if (currentEvent) { + const serverTime = getMsTime(rushData.serverTime); + const startTime = getMsTime(currentEvent.startDateTime); + const endTime = getMsTime(currentEvent.endDateTime); + + if (serverTime < startTime) { + setGamePhase(CARD_PHASE.NOT_STARTED); + } else if (serverTime >= startTime && serverTime <= endTime) { + setGamePhase(CARD_PHASE.IN_PROGRESS); + } else if (serverTime > endTime) { + setGamePhase(CARD_PHASE.COMPLETED); + } } } - }, [rushData, gameState.phase]); - - const preCountdown = useCountdown(initialPreCountdown || 1); - const runCountdown = useCountdown(initialRunCountdown || 1); - - // TEST COUNTDOWN CODE - // const preCountdown = useCountdown(5); - // const runCountdown = useCountdown(20); - - useEffect(() => { - if (preCountdown <= 0 && gameState.phase === CARD_PHASE.NOT_STARTED) { - setGamePhase(CARD_PHASE.IN_PROGRESS); - } else if (runCountdown <= 0 && gameState.phase === CARD_PHASE.IN_PROGRESS) { - setGamePhase(CARD_PHASE.COMPLETED); - } - }, [preCountdown, runCountdown]); - - // useEffect(() => { - // const currentEvent = rushData.events.find( - // (event) => event.rushEventId === rushData.todayEventId - // ); - // - // if (currentEvent && gameState.phase === CARD_PHASE.COMPLETED) { - // const serverTime = getMsTime(rushData.serverTime); - // const endTime = getMsTime(currentEvent.endDateTime); - // - // if (!gameState.userParticipatedStatus) { - // if (serverTime > endTime) { - // navigate("/rush"); - // // TODO: 이벤트 참여기간 아닌 분기 처리(이벤트 종료 후 그 당일 12시 직전까지) - // } - // } else { - // // TODO: 참여한 사람일 경우 당일 12시 직전까지 계속 "COMPLETED" 상태 유지 - // // TODO: 12시 지나면 다시 "NOT_STARTED" 상태로 변경 - // } - // } - // }, [gameState.phase, gameState.userParticipatedStatus, rushData, navigate]); + }, [rushData, setGamePhase]); return ( {children} diff --git a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx index 5fcb173b..b05c248d 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx @@ -1,5 +1,12 @@ +import { useEffect, useState } from "react"; +import { RushAPI } from "@/apis/rushAPI.ts"; +import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import useCountdown from "@/hooks/useCountdown.ts"; +import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { formatTime } from "@/utils/formatTime.ts"; +import { getMsTime } from "@/utils/getMsTime.ts"; function TimeDisplay({ label, value }: { label: string; value: string }) { return ( @@ -11,7 +18,50 @@ function TimeDisplay({ label, value }: { label: string; value: string }) { } export default function RushCountdown() { - const { runCountdown } = useRushGameContext(); + const [initialRunCountdown, setInitialRunCountdown] = useState(null); + const { gameState, setGamePhase } = useRushGameContext(); + + const { + data: rushData, + isSuccess: isSuccessRush, + fetchData: getRush, + } = useFetch(() => RushAPI.getRush()); + + useEffect(() => { + getRush(); + }, []); + + useEffect(() => { + if (isSuccessRush && rushData) { + const currentEvent = rushData.events.find( + (event) => event.rushEventId === rushData.todayEventId + ); + + if (currentEvent) { + const serverTime = getMsTime(rushData.serverTime); + const endTime = getMsTime(currentEvent.endDateTime); + + setInitialRunCountdown(Math.max(0, Math.floor((endTime - serverTime) / 1000))); + } + } + }, [isSuccessRush, rushData]); + + const runCountdown = useCountdown(initialRunCountdown || null); + + useEffect(() => { + if ( + runCountdown !== null && + runCountdown <= 0 && + gameState.phase === CARD_PHASE.IN_PROGRESS + ) { + setGamePhase(CARD_PHASE.COMPLETED); + } + }, [runCountdown, gameState.phase, setGamePhase]); + + if (initialRunCountdown === null || runCountdown === null) { + return
; + } + const minutes = Math.floor((runCountdown % 3600) / 60); const seconds = runCountdown % 60; diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index 0725c441..0b2df2db 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -1,11 +1,63 @@ +import { useEffect, useState } from "react"; import { motion } from "framer-motion"; +import { RushAPI } from "@/apis/rushAPI.ts"; import { Background } from "@/components/Background"; +import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; +import useCountdown from "@/hooks/useCountdown.ts"; +import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { formatTime } from "@/utils/formatTime.ts"; +import { getMsTime } from "@/utils/getMsTime.ts"; function CountdownTimer() { - const { preCountdown } = useRushGameContext(); + const [initialPreCountdown, setInitialPreCountdown] = useState(null); + const { gameState, setGamePhase } = useRushGameContext(); + + const { + data: rushData, + isSuccess: isSuccessRush, + fetchData: getRush, + } = useFetch(() => RushAPI.getRush()); + + useEffect(() => { + getRush(); + }, []); + + useEffect(() => { + if (isSuccessRush && rushData) { + const currentEvent = rushData.events.find( + (event) => event.rushEventId === rushData.todayEventId + ); + + if (currentEvent) { + const serverTime = getMsTime(rushData.serverTime); + const startDateTime = getMsTime(currentEvent.startDateTime); + + setInitialPreCountdown( + Math.max(0, Math.floor((startDateTime - serverTime) / 1000)) + ); + } + } + }, [isSuccessRush, rushData]); + + const preCountdown = useCountdown(initialPreCountdown || null); + + useEffect(() => { + if ( + preCountdown !== null && + preCountdown <= 0 && + gameState.phase === CARD_PHASE.NOT_STARTED + ) { + setGamePhase(CARD_PHASE.IN_PROGRESS); + } + }, [preCountdown, gameState.phase, setGamePhase]); + + if (initialPreCountdown === null || preCountdown === null) { + return ; + } + const hours = Math.floor(preCountdown / 3600); const minutes = Math.floor((preCountdown % 3600) / 60); const seconds = preCountdown % 60; diff --git a/client/src/hooks/useCountdown.ts b/client/src/hooks/useCountdown.ts index d56e0494..9b47ba03 100644 --- a/client/src/hooks/useCountdown.ts +++ b/client/src/hooks/useCountdown.ts @@ -1,17 +1,24 @@ import { useEffect, useState } from "react"; -export default function useCountdown(initialTime: number) { - const [time, setTime] = useState(initialTime); +export default function useCountdown(initialTime: number | null) { + const [time, setTime] = useState(initialTime); useEffect(() => { setTime(initialTime); }, [initialTime]); useEffect(() => { - if (time < 0) return; + if (time === null || time < 0) return; const timer = setInterval(() => { - if (time >= 0) setTime((prevTime) => prevTime - 1); + setTime((prevTime) => { + if (prevTime !== null && prevTime >= 0) { + return prevTime - 1; + } else { + clearInterval(timer); + return prevTime; + } + }); }, 1000); return () => clearInterval(timer); diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index bf236939..3dafce44 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -1,37 +1,62 @@ +import { useEffect } from "react"; import { motion } from "framer-motion"; +import { useCookies } from "react-cookie"; +import { RushAPI } from "@/apis/rushAPI.ts"; import CTAButton from "@/components/CTAButton"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; +import { COOKIE_KEY } from "@/constants/cookie.ts"; import CardOptions from "@/features/RushGame/RushGameSections/CardOptions.tsx"; import Countdown from "@/features/RushGame/RushGameSections/Countdown.tsx"; import FinalResult from "@/features/RushGame/RushGameSections/FinalResult.tsx"; import SelectedCard from "@/features/RushGame/RushGameSections/SelectedCard.tsx"; import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; +import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToast from "@/hooks/useToast.tsx"; +import { GetRushUserParticipationStatusResponse } from "@/types/rushApi.ts"; import { writeClipboard } from "@/utils/writeClipboard.ts"; export default function RushGame() { + const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); const { unblockNavigation } = useBlockNavigation( "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); - const { gameState } = useRushGameContext(); + const { gameState, setUserParticipationStatus } = useRushGameContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); const handleClickShareButton = () => { writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); }; + const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< + GetRushUserParticipationStatusResponse, + string + >((token) => RushAPI.getRushUserParticipationStatus(token)); + + useEffect(() => { + getRushUserParticipationStatus(cookies[COOKIE_KEY.ACCESS_TOKEN]); + }, []); + + useEffect(() => { + if (userParticipatedStatus !== null) { + setUserParticipationStatus(userParticipatedStatus); + } + }, [userParticipatedStatus]); + const renderRushGameContent = () => { switch (gameState.phase) { case CARD_PHASE.NOT_STARTED: return ; case CARD_PHASE.IN_PROGRESS: - if (!gameState.userParticipatedStatus) { - return ; - } else { - return ; + if (userParticipatedStatus === null) return <>; + else { + if (!gameState.userParticipatedStatus) { + return ; + } else { + return ; + } } case CARD_PHASE.COMPLETED: return ; diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index f8eb36ed..3bdabf86 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -23,12 +23,12 @@ export interface RushGameContextType { [key in CardOption]: CardOptionState; }; }; - preCountdown: number; - runCountdown: number; updateCardOptions: (option: CardOption, updates: Partial) => void; - updateUserStatus: (token: string) => Promise; updateUserStatusAndSelectedOption: (token: string, selectedOption: CardOption) => Promise; getSelectedCardInfo: (option: CardOption) => CardOptionState; getOptionRatio: (option: CardOption) => number; fetchRushBalance: () => Promise; + setUserParticipationStatus: (status: boolean) => void; + setGamePhase: (phase: GamePhase) => void; + setUserSelectedOption: (option: CardOption) => void; } From 2a1da5a0844933774b25481757e759aafde11c0b Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 11:12:40 +0900 Subject: [PATCH 12/36] =?UTF-8?q?feat:=20=EC=98=A4=EB=8A=98=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=ED=95=84=ED=84=B0=EB=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 9 ++++++--- .../RushGame/RushGameComponents/RushCountdown.tsx | 9 ++++++--- .../src/features/RushGame/RushGameSections/Countdown.tsx | 9 ++++++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index e84e9ca7..de318787 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -141,9 +141,12 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { useEffect(() => { if (rushData) { - const currentEvent = rushData.events.find( - (event) => event.rushEventId === rushData.todayEventId - ); + const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + + const currentEvent = rushData.events.find((event) => { + const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + return eventDate === serverDate && event.rushEventId === rushData.todayEventId; + }); if (currentEvent) { const serverTime = getMsTime(rushData.serverTime); diff --git a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx index b05c248d..2dcc25d3 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx @@ -33,9 +33,12 @@ export default function RushCountdown() { useEffect(() => { if (isSuccessRush && rushData) { - const currentEvent = rushData.events.find( - (event) => event.rushEventId === rushData.todayEventId - ); + const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + + const currentEvent = rushData.events.find((event) => { + const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + return eventDate === serverDate && event.rushEventId === rushData.todayEventId; + }); if (currentEvent) { const serverTime = getMsTime(rushData.serverTime); diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index 0b2df2db..6ed687dd 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -27,9 +27,12 @@ function CountdownTimer() { useEffect(() => { if (isSuccessRush && rushData) { - const currentEvent = rushData.events.find( - (event) => event.rushEventId === rushData.todayEventId - ); + const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + + const currentEvent = rushData.events.find((event) => { + const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + return eventDate === serverDate && event.rushEventId === rushData.todayEventId; + }); if (currentEvent) { const serverTime = getMsTime(rushData.serverTime); From 276b53891aa6822cbecea0a97c991b370bec7ff2 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 11:20:50 +0900 Subject: [PATCH 13/36] =?UTF-8?q?refactor:=20Context=20=EB=82=B4=EB=B6=80?= =?UTF-8?q?=20getRushUserParticipationStatus=20API=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EB=B0=96=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 28 +------------ .../RushGameComponents/RushCardComparison.tsx | 39 +++++++++++-------- client/src/types/rushGame.ts | 1 - 3 files changed, 24 insertions(+), 44 deletions(-) diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index de318787..87658fcd 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -5,11 +5,7 @@ import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_COLOR, CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { - GetRushBalanceResponse, - GetRushUserParticipationStatusResponse, - GetTotalRushEventsResponse, -} from "@/types/rushApi.ts"; +import { GetRushBalanceResponse, GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { CardOption, CardOptionState, GamePhase, RushGameContextType } from "@/types/rushGame"; import { getMsTime } from "@/utils/getMsTime.ts"; @@ -68,27 +64,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { [] ); - const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< - GetRushUserParticipationStatusResponse, - string - >((token) => RushAPI.getRushUserParticipationStatus(token)); - - // TODO: 상태 업데이트랑 옵션 업데이트 분리할까? 어차피 setUserSelectedOption이랑 setUserParticipationStatus 함수 다 내려줄건데 뭐하러 이렇게 하남..? - // TODO: 그냥 updateUserStatusAndSelectedOption 이 함수 호출해주는 곳에서 RushAPI.getRushUserParticipationStatus 이거 호출해주고, setUserSelectedOption 함수만 받아서 쓰면 될 것 같은데 - const updateUserStatusAndSelectedOption = useCallback( - async (token: string, selectedOption: CardOption) => { - await getRushUserParticipationStatus(token); - setUserSelectedOption(selectedOption); - }, - [] - ); - - useEffect(() => { - if (userParticipatedStatus !== null) { - setUserParticipationStatus(userParticipatedStatus); - } - }, [userParticipatedStatus]); - const getSelectedCardInfo = useCallback( (option: CardOption) => { const cardInfo = gameState.cardOptions[option]; @@ -169,7 +144,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { value={{ gameState, updateCardOptions, - updateUserStatusAndSelectedOption, getSelectedCardInfo, getOptionRatio, fetchRushBalance, diff --git a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx index 3b68313a..23fea807 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { useCookies } from "react-cookie"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; @@ -6,20 +6,20 @@ import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushCard from "@/features/RushGame/RushGameComponents/RushCard.tsx"; import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; -import { GetTodayRushEventResponse, RushEventStatusCodeResponse } from "@/types/rushApi.ts"; +import { + GetRushUserParticipationStatusResponse, + GetTodayRushEventResponse, + RushEventStatusCodeResponse, +} from "@/types/rushApi.ts"; import { CardOption } from "@/types/rushGame.ts"; import { getRandomCardColors } from "@/utils/getRandomCardColors.ts"; -const INITIAL_OPTION_NUMBER = -1 as const; - export default function RushCardComparison() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const [optionId, setOptionId] = useState( - INITIAL_OPTION_NUMBER - ); - const { gameState, updateUserStatusAndSelectedOption, updateCardOptions } = + const { gameState, setUserSelectedOption, updateCardOptions, setUserParticipationStatus } = useRushGameContext(); + // TODO: getTodayRushEvent -> RushGame 컴포넌트로 옮기기 const { data: todayRushEventData, isSuccess: isSuccessTodayRushEvent, @@ -34,6 +34,11 @@ export default function RushCardComparison() { ({ token, optionId }) => RushAPI.postSelectedRushOptionApply(token, optionId) ); + const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< + GetRushUserParticipationStatusResponse, + string + >((token) => RushAPI.getRushUserParticipationStatus(token)); + useEffect(() => { getTodayRushEvent(cookies[COOKIE_KEY.ACCESS_TOKEN]); }, []); @@ -57,18 +62,20 @@ export default function RushCardComparison() { const handleCardSelection = async (optionId: CardOption) => { await postSelectedRushOptionApply({ token: cookies[COOKIE_KEY.ACCESS_TOKEN], optionId }); - setOptionId(optionId); + setUserSelectedOption(optionId); }; useEffect(() => { - if ( - isSuccessPostSelectedRushOption && - postSelectedRushOptionResponse === 204 && - optionId !== INITIAL_OPTION_NUMBER - ) { - updateUserStatusAndSelectedOption(cookies[COOKIE_KEY.ACCESS_TOKEN], optionId); + if (isSuccessPostSelectedRushOption && postSelectedRushOptionResponse === 204) { + getRushUserParticipationStatus(cookies[COOKIE_KEY.ACCESS_TOKEN]); + } + }, [isSuccessPostSelectedRushOption, postSelectedRushOptionResponse]); + + useEffect(() => { + if (userParticipatedStatus !== null) { + setUserParticipationStatus(userParticipatedStatus); } - }, [optionId]); + }, [userParticipatedStatus]); const leftOptionData = gameState.cardOptions[CARD_OPTION.LEFT_OPTIONS]; const rightOptionData = gameState.cardOptions[CARD_OPTION.RIGHT_OPTIONS]; diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index 3bdabf86..4bee5f73 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -24,7 +24,6 @@ export interface RushGameContextType { }; }; updateCardOptions: (option: CardOption, updates: Partial) => void; - updateUserStatusAndSelectedOption: (token: string, selectedOption: CardOption) => Promise; getSelectedCardInfo: (option: CardOption) => CardOptionState; getOptionRatio: (option: CardOption) => number; fetchRushBalance: () => Promise; From 4c8f181da3bb6a880cbf821debf92ce0f8d39c8b Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 16:41:02 +0900 Subject: [PATCH 14/36] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=9E=AC?= =?UTF-8?q?=EC=A0=91=EC=86=8D=20=EC=8B=9C=20=EC=9C=A0=EC=A0=80=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 11 ++++- .../RushGameComponents/RushCardComparison.tsx | 37 +++------------- .../RushCardResultDescription.tsx | 2 +- .../RushGame/RushGameSections/Countdown.tsx | 2 +- client/src/pages/RushGame/index.tsx | 42 +++++++++++++++++-- 5 files changed, 55 insertions(+), 39 deletions(-) diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index 87658fcd..c486f919 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -51,6 +51,7 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { setGameState((prevState) => ({ ...prevState, userSelectedOption: option })); }, []); + // TODO: set으로 이름 바꾸기 const updateCardOptions = useCallback( (option: CardOption, updates: Partial) => { setGameState((prevState) => ({ @@ -64,6 +65,7 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { [] ); + // TODO: getter 니까 유틸로? const getSelectedCardInfo = useCallback( (option: CardOption) => { const cardInfo = gameState.cardOptions[option]; @@ -79,6 +81,7 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { [gameState.userSelectedOption, gameState.cardOptions] ); + // TODO: 훅으로 빼기 const { data: rushBalanceData, isSuccess: isSuccessRushBalance, @@ -91,7 +94,9 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { useEffect(() => { if (isSuccessRushBalance && rushBalanceData) { - const { leftOption, rightOption } = rushBalanceData; + const { optionId, leftOption, rightOption } = rushBalanceData; + + setUserSelectedOption(optionId); updateCardOptions(CARD_OPTION.LEFT_OPTIONS, { selectionCount: leftOption, @@ -100,8 +105,9 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { selectionCount: rightOption, }); } - }, [isSuccessRushBalance, rushBalanceData]); + }, [isSuccessRushBalance, rushBalanceData, setUserSelectedOption, updateCardOptions]); + // TODO: 유틸로 빼기 const getOptionRatio = useCallback( (option: CardOption): number => { const total = @@ -114,6 +120,7 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { [gameState.cardOptions] ); + // TODO: dispatch action으로 함수로 빼서 RushGame 컴포넌트에서 함수를 호출해서 초기화해주는 것이 맞다고 생각.. useEffect(() => { if (rushData) { const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; diff --git a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx index 23fea807..01b2a30f 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx @@ -1,31 +1,22 @@ import { useEffect } from "react"; import { useCookies } from "react-cookie"; import { RushAPI } from "@/apis/rushAPI.ts"; -import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; +import { CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushCard from "@/features/RushGame/RushGameComponents/RushCard.tsx"; import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import { GetRushUserParticipationStatusResponse, - GetTodayRushEventResponse, RushEventStatusCodeResponse, } from "@/types/rushApi.ts"; import { CardOption } from "@/types/rushGame.ts"; -import { getRandomCardColors } from "@/utils/getRandomCardColors.ts"; export default function RushCardComparison() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setUserSelectedOption, updateCardOptions, setUserParticipationStatus } = + const { gameState, setUserSelectedOption, setUserParticipationStatus, fetchRushBalance } = useRushGameContext(); - // TODO: getTodayRushEvent -> RushGame 컴포넌트로 옮기기 - const { - data: todayRushEventData, - isSuccess: isSuccessTodayRushEvent, - fetchData: getTodayRushEvent, - } = useFetch((token) => RushAPI.getTodayRushEvent(token)); - const { data: postSelectedRushOptionResponse, isSuccess: isSuccessPostSelectedRushOption, @@ -39,27 +30,6 @@ export default function RushCardComparison() { string >((token) => RushAPI.getRushUserParticipationStatus(token)); - useEffect(() => { - getTodayRushEvent(cookies[COOKIE_KEY.ACCESS_TOKEN]); - }, []); - - useEffect(() => { - if (isSuccessTodayRushEvent && todayRushEventData) { - const { leftColor, rightColor } = getRandomCardColors(); - - updateCardOptions(CARD_OPTION.LEFT_OPTIONS, { - mainText: todayRushEventData.leftOption.mainText, - subText: todayRushEventData.leftOption.subText, - color: leftColor, - }); - updateCardOptions(CARD_OPTION.RIGHT_OPTIONS, { - mainText: todayRushEventData.rightOption.mainText, - subText: todayRushEventData.rightOption.subText, - color: rightColor, - }); - } - }, [isSuccessTodayRushEvent, todayRushEventData]); - const handleCardSelection = async (optionId: CardOption) => { await postSelectedRushOptionApply({ token: cookies[COOKIE_KEY.ACCESS_TOKEN], optionId }); setUserSelectedOption(optionId); @@ -74,6 +44,9 @@ export default function RushCardComparison() { useEffect(() => { if (userParticipatedStatus !== null) { setUserParticipationStatus(userParticipatedStatus); + if (userParticipatedStatus && CARD_PHASE.IN_PROGRESS) { + fetchRushBalance(); + } } }, [userParticipatedStatus]); diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index 50addc01..67efd7d7 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -45,7 +45,7 @@ export default function RushCardResultDescription() { token: cookies[COOKIE_KEY.ACCESS_TOKEN], optionId: gameState.userSelectedOption, }); - }, []); + }, [cookies, gameState.userSelectedOption, getUserResultData]); useEffect(() => { if (isSuccessUserResultData && userResultData) { diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index 6ed687dd..e05d2933 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -75,7 +75,7 @@ function CountdownTimer() {

:

:

- +
); diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index 3dafce44..e4fc7f7e 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -3,7 +3,7 @@ import { motion } from "framer-motion"; import { useCookies } from "react-cookie"; import { RushAPI } from "@/apis/rushAPI.ts"; import CTAButton from "@/components/CTAButton"; -import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import { CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import CardOptions from "@/features/RushGame/RushGameSections/CardOptions.tsx"; @@ -14,7 +14,11 @@ import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToast from "@/hooks/useToast.tsx"; -import { GetRushUserParticipationStatusResponse } from "@/types/rushApi.ts"; +import { + GetRushUserParticipationStatusResponse, + GetTodayRushEventResponse, +} from "@/types/rushApi.ts"; +import { getRandomCardColors } from "@/utils/getRandomCardColors.ts"; import { writeClipboard } from "@/utils/writeClipboard.ts"; export default function RushGame() { @@ -23,13 +27,42 @@ export default function RushGame() { "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); - const { gameState, setUserParticipationStatus } = useRushGameContext(); + const { gameState, setUserParticipationStatus, updateCardOptions, fetchRushBalance } = + useRushGameContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); const handleClickShareButton = () => { writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); }; + // TODO: 훅으로 빼기 + const { + data: todayRushEventData, + isSuccess: isSuccessTodayRushEvent, + fetchData: getTodayRushEvent, + } = useFetch((token) => RushAPI.getTodayRushEvent(token)); + + useEffect(() => { + getTodayRushEvent(cookies[COOKIE_KEY.ACCESS_TOKEN]); + }, []); + + useEffect(() => { + if (isSuccessTodayRushEvent && todayRushEventData) { + const { leftColor, rightColor } = getRandomCardColors(); + + updateCardOptions(CARD_OPTION.LEFT_OPTIONS, { + mainText: todayRushEventData.leftOption.mainText, + subText: todayRushEventData.leftOption.subText, + color: leftColor, + }); + updateCardOptions(CARD_OPTION.RIGHT_OPTIONS, { + mainText: todayRushEventData.rightOption.mainText, + subText: todayRushEventData.rightOption.subText, + color: rightColor, + }); + } + }, [isSuccessTodayRushEvent, todayRushEventData]); + const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< GetRushUserParticipationStatusResponse, string @@ -42,6 +75,9 @@ export default function RushGame() { useEffect(() => { if (userParticipatedStatus !== null) { setUserParticipationStatus(userParticipatedStatus); + if (userParticipatedStatus && CARD_PHASE.IN_PROGRESS) { + fetchRushBalance(); + } } }, [userParticipatedStatus]); From cd478e70f263f0e5174865783af7b3ee35d54ea1 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 16:53:30 +0900 Subject: [PATCH 15/36] =?UTF-8?q?rename:=20updateCardOptions=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 30 ++++++++----------- .../RushCardResultDescription.tsx | 5 ++-- .../RushGame/RushGameSections/FinalResult.tsx | 8 ++--- client/src/pages/RushGame/index.tsx | 6 ++-- client/src/types/rushGame.ts | 2 +- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index c486f919..260a652b 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -51,19 +51,15 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { setGameState((prevState) => ({ ...prevState, userSelectedOption: option })); }, []); - // TODO: set으로 이름 바꾸기 - const updateCardOptions = useCallback( - (option: CardOption, updates: Partial) => { - setGameState((prevState) => ({ - ...prevState, - cardOptions: { - ...prevState.cardOptions, - [option]: { ...prevState.cardOptions[option], ...updates }, - }, - })); - }, - [] - ); + const setCardOptions = useCallback((option: CardOption, updates: Partial) => { + setGameState((prevState) => ({ + ...prevState, + cardOptions: { + ...prevState.cardOptions, + [option]: { ...prevState.cardOptions[option], ...updates }, + }, + })); + }, []); // TODO: getter 니까 유틸로? const getSelectedCardInfo = useCallback( @@ -98,14 +94,14 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { setUserSelectedOption(optionId); - updateCardOptions(CARD_OPTION.LEFT_OPTIONS, { + setCardOptions(CARD_OPTION.LEFT_OPTIONS, { selectionCount: leftOption, }); - updateCardOptions(CARD_OPTION.RIGHT_OPTIONS, { + setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { selectionCount: rightOption, }); } - }, [isSuccessRushBalance, rushBalanceData, setUserSelectedOption, updateCardOptions]); + }, [isSuccessRushBalance, rushBalanceData, setUserSelectedOption, setCardOptions]); // TODO: 유틸로 빼기 const getOptionRatio = useCallback( @@ -150,7 +146,7 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { { if (isSuccessUserResultData && userResultData) { - updateCardOptions(gameState.userSelectedOption, { + setCardOptions(gameState.userSelectedOption, { mainText: userResultData.mainText, resultMainText: userResultData.resultMainText, resultSubText: userResultData.resultSubText, diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 1b14ef71..13a6d5d3 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -32,7 +32,7 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { gameState, getOptionRatio, getSelectedCardInfo, - updateCardOptions, + setCardOptions, setUserSelectedOption, } = useRushGameContext(); @@ -56,14 +56,14 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { if (optionId) setUserSelectedOption(optionId); - updateCardOptions(CARD_OPTION.LEFT_OPTIONS, { + setCardOptions(CARD_OPTION.LEFT_OPTIONS, { selectionCount: leftOption, }); - updateCardOptions(CARD_OPTION.RIGHT_OPTIONS, { + setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { selectionCount: rightOption, }); } - }, [resultData, isSuccessRushResult, updateCardOptions]); + }, [resultData, isSuccessRushResult, setCardOptions]); const userParticipatedStatus = gameState.userParticipatedStatus; diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index e4fc7f7e..0f61f84d 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -27,7 +27,7 @@ export default function RushGame() { "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); - const { gameState, setUserParticipationStatus, updateCardOptions, fetchRushBalance } = + const { gameState, setUserParticipationStatus, setCardOptions, fetchRushBalance } = useRushGameContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); @@ -50,12 +50,12 @@ export default function RushGame() { if (isSuccessTodayRushEvent && todayRushEventData) { const { leftColor, rightColor } = getRandomCardColors(); - updateCardOptions(CARD_OPTION.LEFT_OPTIONS, { + setCardOptions(CARD_OPTION.LEFT_OPTIONS, { mainText: todayRushEventData.leftOption.mainText, subText: todayRushEventData.leftOption.subText, color: leftColor, }); - updateCardOptions(CARD_OPTION.RIGHT_OPTIONS, { + setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { mainText: todayRushEventData.rightOption.mainText, subText: todayRushEventData.rightOption.subText, color: rightColor, diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index 4bee5f73..f6db730d 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -23,7 +23,7 @@ export interface RushGameContextType { [key in CardOption]: CardOptionState; }; }; - updateCardOptions: (option: CardOption, updates: Partial) => void; + setCardOptions: (option: CardOption, updates: Partial) => void; getSelectedCardInfo: (option: CardOption) => CardOptionState; getOptionRatio: (option: CardOption) => number; fetchRushBalance: () => Promise; From c88e43de199999134d7b2972f428425d89b5231d Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 17:34:22 +0900 Subject: [PATCH 16/36] =?UTF-8?q?refactor:=20getSelectedCardInfo=20?= =?UTF-8?q?=EC=9C=A0=ED=8B=B8=20=ED=95=A8=EC=88=98=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 17 ---------------- .../RushCardCurrentRatio.tsx | 14 +++++++++---- .../RushCardResultDescription.tsx | 10 ++++++---- .../RushGame/RushGameSections/FinalResult.tsx | 20 ++++++++++--------- client/src/types/rushGame.ts | 1 - .../src/utils/RushGame/getSelectedCardInfo.ts | 18 +++++++++++++++++ 6 files changed, 45 insertions(+), 35 deletions(-) create mode 100644 client/src/utils/RushGame/getSelectedCardInfo.ts diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index 260a652b..31d16e2d 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -61,22 +61,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { })); }, []); - // TODO: getter 니까 유틸로? - const getSelectedCardInfo = useCallback( - (option: CardOption) => { - const cardInfo = gameState.cardOptions[option]; - return { - mainText: cardInfo.mainText, - subText: cardInfo.subText, - resultMainText: cardInfo.resultMainText, - resultSubText: cardInfo.resultSubText, - color: cardInfo.color, - selectionCount: cardInfo.selectionCount, - }; - }, - [gameState.userSelectedOption, gameState.cardOptions] - ); - // TODO: 훅으로 빼기 const { data: rushBalanceData, @@ -147,7 +131,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { value={{ gameState, setCardOptions, - getSelectedCardInfo, getOptionRatio, fetchRushBalance, setUserParticipationStatus, diff --git a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx index b52a276b..a095c9d0 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx @@ -6,6 +6,7 @@ import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgress import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import { CardOption } from "@/types/rushGame.ts"; +import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; import Reload from "/public/assets/icons/reload.svg?react"; const tooltipVariants = cva(`absolute transition-opacity duration-300 ease-in-out`, { @@ -51,8 +52,7 @@ function getMessage(leftRatio: number, rightRatio: number, userSelectedOption: C } export default function RushCardCurrentRatio() { - const { gameState, getOptionRatio, fetchRushBalance, getSelectedCardInfo } = - useRushGameContext(); + const { gameState, getOptionRatio, fetchRushBalance } = useRushGameContext(); const { toggleContents } = useToggleContents(); const leftOptionRatio = getOptionRatio(CARD_OPTION.LEFT_OPTIONS); @@ -60,8 +60,14 @@ export default function RushCardCurrentRatio() { const message = getMessage(leftOptionRatio, rightOptionRatio, gameState.userSelectedOption); - const { mainText: leftMainText } = getSelectedCardInfo(CARD_OPTION.LEFT_OPTIONS); - const { mainText: rightMainText } = getSelectedCardInfo(CARD_OPTION.RIGHT_OPTIONS); + const { mainText: leftMainText } = getSelectedCardInfo({ + gameState: gameState, + option: CARD_OPTION.LEFT_OPTIONS, + }); + const { mainText: rightMainText } = getSelectedCardInfo({ + gameState: gameState, + option: CARD_OPTION.RIGHT_OPTIONS, + }); return (
diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index 85808262..31cb3eb7 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -9,6 +9,7 @@ import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import { GetRushOptionResultResponse } from "@/types/rushApi.ts"; import { CardOption } from "@/types/rushGame.ts"; +import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; const backgroundGradients = cva( `flex gap-[35px] w-[834px] h-[400px] rounded-800 py-6 px-[37px] justify-between break-keep`, @@ -29,7 +30,7 @@ const backgroundGradients = cva( export default function RushCardResultDescription() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setCardOptions, getSelectedCardInfo, getOptionRatio } = useRushGameContext(); + const { gameState, setCardOptions, getOptionRatio } = useRushGameContext(); const { data: userResultData, @@ -56,9 +57,10 @@ export default function RushCardResultDescription() { } }, [isSuccessUserResultData, userResultData]); - const { mainText, resultMainText, resultSubText, color } = getSelectedCardInfo( - gameState.userSelectedOption - ); + const { mainText, resultMainText, resultSubText, color } = getSelectedCardInfo({ + gameState: gameState, + option: gameState.userSelectedOption, + }); const selectedOptionRatio = getOptionRatio(gameState.userSelectedOption); diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 13a6d5d3..3bceb54a 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -11,6 +11,7 @@ import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import { GetRushResultResponse } from "@/types/rushApi.ts"; import { WinStatus } from "@/types/rushGame.ts"; +import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; const MESSAGES = { WINNING: "축하해요! 선착순 경품 당첨이에요.", @@ -28,13 +29,8 @@ interface FinalResultProps { export default function FinalResult({ unblockNavigation }: FinalResultProps) { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { - gameState, - getOptionRatio, - getSelectedCardInfo, - setCardOptions, - setUserSelectedOption, - } = useRushGameContext(); + const { gameState, getOptionRatio, setCardOptions, setUserSelectedOption } = + useRushGameContext(); const { data: resultData, @@ -73,8 +69,14 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { const message = isWinner ? MESSAGES.WINNING : MESSAGES.LOSING; - const { mainText: leftMainText } = getSelectedCardInfo(CARD_OPTION.LEFT_OPTIONS); - const { mainText: rightMainText } = getSelectedCardInfo(CARD_OPTION.RIGHT_OPTIONS); + const { mainText: leftMainText } = getSelectedCardInfo({ + gameState: gameState, + option: CARD_OPTION.LEFT_OPTIONS, + }); + const { mainText: rightMainText } = getSelectedCardInfo({ + gameState: gameState, + option: CARD_OPTION.RIGHT_OPTIONS, + }); const leftOptionRatio = getOptionRatio(CARD_OPTION.LEFT_OPTIONS); const rightOptionRatio = getOptionRatio(CARD_OPTION.RIGHT_OPTIONS); diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index f6db730d..e36d7a99 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -24,7 +24,6 @@ export interface RushGameContextType { }; }; setCardOptions: (option: CardOption, updates: Partial) => void; - getSelectedCardInfo: (option: CardOption) => CardOptionState; getOptionRatio: (option: CardOption) => number; fetchRushBalance: () => Promise; setUserParticipationStatus: (status: boolean) => void; diff --git a/client/src/utils/RushGame/getSelectedCardInfo.ts b/client/src/utils/RushGame/getSelectedCardInfo.ts new file mode 100644 index 00000000..3da60bee --- /dev/null +++ b/client/src/utils/RushGame/getSelectedCardInfo.ts @@ -0,0 +1,18 @@ +import { CardOption, RushGameContextType } from "@/types/rushGame.ts"; + +interface GetSelectedCardInfoProps { + gameState: RushGameContextType["gameState"]; + option: CardOption; +} + +export const getSelectedCardInfo = ({ gameState, option }: GetSelectedCardInfoProps) => { + const cardInfo = gameState.cardOptions[option]; + return { + mainText: cardInfo.mainText, + subText: cardInfo.subText, + resultMainText: cardInfo.resultMainText, + resultSubText: cardInfo.resultSubText, + color: cardInfo.color, + selectionCount: cardInfo.selectionCount, + }; +}; From 47ab45b80880a9cde64d4f3b7cdae69b1b12107e Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 17:59:43 +0900 Subject: [PATCH 17/36] =?UTF-8?q?refactor:=20getOptionRatio=20=EC=9C=A0?= =?UTF-8?q?=ED=8B=B8=20=ED=95=A8=EC=88=98=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 14 -------------- .../RushGameComponents/RushCardCurrentRatio.tsx | 13 ++++++++++--- .../RushCardResultDescription.tsx | 8 ++++++-- .../RushGame/RushGameSections/FinalResult.tsx | 14 ++++++++++---- client/src/types/rushGame.ts | 1 - client/src/utils/RushGame/getOptionRatio.ts | 16 ++++++++++++++++ 6 files changed, 42 insertions(+), 24 deletions(-) create mode 100644 client/src/utils/RushGame/getOptionRatio.ts diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index 31d16e2d..b459f1d5 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -87,19 +87,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { } }, [isSuccessRushBalance, rushBalanceData, setUserSelectedOption, setCardOptions]); - // TODO: 유틸로 빼기 - const getOptionRatio = useCallback( - (option: CardOption): number => { - const total = - gameState.cardOptions[CARD_OPTION.LEFT_OPTIONS].selectionCount + - gameState.cardOptions[CARD_OPTION.RIGHT_OPTIONS].selectionCount; - if (total === 0) return 0; - const ratio = (gameState.cardOptions[option].selectionCount / total) * 100; - return Math.round(ratio * 100) / 100; - }, - [gameState.cardOptions] - ); - // TODO: dispatch action으로 함수로 빼서 RushGame 컴포넌트에서 함수를 호출해서 초기화해주는 것이 맞다고 생각.. useEffect(() => { if (rushData) { @@ -131,7 +118,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { value={{ gameState, setCardOptions, - getOptionRatio, fetchRushBalance, setUserParticipationStatus, setGamePhase, diff --git a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx index a095c9d0..389ac309 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx @@ -6,6 +6,7 @@ import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgress import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import { CardOption } from "@/types/rushGame.ts"; +import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; import Reload from "/public/assets/icons/reload.svg?react"; @@ -52,11 +53,17 @@ function getMessage(leftRatio: number, rightRatio: number, userSelectedOption: C } export default function RushCardCurrentRatio() { - const { gameState, getOptionRatio, fetchRushBalance } = useRushGameContext(); + const { gameState, fetchRushBalance } = useRushGameContext(); const { toggleContents } = useToggleContents(); - const leftOptionRatio = getOptionRatio(CARD_OPTION.LEFT_OPTIONS); - const rightOptionRatio = getOptionRatio(CARD_OPTION.RIGHT_OPTIONS); + const leftOptionRatio = getOptionRatio({ + gameState: gameState, + option: CARD_OPTION.LEFT_OPTIONS, + }); + const rightOptionRatio = getOptionRatio({ + gameState: gameState, + option: CARD_OPTION.RIGHT_OPTIONS, + }); const message = getMessage(leftOptionRatio, rightOptionRatio, gameState.userSelectedOption); diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index 31cb3eb7..f11567cf 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -9,6 +9,7 @@ import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import { GetRushOptionResultResponse } from "@/types/rushApi.ts"; import { CardOption } from "@/types/rushGame.ts"; +import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; const backgroundGradients = cva( @@ -30,7 +31,7 @@ const backgroundGradients = cva( export default function RushCardResultDescription() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setCardOptions, getOptionRatio } = useRushGameContext(); + const { gameState, setCardOptions } = useRushGameContext(); const { data: userResultData, @@ -62,7 +63,10 @@ export default function RushCardResultDescription() { option: gameState.userSelectedOption, }); - const selectedOptionRatio = getOptionRatio(gameState.userSelectedOption); + const selectedOptionRatio = getOptionRatio({ + gameState: gameState, + option: gameState.userSelectedOption, + }); return (
diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 3bceb54a..7c441281 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -11,6 +11,7 @@ import useFetch from "@/hooks/useFetch.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import { GetRushResultResponse } from "@/types/rushApi.ts"; import { WinStatus } from "@/types/rushGame.ts"; +import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; const MESSAGES = { @@ -29,8 +30,7 @@ interface FinalResultProps { export default function FinalResult({ unblockNavigation }: FinalResultProps) { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, getOptionRatio, setCardOptions, setUserSelectedOption } = - useRushGameContext(); + const { gameState, setCardOptions, setUserSelectedOption } = useRushGameContext(); const { data: resultData, @@ -78,8 +78,14 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { option: CARD_OPTION.RIGHT_OPTIONS, }); - const leftOptionRatio = getOptionRatio(CARD_OPTION.LEFT_OPTIONS); - const rightOptionRatio = getOptionRatio(CARD_OPTION.RIGHT_OPTIONS); + const leftOptionRatio = getOptionRatio({ + gameState: gameState, + option: CARD_OPTION.LEFT_OPTIONS, + }); + const rightOptionRatio = getOptionRatio({ + gameState: gameState, + option: CARD_OPTION.RIGHT_OPTIONS, + }); const leftWinStatus = getWinStatus(leftOptionRatio, rightOptionRatio); const rightWinStatus = getWinStatus(rightOptionRatio, leftOptionRatio); diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index e36d7a99..667eb6fe 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -24,7 +24,6 @@ export interface RushGameContextType { }; }; setCardOptions: (option: CardOption, updates: Partial) => void; - getOptionRatio: (option: CardOption) => number; fetchRushBalance: () => Promise; setUserParticipationStatus: (status: boolean) => void; setGamePhase: (phase: GamePhase) => void; diff --git a/client/src/utils/RushGame/getOptionRatio.ts b/client/src/utils/RushGame/getOptionRatio.ts new file mode 100644 index 00000000..b052ac87 --- /dev/null +++ b/client/src/utils/RushGame/getOptionRatio.ts @@ -0,0 +1,16 @@ +import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; +import { CardOption, RushGameContextType } from "@/types/rushGame.ts"; + +interface GetOptionRatioProps { + gameState: RushGameContextType["gameState"]; + option: CardOption; +} + +export const getOptionRatio = ({ gameState, option }: GetOptionRatioProps) => { + const total = + gameState.cardOptions[CARD_OPTION.LEFT_OPTIONS].selectionCount + + gameState.cardOptions[CARD_OPTION.RIGHT_OPTIONS].selectionCount; + if (total === 0) return 0; + const ratio = (gameState.cardOptions[option].selectionCount / total) * 100; + return Math.round(ratio * 100) / 100; +}; From dff318127d52ddcd4e6da98c23ab63bb238f6b47 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 18:07:21 +0900 Subject: [PATCH 18/36] =?UTF-8?q?fix:=20useFetch=20=EC=BD=9C=EB=B0=B1=20?= =?UTF-8?q?=EC=8C=93=EC=9D=B4=EB=8A=94=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGame/RushGameComponents/RushCardResultDescription.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index f11567cf..ce991ef6 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -46,7 +46,7 @@ export default function RushCardResultDescription() { token: cookies[COOKIE_KEY.ACCESS_TOKEN], optionId: gameState.userSelectedOption, }); - }, [cookies, gameState.userSelectedOption, getUserResultData]); + }, [cookies, gameState.userSelectedOption]); useEffect(() => { if (isSuccessUserResultData && userResultData) { From 9312f4bba591a5c49b902fec5ba347fb3e04215d Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 18:53:56 +0900 Subject: [PATCH 19/36] =?UTF-8?q?refactor:=20rushBalanceData=20=ED=8C=A8?= =?UTF-8?q?=EC=B9=AD=20=EB=B0=8F=20=EC=83=81=ED=83=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 34 +--------------- .../RushGameComponents/RushCardComparison.tsx | 5 ++- .../RushCardCurrentRatio.tsx | 4 +- .../RushGameSections/SelectedCard.tsx | 4 +- client/src/hooks/useFetchRushBalance.ts | 40 +++++++++++++++++++ client/src/pages/RushGame/index.tsx | 5 ++- client/src/types/rushGame.ts | 1 - 7 files changed, 52 insertions(+), 41 deletions(-) create mode 100644 client/src/hooks/useFetchRushBalance.ts diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index b459f1d5..9a0c8bd4 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -1,18 +1,13 @@ import { ReactNode, createContext, useCallback, useEffect, useState } from "react"; -import { useCookies } from "react-cookie"; import { useLoaderData } from "react-router-dom"; -import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_COLOR, CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard"; -import { COOKIE_KEY } from "@/constants/cookie.ts"; -import useFetch from "@/hooks/useFetch.ts"; -import { GetRushBalanceResponse, GetTotalRushEventsResponse } from "@/types/rushApi.ts"; +import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { CardOption, CardOptionState, GamePhase, RushGameContextType } from "@/types/rushGame"; import { getMsTime } from "@/utils/getMsTime.ts"; export const RushGameContext = createContext(undefined); export const RushGameProvider = ({ children }: { children: ReactNode }) => { - const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); const rushData = useLoaderData() as GetTotalRushEventsResponse; const [gameState, setGameState] = useState({ @@ -61,32 +56,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { })); }, []); - // TODO: 훅으로 빼기 - const { - data: rushBalanceData, - isSuccess: isSuccessRushBalance, - fetchData: getRushBalance, - } = useFetch((token) => RushAPI.getRushBalance(token)); - - const fetchRushBalance = useCallback(async (): Promise => { - await getRushBalance(cookies[COOKIE_KEY.ACCESS_TOKEN]); - }, [cookies, getRushBalance]); - - useEffect(() => { - if (isSuccessRushBalance && rushBalanceData) { - const { optionId, leftOption, rightOption } = rushBalanceData; - - setUserSelectedOption(optionId); - - setCardOptions(CARD_OPTION.LEFT_OPTIONS, { - selectionCount: leftOption, - }); - setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { - selectionCount: rightOption, - }); - } - }, [isSuccessRushBalance, rushBalanceData, setUserSelectedOption, setCardOptions]); - // TODO: dispatch action으로 함수로 빼서 RushGame 컴포넌트에서 함수를 호출해서 초기화해주는 것이 맞다고 생각.. useEffect(() => { if (rushData) { @@ -118,7 +87,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { value={{ gameState, setCardOptions, - fetchRushBalance, setUserParticipationStatus, setGamePhase, setUserSelectedOption, diff --git a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx index 01b2a30f..3b2c869e 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx @@ -5,6 +5,7 @@ import { CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushCard from "@/features/RushGame/RushGameComponents/RushCard.tsx"; import useFetch from "@/hooks/useFetch.ts"; +import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import { GetRushUserParticipationStatusResponse, @@ -14,8 +15,8 @@ import { CardOption } from "@/types/rushGame.ts"; export default function RushCardComparison() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setUserSelectedOption, setUserParticipationStatus, fetchRushBalance } = - useRushGameContext(); + const { gameState, setUserSelectedOption, setUserParticipationStatus } = useRushGameContext(); + const fetchRushBalance = useFetchRushBalance(); const { data: postSelectedRushOptionResponse, diff --git a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx index 389ac309..8caafe47 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx @@ -3,6 +3,7 @@ import Tooltip from "@/components/Tooltip"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import RushCurrentOptionDisplay from "@/features/RushGame/RushGameComponents/RushCurrentOptionDisplay.tsx"; import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgressBar.tsx"; +import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import { CardOption } from "@/types/rushGame.ts"; @@ -53,8 +54,9 @@ function getMessage(leftRatio: number, rightRatio: number, userSelectedOption: C } export default function RushCardCurrentRatio() { - const { gameState, fetchRushBalance } = useRushGameContext(); + const { gameState } = useRushGameContext(); const { toggleContents } = useToggleContents(); + const fetchRushBalance = useFetchRushBalance(); const leftOptionRatio = getOptionRatio({ gameState: gameState, diff --git a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx index d81384aa..a1217608 100644 --- a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx +++ b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx @@ -4,7 +4,7 @@ import { ASCEND, DISSOLVE, SCROLL_MOTION } from "@/constants/animation.ts"; import RushCardCurrentRatio from "@/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx"; import RushCardResultDescription from "@/features/RushGame/RushGameComponents/RushCardResultDescription.tsx"; import RushCountdown from "@/features/RushGame/RushGameComponents/RushCountdown.tsx"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import ArrowLeftIcon from "/public/assets/icons/arrow-line-left.svg?react"; import ArrowRightIcon from "/public/assets/icons/arrow-line-right.svg?react"; @@ -57,7 +57,7 @@ interface SelectedCardProps { export default function SelectedCard({ unblockNavigation }: SelectedCardProps) { const { toggleContents, toggle } = useToggleContents({ useDuration: false }); - const { fetchRushBalance } = useRushGameContext(); + const fetchRushBalance = useFetchRushBalance(); useEffect(() => { fetchRushBalance(); diff --git a/client/src/hooks/useFetchRushBalance.ts b/client/src/hooks/useFetchRushBalance.ts new file mode 100644 index 00000000..df9281ff --- /dev/null +++ b/client/src/hooks/useFetchRushBalance.ts @@ -0,0 +1,40 @@ +import { useCallback, useEffect } from "react"; +import { useCookies } from "react-cookie"; +import { RushAPI } from "@/apis/rushAPI.ts"; +import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; +import { COOKIE_KEY } from "@/constants/cookie.ts"; +import useFetch from "@/hooks/useFetch.ts"; +import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import { GetRushBalanceResponse } from "@/types/rushApi.ts"; + +export default function useFetchRushBalance() { + const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); + const { setUserSelectedOption, setCardOptions } = useRushGameContext(); + + const { + data: rushBalanceData, + isSuccess: isSuccessRushBalance, + fetchData: getRushBalance, + } = useFetch((token) => RushAPI.getRushBalance(token)); + + const fetchRushBalance = useCallback(async (): Promise => { + await getRushBalance(cookies[COOKIE_KEY.ACCESS_TOKEN]); + }, [cookies, getRushBalance]); + + useEffect(() => { + if (isSuccessRushBalance && rushBalanceData) { + const { optionId, leftOption, rightOption } = rushBalanceData; + + setUserSelectedOption(optionId); + + setCardOptions(CARD_OPTION.LEFT_OPTIONS, { + selectionCount: leftOption, + }); + setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { + selectionCount: rightOption, + }); + } + }, [isSuccessRushBalance, rushBalanceData, setUserSelectedOption, setCardOptions]); + + return fetchRushBalance; +} diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index 0f61f84d..0741a344 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -12,6 +12,7 @@ import FinalResult from "@/features/RushGame/RushGameSections/FinalResult.tsx"; import SelectedCard from "@/features/RushGame/RushGameSections/SelectedCard.tsx"; import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; import useFetch from "@/hooks/useFetch.ts"; +import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToast from "@/hooks/useToast.tsx"; import { @@ -27,9 +28,9 @@ export default function RushGame() { "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); - const { gameState, setUserParticipationStatus, setCardOptions, fetchRushBalance } = - useRushGameContext(); + const { gameState, setUserParticipationStatus, setCardOptions } = useRushGameContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); + const fetchRushBalance = useFetchRushBalance(); const handleClickShareButton = () => { writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index 667eb6fe..a3d4bae4 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -24,7 +24,6 @@ export interface RushGameContextType { }; }; setCardOptions: (option: CardOption, updates: Partial) => void; - fetchRushBalance: () => Promise; setUserParticipationStatus: (status: boolean) => void; setGamePhase: (phase: GamePhase) => void; setUserSelectedOption: (option: CardOption) => void; From b5e604c7add9c9035a64bfe6406f1e215e641c85 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 22:02:09 +0900 Subject: [PATCH 20/36] =?UTF-8?q?refactor:=20todayRushEventData=20?= =?UTF-8?q?=ED=8C=A8=EC=B9=AD=20=EB=B0=8F=20=EC=83=81=ED=83=9C=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useFetchTodayRushEvent.ts | 36 ++++++++++++++++++++++ client/src/pages/RushGame/index.tsx | 36 +++------------------- 2 files changed, 41 insertions(+), 31 deletions(-) create mode 100644 client/src/hooks/useFetchTodayRushEvent.ts diff --git a/client/src/hooks/useFetchTodayRushEvent.ts b/client/src/hooks/useFetchTodayRushEvent.ts new file mode 100644 index 00000000..e2d33a22 --- /dev/null +++ b/client/src/hooks/useFetchTodayRushEvent.ts @@ -0,0 +1,36 @@ +import { useEffect } from "react"; +import { RushAPI } from "@/apis/rushAPI.ts"; +import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; +import useFetch from "@/hooks/useFetch.ts"; +import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import { GetTodayRushEventResponse } from "@/types/rushApi.ts"; +import { getRandomCardColors } from "@/utils/getRandomCardColors"; + +export const useFetchTodayRushEvent = () => { + const { setCardOptions } = useRushGameContext(); + + const { + data: todayRushEventData, + isSuccess: isSuccessTodayRushEvent, + fetchData: getTodayRushEvent, + } = useFetch((token) => RushAPI.getTodayRushEvent(token)); + + useEffect(() => { + if (isSuccessTodayRushEvent && todayRushEventData) { + const { leftColor, rightColor } = getRandomCardColors(); + + setCardOptions(CARD_OPTION.LEFT_OPTIONS, { + mainText: todayRushEventData.leftOption.mainText, + subText: todayRushEventData.leftOption.subText, + color: leftColor, + }); + setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { + mainText: todayRushEventData.rightOption.mainText, + subText: todayRushEventData.rightOption.subText, + color: rightColor, + }); + } + }, [isSuccessTodayRushEvent, todayRushEventData]); + + return { getTodayRushEvent }; +}; diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index 0741a344..d922d47d 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -3,7 +3,7 @@ import { motion } from "framer-motion"; import { useCookies } from "react-cookie"; import { RushAPI } from "@/apis/rushAPI.ts"; import CTAButton from "@/components/CTAButton"; -import { CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import CardOptions from "@/features/RushGame/RushGameSections/CardOptions.tsx"; @@ -13,13 +13,10 @@ import SelectedCard from "@/features/RushGame/RushGameSections/SelectedCard.tsx" import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; import useFetch from "@/hooks/useFetch.ts"; import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; +import { useFetchTodayRushEvent } from "@/hooks/useFetchTodayRushEvent.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToast from "@/hooks/useToast.tsx"; -import { - GetRushUserParticipationStatusResponse, - GetTodayRushEventResponse, -} from "@/types/rushApi.ts"; -import { getRandomCardColors } from "@/utils/getRandomCardColors.ts"; +import { GetRushUserParticipationStatusResponse } from "@/types/rushApi.ts"; import { writeClipboard } from "@/utils/writeClipboard.ts"; export default function RushGame() { @@ -27,8 +24,9 @@ export default function RushGame() { const { unblockNavigation } = useBlockNavigation( "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); + const { getTodayRushEvent } = useFetchTodayRushEvent(); - const { gameState, setUserParticipationStatus, setCardOptions } = useRushGameContext(); + const { gameState, setUserParticipationStatus } = useRushGameContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); const fetchRushBalance = useFetchRushBalance(); @@ -36,34 +34,10 @@ export default function RushGame() { writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); }; - // TODO: 훅으로 빼기 - const { - data: todayRushEventData, - isSuccess: isSuccessTodayRushEvent, - fetchData: getTodayRushEvent, - } = useFetch((token) => RushAPI.getTodayRushEvent(token)); - useEffect(() => { getTodayRushEvent(cookies[COOKIE_KEY.ACCESS_TOKEN]); }, []); - useEffect(() => { - if (isSuccessTodayRushEvent && todayRushEventData) { - const { leftColor, rightColor } = getRandomCardColors(); - - setCardOptions(CARD_OPTION.LEFT_OPTIONS, { - mainText: todayRushEventData.leftOption.mainText, - subText: todayRushEventData.leftOption.subText, - color: leftColor, - }); - setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { - mainText: todayRushEventData.rightOption.mainText, - subText: todayRushEventData.rightOption.subText, - color: rightColor, - }); - } - }, [isSuccessTodayRushEvent, todayRushEventData]); - const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< GetRushUserParticipationStatusResponse, string From 270c911c822026e26a6fc2e5125ba5711ca2e150 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 22:28:51 +0900 Subject: [PATCH 21/36] =?UTF-8?q?refactor:=20rushUserParticipationStatus?= =?UTF-8?q?=20=ED=8C=A8=EC=B9=AD=20=EB=B0=8F=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGameComponents/RushCardComparison.tsx | 27 ++++-------------- .../useFetchRushUserParticipationStatus.ts | 28 +++++++++++++++++++ client/src/hooks/useFetchTodayRushEvent.ts | 4 +-- client/src/pages/RushGame/index.tsx | 28 +++---------------- 4 files changed, 39 insertions(+), 48 deletions(-) create mode 100644 client/src/hooks/useFetchRushUserParticipationStatus.ts diff --git a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx index 3b2c869e..0f871898 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx @@ -1,22 +1,19 @@ import { useEffect } from "react"; import { useCookies } from "react-cookie"; import { RushAPI } from "@/apis/rushAPI.ts"; -import { CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushCard from "@/features/RushGame/RushGameComponents/RushCard.tsx"; import useFetch from "@/hooks/useFetch.ts"; -import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; +import { useFetchRushUserParticipationStatus } from "@/hooks/useFetchRushUserParticipationStatus.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; -import { - GetRushUserParticipationStatusResponse, - RushEventStatusCodeResponse, -} from "@/types/rushApi.ts"; +import { RushEventStatusCodeResponse } from "@/types/rushApi.ts"; import { CardOption } from "@/types/rushGame.ts"; export default function RushCardComparison() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setUserSelectedOption, setUserParticipationStatus } = useRushGameContext(); - const fetchRushBalance = useFetchRushBalance(); + const { gameState, setUserSelectedOption } = useRushGameContext(); + const { getRushUserParticipationStatus } = useFetchRushUserParticipationStatus(); const { data: postSelectedRushOptionResponse, @@ -26,11 +23,6 @@ export default function RushCardComparison() { ({ token, optionId }) => RushAPI.postSelectedRushOptionApply(token, optionId) ); - const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< - GetRushUserParticipationStatusResponse, - string - >((token) => RushAPI.getRushUserParticipationStatus(token)); - const handleCardSelection = async (optionId: CardOption) => { await postSelectedRushOptionApply({ token: cookies[COOKIE_KEY.ACCESS_TOKEN], optionId }); setUserSelectedOption(optionId); @@ -42,15 +34,6 @@ export default function RushCardComparison() { } }, [isSuccessPostSelectedRushOption, postSelectedRushOptionResponse]); - useEffect(() => { - if (userParticipatedStatus !== null) { - setUserParticipationStatus(userParticipatedStatus); - if (userParticipatedStatus && CARD_PHASE.IN_PROGRESS) { - fetchRushBalance(); - } - } - }, [userParticipatedStatus]); - const leftOptionData = gameState.cardOptions[CARD_OPTION.LEFT_OPTIONS]; const rightOptionData = gameState.cardOptions[CARD_OPTION.RIGHT_OPTIONS]; diff --git a/client/src/hooks/useFetchRushUserParticipationStatus.ts b/client/src/hooks/useFetchRushUserParticipationStatus.ts new file mode 100644 index 00000000..11d90ae5 --- /dev/null +++ b/client/src/hooks/useFetchRushUserParticipationStatus.ts @@ -0,0 +1,28 @@ +import { useEffect } from "react"; +import { RushAPI } from "@/apis/rushAPI.ts"; +import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import useFetch from "@/hooks/useFetch.ts"; +import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; +import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import { GetRushUserParticipationStatusResponse } from "@/types/rushApi.ts"; + +export function useFetchRushUserParticipationStatus() { + const { setUserParticipationStatus } = useRushGameContext(); + const fetchRushBalance = useFetchRushBalance(); + + const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< + GetRushUserParticipationStatusResponse, + string + >((token) => RushAPI.getRushUserParticipationStatus(token)); + + useEffect(() => { + if (userParticipatedStatus !== null) { + setUserParticipationStatus(userParticipatedStatus); + if (userParticipatedStatus && CARD_PHASE.IN_PROGRESS) { + fetchRushBalance(); + } + } + }, [userParticipatedStatus]); + + return { userParticipatedStatus, getRushUserParticipationStatus }; +} diff --git a/client/src/hooks/useFetchTodayRushEvent.ts b/client/src/hooks/useFetchTodayRushEvent.ts index e2d33a22..019365f8 100644 --- a/client/src/hooks/useFetchTodayRushEvent.ts +++ b/client/src/hooks/useFetchTodayRushEvent.ts @@ -6,7 +6,7 @@ import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import { GetTodayRushEventResponse } from "@/types/rushApi.ts"; import { getRandomCardColors } from "@/utils/getRandomCardColors"; -export const useFetchTodayRushEvent = () => { +export function useFetchTodayRushEvent() { const { setCardOptions } = useRushGameContext(); const { @@ -33,4 +33,4 @@ export const useFetchTodayRushEvent = () => { }, [isSuccessTodayRushEvent, todayRushEventData]); return { getTodayRushEvent }; -}; +} diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index d922d47d..82761780 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -1,7 +1,6 @@ import { useEffect } from "react"; import { motion } from "framer-motion"; import { useCookies } from "react-cookie"; -import { RushAPI } from "@/apis/rushAPI.ts"; import CTAButton from "@/components/CTAButton"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; @@ -11,12 +10,10 @@ import Countdown from "@/features/RushGame/RushGameSections/Countdown.tsx"; import FinalResult from "@/features/RushGame/RushGameSections/FinalResult.tsx"; import SelectedCard from "@/features/RushGame/RushGameSections/SelectedCard.tsx"; import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; -import useFetch from "@/hooks/useFetch.ts"; -import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; +import { useFetchRushUserParticipationStatus } from "@/hooks/useFetchRushUserParticipationStatus.ts"; import { useFetchTodayRushEvent } from "@/hooks/useFetchTodayRushEvent.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; import useToast from "@/hooks/useToast.tsx"; -import { GetRushUserParticipationStatusResponse } from "@/types/rushApi.ts"; import { writeClipboard } from "@/utils/writeClipboard.ts"; export default function RushGame() { @@ -25,10 +22,10 @@ export default function RushGame() { "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); const { getTodayRushEvent } = useFetchTodayRushEvent(); - - const { gameState, setUserParticipationStatus } = useRushGameContext(); + const { gameState } = useRushGameContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); - const fetchRushBalance = useFetchRushBalance(); + const { getRushUserParticipationStatus, userParticipatedStatus } = + useFetchRushUserParticipationStatus(); const handleClickShareButton = () => { writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); @@ -36,26 +33,9 @@ export default function RushGame() { useEffect(() => { getTodayRushEvent(cookies[COOKIE_KEY.ACCESS_TOKEN]); - }, []); - - const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< - GetRushUserParticipationStatusResponse, - string - >((token) => RushAPI.getRushUserParticipationStatus(token)); - - useEffect(() => { getRushUserParticipationStatus(cookies[COOKIE_KEY.ACCESS_TOKEN]); }, []); - useEffect(() => { - if (userParticipatedStatus !== null) { - setUserParticipationStatus(userParticipatedStatus); - if (userParticipatedStatus && CARD_PHASE.IN_PROGRESS) { - fetchRushBalance(); - } - } - }, [userParticipatedStatus]); - const renderRushGameContent = () => { switch (gameState.phase) { case CARD_PHASE.NOT_STARTED: From ab56abd3ee28537a0c405346a1ad796340ec22ae Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 22:38:29 +0900 Subject: [PATCH 22/36] =?UTF-8?q?refactor:=20resultData=20=ED=8C=A8?= =?UTF-8?q?=EC=B9=AD=20=EB=B0=8F=20=EC=83=81=ED=83=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGame/RushGameSections/FinalResult.tsx | 33 +++---------------- client/src/hooks/useFetchRushResult.ts | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+), 29 deletions(-) create mode 100644 client/src/hooks/useFetchRushResult.ts diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 7c441281..72bbb822 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -1,15 +1,13 @@ import { useEffect } from "react"; import { motion } from "framer-motion"; import { useCookies } from "react-cookie"; -import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION, WIN_STATUS } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgressBar.tsx"; import RushResultOptionDisplay from "@/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx"; -import useFetch from "@/hooks/useFetch.ts"; +import { useFetchRushResult } from "@/hooks/useFetchRushResult.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; -import { GetRushResultResponse } from "@/types/rushApi.ts"; import { WinStatus } from "@/types/rushGame.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; @@ -30,37 +28,14 @@ interface FinalResultProps { export default function FinalResult({ unblockNavigation }: FinalResultProps) { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setCardOptions, setUserSelectedOption } = useRushGameContext(); - - const { - data: resultData, - isSuccess: isSuccessRushResult, - fetchData: getRushResult, - } = useFetch( - () => RushAPI.getRushResult(cookies[COOKIE_KEY.ACCESS_TOKEN]), - false - ); + const { gameState } = useRushGameContext(); + const { getRushResult, resultData } = useFetchRushResult(); useEffect(() => { - getRushResult(); + getRushResult(cookies[COOKIE_KEY.ACCESS_TOKEN]); unblockNavigation(); }, []); - useEffect(() => { - if (resultData && isSuccessRushResult) { - const { optionId, leftOption, rightOption } = resultData; - - if (optionId) setUserSelectedOption(optionId); - - setCardOptions(CARD_OPTION.LEFT_OPTIONS, { - selectionCount: leftOption, - }); - setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { - selectionCount: rightOption, - }); - } - }, [resultData, isSuccessRushResult, setCardOptions]); - const userParticipatedStatus = gameState.userParticipatedStatus; const isWinner = resultData?.isWinner; diff --git a/client/src/hooks/useFetchRushResult.ts b/client/src/hooks/useFetchRushResult.ts new file mode 100644 index 00000000..0e0f1878 --- /dev/null +++ b/client/src/hooks/useFetchRushResult.ts @@ -0,0 +1,33 @@ +import { useEffect } from "react"; +import { RushAPI } from "@/apis/rushAPI.ts"; +import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; +import useFetch from "@/hooks/useFetch.ts"; +import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import { GetRushResultResponse } from "@/types/rushApi.ts"; + +export function useFetchRushResult() { + const { setUserSelectedOption, setCardOptions } = useRushGameContext(); + + const { + data: resultData, + isSuccess: isSuccessRushResult, + fetchData: getRushResult, + } = useFetch((token) => RushAPI.getRushResult(token), false); + + useEffect(() => { + if (resultData && isSuccessRushResult) { + const { optionId, leftOption, rightOption } = resultData; + + if (optionId) setUserSelectedOption(optionId); + + setCardOptions(CARD_OPTION.LEFT_OPTIONS, { + selectionCount: leftOption, + }); + setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { + selectionCount: rightOption, + }); + } + }, [resultData, isSuccessRushResult, setCardOptions]); + + return { getRushResult, resultData }; +} From 1120dee6a2afdea5b22f0e1b3062976ee954fa86 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 22:50:33 +0900 Subject: [PATCH 23/36] =?UTF-8?q?refactor:=20userResultData=20=ED=8C=A8?= =?UTF-8?q?=EC=B9=AD=20=EB=B0=8F=20=EC=83=81=ED=83=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushCardResultDescription.tsx | 26 ++-------------- client/src/hooks/useFetchRushOptionResult.ts | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 23 deletions(-) create mode 100644 client/src/hooks/useFetchRushOptionResult.ts diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index ce991ef6..4b7004fd 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -1,14 +1,11 @@ import { useEffect } from "react"; import { cva } from "class-variance-authority"; import { useCookies } from "react-cookie"; -import { RushAPI } from "@/apis/rushAPI.ts"; import Category from "@/components/Category"; import { CARD_COLOR } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; -import useFetch from "@/hooks/useFetch.ts"; +import { useFetchRushOptionResult } from "@/hooks/useFetchRushOptionResult.ts"; import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; -import { GetRushOptionResultResponse } from "@/types/rushApi.ts"; -import { CardOption } from "@/types/rushGame.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; @@ -31,15 +28,8 @@ const backgroundGradients = cva( export default function RushCardResultDescription() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setCardOptions } = useRushGameContext(); - - const { - data: userResultData, - isSuccess: isSuccessUserResultData, - fetchData: getUserResultData, - } = useFetch( - ({ token, optionId }) => RushAPI.getRushOptionResult(token, optionId) - ); + const { gameState } = useRushGameContext(); + const { getUserResultData } = useFetchRushOptionResult(); useEffect(() => { getUserResultData({ @@ -48,16 +38,6 @@ export default function RushCardResultDescription() { }); }, [cookies, gameState.userSelectedOption]); - useEffect(() => { - if (isSuccessUserResultData && userResultData) { - setCardOptions(gameState.userSelectedOption, { - mainText: userResultData.mainText, - resultMainText: userResultData.resultMainText, - resultSubText: userResultData.resultSubText, - }); - } - }, [isSuccessUserResultData, userResultData]); - const { mainText, resultMainText, resultSubText, color } = getSelectedCardInfo({ gameState: gameState, option: gameState.userSelectedOption, diff --git a/client/src/hooks/useFetchRushOptionResult.ts b/client/src/hooks/useFetchRushOptionResult.ts new file mode 100644 index 00000000..f2dc0542 --- /dev/null +++ b/client/src/hooks/useFetchRushOptionResult.ts @@ -0,0 +1,30 @@ +import { useEffect } from "react"; +import { RushAPI } from "@/apis/rushAPI.ts"; +import useFetch from "@/hooks/useFetch.ts"; +import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import { GetRushOptionResultResponse } from "@/types/rushApi.ts"; +import { CardOption } from "@/types/rushGame.ts"; + +export function useFetchRushOptionResult() { + const { gameState, setCardOptions } = useRushGameContext(); + + const { + data: userResultData, + isSuccess: isSuccessUserResultData, + fetchData: getUserResultData, + } = useFetch( + ({ token, optionId }) => RushAPI.getRushOptionResult(token, optionId) + ); + + useEffect(() => { + if (isSuccessUserResultData && userResultData) { + setCardOptions(gameState.userSelectedOption, { + mainText: userResultData.mainText, + resultMainText: userResultData.resultMainText, + resultSubText: userResultData.resultSubText, + }); + } + }, [isSuccessUserResultData, userResultData]); + + return { getUserResultData }; +} From b24076e16c36a7120a20b04c81af59dc40c5d995 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 23:27:25 +0900 Subject: [PATCH 24/36] =?UTF-8?q?refactor:=20rushData=20=EB=B0=9B=EC=95=84?= =?UTF-8?q?=EC=84=9C=20=EA=B2=8C=EC=9E=84=20=EC=B4=88=EA=B8=B0=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EC=84=A4=EC=A0=95=ED=95=B4=EC=A3=BC=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 33 +------------------------ client/src/pages/RushGame/index.tsx | 10 ++++++-- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index 9a0c8bd4..f6af304f 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -1,15 +1,10 @@ -import { ReactNode, createContext, useCallback, useEffect, useState } from "react"; -import { useLoaderData } from "react-router-dom"; +import { ReactNode, createContext, useCallback, useState } from "react"; import { CARD_COLOR, CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard"; -import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { CardOption, CardOptionState, GamePhase, RushGameContextType } from "@/types/rushGame"; -import { getMsTime } from "@/utils/getMsTime.ts"; export const RushGameContext = createContext(undefined); export const RushGameProvider = ({ children }: { children: ReactNode }) => { - const rushData = useLoaderData() as GetTotalRushEventsResponse; - const [gameState, setGameState] = useState({ phase: CARD_PHASE.NOT_STARTED, userParticipatedStatus: false, @@ -56,32 +51,6 @@ export const RushGameProvider = ({ children }: { children: ReactNode }) => { })); }, []); - // TODO: dispatch action으로 함수로 빼서 RushGame 컴포넌트에서 함수를 호출해서 초기화해주는 것이 맞다고 생각.. - useEffect(() => { - if (rushData) { - const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; - - const currentEvent = rushData.events.find((event) => { - const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; - return eventDate === serverDate && event.rushEventId === rushData.todayEventId; - }); - - if (currentEvent) { - const serverTime = getMsTime(rushData.serverTime); - const startTime = getMsTime(currentEvent.startDateTime); - const endTime = getMsTime(currentEvent.endDateTime); - - if (serverTime < startTime) { - setGamePhase(CARD_PHASE.NOT_STARTED); - } else if (serverTime >= startTime && serverTime <= endTime) { - setGamePhase(CARD_PHASE.IN_PROGRESS); - } else if (serverTime > endTime) { - setGamePhase(CARD_PHASE.COMPLETED); - } - } - } - }, [rushData, setGamePhase]); - return ( { writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); }; From 9b1b8db5fe5af54841fff12020f4a2ccbfa35fd6 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Wed, 21 Aug 2024 23:30:50 +0900 Subject: [PATCH 25/36] =?UTF-8?q?refactor:=20=EC=9D=B4=EC=A0=84=20?= =?UTF-8?q?=EC=BB=A4=EB=B0=8B=EC=97=90=20=EB=8C=80=ED=95=9C=20useSetGamePh?= =?UTF-8?q?ase=20=ED=9B=85=20=EC=B6=94=EA=B0=80=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useSetGamePhase.ts | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 client/src/hooks/useSetGamePhase.ts diff --git a/client/src/hooks/useSetGamePhase.ts b/client/src/hooks/useSetGamePhase.ts new file mode 100644 index 00000000..1b0efd66 --- /dev/null +++ b/client/src/hooks/useSetGamePhase.ts @@ -0,0 +1,34 @@ +import { useEffect } from "react"; +import { CARD_PHASE } from "@/constants/Rush/rushCard"; +import { useRushGameStateContext } from "@/hooks/useRushGameStateContext.ts"; +import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; +import { getMsTime } from "@/utils/getMsTime"; + +export default function useSetGamePhase(rushData: GetTotalRushEventsResponse) { + const { setGamePhase } = useRushGameStateContext(); + + useEffect(() => { + if (rushData) { + const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + + const currentEvent = rushData.events.find((event) => { + const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + return eventDate === serverDate && event.rushEventId === rushData.todayEventId; + }); + + if (currentEvent) { + const serverTime = getMsTime(rushData.serverTime); + const startTime = getMsTime(currentEvent.startDateTime); + const endTime = getMsTime(currentEvent.endDateTime); + + if (serverTime < startTime) { + setGamePhase(CARD_PHASE.NOT_STARTED); + } else if (serverTime >= startTime && serverTime <= endTime) { + setGamePhase(CARD_PHASE.IN_PROGRESS); + } else if (serverTime > endTime) { + setGamePhase(CARD_PHASE.COMPLETED); + } + } + } + }, [rushData]); +} From 7ddf7701e0bf5c4deacb30dc15c0097e8554e643 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 01:26:19 +0900 Subject: [PATCH 26/36] =?UTF-8?q?refactor:=20context=EC=97=90=20flux=20?= =?UTF-8?q?=ED=8C=A8=ED=84=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 118 +++++++++--------- .../RushGameComponents/RushCardComparison.tsx | 10 +- .../RushCardCurrentRatio.tsx | 4 +- .../RushCardResultDescription.tsx | 4 +- .../RushGameComponents/RushCountdown.tsx | 11 +- .../RushGameComponents/RushProgressBar.tsx | 4 +- .../RushGame/RushGameSections/Countdown.tsx | 11 +- .../RushGame/RushGameSections/FinalResult.tsx | 4 +- client/src/hooks/useFetchRushBalance.ts | 30 +++-- client/src/hooks/useFetchRushOptionResult.ts | 22 ++-- client/src/hooks/useFetchRushResult.ts | 32 +++-- .../useFetchRushUserParticipationStatus.ts | 7 +- client/src/hooks/useFetchTodayRushEvent.ts | 34 +++-- client/src/hooks/useRushGameContext.ts | 10 -- .../src/hooks/useRushGameDispatchContext.ts | 11 ++ client/src/hooks/useRushGameStateContext.ts | 11 ++ client/src/hooks/useSetGamePhase.ts | 11 +- client/src/pages/RushGame/index.tsx | 4 +- client/src/types/rushGame.ts | 37 ++++-- client/src/utils/RushGame/getOptionRatio.ts | 4 +- .../src/utils/RushGame/getSelectedCardInfo.ts | 4 +- 21 files changed, 237 insertions(+), 146 deletions(-) delete mode 100644 client/src/hooks/useRushGameContext.ts create mode 100644 client/src/hooks/useRushGameDispatchContext.ts create mode 100644 client/src/hooks/useRushGameStateContext.ts diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index f6af304f..f95a1880 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -1,67 +1,71 @@ -import { ReactNode, createContext, useCallback, useState } from "react"; +import { ReactNode, createContext, useReducer } from "react"; import { CARD_COLOR, CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard"; -import { CardOption, CardOptionState, GamePhase, RushGameContextType } from "@/types/rushGame"; +import { + RUSH_ACTION, + RushGameAction, + RushGameDispatchType, + RushGameStateType, +} from "@/types/rushGame"; -export const RushGameContext = createContext(undefined); +export const RushGameStateContext = createContext(undefined); +export const RushGameDispatchContext = createContext(undefined); -export const RushGameProvider = ({ children }: { children: ReactNode }) => { - const [gameState, setGameState] = useState({ - phase: CARD_PHASE.NOT_STARTED, - userParticipatedStatus: false, - userSelectedOption: CARD_OPTION.LEFT_OPTIONS, - cardOptions: { - [CARD_OPTION.LEFT_OPTIONS]: { - mainText: "", - subText: "", - resultMainText: "", - resultSubText: "", - color: CARD_COLOR.GREEN, - selectionCount: 0, - }, - [CARD_OPTION.RIGHT_OPTIONS]: { - mainText: "", - subText: "", - resultMainText: "", - resultSubText: "", - color: CARD_COLOR.BLUE, - selectionCount: 0, - }, +const initialGameState: RushGameStateType = { + phase: CARD_PHASE.NOT_STARTED, + userParticipatedStatus: false, + userSelectedOption: CARD_OPTION.LEFT_OPTIONS, + cardOptions: { + [CARD_OPTION.LEFT_OPTIONS]: { + mainText: "", + subText: "", + resultMainText: "", + resultSubText: "", + color: CARD_COLOR.GREEN, + selectionCount: 0, }, - }); - - const setGamePhase = useCallback((phase: GamePhase) => { - setGameState((prevState) => ({ ...prevState, phase })); - }, []); - - const setUserParticipationStatus = useCallback((status: boolean) => { - setGameState((prevState) => ({ ...prevState, userParticipatedStatus: status })); - }, []); + [CARD_OPTION.RIGHT_OPTIONS]: { + mainText: "", + subText: "", + resultMainText: "", + resultSubText: "", + color: CARD_COLOR.BLUE, + selectionCount: 0, + }, + }, +}; - const setUserSelectedOption = useCallback((option: CardOption) => { - setGameState((prevState) => ({ ...prevState, userSelectedOption: option })); - }, []); +const rushGameReducer = (state: RushGameStateType, action: RushGameAction): RushGameStateType => { + switch (action.type) { + case RUSH_ACTION.SET_PHASE: + return { ...state, phase: action.payload }; + case RUSH_ACTION.SET_USER_PARTICIPATION: + return { ...state, userParticipatedStatus: action.payload }; + case RUSH_ACTION.SET_USER_OPTION: + return { ...state, userSelectedOption: action.payload }; + case RUSH_ACTION.SET_CARD_OPTIONS: + return { + ...state, + cardOptions: { + ...state.cardOptions, + [action.payload.option]: { + ...state.cardOptions[action.payload.option], + ...action.payload.updates, + }, + }, + }; + default: + return state; + } +}; - const setCardOptions = useCallback((option: CardOption, updates: Partial) => { - setGameState((prevState) => ({ - ...prevState, - cardOptions: { - ...prevState.cardOptions, - [option]: { ...prevState.cardOptions[option], ...updates }, - }, - })); - }, []); +export const RushGameProvider = ({ children }: { children: ReactNode }) => { + const [gameState, dispatch] = useReducer(rushGameReducer, initialGameState); return ( - - {children} - + + + {children} + + ); }; diff --git a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx index 0f871898..8d82378d 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx @@ -6,13 +6,15 @@ import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushCard from "@/features/RushGame/RushGameComponents/RushCard.tsx"; import useFetch from "@/hooks/useFetch.ts"; import { useFetchRushUserParticipationStatus } from "@/hooks/useFetchRushUserParticipationStatus.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { RushEventStatusCodeResponse } from "@/types/rushApi.ts"; -import { CardOption } from "@/types/rushGame.ts"; +import { CardOption, RUSH_ACTION } from "@/types/rushGame.ts"; export default function RushCardComparison() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState, setUserSelectedOption } = useRushGameContext(); + const gameState = useRushGameStateContext(); + const dispatch = useRushGameDispatchContext(); const { getRushUserParticipationStatus } = useFetchRushUserParticipationStatus(); const { @@ -25,7 +27,7 @@ export default function RushCardComparison() { const handleCardSelection = async (optionId: CardOption) => { await postSelectedRushOptionApply({ token: cookies[COOKIE_KEY.ACCESS_TOKEN], optionId }); - setUserSelectedOption(optionId); + dispatch({ type: RUSH_ACTION.SET_USER_OPTION, payload: optionId }); }; useEffect(() => { diff --git a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx index 8caafe47..2ce0397a 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx @@ -4,7 +4,7 @@ import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import RushCurrentOptionDisplay from "@/features/RushGame/RushGameComponents/RushCurrentOptionDisplay.tsx"; import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgressBar.tsx"; import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import { CardOption } from "@/types/rushGame.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; @@ -54,7 +54,7 @@ function getMessage(leftRatio: number, rightRatio: number, userSelectedOption: C } export default function RushCardCurrentRatio() { - const { gameState } = useRushGameContext(); + const gameState = useRushGameStateContext(); const { toggleContents } = useToggleContents(); const fetchRushBalance = useFetchRushBalance(); diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index 4b7004fd..ee75ffdb 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -5,7 +5,7 @@ import Category from "@/components/Category"; import { CARD_COLOR } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import { useFetchRushOptionResult } from "@/hooks/useFetchRushOptionResult.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; @@ -28,7 +28,7 @@ const backgroundGradients = cva( export default function RushCardResultDescription() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState } = useRushGameContext(); + const gameState = useRushGameStateContext(); const { getUserResultData } = useFetchRushOptionResult(); useEffect(() => { diff --git a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx index 2dcc25d3..529f3b70 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx @@ -3,8 +3,10 @@ import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import useCountdown from "@/hooks/useCountdown.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; +import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; import { getMsTime } from "@/utils/getMsTime.ts"; @@ -19,7 +21,8 @@ function TimeDisplay({ label, value }: { label: string; value: string }) { export default function RushCountdown() { const [initialRunCountdown, setInitialRunCountdown] = useState(null); - const { gameState, setGamePhase } = useRushGameContext(); + const gameState = useRushGameStateContext(); + const dispatch = useRushGameDispatchContext(); const { data: rushData, @@ -57,9 +60,9 @@ export default function RushCountdown() { runCountdown <= 0 && gameState.phase === CARD_PHASE.IN_PROGRESS ) { - setGamePhase(CARD_PHASE.COMPLETED); + dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.COMPLETED }); } - }, [runCountdown, gameState.phase, setGamePhase]); + }, [runCountdown, gameState.phase]); if (initialRunCountdown === null || runCountdown === null) { return
; diff --git a/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx b/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx index 7e34d907..a1143764 100644 --- a/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx @@ -1,6 +1,6 @@ import { CARD_COLOR, CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import RushBar from "@/features/RushGame/RushGameComponents/RushBar.tsx"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; interface RushProgressBarProps { leftOptionRatio: number; @@ -11,7 +11,7 @@ export default function RushProgressBar({ leftOptionRatio, rightOptionRatio, }: RushProgressBarProps) { - const { gameState } = useRushGameContext(); + const gameState = useRushGameStateContext(); const isCompleted = gameState.phase === CARD_PHASE.COMPLETED; const isAllZero = leftOptionRatio === 0 && rightOptionRatio === 0; diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index e05d2933..c681a845 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -6,14 +6,17 @@ import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import useCountdown from "@/hooks/useCountdown.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; +import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; import { getMsTime } from "@/utils/getMsTime.ts"; function CountdownTimer() { const [initialPreCountdown, setInitialPreCountdown] = useState(null); - const { gameState, setGamePhase } = useRushGameContext(); + const gameState = useRushGameStateContext(); + const dispatch = useRushGameDispatchContext(); const { data: rushData, @@ -53,9 +56,9 @@ function CountdownTimer() { preCountdown <= 0 && gameState.phase === CARD_PHASE.NOT_STARTED ) { - setGamePhase(CARD_PHASE.IN_PROGRESS); + dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.IN_PROGRESS }); } - }, [preCountdown, gameState.phase, setGamePhase]); + }, [preCountdown, gameState.phase]); if (initialPreCountdown === null || preCountdown === null) { return ; diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 72bbb822..30a6919f 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -7,7 +7,7 @@ import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgressBar.tsx"; import RushResultOptionDisplay from "@/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx"; import { useFetchRushResult } from "@/hooks/useFetchRushResult.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { WinStatus } from "@/types/rushGame.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; @@ -28,7 +28,7 @@ interface FinalResultProps { export default function FinalResult({ unblockNavigation }: FinalResultProps) { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { gameState } = useRushGameContext(); + const gameState = useRushGameStateContext(); const { getRushResult, resultData } = useFetchRushResult(); useEffect(() => { diff --git a/client/src/hooks/useFetchRushBalance.ts b/client/src/hooks/useFetchRushBalance.ts index df9281ff..0650e0c6 100644 --- a/client/src/hooks/useFetchRushBalance.ts +++ b/client/src/hooks/useFetchRushBalance.ts @@ -4,12 +4,13 @@ import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetRushBalanceResponse } from "@/types/rushApi.ts"; +import { RUSH_ACTION } from "@/types/rushGame.ts"; export default function useFetchRushBalance() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const { setUserSelectedOption, setCardOptions } = useRushGameContext(); + const dispatch = useRushGameDispatchContext(); const { data: rushBalanceData, @@ -25,16 +26,29 @@ export default function useFetchRushBalance() { if (isSuccessRushBalance && rushBalanceData) { const { optionId, leftOption, rightOption } = rushBalanceData; - setUserSelectedOption(optionId); + dispatch({ type: RUSH_ACTION.SET_USER_OPTION, payload: optionId }); - setCardOptions(CARD_OPTION.LEFT_OPTIONS, { - selectionCount: leftOption, + dispatch({ + type: RUSH_ACTION.SET_CARD_OPTIONS, + payload: { + option: CARD_OPTION.LEFT_OPTIONS, + updates: { + selectionCount: leftOption, + }, + }, }); - setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { - selectionCount: rightOption, + + dispatch({ + type: RUSH_ACTION.SET_CARD_OPTIONS, + payload: { + option: CARD_OPTION.RIGHT_OPTIONS, + updates: { + selectionCount: rightOption, + }, + }, }); } - }, [isSuccessRushBalance, rushBalanceData, setUserSelectedOption, setCardOptions]); + }, [isSuccessRushBalance, rushBalanceData]); return fetchRushBalance; } diff --git a/client/src/hooks/useFetchRushOptionResult.ts b/client/src/hooks/useFetchRushOptionResult.ts index f2dc0542..567f3af5 100644 --- a/client/src/hooks/useFetchRushOptionResult.ts +++ b/client/src/hooks/useFetchRushOptionResult.ts @@ -1,12 +1,14 @@ import { useEffect } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { GetRushOptionResultResponse } from "@/types/rushApi.ts"; -import { CardOption } from "@/types/rushGame.ts"; +import { CardOption, RUSH_ACTION } from "@/types/rushGame.ts"; export function useFetchRushOptionResult() { - const { gameState, setCardOptions } = useRushGameContext(); + const gameState = useRushGameStateContext(); + const dispatch = useRushGameDispatchContext(); const { data: userResultData, @@ -18,10 +20,16 @@ export function useFetchRushOptionResult() { useEffect(() => { if (isSuccessUserResultData && userResultData) { - setCardOptions(gameState.userSelectedOption, { - mainText: userResultData.mainText, - resultMainText: userResultData.resultMainText, - resultSubText: userResultData.resultSubText, + dispatch({ + type: RUSH_ACTION.SET_CARD_OPTIONS, + payload: { + option: gameState.userSelectedOption, + updates: { + mainText: userResultData.mainText, + resultMainText: userResultData.resultMainText, + resultSubText: userResultData.resultSubText, + }, + }, }); } }, [isSuccessUserResultData, userResultData]); diff --git a/client/src/hooks/useFetchRushResult.ts b/client/src/hooks/useFetchRushResult.ts index 0e0f1878..09c84087 100644 --- a/client/src/hooks/useFetchRushResult.ts +++ b/client/src/hooks/useFetchRushResult.ts @@ -2,11 +2,12 @@ import { useEffect } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetRushResultResponse } from "@/types/rushApi.ts"; +import { RUSH_ACTION } from "@/types/rushGame.ts"; export function useFetchRushResult() { - const { setUserSelectedOption, setCardOptions } = useRushGameContext(); + const dispatch = useRushGameDispatchContext(); const { data: resultData, @@ -18,16 +19,31 @@ export function useFetchRushResult() { if (resultData && isSuccessRushResult) { const { optionId, leftOption, rightOption } = resultData; - if (optionId) setUserSelectedOption(optionId); + if (optionId) { + dispatch({ type: RUSH_ACTION.SET_USER_OPTION, payload: optionId }); + } - setCardOptions(CARD_OPTION.LEFT_OPTIONS, { - selectionCount: leftOption, + dispatch({ + type: RUSH_ACTION.SET_CARD_OPTIONS, + payload: { + option: CARD_OPTION.LEFT_OPTIONS, + updates: { + selectionCount: leftOption, + }, + }, }); - setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { - selectionCount: rightOption, + + dispatch({ + type: RUSH_ACTION.SET_CARD_OPTIONS, + payload: { + option: CARD_OPTION.RIGHT_OPTIONS, + updates: { + selectionCount: rightOption, + }, + }, }); } - }, [resultData, isSuccessRushResult, setCardOptions]); + }, [resultData, isSuccessRushResult]); return { getRushResult, resultData }; } diff --git a/client/src/hooks/useFetchRushUserParticipationStatus.ts b/client/src/hooks/useFetchRushUserParticipationStatus.ts index 11d90ae5..de9a53eb 100644 --- a/client/src/hooks/useFetchRushUserParticipationStatus.ts +++ b/client/src/hooks/useFetchRushUserParticipationStatus.ts @@ -3,11 +3,12 @@ import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import useFetch from "@/hooks/useFetch.ts"; import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetRushUserParticipationStatusResponse } from "@/types/rushApi.ts"; +import { RUSH_ACTION } from "@/types/rushGame.ts"; export function useFetchRushUserParticipationStatus() { - const { setUserParticipationStatus } = useRushGameContext(); + const dispatch = useRushGameDispatchContext(); const fetchRushBalance = useFetchRushBalance(); const { data: userParticipatedStatus, fetchData: getRushUserParticipationStatus } = useFetch< @@ -17,7 +18,7 @@ export function useFetchRushUserParticipationStatus() { useEffect(() => { if (userParticipatedStatus !== null) { - setUserParticipationStatus(userParticipatedStatus); + dispatch({ type: RUSH_ACTION.SET_USER_PARTICIPATION, payload: userParticipatedStatus }); if (userParticipatedStatus && CARD_PHASE.IN_PROGRESS) { fetchRushBalance(); } diff --git a/client/src/hooks/useFetchTodayRushEvent.ts b/client/src/hooks/useFetchTodayRushEvent.ts index 019365f8..fd7b75e6 100644 --- a/client/src/hooks/useFetchTodayRushEvent.ts +++ b/client/src/hooks/useFetchTodayRushEvent.ts @@ -2,12 +2,13 @@ import { useEffect } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { useRushGameContext } from "@/hooks/useRushGameContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetTodayRushEventResponse } from "@/types/rushApi.ts"; +import { RUSH_ACTION } from "@/types/rushGame.ts"; import { getRandomCardColors } from "@/utils/getRandomCardColors"; export function useFetchTodayRushEvent() { - const { setCardOptions } = useRushGameContext(); + const dispatch = useRushGameDispatchContext(); const { data: todayRushEventData, @@ -19,15 +20,28 @@ export function useFetchTodayRushEvent() { if (isSuccessTodayRushEvent && todayRushEventData) { const { leftColor, rightColor } = getRandomCardColors(); - setCardOptions(CARD_OPTION.LEFT_OPTIONS, { - mainText: todayRushEventData.leftOption.mainText, - subText: todayRushEventData.leftOption.subText, - color: leftColor, + dispatch({ + type: RUSH_ACTION.SET_CARD_OPTIONS, + payload: { + option: CARD_OPTION.LEFT_OPTIONS, + updates: { + mainText: todayRushEventData.leftOption.mainText, + subText: todayRushEventData.leftOption.subText, + color: leftColor, + }, + }, }); - setCardOptions(CARD_OPTION.RIGHT_OPTIONS, { - mainText: todayRushEventData.rightOption.mainText, - subText: todayRushEventData.rightOption.subText, - color: rightColor, + + dispatch({ + type: RUSH_ACTION.SET_CARD_OPTIONS, + payload: { + option: CARD_OPTION.RIGHT_OPTIONS, + updates: { + mainText: todayRushEventData.rightOption.mainText, + subText: todayRushEventData.rightOption.subText, + color: rightColor, + }, + }, }); } }, [isSuccessTodayRushEvent, todayRushEventData]); diff --git a/client/src/hooks/useRushGameContext.ts b/client/src/hooks/useRushGameContext.ts deleted file mode 100644 index 45d785b5..00000000 --- a/client/src/hooks/useRushGameContext.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { useContext } from "react"; -import { RushGameContext } from "@/contexts/rushGameContext.tsx"; - -export const useRushGameContext = () => { - const context = useContext(RushGameContext); - if (context === undefined) { - throw new Error("useRushGameContext must be used within a RushGameProvider"); - } - return context; -}; diff --git a/client/src/hooks/useRushGameDispatchContext.ts b/client/src/hooks/useRushGameDispatchContext.ts new file mode 100644 index 00000000..8222d6d0 --- /dev/null +++ b/client/src/hooks/useRushGameDispatchContext.ts @@ -0,0 +1,11 @@ +import { useContext } from "react"; +import { RushGameDispatchContext } from "@/contexts/rushGameContext.tsx"; +import { RushGameDispatchType } from "@/types/rushGame.ts"; + +export default function useRushGameDispatchContext(): RushGameDispatchType { + const context = useContext(RushGameDispatchContext); + if (context === undefined) { + throw new Error("useRushGameDispatchContext must be used within a RushGameProvider"); + } + return context; +} diff --git a/client/src/hooks/useRushGameStateContext.ts b/client/src/hooks/useRushGameStateContext.ts new file mode 100644 index 00000000..ba5fd6bf --- /dev/null +++ b/client/src/hooks/useRushGameStateContext.ts @@ -0,0 +1,11 @@ +import { useContext } from "react"; +import { RushGameStateContext } from "@/contexts/rushGameContext.tsx"; +import { RushGameStateType } from "@/types/rushGame.ts"; + +export default function useRushGameStateContext(): RushGameStateType { + const context = useContext(RushGameStateContext); + if (context === undefined) { + throw new Error("useRushGameStateContext must be used within a RushGameProvider"); + } + return context; +} diff --git a/client/src/hooks/useSetGamePhase.ts b/client/src/hooks/useSetGamePhase.ts index 1b0efd66..49c545d7 100644 --- a/client/src/hooks/useSetGamePhase.ts +++ b/client/src/hooks/useSetGamePhase.ts @@ -1,11 +1,12 @@ import { useEffect } from "react"; import { CARD_PHASE } from "@/constants/Rush/rushCard"; -import { useRushGameStateContext } from "@/hooks/useRushGameStateContext.ts"; +import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; +import { RUSH_ACTION } from "@/types/rushGame.ts"; import { getMsTime } from "@/utils/getMsTime"; export default function useSetGamePhase(rushData: GetTotalRushEventsResponse) { - const { setGamePhase } = useRushGameStateContext(); + const dispatch = useRushGameDispatchContext(); useEffect(() => { if (rushData) { @@ -22,11 +23,11 @@ export default function useSetGamePhase(rushData: GetTotalRushEventsResponse) { const endTime = getMsTime(currentEvent.endDateTime); if (serverTime < startTime) { - setGamePhase(CARD_PHASE.NOT_STARTED); + dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.NOT_STARTED }); } else if (serverTime >= startTime && serverTime <= endTime) { - setGamePhase(CARD_PHASE.IN_PROGRESS); + dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.IN_PROGRESS }); } else if (serverTime > endTime) { - setGamePhase(CARD_PHASE.COMPLETED); + dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.COMPLETED }); } } } diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index b2bd89a5..cf6e98b2 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -13,7 +13,7 @@ import SelectedCard from "@/features/RushGame/RushGameSections/SelectedCard.tsx" import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; import { useFetchRushUserParticipationStatus } from "@/hooks/useFetchRushUserParticipationStatus.ts"; import { useFetchTodayRushEvent } from "@/hooks/useFetchTodayRushEvent.ts"; -import { useRushGameStateContext } from "@/hooks/useRushGameStateContext.ts"; +import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import useSetGamePhase from "@/hooks/useSetGamePhase.ts"; import useToast from "@/hooks/useToast.tsx"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; @@ -25,7 +25,7 @@ export default function RushGame() { "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?" ); const { getTodayRushEvent } = useFetchTodayRushEvent(); - const { gameState } = useRushGameStateContext(); + const gameState = useRushGameStateContext(); const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); const { getRushUserParticipationStatus, userParticipatedStatus } = useFetchRushUserParticipationStatus(); diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index a3d4bae4..f2d9788b 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -1,3 +1,4 @@ +import { Dispatch } from "react"; import { CARD_COLOR, CARD_OPTION, CARD_PHASE, WIN_STATUS } from "@/constants/Rush/rushCard.ts"; export type GamePhase = (typeof CARD_PHASE)[keyof typeof CARD_PHASE]; @@ -14,17 +15,29 @@ export interface CardOptionState { selectionCount: number; } -export interface RushGameContextType { - gameState: { - phase: GamePhase; - userParticipatedStatus: boolean; - userSelectedOption: CardOption; - cardOptions: { - [key in CardOption]: CardOptionState; - }; +export interface RushGameStateType { + phase: GamePhase; + userParticipatedStatus: boolean; + userSelectedOption: CardOption; + cardOptions: { + [key in CardOption]: CardOptionState; }; - setCardOptions: (option: CardOption, updates: Partial) => void; - setUserParticipationStatus: (status: boolean) => void; - setGamePhase: (phase: GamePhase) => void; - setUserSelectedOption: (option: CardOption) => void; } + +export const RUSH_ACTION = { + SET_PHASE: "SET_PHASE", + SET_USER_PARTICIPATION: "SET_USER_PARTICIPATION", + SET_USER_OPTION: "SET_USER_OPTION", + SET_CARD_OPTIONS: "SET_CARD_OPTIONS", +} as const; + +export type RushGameAction = + | { type: typeof RUSH_ACTION.SET_PHASE; payload: GamePhase } + | { type: typeof RUSH_ACTION.SET_USER_PARTICIPATION; payload: boolean } + | { type: typeof RUSH_ACTION.SET_USER_OPTION; payload: CardOption } + | { + type: typeof RUSH_ACTION.SET_CARD_OPTIONS; + payload: { option: CardOption; updates: Partial }; + }; + +export type RushGameDispatchType = Dispatch; diff --git a/client/src/utils/RushGame/getOptionRatio.ts b/client/src/utils/RushGame/getOptionRatio.ts index b052ac87..f26176d1 100644 --- a/client/src/utils/RushGame/getOptionRatio.ts +++ b/client/src/utils/RushGame/getOptionRatio.ts @@ -1,8 +1,8 @@ import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; -import { CardOption, RushGameContextType } from "@/types/rushGame.ts"; +import { CardOption, RushGameStateType } from "@/types/rushGame.ts"; interface GetOptionRatioProps { - gameState: RushGameContextType["gameState"]; + gameState: RushGameStateType; option: CardOption; } diff --git a/client/src/utils/RushGame/getSelectedCardInfo.ts b/client/src/utils/RushGame/getSelectedCardInfo.ts index 3da60bee..59402f04 100644 --- a/client/src/utils/RushGame/getSelectedCardInfo.ts +++ b/client/src/utils/RushGame/getSelectedCardInfo.ts @@ -1,7 +1,7 @@ -import { CardOption, RushGameContextType } from "@/types/rushGame.ts"; +import { CardOption, RushGameStateType } from "@/types/rushGame.ts"; interface GetSelectedCardInfoProps { - gameState: RushGameContextType["gameState"]; + gameState: RushGameStateType; option: CardOption; } From 47b4249bc92df56f1f772fb8197d7f8b2f6b9f9c Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 10:54:06 +0900 Subject: [PATCH 27/36] =?UTF-8?q?refactor:=20hooks=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EB=B0=8F=20RushGame=20e?= =?UTF-8?q?num=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/constants/Rush/rushCard.ts | 40 +++++++++---------- .../CasperCard/MyCasperCardBack.tsx | 2 +- .../CasperCard/MyCasperCardFront.tsx | 4 +- .../CasperCustomPanel/CasperCustomPanel.tsx | 4 +- .../CasperCustomPanel/EyesPanel.tsx | 4 +- .../CustomProcess/CasperCustomFinish.tsx | 4 +- .../CustomProcess/CasperCustomFinishing.tsx | 2 +- .../CustomProcess/CasperCustomForm.tsx | 4 +- .../CustomProcess/CasperCustomProcess.tsx | 2 +- .../RushGameComponents/RushCardComparison.tsx | 6 +-- .../RushCardCurrentRatio.tsx | 4 +- .../RushCardResultDescription.tsx | 4 +- .../RushGameComponents/RushCountdown.tsx | 4 +- .../RushGameComponents/RushProgressBar.tsx | 2 +- .../RushGame/RushGameSections/Countdown.tsx | 4 +- .../RushGame/RushGameSections/FinalResult.tsx | 4 +- .../RushGameSections/SelectedCard.tsx | 2 +- .../useCasperCustomDispatchContext.ts | 4 +- .../useCasperCustomStateContext.ts | 4 +- .../usePhoneNumberDispatchContext.ts | 4 +- .../usePhoneNumberStateContext.ts | 4 +- .../useRushGameDispatchContext.ts | 0 .../{ => Contexts}/useRushGameStateContext.ts | 0 .../{ => RushGame}/useFetchRushBalance.ts | 2 +- .../useFetchRushOptionResult.ts | 4 +- .../{ => RushGame}/useFetchRushResult.ts | 2 +- .../useFetchRushUserParticipationStatus.ts | 4 +- .../{ => RushGame}/useFetchTodayRushEvent.ts | 4 +- .../hooks/{ => RushGame}/useSetGamePhase.ts | 6 +-- client/src/hooks/useAuth.ts | 4 +- client/src/pages/RushGame/index.tsx | 8 ++-- client/src/types/rushGame.ts | 28 ++++++------- 32 files changed, 87 insertions(+), 87 deletions(-) rename client/src/hooks/{ => Contexts}/useCasperCustomDispatchContext.ts (70%) rename client/src/hooks/{ => Contexts}/useCasperCustomStateContext.ts (70%) rename client/src/hooks/{ => Contexts}/usePhoneNumberDispatchContext.ts (70%) rename client/src/hooks/{ => Contexts}/usePhoneNumberStateContext.ts (70%) rename client/src/hooks/{ => Contexts}/useRushGameDispatchContext.ts (100%) rename client/src/hooks/{ => Contexts}/useRushGameStateContext.ts (100%) rename client/src/hooks/{ => RushGame}/useFetchRushBalance.ts (95%) rename client/src/hooks/{ => RushGame}/useFetchRushOptionResult.ts (88%) rename client/src/hooks/{ => RushGame}/useFetchRushResult.ts (94%) rename client/src/hooks/{ => RushGame}/useFetchRushUserParticipationStatus.ts (87%) rename client/src/hooks/{ => RushGame}/useFetchTodayRushEvent.ts (95%) rename client/src/hooks/{ => RushGame}/useSetGamePhase.ts (88%) diff --git a/client/src/constants/Rush/rushCard.ts b/client/src/constants/Rush/rushCard.ts index 86a3e75f..d0b8c8b0 100644 --- a/client/src/constants/Rush/rushCard.ts +++ b/client/src/constants/Rush/rushCard.ts @@ -1,23 +1,23 @@ -export const CARD_PHASE = { - NOT_STARTED: "NOT_STARTED", - IN_PROGRESS: "IN_PROGRESS", - COMPLETED: "COMPLETED", -} as const; +export const enum CARD_PHASE { + NOT_STARTED = "NOT_STARTED", + IN_PROGRESS = "IN_PROGRESS", + COMPLETED = "COMPLETED", +} -export const CARD_COLOR = { - BLUE: "blue", - RED: "red", - YELLOW: "yellow", - GREEN: "green", -} as const; +export enum CARD_COLOR { + BLUE = "blue", + RED = "red", + YELLOW = "yellow", + GREEN = "green", +} -export const CARD_OPTION = { - LEFT_OPTIONS: 1, - RIGHT_OPTIONS: 2, -} as const; +export const enum CARD_OPTION { + LEFT_OPTIONS = 1, + RIGHT_OPTIONS = 2, +} -export const WIN_STATUS = { - WIN: "Win", - LOSE: "Lose", - TIE: "Tie", -} as const; +export const enum WIN_STATUS { + WIN = "Win", + LOSE = "Lose", + TIE = "Tie", +} diff --git a/client/src/features/CasperCustom/CasperCard/MyCasperCardBack.tsx b/client/src/features/CasperCustom/CasperCard/MyCasperCardBack.tsx index 6749f62d..89a0558b 100644 --- a/client/src/features/CasperCustom/CasperCard/MyCasperCardBack.tsx +++ b/client/src/features/CasperCustom/CasperCard/MyCasperCardBack.tsx @@ -1,5 +1,5 @@ import { CASPER_SIZE_OPTION } from "@/constants/CasperCustom/casper"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import { CasperCardBackUI } from "./CasperCardBackUI"; interface MyCasperCardBackProps { diff --git a/client/src/features/CasperCustom/CasperCard/MyCasperCardFront.tsx b/client/src/features/CasperCustom/CasperCard/MyCasperCardFront.tsx index 924ba2f5..1844704d 100644 --- a/client/src/features/CasperCustom/CasperCard/MyCasperCardFront.tsx +++ b/client/src/features/CasperCustom/CasperCard/MyCasperCardFront.tsx @@ -1,7 +1,7 @@ import { memo, useCallback } from "react"; import { CASPER_SIZE_OPTION } from "@/constants/CasperCustom/casper"; -import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomDispatchContext from "@/hooks/Contexts/useCasperCustomDispatchContext.ts"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import { CASPER_ACTION } from "@/types/casperCustom"; import { CasperCardFrontUI } from "./CasperCardFrontUI"; diff --git a/client/src/features/CasperCustom/CasperCustomPanel/CasperCustomPanel.tsx b/client/src/features/CasperCustom/CasperCustomPanel/CasperCustomPanel.tsx index 7c3b331d..d7ec2324 100644 --- a/client/src/features/CasperCustom/CasperCustomPanel/CasperCustomPanel.tsx +++ b/client/src/features/CasperCustom/CasperCustomPanel/CasperCustomPanel.tsx @@ -1,8 +1,8 @@ import { useCallback, useEffect } from "react"; import { cva } from "class-variance-authority"; import { CASPER_OPTION, CUSTOM_OPTION, OPTION_TYPE } from "@/constants/CasperCustom/casper"; -import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomDispatchContext from "@/hooks/Contexts/useCasperCustomDispatchContext.ts"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import { CASPER_ACTION } from "@/types/casperCustom"; import { CustomOptionImageItem } from "./CustomOptionImageItem"; import { EyesPanel as EyesPanelComponent } from "./EyesPanel"; diff --git a/client/src/features/CasperCustom/CasperCustomPanel/EyesPanel.tsx b/client/src/features/CasperCustom/CasperCustomPanel/EyesPanel.tsx index 827c4e60..97d4d299 100644 --- a/client/src/features/CasperCustom/CasperCustomPanel/EyesPanel.tsx +++ b/client/src/features/CasperCustom/CasperCustomPanel/EyesPanel.tsx @@ -6,8 +6,8 @@ import { OPTION_TYPE, POSITION_OPTION, } from "@/constants/CasperCustom/casper"; -import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomDispatchContext from "@/hooks/Contexts/useCasperCustomDispatchContext.ts"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import { CASPER_ACTION } from "@/types/casperCustom"; import { CasperCustomPanelLayout } from "./CasperCustomPanelLayout"; import { EyesOptionImageItem } from "./EyesOptionImageItem"; diff --git a/client/src/features/CasperCustom/CustomProcess/CasperCustomFinish.tsx b/client/src/features/CasperCustom/CustomProcess/CasperCustomFinish.tsx index d1092a5d..7091adb7 100644 --- a/client/src/features/CasperCustom/CustomProcess/CasperCustomFinish.tsx +++ b/client/src/features/CasperCustom/CustomProcess/CasperCustomFinish.tsx @@ -10,8 +10,8 @@ import { DISSOLVE } from "@/constants/animation"; import { SCROLL_MOTION } from "@/constants/animation"; import { COOKIE_KEY } from "@/constants/cookie"; import { MyCasperCardFront } from "@/features/CasperCustom/CasperCard/MyCasperCardFront"; -import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomDispatchContext from "@/hooks/Contexts/useCasperCustomDispatchContext.ts"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import useFetch from "@/hooks/useFetch"; import useToast from "@/hooks/useToast"; import { CASPER_ACTION } from "@/types/casperCustom"; diff --git a/client/src/features/CasperCustom/CustomProcess/CasperCustomFinishing.tsx b/client/src/features/CasperCustom/CustomProcess/CasperCustomFinishing.tsx index 74c53203..6906a8fe 100644 --- a/client/src/features/CasperCustom/CustomProcess/CasperCustomFinishing.tsx +++ b/client/src/features/CasperCustom/CustomProcess/CasperCustomFinishing.tsx @@ -4,7 +4,7 @@ import { CASPER_SIZE_OPTION } from "@/constants/CasperCustom/casper"; import { DISSOLVE } from "@/constants/animation"; import { SCROLL_MOTION } from "@/constants/animation"; import { CasperFlipCard } from "@/features/CasperCustom/CasperCard/CasperFlipCard"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import useToast from "@/hooks/useToast"; import type { CasperCardType } from "@/types/casper"; diff --git a/client/src/features/CasperCustom/CustomProcess/CasperCustomForm.tsx b/client/src/features/CasperCustom/CustomProcess/CasperCustomForm.tsx index b58d4d49..25be67ec 100644 --- a/client/src/features/CasperCustom/CustomProcess/CasperCustomForm.tsx +++ b/client/src/features/CasperCustom/CustomProcess/CasperCustomForm.tsx @@ -9,8 +9,8 @@ import { DISSOLVE } from "@/constants/animation"; import { SCROLL_MOTION } from "@/constants/animation"; import { COOKIE_KEY } from "@/constants/cookie"; import { MyCasperCardFront } from "@/features/CasperCustom/CasperCard/MyCasperCardFront"; -import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomDispatchContext from "@/hooks/Contexts/useCasperCustomDispatchContext.ts"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import useFetch from "@/hooks/useFetch"; import { CASPER_ACTION } from "@/types/casperCustom"; import { CasperInformationType, PostCasperResponse } from "@/types/lotteryApi"; diff --git a/client/src/features/CasperCustom/CustomProcess/CasperCustomProcess.tsx b/client/src/features/CasperCustom/CustomProcess/CasperCustomProcess.tsx index bc03fef7..ff680835 100644 --- a/client/src/features/CasperCustom/CustomProcess/CasperCustomProcess.tsx +++ b/client/src/features/CasperCustom/CustomProcess/CasperCustomProcess.tsx @@ -6,7 +6,7 @@ import { CUSTOM_OPTION_ARRAY } from "@/constants/CasperCustom/customStep"; import { DISSOLVE } from "@/constants/animation"; import { SCROLL_MOTION } from "@/constants/animation"; import { MyCasperCardFront } from "@/features/CasperCustom/CasperCard/MyCasperCardFront"; -import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext"; +import useCasperCustomStateContext from "@/hooks/Contexts/useCasperCustomStateContext.ts"; import { getCasperOptionDescription } from "@/utils/CasperCustom/getCasperOptionDescription"; interface CasperCustomProcessProps { diff --git a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx index 8d82378d..75eb6a85 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardComparison.tsx @@ -4,10 +4,10 @@ import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushCard from "@/features/RushGame/RushGameComponents/RushCard.tsx"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; +import { useFetchRushUserParticipationStatus } from "@/hooks/RushGame/useFetchRushUserParticipationStatus.ts"; import useFetch from "@/hooks/useFetch.ts"; -import { useFetchRushUserParticipationStatus } from "@/hooks/useFetchRushUserParticipationStatus.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { RushEventStatusCodeResponse } from "@/types/rushApi.ts"; import { CardOption, RUSH_ACTION } from "@/types/rushGame.ts"; diff --git a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx index 2ce0397a..667115f9 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx @@ -3,8 +3,8 @@ import Tooltip from "@/components/Tooltip"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import RushCurrentOptionDisplay from "@/features/RushGame/RushGameComponents/RushCurrentOptionDisplay.tsx"; import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgressBar.tsx"; -import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; +import useFetchRushBalance from "@/hooks/RushGame/useFetchRushBalance.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import { CardOption } from "@/types/rushGame.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index ee75ffdb..153708da 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -4,8 +4,8 @@ import { useCookies } from "react-cookie"; import Category from "@/components/Category"; import { CARD_COLOR } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; -import { useFetchRushOptionResult } from "@/hooks/useFetchRushOptionResult.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; +import { useFetchRushOptionResult } from "@/hooks/RushGame/useFetchRushOptionResult.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; diff --git a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx index 529f3b70..95917b2c 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx @@ -1,10 +1,10 @@ import { useEffect, useState } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; import useCountdown from "@/hooks/useCountdown.ts"; import useFetch from "@/hooks/useFetch.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; diff --git a/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx b/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx index a1143764..a8c9f4a4 100644 --- a/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushProgressBar.tsx @@ -1,6 +1,6 @@ import { CARD_COLOR, CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import RushBar from "@/features/RushGame/RushGameComponents/RushBar.tsx"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; interface RushProgressBarProps { leftOptionRatio: number; diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index c681a845..138c29bc 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -4,10 +4,10 @@ import { RushAPI } from "@/apis/rushAPI.ts"; import { Background } from "@/components/Background"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; import useCountdown from "@/hooks/useCountdown.ts"; import useFetch from "@/hooks/useFetch.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 30a6919f..2ec4ae16 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -6,8 +6,8 @@ import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgressBar.tsx"; import RushResultOptionDisplay from "@/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx"; -import { useFetchRushResult } from "@/hooks/useFetchRushResult.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; +import { useFetchRushResult } from "@/hooks/RushGame/useFetchRushResult.ts"; import { WinStatus } from "@/types/rushGame.ts"; import { getOptionRatio } from "@/utils/RushGame/getOptionRatio.ts"; import { getSelectedCardInfo } from "@/utils/RushGame/getSelectedCardInfo.ts"; diff --git a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx index a1217608..61cf20b7 100644 --- a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx +++ b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx @@ -4,7 +4,7 @@ import { ASCEND, DISSOLVE, SCROLL_MOTION } from "@/constants/animation.ts"; import RushCardCurrentRatio from "@/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx"; import RushCardResultDescription from "@/features/RushGame/RushGameComponents/RushCardResultDescription.tsx"; import RushCountdown from "@/features/RushGame/RushGameComponents/RushCountdown.tsx"; -import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; +import useFetchRushBalance from "@/hooks/RushGame/useFetchRushBalance.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import ArrowLeftIcon from "/public/assets/icons/arrow-line-left.svg?react"; import ArrowRightIcon from "/public/assets/icons/arrow-line-right.svg?react"; diff --git a/client/src/hooks/useCasperCustomDispatchContext.ts b/client/src/hooks/Contexts/useCasperCustomDispatchContext.ts similarity index 70% rename from client/src/hooks/useCasperCustomDispatchContext.ts rename to client/src/hooks/Contexts/useCasperCustomDispatchContext.ts index 63be8868..bcc4aa36 100644 --- a/client/src/hooks/useCasperCustomDispatchContext.ts +++ b/client/src/hooks/Contexts/useCasperCustomDispatchContext.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; -import { CasperCustomDispatchType } from "@/types/casperCustom"; -import { CasperCustomDispatchContext } from "../contexts/casperCustomContext"; +import { CasperCustomDispatchType } from "@/types/casperCustom.ts"; +import { CasperCustomDispatchContext } from "../../contexts/casperCustomContext.tsx"; export default function useCasperCustomDispatchContext(): CasperCustomDispatchType { const context = useContext(CasperCustomDispatchContext); diff --git a/client/src/hooks/useCasperCustomStateContext.ts b/client/src/hooks/Contexts/useCasperCustomStateContext.ts similarity index 70% rename from client/src/hooks/useCasperCustomStateContext.ts rename to client/src/hooks/Contexts/useCasperCustomStateContext.ts index 31979d6d..cc7b6ff9 100644 --- a/client/src/hooks/useCasperCustomStateContext.ts +++ b/client/src/hooks/Contexts/useCasperCustomStateContext.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; -import { CasperCustomStateType } from "@/types/casperCustom"; -import { CasperCustomStateContext } from "../contexts/casperCustomContext"; +import { CasperCustomStateType } from "@/types/casperCustom.ts"; +import { CasperCustomStateContext } from "../../contexts/casperCustomContext.tsx"; export default function useCasperCustomStateContext(): CasperCustomStateType { const context = useContext(CasperCustomStateContext); diff --git a/client/src/hooks/usePhoneNumberDispatchContext.ts b/client/src/hooks/Contexts/usePhoneNumberDispatchContext.ts similarity index 70% rename from client/src/hooks/usePhoneNumberDispatchContext.ts rename to client/src/hooks/Contexts/usePhoneNumberDispatchContext.ts index 195b48e7..090e1b54 100644 --- a/client/src/hooks/usePhoneNumberDispatchContext.ts +++ b/client/src/hooks/Contexts/usePhoneNumberDispatchContext.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; -import { PhoneNumberDispatchType } from "@/types/phoneNumber"; -import { PhoneNumberDispatchContext } from "../contexts/phoneNumberContext"; +import { PhoneNumberDispatchType } from "@/types/phoneNumber.ts"; +import { PhoneNumberDispatchContext } from "../../contexts/phoneNumberContext.tsx"; export default function usePhoneNumberDispatchContext(): PhoneNumberDispatchType { const context = useContext(PhoneNumberDispatchContext); diff --git a/client/src/hooks/usePhoneNumberStateContext.ts b/client/src/hooks/Contexts/usePhoneNumberStateContext.ts similarity index 70% rename from client/src/hooks/usePhoneNumberStateContext.ts rename to client/src/hooks/Contexts/usePhoneNumberStateContext.ts index 286f38b9..475a4fc7 100644 --- a/client/src/hooks/usePhoneNumberStateContext.ts +++ b/client/src/hooks/Contexts/usePhoneNumberStateContext.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; -import { PhoneNumberStateType } from "@/types/phoneNumber"; -import { PhoneNumberStateContext } from "../contexts/phoneNumberContext"; +import { PhoneNumberStateType } from "@/types/phoneNumber.ts"; +import { PhoneNumberStateContext } from "../../contexts/phoneNumberContext.tsx"; export default function usePhoneNumberStateContext(): PhoneNumberStateType { const context = useContext(PhoneNumberStateContext); diff --git a/client/src/hooks/useRushGameDispatchContext.ts b/client/src/hooks/Contexts/useRushGameDispatchContext.ts similarity index 100% rename from client/src/hooks/useRushGameDispatchContext.ts rename to client/src/hooks/Contexts/useRushGameDispatchContext.ts diff --git a/client/src/hooks/useRushGameStateContext.ts b/client/src/hooks/Contexts/useRushGameStateContext.ts similarity index 100% rename from client/src/hooks/useRushGameStateContext.ts rename to client/src/hooks/Contexts/useRushGameStateContext.ts diff --git a/client/src/hooks/useFetchRushBalance.ts b/client/src/hooks/RushGame/useFetchRushBalance.ts similarity index 95% rename from client/src/hooks/useFetchRushBalance.ts rename to client/src/hooks/RushGame/useFetchRushBalance.ts index 0650e0c6..4a0573be 100644 --- a/client/src/hooks/useFetchRushBalance.ts +++ b/client/src/hooks/RushGame/useFetchRushBalance.ts @@ -3,8 +3,8 @@ import { useCookies } from "react-cookie"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; import useFetch from "@/hooks/useFetch.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetRushBalanceResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; diff --git a/client/src/hooks/useFetchRushOptionResult.ts b/client/src/hooks/RushGame/useFetchRushOptionResult.ts similarity index 88% rename from client/src/hooks/useFetchRushOptionResult.ts rename to client/src/hooks/RushGame/useFetchRushOptionResult.ts index 567f3af5..1c06dd86 100644 --- a/client/src/hooks/useFetchRushOptionResult.ts +++ b/client/src/hooks/RushGame/useFetchRushOptionResult.ts @@ -1,8 +1,8 @@ import { useEffect } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; import useFetch from "@/hooks/useFetch.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; import { GetRushOptionResultResponse } from "@/types/rushApi.ts"; import { CardOption, RUSH_ACTION } from "@/types/rushGame.ts"; diff --git a/client/src/hooks/useFetchRushResult.ts b/client/src/hooks/RushGame/useFetchRushResult.ts similarity index 94% rename from client/src/hooks/useFetchRushResult.ts rename to client/src/hooks/RushGame/useFetchRushResult.ts index 09c84087..42fbe25a 100644 --- a/client/src/hooks/useFetchRushResult.ts +++ b/client/src/hooks/RushGame/useFetchRushResult.ts @@ -1,8 +1,8 @@ import { useEffect } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; import useFetch from "@/hooks/useFetch.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetRushResultResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; diff --git a/client/src/hooks/useFetchRushUserParticipationStatus.ts b/client/src/hooks/RushGame/useFetchRushUserParticipationStatus.ts similarity index 87% rename from client/src/hooks/useFetchRushUserParticipationStatus.ts rename to client/src/hooks/RushGame/useFetchRushUserParticipationStatus.ts index de9a53eb..642d4518 100644 --- a/client/src/hooks/useFetchRushUserParticipationStatus.ts +++ b/client/src/hooks/RushGame/useFetchRushUserParticipationStatus.ts @@ -1,9 +1,9 @@ import { useEffect } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; +import useFetchRushBalance from "@/hooks/RushGame/useFetchRushBalance.ts"; import useFetch from "@/hooks/useFetch.ts"; -import useFetchRushBalance from "@/hooks/useFetchRushBalance.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetRushUserParticipationStatusResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; diff --git a/client/src/hooks/useFetchTodayRushEvent.ts b/client/src/hooks/RushGame/useFetchTodayRushEvent.ts similarity index 95% rename from client/src/hooks/useFetchTodayRushEvent.ts rename to client/src/hooks/RushGame/useFetchTodayRushEvent.ts index fd7b75e6..299a4970 100644 --- a/client/src/hooks/useFetchTodayRushEvent.ts +++ b/client/src/hooks/RushGame/useFetchTodayRushEvent.ts @@ -1,11 +1,11 @@ import { useEffect } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; import useFetch from "@/hooks/useFetch.ts"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; import { GetTodayRushEventResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; -import { getRandomCardColors } from "@/utils/getRandomCardColors"; +import { getRandomCardColors } from "@/utils/getRandomCardColors.ts"; export function useFetchTodayRushEvent() { const dispatch = useRushGameDispatchContext(); diff --git a/client/src/hooks/useSetGamePhase.ts b/client/src/hooks/RushGame/useSetGamePhase.ts similarity index 88% rename from client/src/hooks/useSetGamePhase.ts rename to client/src/hooks/RushGame/useSetGamePhase.ts index 49c545d7..1017115b 100644 --- a/client/src/hooks/useSetGamePhase.ts +++ b/client/src/hooks/RushGame/useSetGamePhase.ts @@ -1,9 +1,9 @@ import { useEffect } from "react"; -import { CARD_PHASE } from "@/constants/Rush/rushCard"; -import useRushGameDispatchContext from "@/hooks/useRushGameDispatchContext.ts"; +import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; +import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; -import { getMsTime } from "@/utils/getMsTime"; +import { getMsTime } from "@/utils/getMsTime.ts"; export default function useSetGamePhase(rushData: GetTotalRushEventsResponse) { const dispatch = useRushGameDispatchContext(); diff --git a/client/src/hooks/useAuth.ts b/client/src/hooks/useAuth.ts index d9ada041..8ad42a08 100644 --- a/client/src/hooks/useAuth.ts +++ b/client/src/hooks/useAuth.ts @@ -3,9 +3,9 @@ import { useCookies } from "react-cookie"; import { useLocation, useNavigate } from "react-router-dom"; import { AuthAPI } from "@/apis/authAPI"; import { COOKIE_KEY } from "@/constants/cookie"; +import usePhoneNumberDispatchContext from "@/hooks/Contexts/usePhoneNumberDispatchContext.ts"; +import usePhoneNumberStateContext from "@/hooks/Contexts/usePhoneNumberStateContext.ts"; import useFetch from "@/hooks/useFetch"; -import usePhoneNumberDispatchContext from "@/hooks/usePhoneNumberDispatchContext"; -import usePhoneNumberStateContext from "@/hooks/usePhoneNumberStateContext"; import { PostAuthResponse } from "@/types/authApi"; import { PHONE_NUMBER_ACTION } from "@/types/phoneNumber"; diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index cf6e98b2..1670d0d9 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -10,11 +10,11 @@ import CardOptions from "@/features/RushGame/RushGameSections/CardOptions.tsx"; import Countdown from "@/features/RushGame/RushGameSections/Countdown.tsx"; import FinalResult from "@/features/RushGame/RushGameSections/FinalResult.tsx"; import SelectedCard from "@/features/RushGame/RushGameSections/SelectedCard.tsx"; +import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; +import { useFetchRushUserParticipationStatus } from "@/hooks/RushGame/useFetchRushUserParticipationStatus.ts"; +import { useFetchTodayRushEvent } from "@/hooks/RushGame/useFetchTodayRushEvent.ts"; +import useSetGamePhase from "@/hooks/RushGame/useSetGamePhase.ts"; import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; -import { useFetchRushUserParticipationStatus } from "@/hooks/useFetchRushUserParticipationStatus.ts"; -import { useFetchTodayRushEvent } from "@/hooks/useFetchTodayRushEvent.ts"; -import useRushGameStateContext from "@/hooks/useRushGameStateContext.ts"; -import useSetGamePhase from "@/hooks/useSetGamePhase.ts"; import useToast from "@/hooks/useToast.tsx"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { writeClipboard } from "@/utils/writeClipboard.ts"; diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index f2d9788b..60f7711f 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -1,10 +1,10 @@ import { Dispatch } from "react"; import { CARD_COLOR, CARD_OPTION, CARD_PHASE, WIN_STATUS } from "@/constants/Rush/rushCard.ts"; -export type GamePhase = (typeof CARD_PHASE)[keyof typeof CARD_PHASE]; -export type CardColor = (typeof CARD_COLOR)[keyof typeof CARD_COLOR]; -export type CardOption = (typeof CARD_OPTION)[keyof typeof CARD_OPTION]; -export type WinStatus = (typeof WIN_STATUS)[keyof typeof WIN_STATUS]; +export type GamePhase = CARD_PHASE; +export type CardColor = CARD_COLOR; +export type CardOption = CARD_OPTION; +export type WinStatus = WIN_STATUS; export interface CardOptionState { mainText: string; @@ -24,19 +24,19 @@ export interface RushGameStateType { }; } -export const RUSH_ACTION = { - SET_PHASE: "SET_PHASE", - SET_USER_PARTICIPATION: "SET_USER_PARTICIPATION", - SET_USER_OPTION: "SET_USER_OPTION", - SET_CARD_OPTIONS: "SET_CARD_OPTIONS", -} as const; +export enum RUSH_ACTION { + SET_PHASE = "SET_PHASE", + SET_USER_PARTICIPATION = "SET_USER_PARTICIPATION", + SET_USER_OPTION = "SET_USER_OPTION", + SET_CARD_OPTIONS = "SET_CARD_OPTIONS", +} export type RushGameAction = - | { type: typeof RUSH_ACTION.SET_PHASE; payload: GamePhase } - | { type: typeof RUSH_ACTION.SET_USER_PARTICIPATION; payload: boolean } - | { type: typeof RUSH_ACTION.SET_USER_OPTION; payload: CardOption } + | { type: RUSH_ACTION.SET_PHASE; payload: GamePhase } + | { type: RUSH_ACTION.SET_USER_PARTICIPATION; payload: boolean } + | { type: RUSH_ACTION.SET_USER_OPTION; payload: CardOption } | { - type: typeof RUSH_ACTION.SET_CARD_OPTIONS; + type: RUSH_ACTION.SET_CARD_OPTIONS; payload: { option: CardOption; updates: Partial }; }; From a9aad6f2838a945c6a83594a9b3d40d6b699141c Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 11:54:19 +0900 Subject: [PATCH 28/36] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8?= =?UTF-8?q?=20=EA=B3=B5=EC=9C=A0=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20FinalResult=20UX=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/rushGameContext.tsx | 4 +- .../RushGameComponents/RushShareLink.tsx | 28 +++++ .../RushGame/RushGameSections/CardOptions.tsx | 40 +++---- .../RushGame/RushGameSections/Countdown.tsx | 2 + .../RushGame/RushGameSections/FinalResult.tsx | 100 ++++++++++-------- .../RushGameSections/SelectedCard.tsx | 26 +++-- client/src/pages/RushGame/index.tsx | 22 +--- client/src/types/rushGame.ts | 2 +- 8 files changed, 125 insertions(+), 99 deletions(-) create mode 100644 client/src/features/RushGame/RushGameComponents/RushShareLink.tsx diff --git a/client/src/contexts/rushGameContext.tsx b/client/src/contexts/rushGameContext.tsx index f95a1880..7a56b586 100644 --- a/client/src/contexts/rushGameContext.tsx +++ b/client/src/contexts/rushGameContext.tsx @@ -1,5 +1,5 @@ import { ReactNode, createContext, useReducer } from "react"; -import { CARD_COLOR, CARD_OPTION, CARD_PHASE } from "@/constants/Rush/rushCard"; +import { CARD_COLOR, CARD_OPTION } from "@/constants/Rush/rushCard"; import { RUSH_ACTION, RushGameAction, @@ -11,7 +11,7 @@ export const RushGameStateContext = createContext export const RushGameDispatchContext = createContext(undefined); const initialGameState: RushGameStateType = { - phase: CARD_PHASE.NOT_STARTED, + phase: null, userParticipatedStatus: false, userSelectedOption: CARD_OPTION.LEFT_OPTIONS, cardOptions: { diff --git a/client/src/features/RushGame/RushGameComponents/RushShareLink.tsx b/client/src/features/RushGame/RushGameComponents/RushShareLink.tsx new file mode 100644 index 00000000..7644c61e --- /dev/null +++ b/client/src/features/RushGame/RushGameComponents/RushShareLink.tsx @@ -0,0 +1,28 @@ +import { motion } from "framer-motion"; +import CTAButton from "@/components/CTAButton"; +import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; +import useToast from "@/hooks/useToast.tsx"; +import { writeClipboard } from "@/utils/writeClipboard.ts"; + +export default function RushShareLink() { + const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); + + const handleClickShareButton = () => { + writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); + }; + + return ( + <> + +

+ 우리 편에 투표할 친구를 불러오세요! +

+ +
+ {ToastComponent} + + ); +} diff --git a/client/src/features/RushGame/RushGameSections/CardOptions.tsx b/client/src/features/RushGame/RushGameSections/CardOptions.tsx index e6d573ae..42b2008b 100644 --- a/client/src/features/RushGame/RushGameSections/CardOptions.tsx +++ b/client/src/features/RushGame/RushGameSections/CardOptions.tsx @@ -2,29 +2,33 @@ import { motion } from "framer-motion"; import { ASCEND, DISSOLVE, SCROLL_MOTION } from "@/constants/animation.ts"; import RushCardComparison from "@/features/RushGame/RushGameComponents/RushCardComparison.tsx"; import RushCountdown from "@/features/RushGame/RushGameComponents/RushCountdown.tsx"; +import RushShareLink from "@/features/RushGame/RushGameComponents/RushShareLink.tsx"; import useToggleContents from "@/hooks/useToggleContents.ts"; export default function CardOptions() { const { toggleContents } = useToggleContents(); return ( - - {toggleContents ? ( - - 2개의 후보 중 하나를 선택해주세요 - - ) : ( - - - - )} - - + <> + + {toggleContents ? ( + + 2개의 후보 중 하나를 선택해주세요 + + ) : ( + + + + )} + + + + ); } diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index 138c29bc..f44d35bf 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -4,6 +4,7 @@ import { RushAPI } from "@/apis/rushAPI.ts"; import { Background } from "@/components/Background"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; +import RushShareLink from "@/features/RushGame/RushGameComponents/RushShareLink.tsx"; import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; import useCountdown from "@/hooks/useCountdown.ts"; @@ -100,6 +101,7 @@ export default function Countdown() { 이제 곧 하단에 밸런스 게임 주제가 공개돼요! + ); } diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 2ec4ae16..23e32e59 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -6,6 +6,7 @@ import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import RushProgressBar from "@/features/RushGame/RushGameComponents/RushProgressBar.tsx"; import RushResultOptionDisplay from "@/features/RushGame/RushGameComponents/RushResultOptionDisplay.tsx"; +import RushShareLink from "@/features/RushGame/RushGameComponents/RushShareLink.tsx"; import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; import { useFetchRushResult } from "@/hooks/RushGame/useFetchRushResult.ts"; import { WinStatus } from "@/types/rushGame.ts"; @@ -39,8 +40,8 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { const userParticipatedStatus = gameState.userParticipatedStatus; const isWinner = resultData?.isWinner; - const rank = resultData?.rank || 0; - const totalParticipants = resultData?.totalParticipants || 0; + const rank = resultData?.rank; + const totalParticipants = resultData?.totalParticipants; const message = isWinner ? MESSAGES.WINNING : MESSAGES.LOSING; @@ -65,54 +66,61 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { const leftWinStatus = getWinStatus(leftOptionRatio, rightOptionRatio); const rightWinStatus = getWinStatus(rightOptionRatio, leftOptionRatio); + const isValidData = + isWinner !== undefined && rank !== undefined && totalParticipants !== undefined; + if (!isValidData) return null; + return ( - -

{message}

- -

*이 화면은 밤 12시 이후 재접속이 불가능합니다.

-

입력하신 전화번호로 경품 수령 관련 메시지가 전송될 예정이에요.

-
-
- {userParticipatedStatus && ( - -

나의 선착순 등수

- -

{rank}등

-

- / {totalParticipants.toLocaleString("en-US")}명 중 -

+ <> + +

{message}

+ +

*이 화면은 밤 12시 이후 재접속이 불가능합니다.

+

입력하신 전화번호로 경품 수령 관련 메시지가 전송될 예정이에요.

+
+
+ {userParticipatedStatus && ( + +

나의 선착순 등수

+ +

{rank}등

+

+ / {totalParticipants.toLocaleString("en-US")}명 중 +

+
- - )} -
-

최종 밸런스 게임 결과

-
- - +

최종 밸런스 게임 결과

+
+ + +
+
-
-
-
+ + + ); } diff --git a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx index 61cf20b7..8a7543b7 100644 --- a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx +++ b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx @@ -4,6 +4,7 @@ import { ASCEND, DISSOLVE, SCROLL_MOTION } from "@/constants/animation.ts"; import RushCardCurrentRatio from "@/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx"; import RushCardResultDescription from "@/features/RushGame/RushGameComponents/RushCardResultDescription.tsx"; import RushCountdown from "@/features/RushGame/RushGameComponents/RushCountdown.tsx"; +import RushShareLink from "@/features/RushGame/RushGameComponents/RushShareLink.tsx"; import useFetchRushBalance from "@/hooks/RushGame/useFetchRushBalance.ts"; import useToggleContents from "@/hooks/useToggleContents.ts"; import ArrowLeftIcon from "/public/assets/icons/arrow-line-left.svg?react"; @@ -65,16 +66,19 @@ export default function SelectedCard({ unblockNavigation }: SelectedCardProps) { }, []); return ( - - - {toggleContents ? ( - - ) : ( - - )} - + <> + + + {toggleContents ? ( + + ) : ( + + )} + + + ); } diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx index 1670d0d9..d3d8ac44 100644 --- a/client/src/pages/RushGame/index.tsx +++ b/client/src/pages/RushGame/index.tsx @@ -1,10 +1,7 @@ import { useEffect } from "react"; -import { motion } from "framer-motion"; import { useCookies } from "react-cookie"; import { useLoaderData } from "react-router-dom"; -import CTAButton from "@/components/CTAButton"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; -import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; import CardOptions from "@/features/RushGame/RushGameSections/CardOptions.tsx"; import Countdown from "@/features/RushGame/RushGameSections/Countdown.tsx"; @@ -15,9 +12,7 @@ import { useFetchRushUserParticipationStatus } from "@/hooks/RushGame/useFetchRu import { useFetchTodayRushEvent } from "@/hooks/RushGame/useFetchTodayRushEvent.ts"; import useSetGamePhase from "@/hooks/RushGame/useSetGamePhase.ts"; import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts"; -import useToast from "@/hooks/useToast.tsx"; import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; -import { writeClipboard } from "@/utils/writeClipboard.ts"; export default function RushGame() { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); @@ -26,23 +21,19 @@ export default function RushGame() { ); const { getTodayRushEvent } = useFetchTodayRushEvent(); const gameState = useRushGameStateContext(); - const { showToast, ToastComponent } = useToast("🔗 링크가 복사되었어요!"); const { getRushUserParticipationStatus, userParticipatedStatus } = useFetchRushUserParticipationStatus(); const rushData = useLoaderData() as GetTotalRushEventsResponse; useSetGamePhase(rushData); - const handleClickShareButton = () => { - writeClipboard(import.meta.env.VITE_RUSH_URL, showToast); - }; - useEffect(() => { getTodayRushEvent(cookies[COOKIE_KEY.ACCESS_TOKEN]); getRushUserParticipationStatus(cookies[COOKIE_KEY.ACCESS_TOKEN]); }, []); const renderRushGameContent = () => { + if (gameState.phase === null) return null; switch (gameState.phase) { case CARD_PHASE.NOT_STARTED: return ; @@ -65,17 +56,6 @@ export default function RushGame() { return (
{renderRushGameContent()} - -

- 우리 편에 투표할 친구를 불러오세요! -

- -
- - {ToastComponent}
); } diff --git a/client/src/types/rushGame.ts b/client/src/types/rushGame.ts index 60f7711f..7ba18812 100644 --- a/client/src/types/rushGame.ts +++ b/client/src/types/rushGame.ts @@ -16,7 +16,7 @@ export interface CardOptionState { } export interface RushGameStateType { - phase: GamePhase; + phase: GamePhase | null; userParticipatedStatus: boolean; userSelectedOption: CardOption; cardOptions: { From 5c02ed30a8afa29d49d89ec5ccba070e60aa079a Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 12:06:09 +0900 Subject: [PATCH 29/36] =?UTF-8?q?refactor:=20Countdown=20UX=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGame/RushGameSections/Countdown.tsx | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index f44d35bf..05221c36 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -14,41 +14,9 @@ import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; import { getMsTime } from "@/utils/getMsTime.ts"; -function CountdownTimer() { - const [initialPreCountdown, setInitialPreCountdown] = useState(null); +function CountdownTimer({ initialPreCountdown }: { initialPreCountdown: number | null }) { const gameState = useRushGameStateContext(); const dispatch = useRushGameDispatchContext(); - - const { - data: rushData, - isSuccess: isSuccessRush, - fetchData: getRush, - } = useFetch(() => RushAPI.getRush()); - - useEffect(() => { - getRush(); - }, []); - - useEffect(() => { - if (isSuccessRush && rushData) { - const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; - - const currentEvent = rushData.events.find((event) => { - const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; - return eventDate === serverDate && event.rushEventId === rushData.todayEventId; - }); - - if (currentEvent) { - const serverTime = getMsTime(rushData.serverTime); - const startDateTime = getMsTime(currentEvent.startDateTime); - - setInitialPreCountdown( - Math.max(0, Math.floor((startDateTime - serverTime) / 1000)) - ); - } - } - }, [isSuccessRush, rushData]); - const preCountdown = useCountdown(initialPreCountdown || null); useEffect(() => { @@ -61,9 +29,7 @@ function CountdownTimer() { } }, [preCountdown, gameState.phase]); - if (initialPreCountdown === null || preCountdown === null) { - return ; - } + if (preCountdown === null) return null; const hours = Math.floor(preCountdown / 3600); const minutes = Math.floor((preCountdown % 3600) / 60); @@ -95,12 +61,45 @@ function TimeDisplay({ label, value }: { label: string; value: string }) { } export default function Countdown() { + const [initialPreCountdown, setInitialPreCountdown] = useState(null); + const { + data: rushData, + isSuccess: isSuccessRush, + fetchData: getRush, + } = useFetch(() => RushAPI.getRush()); + + useEffect(() => { + getRush(); + }, []); + + useEffect(() => { + if (isSuccessRush && rushData) { + const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + + const currentEvent = rushData.events.find((event) => { + const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + return eventDate === serverDate && event.rushEventId === rushData.todayEventId; + }); + + if (currentEvent) { + const serverTime = getMsTime(rushData.serverTime); + const startDateTime = getMsTime(currentEvent.startDateTime); + + setInitialPreCountdown( + Math.max(0, Math.floor((startDateTime - serverTime) / 1000)) + ); + } + } + }, [isSuccessRush, rushData]); + + if (initialPreCountdown === null) return null; + return ( <> 이제 곧 하단에 밸런스 게임 주제가 공개돼요! - + ); From bd01cee54a983cb8d790365c882f3e971ebb324c Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 12:07:53 +0900 Subject: [PATCH 30/36] =?UTF-8?q?refactor:=20CountdownTimer=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/features/RushGame/RushGameSections/Countdown.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index 05221c36..fec51b7e 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -14,7 +14,11 @@ import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; import { getMsTime } from "@/utils/getMsTime.ts"; -function CountdownTimer({ initialPreCountdown }: { initialPreCountdown: number | null }) { +interface CountdownTimerProps { + initialPreCountdown: number | null; +} + +function CountdownTimer({ initialPreCountdown }: CountdownTimerProps) { const gameState = useRushGameStateContext(); const dispatch = useRushGameDispatchContext(); const preCountdown = useCountdown(initialPreCountdown || null); From 48aa9af7c17fad9677019eb60d569fe4beeba72f Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 12:13:12 +0900 Subject: [PATCH 31/36] =?UTF-8?q?feat:=20=ED=86=A0=EA=B8=80=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20=EC=8B=A4=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EB=B9=84=EC=9C=A8=20=EB=B0=98=EC=98=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushGameComponents/RushCardResultDescription.tsx | 2 ++ .../features/RushGame/RushGameSections/SelectedCard.tsx | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx index 153708da..8e3cc1e8 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardResultDescription.tsx @@ -48,6 +48,8 @@ export default function RushCardResultDescription() { option: gameState.userSelectedOption, }); + if (selectedOptionRatio === null) return null; + return (
diff --git a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx index 8a7543b7..161da784 100644 --- a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx +++ b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx @@ -60,6 +60,11 @@ export default function SelectedCard({ unblockNavigation }: SelectedCardProps) { const { toggleContents, toggle } = useToggleContents({ useDuration: false }); const fetchRushBalance = useFetchRushBalance(); + const selectedCardToggle = () => { + toggle(); + fetchRushBalance(); + }; + useEffect(() => { fetchRushBalance(); unblockNavigation(); @@ -73,9 +78,9 @@ export default function SelectedCard({ unblockNavigation }: SelectedCardProps) { > {toggleContents ? ( - + ) : ( - + )} From 45985ff3b298cfa5d195d69d4d5acaec488ed2e7 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 14:46:06 +0900 Subject: [PATCH 32/36] =?UTF-8?q?refactor:=20=EB=82=A0=EC=A7=9C=EC=99=80?= =?UTF-8?q?=20=EC=8B=9C=EA=B0=84=20=EB=B6=84=EB=A6=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=9C=A0=ED=8B=B8=EB=A1=9C=20=EB=B9=BC?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/RushGame/RushGameComponents/RushCountdown.tsx | 5 +++-- client/src/utils/parseIsoDateTime.ts | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 client/src/utils/parseIsoDateTime.ts diff --git a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx index 95917b2c..224dd2a6 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx @@ -9,6 +9,7 @@ import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; import { getMsTime } from "@/utils/getMsTime.ts"; +import parseIsoDateTime from "@/utils/parseIsoDateTime.ts"; function TimeDisplay({ label, value }: { label: string; value: string }) { return ( @@ -36,10 +37,10 @@ export default function RushCountdown() { useEffect(() => { if (isSuccessRush && rushData) { - const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + const serverDate = parseIsoDateTime(rushData.serverTime); const currentEvent = rushData.events.find((event) => { - const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + const eventDate = parseIsoDateTime(event.startDateTime); return eventDate === serverDate && event.rushEventId === rushData.todayEventId; }); diff --git a/client/src/utils/parseIsoDateTime.ts b/client/src/utils/parseIsoDateTime.ts new file mode 100644 index 00000000..537f7d87 --- /dev/null +++ b/client/src/utils/parseIsoDateTime.ts @@ -0,0 +1,3 @@ +export default function parseIsoDateTime(dateTime: string) { + return new Date(dateTime).toISOString().split("T")[0]; +} From e1dc865bbd33c830aacbf44ff0f9bcfd8de805f0 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 14:47:36 +0900 Subject: [PATCH 33/36] =?UTF-8?q?refactor:=20parseIsoDateTime=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/features/RushGame/RushGameSections/Countdown.tsx | 5 +++-- client/src/hooks/RushGame/useSetGamePhase.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index fec51b7e..0e942e45 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -13,6 +13,7 @@ import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; import { formatTime } from "@/utils/formatTime.ts"; import { getMsTime } from "@/utils/getMsTime.ts"; +import parseIsoDateTime from "@/utils/parseIsoDateTime.ts"; interface CountdownTimerProps { initialPreCountdown: number | null; @@ -78,10 +79,10 @@ export default function Countdown() { useEffect(() => { if (isSuccessRush && rushData) { - const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + const serverDate = parseIsoDateTime(rushData.serverTime); const currentEvent = rushData.events.find((event) => { - const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + const eventDate = parseIsoDateTime(event.startDateTime); return eventDate === serverDate && event.rushEventId === rushData.todayEventId; }); diff --git a/client/src/hooks/RushGame/useSetGamePhase.ts b/client/src/hooks/RushGame/useSetGamePhase.ts index 1017115b..92ddd633 100644 --- a/client/src/hooks/RushGame/useSetGamePhase.ts +++ b/client/src/hooks/RushGame/useSetGamePhase.ts @@ -4,16 +4,17 @@ import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchCont import { GetTotalRushEventsResponse } from "@/types/rushApi.ts"; import { RUSH_ACTION } from "@/types/rushGame.ts"; import { getMsTime } from "@/utils/getMsTime.ts"; +import parseIsoDateTime from "@/utils/parseIsoDateTime.ts"; export default function useSetGamePhase(rushData: GetTotalRushEventsResponse) { const dispatch = useRushGameDispatchContext(); useEffect(() => { if (rushData) { - const serverDate = new Date(rushData.serverTime).toISOString().split("T")[0]; + const serverDate = parseIsoDateTime(rushData.serverTime); const currentEvent = rushData.events.find((event) => { - const eventDate = new Date(event.startDateTime).toISOString().split("T")[0]; + const eventDate = parseIsoDateTime(event.startDateTime); return eventDate === serverDate && event.rushEventId === rushData.todayEventId; }); From 0a8f50956e9d29465ed0144d23da8e15a72a9391 Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 14:50:29 +0900 Subject: [PATCH 34/36] =?UTF-8?q?refactor:=20timeout=20if=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=EB=AC=B8=20=EC=83=81=EC=88=98=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/RushGame/RushGameComponents/RushCountdown.tsx | 6 +++--- client/src/features/RushGame/RushGameSections/Countdown.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx index 224dd2a6..b5f63d3c 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx @@ -56,11 +56,11 @@ export default function RushCountdown() { const runCountdown = useCountdown(initialRunCountdown || null); useEffect(() => { - if ( + const isTimeout = runCountdown !== null && runCountdown <= 0 && - gameState.phase === CARD_PHASE.IN_PROGRESS - ) { + gameState.phase === CARD_PHASE.IN_PROGRESS; + if (isTimeout) { dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.COMPLETED }); } }, [runCountdown, gameState.phase]); diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index 0e942e45..92e16933 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -25,11 +25,11 @@ function CountdownTimer({ initialPreCountdown }: CountdownTimerProps) { const preCountdown = useCountdown(initialPreCountdown || null); useEffect(() => { - if ( + const isTimeout = preCountdown !== null && preCountdown <= 0 && - gameState.phase === CARD_PHASE.NOT_STARTED - ) { + gameState.phase === CARD_PHASE.NOT_STARTED; + if (isTimeout) { dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.IN_PROGRESS }); } }, [preCountdown, gameState.phase]); From 895057fcde96d7af063190db46b3b0890a5a3dff Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 15:39:45 +0900 Subject: [PATCH 35/36] =?UTF-8?q?refactor:=20Suspense=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B0=8F=20=EA=B4=80=EB=A0=A8=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Suspense/index.tsx | 9 ++++ .../RushGameComponents/RushCountdown.tsx | 28 ++++++------- .../RushGame/RushGameSections/Countdown.tsx | 42 +++++++++---------- .../RushGame/RushGameSections/FinalResult.tsx | 22 ++++++---- 4 files changed, 59 insertions(+), 42 deletions(-) create mode 100644 client/src/components/Suspense/index.tsx diff --git a/client/src/components/Suspense/index.tsx b/client/src/components/Suspense/index.tsx new file mode 100644 index 00000000..865309f9 --- /dev/null +++ b/client/src/components/Suspense/index.tsx @@ -0,0 +1,9 @@ +import { PropsWithChildren } from "react"; + +interface SuspenseProps extends PropsWithChildren { + isLoading?: boolean; +} + +export default function Suspense({ children, isLoading = false }: SuspenseProps) { + return <>{isLoading ? <> : children}; +} diff --git a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx index b5f63d3c..a3c30f22 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCountdown.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from "react"; import { RushAPI } from "@/apis/rushAPI.ts"; +import Suspense from "@/components/Suspense"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import useRushGameDispatchContext from "@/hooks/Contexts/useRushGameDispatchContext.ts"; import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts"; @@ -60,28 +61,27 @@ export default function RushCountdown() { runCountdown !== null && runCountdown <= 0 && gameState.phase === CARD_PHASE.IN_PROGRESS; + if (isTimeout) { dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.COMPLETED }); } }, [runCountdown, gameState.phase]); - if (initialRunCountdown === null || runCountdown === null) { - return
; - } - - const minutes = Math.floor((runCountdown % 3600) / 60); - const seconds = runCountdown % 60; + const minutes = Math.floor(((runCountdown ?? 0) % 3600) / 60); + const seconds = (runCountdown ?? 0) % 60; return (
-

- 밸런스 게임 결과 공개까지 남은 시간 -

-
- -

:

- -
+ +

+ 밸런스 게임 결과 공개까지 남은 시간 +

+
+ +

:

+ +
+
); } diff --git a/client/src/features/RushGame/RushGameSections/Countdown.tsx b/client/src/features/RushGame/RushGameSections/Countdown.tsx index 92e16933..e0d7c7f3 100644 --- a/client/src/features/RushGame/RushGameSections/Countdown.tsx +++ b/client/src/features/RushGame/RushGameSections/Countdown.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { motion } from "framer-motion"; import { RushAPI } from "@/apis/rushAPI.ts"; import { Background } from "@/components/Background"; +import Suspense from "@/components/Suspense"; import { CARD_PHASE } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import RushShareLink from "@/features/RushGame/RushGameComponents/RushShareLink.tsx"; @@ -29,30 +30,31 @@ function CountdownTimer({ initialPreCountdown }: CountdownTimerProps) { preCountdown !== null && preCountdown <= 0 && gameState.phase === CARD_PHASE.NOT_STARTED; + if (isTimeout) { dispatch({ type: RUSH_ACTION.SET_PHASE, payload: CARD_PHASE.IN_PROGRESS }); } }, [preCountdown, gameState.phase]); - if (preCountdown === null) return null; - - const hours = Math.floor(preCountdown / 3600); - const minutes = Math.floor((preCountdown % 3600) / 60); - const seconds = preCountdown % 60; + const hours = Math.floor((preCountdown ?? 0) / 3600); + const minutes = Math.floor(((preCountdown ?? 0) % 3600) / 60); + const seconds = (preCountdown ?? 0) % 60; return ( - -

- 밸런스 게임 주제 공개까지 남은 시간 -

-
- -

:

- -

:

- -
-
+ + +

+ 밸런스 게임 주제 공개까지 남은 시간 +

+
+ +

:

+ +

:

+ +
+
+
); } @@ -97,15 +99,13 @@ export default function Countdown() { } }, [isSuccessRush, rushData]); - if (initialPreCountdown === null) return null; - return ( - <> + 이제 곧 하단에 밸런스 게임 주제가 공개돼요! - + ); } diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index 23e32e59..eefc8e05 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -1,6 +1,7 @@ import { useEffect } from "react"; import { motion } from "framer-motion"; import { useCookies } from "react-cookie"; +import Suspense from "@/components/Suspense"; import { CARD_OPTION, WIN_STATUS } from "@/constants/Rush/rushCard.ts"; import { ASCEND, SCROLL_MOTION } from "@/constants/animation.ts"; import { COOKIE_KEY } from "@/constants/cookie.ts"; @@ -66,12 +67,19 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { const leftWinStatus = getWinStatus(leftOptionRatio, rightOptionRatio); const rightWinStatus = getWinStatus(rightOptionRatio, leftOptionRatio); - const isValidData = - isWinner !== undefined && rank !== undefined && totalParticipants !== undefined; - if (!isValidData) return null; + function formatNumber(value?: number): string { + if (value === undefined) return ""; + return value.toLocaleString("en-US"); + } + + const formattedRank = formatNumber(rank); + const formattedTotalParticipants = formatNumber(totalParticipants); + + const isNotValidData = + isWinner === undefined || rank === undefined || totalParticipants === undefined; return ( - <> +

나의 선착순 등수

-

{rank}등

+

{formattedRank}등

- / {totalParticipants.toLocaleString("en-US")}명 중 + / {formattedTotalParticipants}명 중

@@ -121,6 +129,6 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) {
- + ); } From a4b635843bd61d6cde6846a905e1ada62d42378b Mon Sep 17 00:00:00 2001 From: sooyeoniya Date: Thu, 22 Aug 2024 15:51:16 +0900 Subject: [PATCH 36/36] =?UTF-8?q?refactor:=20getOptionRatio,=20getSelected?= =?UTF-8?q?CardInfo=20props=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RushCardCurrentRatio.tsx | 16 +++++++-------- .../RushCardResultDescription.tsx | 14 ++++++------- .../RushGame/RushGameSections/FinalResult.tsx | 20 +++++++------------ client/src/utils/RushGame/getOptionRatio.ts | 14 +++++++------ .../src/utils/RushGame/getSelectedCardInfo.ts | 10 ++++++---- 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx index 667115f9..d6d8dd83 100644 --- a/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx +++ b/client/src/features/RushGame/RushGameComponents/RushCardCurrentRatio.tsx @@ -54,27 +54,27 @@ function getMessage(leftRatio: number, rightRatio: number, userSelectedOption: C } export default function RushCardCurrentRatio() { - const gameState = useRushGameStateContext(); + const { userSelectedOption, cardOptions } = useRushGameStateContext(); const { toggleContents } = useToggleContents(); const fetchRushBalance = useFetchRushBalance(); const leftOptionRatio = getOptionRatio({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.LEFT_OPTIONS, }); const rightOptionRatio = getOptionRatio({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.RIGHT_OPTIONS, }); - const message = getMessage(leftOptionRatio, rightOptionRatio, gameState.userSelectedOption); + const message = getMessage(leftOptionRatio, rightOptionRatio, userSelectedOption); const { mainText: leftMainText } = getSelectedCardInfo({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.LEFT_OPTIONS, }); const { mainText: rightMainText } = getSelectedCardInfo({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.RIGHT_OPTIONS, }); @@ -90,13 +90,13 @@ export default function RushCardCurrentRatio() { mainText={leftMainText} userSelectedOptionRatio={leftOptionRatio} oppositeOptionRatio={rightOptionRatio} - isUserSelected={gameState.userSelectedOption === CARD_OPTION.LEFT_OPTIONS} + isUserSelected={userSelectedOption === CARD_OPTION.LEFT_OPTIONS} />
{ getUserResultData({ token: cookies[COOKIE_KEY.ACCESS_TOKEN], - optionId: gameState.userSelectedOption, + optionId: userSelectedOption, }); - }, [cookies, gameState.userSelectedOption]); + }, [cookies, userSelectedOption]); const { mainText, resultMainText, resultSubText, color } = getSelectedCardInfo({ - gameState: gameState, - option: gameState.userSelectedOption, + cardOptions: cardOptions, + option: userSelectedOption, }); const selectedOptionRatio = getOptionRatio({ - gameState: gameState, - option: gameState.userSelectedOption, + cardOptions: cardOptions, + option: userSelectedOption, }); if (selectedOptionRatio === null) return null; diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx index eefc8e05..82e52117 100644 --- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx +++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx @@ -30,7 +30,7 @@ interface FinalResultProps { export default function FinalResult({ unblockNavigation }: FinalResultProps) { const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]); - const gameState = useRushGameStateContext(); + const { cardOptions, userParticipatedStatus, userSelectedOption } = useRushGameStateContext(); const { getRushResult, resultData } = useFetchRushResult(); useEffect(() => { @@ -38,8 +38,6 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { unblockNavigation(); }, []); - const userParticipatedStatus = gameState.userParticipatedStatus; - const isWinner = resultData?.isWinner; const rank = resultData?.rank; const totalParticipants = resultData?.totalParticipants; @@ -47,20 +45,20 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) { const message = isWinner ? MESSAGES.WINNING : MESSAGES.LOSING; const { mainText: leftMainText } = getSelectedCardInfo({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.LEFT_OPTIONS, }); const { mainText: rightMainText } = getSelectedCardInfo({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.RIGHT_OPTIONS, }); const leftOptionRatio = getOptionRatio({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.LEFT_OPTIONS, }); const rightOptionRatio = getOptionRatio({ - gameState: gameState, + cardOptions: cardOptions, option: CARD_OPTION.RIGHT_OPTIONS, }); @@ -107,17 +105,13 @@ export default function FinalResult({ unblockNavigation }: FinalResultProps) {
diff --git a/client/src/utils/RushGame/getOptionRatio.ts b/client/src/utils/RushGame/getOptionRatio.ts index f26176d1..f57c6c01 100644 --- a/client/src/utils/RushGame/getOptionRatio.ts +++ b/client/src/utils/RushGame/getOptionRatio.ts @@ -1,16 +1,18 @@ import { CARD_OPTION } from "@/constants/Rush/rushCard.ts"; -import { CardOption, RushGameStateType } from "@/types/rushGame.ts"; +import { CardOption, CardOptionState } from "@/types/rushGame.ts"; interface GetOptionRatioProps { - gameState: RushGameStateType; + cardOptions: { + [key in CardOption]: CardOptionState; + }; option: CardOption; } -export const getOptionRatio = ({ gameState, option }: GetOptionRatioProps) => { +export const getOptionRatio = ({ cardOptions, option }: GetOptionRatioProps) => { const total = - gameState.cardOptions[CARD_OPTION.LEFT_OPTIONS].selectionCount + - gameState.cardOptions[CARD_OPTION.RIGHT_OPTIONS].selectionCount; + cardOptions[CARD_OPTION.LEFT_OPTIONS].selectionCount + + cardOptions[CARD_OPTION.RIGHT_OPTIONS].selectionCount; if (total === 0) return 0; - const ratio = (gameState.cardOptions[option].selectionCount / total) * 100; + const ratio = (cardOptions[option].selectionCount / total) * 100; return Math.round(ratio * 100) / 100; }; diff --git a/client/src/utils/RushGame/getSelectedCardInfo.ts b/client/src/utils/RushGame/getSelectedCardInfo.ts index 59402f04..3e431951 100644 --- a/client/src/utils/RushGame/getSelectedCardInfo.ts +++ b/client/src/utils/RushGame/getSelectedCardInfo.ts @@ -1,12 +1,14 @@ -import { CardOption, RushGameStateType } from "@/types/rushGame.ts"; +import { CardOption, CardOptionState } from "@/types/rushGame.ts"; interface GetSelectedCardInfoProps { - gameState: RushGameStateType; + cardOptions: { + [key in CardOption]: CardOptionState; + }; option: CardOption; } -export const getSelectedCardInfo = ({ gameState, option }: GetSelectedCardInfoProps) => { - const cardInfo = gameState.cardOptions[option]; +export const getSelectedCardInfo = ({ cardOptions, option }: GetSelectedCardInfoProps) => { + const cardInfo = cardOptions[option]; return { mainText: cardInfo.mainText, subText: cardInfo.subText,