diff --git a/src/components/GoToDebateEndButton/GoToDebateEndButton.tsx b/src/components/GoToDebateEndButton/GoToDebateEndButton.tsx new file mode 100644 index 00000000..a94bbc4f --- /dev/null +++ b/src/components/GoToDebateEndButton/GoToDebateEndButton.tsx @@ -0,0 +1,31 @@ +import clsx from 'clsx'; +import { useNavigate } from 'react-router-dom'; + +interface GoToDebateEndButtonProps { + tableId: number; + className?: string; +} + +export default function GoToDebateEndButton({ + tableId, + className = '', +}: GoToDebateEndButtonProps) { + const navigate = useNavigate(); + const handleClick = (tableId: number) => { + navigate(`/table/customize/${tableId}/end`); + }; + + return ( + + ); +} diff --git a/src/components/GoToHomeButton/GoToHomeButton.tsx b/src/components/GoToHomeButton/GoToHomeButton.tsx deleted file mode 100644 index 5d80226b..00000000 --- a/src/components/GoToHomeButton/GoToHomeButton.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useNavigate } from 'react-router-dom'; - -export default function GoToHomeButton() { - const navigate = useNavigate(); - - const handleClick = () => { - navigate('/'); - }; - - return ( - - ); -} diff --git a/src/page/DebateEndPage/DebateEndPage.tsx b/src/page/DebateEndPage/DebateEndPage.tsx index bb535cf2..c695f400 100644 --- a/src/page/DebateEndPage/DebateEndPage.tsx +++ b/src/page/DebateEndPage/DebateEndPage.tsx @@ -3,27 +3,33 @@ import { useNavigate, useParams } from 'react-router-dom'; import clapImage from '../../assets/debateEnd/clap.png'; import feedbackTimerImage from '../../assets/debateEnd/feedback_timer.png'; import voteStampImage from '../../assets/debateEnd/vote_stamp.png'; -import GoToHomeButton from '../../components/GoToHomeButton/GoToHomeButton'; import usePostPoll from '../../hooks/mutations/useCreatePoll'; import MenuCard from './components/MenuCard'; +import GoToOverviewButton from './components/GoToOverviewButton'; export default function DebateEndPage() { - const { id: tableId } = useParams(); + const { id } = useParams(); + const tableId = Number(id); const navigate = useNavigate(); const handleFeedbackClick = () => { navigate(`/table/customize/${tableId}/end/feedback`); }; - const handleVoteClick = (pollId: number) => { - navigate(`/table/customize/${pollId}/end/vote`); + navigate(`/table/customize/${tableId}/end/vote/${pollId}`); }; const { mutate } = usePostPoll(handleVoteClick); + const backgroundStyle = { background: 'radial-gradient(50% 50% at 50% 50%, #fecd4c21 0%, #ffffff42 100%)', }; + // 테이블 ID 검증 + if (!id || isNaN(tableId)) { + throw new Error('테이블 ID가 올바르지 않습니다.'); + } + return (
{ - if (!tableId) return; // NaN 방지 - mutate(Number(tableId)); - }} + onClick={() => mutate(tableId)} ariaLabel="승패투표 생성 및 진행" />
- +
); diff --git a/src/page/DebateEndPage/components/GoToOverviewButton.tsx b/src/page/DebateEndPage/components/GoToOverviewButton.tsx new file mode 100644 index 00000000..6300edf7 --- /dev/null +++ b/src/page/DebateEndPage/components/GoToOverviewButton.tsx @@ -0,0 +1,33 @@ +import clsx from 'clsx'; +import { RiCalendarScheduleLine } from 'react-icons/ri'; +import { useNavigate } from 'react-router-dom'; + +interface GoToOverviewButtonProps { + tableId: number; + className?: string; +} + +export default function GoToOverviewButton({ + tableId, + className = '', +}: GoToOverviewButtonProps) { + const navigate = useNavigate(); + const handleClick = (tableId: number) => { + navigate(`/overview/customize/${tableId}`); + }; + + return ( + + ); +} diff --git a/src/page/DebateVotePage/DebateVotePage.tsx b/src/page/DebateVotePage/DebateVotePage.tsx index dd08bcb1..70061bdc 100644 --- a/src/page/DebateVotePage/DebateVotePage.tsx +++ b/src/page/DebateVotePage/DebateVotePage.tsx @@ -5,26 +5,30 @@ import DefaultLayout from '../../layout/defaultLayout/DefaultLayout'; import { useGetPollInfo } from '../../hooks/query/useGetPollInfo'; import ErrorIndicator from '../../components/ErrorIndicator/ErrorIndicator'; import useFetchEndPoll from '../../hooks/mutations/useFetchEndPoll'; +import GoToDebateEndButton from '../../components/GoToDebateEndButton/GoToDebateEndButton'; export default function DebateVotePage() { - const { id: pollIdParam } = useParams(); - const pollId = pollIdParam ? Number(pollIdParam) : NaN; - const isValidPollId = !!pollIdParam && !Number.isNaN(pollId); const navigate = useNavigate(); const baseUrl = import.meta.env.MODE !== 'production' ? undefined : import.meta.env.VITE_SHARE_BASE_URL; + + // 매개변수 검증 + const { pollId: rawPollId, tableId: rawTableId } = useParams(); + const pollId = rawPollId ? Number(rawPollId) : NaN; + const isPollIdValid = !!rawPollId && !Number.isNaN(pollId); + const tableId = rawTableId ? Number(rawTableId) : NaN; + const isTableIdValid = !!rawTableId && !Number.isNaN(tableId); + const isArgsValid = isPollIdValid && isTableIdValid; + const voteUrl = useMemo(() => { return `${baseUrl}/vote/${pollId}`; }, [baseUrl, pollId]); const handleGoToResult = () => { - navigate(`/table/customize/${pollId}/end/vote/result`); + navigate(`/table/customize/${tableId}/end/vote/${pollId}/result`); }; - const handleGoHome = () => { - navigate('/'); - }; const { data, isLoading: isFetching, @@ -32,7 +36,7 @@ export default function DebateVotePage() { isRefetching, refetch, isRefetchError, - } = useGetPollInfo(pollId, { refetchInterval: 5000, enabled: isValidPollId }); + } = useGetPollInfo(pollId, { refetchInterval: 5000, enabled: isArgsValid }); const { mutate } = useFetchEndPoll(handleGoToResult); const participants = data?.voterNames; @@ -48,7 +52,8 @@ export default function DebateVotePage() { ); } - if (!isValidPollId) { + + if (!isArgsValid) { return ( @@ -59,6 +64,7 @@ export default function DebateVotePage() { ); } + return ( @@ -108,21 +114,15 @@ export default function DebateVotePage() { -
+
+ -
diff --git a/src/page/DebateVoteResultPage/DebateVoteResultPage.tsx b/src/page/DebateVoteResultPage/DebateVoteResultPage.tsx index 69c19682..4c6cac66 100644 --- a/src/page/DebateVoteResultPage/DebateVoteResultPage.tsx +++ b/src/page/DebateVoteResultPage/DebateVoteResultPage.tsx @@ -7,11 +7,18 @@ import VoteDetailResult from './components/VoteDetailResult'; import { useGetPollInfo } from '../../hooks/query/useGetPollInfo'; import ErrorIndicator from '../../components/ErrorIndicator/ErrorIndicator'; import { TeamKey } from '../../type/type'; +import { useState } from 'react'; +import DialogModal from '../../components/DialogModal/DialogModal'; export default function DebateVoteResultPage() { - const { id: pollIdParam } = useParams(); + // 매개변수 검증 + const { pollId: rawPollId, tableId: rawTableId } = useParams(); + const pollId = rawPollId ? Number(rawPollId) : NaN; + const isPollIdValid = !!rawPollId && !Number.isNaN(pollId); + const tableId = rawTableId ? Number(rawTableId) : NaN; + const isTableIdValid = !!rawTableId && !Number.isNaN(tableId); + const isArgsValid = isPollIdValid && isTableIdValid; - const pollId = pollIdParam ? Number(pollIdParam) : NaN; - const isValidPollId = !!pollIdParam && !Number.isNaN(pollId); + const [isConfirmed, setIsConfirmed] = useState(false); const navigate = useNavigate(); const { @@ -21,13 +28,15 @@ export default function DebateVoteResultPage() { isRefetching, refetch, isRefetchError, - } = useGetPollInfo(pollId, { enabled: isValidPollId }); + } = useGetPollInfo(pollId, { enabled: isArgsValid }); const handleGoHome = () => { navigate('/'); }; const isLoading = isFetching || isRefetching; const isError = isFetchError || isRefetchError; - const { openModal, ModalWrapper } = useModal(); + const { openModal, ModalWrapper, closeModal } = useModal({ + onClose: () => setIsConfirmed(false), + }); const getWinner = (result: { prosTeamName: string; @@ -55,7 +64,7 @@ export default function DebateVoteResultPage() { } }; - if (!isValidPollId) { + if (!isArgsValid) { return ( @@ -96,38 +105,57 @@ export default function DebateVoteResultPage() { -
+
- + {isConfirmed ? ( + + ) : ( + closeModal(), + }} + right={{ + text: '네', + onClick: () => setIsConfirmed(true), + isBold: true, + }} + > +
+ 정말로 세부 결과를 공개할까요? +
+
+ )}
); diff --git a/src/page/DebateVoteResultPage/components/VoteDetailResult.tsx b/src/page/DebateVoteResultPage/components/VoteDetailResult.tsx index 64eae086..e22a2bcf 100644 --- a/src/page/DebateVoteResultPage/components/VoteDetailResult.tsx +++ b/src/page/DebateVoteResultPage/components/VoteDetailResult.tsx @@ -44,14 +44,14 @@ export default function VoteDetailResult({ {/* 하단 CTA 바 */} -
- -
+ + ); diff --git a/src/page/TimerPage/FeedbackTimerPage.tsx b/src/page/TimerPage/FeedbackTimerPage.tsx index 1bf02ccd..d1f488cd 100644 --- a/src/page/TimerPage/FeedbackTimerPage.tsx +++ b/src/page/TimerPage/FeedbackTimerPage.tsx @@ -1,10 +1,18 @@ import { useFeedbackTimer } from './hooks/useFeedbackTimer'; import FeedbackTimer from './components/FeedbackTimer'; import DefaultLayout from '../../layout/defaultLayout/DefaultLayout'; -import GoToHomeButton from '../../components/GoToHomeButton/GoToHomeButton'; +import GoToDebateEndButton from '../../components/GoToDebateEndButton/GoToDebateEndButton'; +import { useParams } from 'react-router-dom'; export default function FeedbackTimerPage() { const feedbackTimerInstance = useFeedbackTimer(); + const { id } = useParams(); + const tableId = Number(id); + + // 테이블 ID 검증 로직 + if (!id || isNaN(tableId)) { + throw new Error('테이블 ID가 올바르지 않습니다.'); + } return ( @@ -13,7 +21,7 @@ export default function FeedbackTimerPage() {
- +
diff --git a/src/routes/routes.tsx b/src/routes/routes.tsx index 9bf5a5d5..6310ae14 100644 --- a/src/routes/routes.tsx +++ b/src/routes/routes.tsx @@ -55,12 +55,12 @@ const routesConfig = [ requiresAuth: true, }, { - path: '/table/customize/:id/end/vote', + path: '/table/customize/:tableId/end/vote/:pollId', element: , requiresAuth: true, }, { - path: '/table/customize/:id/end/vote/result', + path: '/table/customize/:tableId/end/vote/:pollId/result', element: , requiresAuth: true, },