Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a163505
feat: 시간표로 돌아가기 버튼 구현
i-meant-to-be Nov 18, 2025
5288572
feat: 토론 종료 화면에 시간으로 돌아가기 버튼 추가
i-meant-to-be Nov 18, 2025
78dc924
feat: 토론 종료 화면으로 돌아가기 버튼 구현
i-meant-to-be Nov 18, 2025
824ee2a
feat: 피드백 타이머에 돌아가기 버튼 추가
i-meant-to-be Nov 18, 2025
ff2f32d
feat: 투표 URL이 테이블 ID도 표기하도록 수정
i-meant-to-be Nov 18, 2025
00a8f5d
feat: URL 변경 사항 관련 페이지에 반영
i-meant-to-be Nov 18, 2025
955a9ea
refactor: 버튼들이 `className` 받을 수 있게 개선
i-meant-to-be Nov 18, 2025
9a3509b
refactor: 버튼 변경 사항 반영
i-meant-to-be Nov 18, 2025
e02980b
fix: 불필요한 배경색 삭제
i-meant-to-be Nov 18, 2025
69e5de4
chore: 더 이상 사용되지 않는 파일 삭제
i-meant-to-be Nov 18, 2025
f54fe1b
design: 써니 의견에 따라 아이콘 변경
i-meant-to-be Nov 18, 2025
7eed4ec
fix: 라우팅 테이블과 실제 페이지 간 경로 다른 문제 수정
i-meant-to-be Nov 19, 2025
b9ec785
refactor: 테이블 ID 검증 로직 보강
i-meant-to-be Nov 19, 2025
078c181
fix: 쿼리 실행 조건 수정
i-meant-to-be Nov 19, 2025
645effb
fix: 매개변수 이름 수정
i-meant-to-be Nov 19, 2025
a1cfe4a
fix: VoteDetailResult 모달에서 버튼이 제대로 눌리지 않는 문제 수정
i-meant-to-be Nov 19, 2025
bfe1710
fix: 핸들링 함수 중첩되어 사용된 문제 수정
i-meant-to-be Nov 19, 2025
25a0595
design: 뒤로 가기 버튼 화살표 방향 수정
i-meant-to-be Nov 24, 2025
ff17288
feat: 투표 결과 화면에 토론 종료 화면으로 돌아가기 버튼 추가
i-meant-to-be Nov 24, 2025
bef54e0
design: 버튼 위치 시안에 맞게 변경
i-meant-to-be Nov 24, 2025
521721b
feat: 투표 세부 결과 페이지에 확인 모달 추가
i-meant-to-be Nov 24, 2025
0a67d6d
refactor: 투표 결과 화면 스타일 태그 일부 수정
i-meant-to-be Nov 24, 2025
55bba16
fix: `tableId` 잘못 기입되어 있던 문제 수정
i-meant-to-be Nov 24, 2025
235c0dc
Merge branch 'develop' into feat/#400
i-meant-to-be Nov 24, 2025
7ebf328
feat: 투표 결과 화면 뒤로 가기 버튼이 뒤로 가도록 변경
i-meant-to-be Nov 24, 2025
c5a1c06
fix: 불필요한 참조 제거
i-meant-to-be Nov 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/components/GoToDebateEndButton/GoToDebateEndButton.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<button
type="button"
aria-label="토론 종료 화면으로 돌아가기"
onClick={() => handleClick(tableId)}
className={clsx(
'button enabled neutral flex flex-row rounded-full p-[24px]',
className,
)}
>
뒤로 가기 ←
</button>
);
}
20 changes: 0 additions & 20 deletions src/components/GoToHomeButton/GoToHomeButton.tsx

This file was deleted.

21 changes: 12 additions & 9 deletions src/page/DebateEndPage/DebateEndPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div
style={backgroundStyle}
Expand Down Expand Up @@ -55,16 +61,13 @@ export default function DebateEndPage() {
description="QR 코드를 통해 투표 페이지로 이동해요."
imgSrc={voteStampImage}
imgAlt="승패투표"
onClick={() => {
if (!tableId) return; // NaN 방지
mutate(Number(tableId));
}}
onClick={() => mutate(tableId)}
ariaLabel="승패투표 생성 및 진행"
/>
</div>

<div className="fixed bottom-[8%] xl:bottom-[12%]">
<GoToHomeButton />
<GoToOverviewButton tableId={Number(tableId)} className="w-[478px]" />
</div>
</div>
);
Expand Down
33 changes: 33 additions & 0 deletions src/page/DebateEndPage/components/GoToOverviewButton.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<button
type="button"
aria-label="시간표로 돌아가기"
onClick={() => handleClick(tableId)}
className={clsx(
'button enabled neutral flex flex-row space-x-2 rounded-full p-[24px]',
className,
)}
>
<RiCalendarScheduleLine className="aspect-square h-full" />
<p>시간표로 돌아가기</p>
</button>
);
}
36 changes: 18 additions & 18 deletions src/page/DebateVotePage/DebateVotePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,38 @@ 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,
isError: isFetchError,
isRefetching,
refetch,
isRefetchError,
} = useGetPollInfo(pollId, { refetchInterval: 5000, enabled: isValidPollId });
} = useGetPollInfo(pollId, { refetchInterval: 5000, enabled: isArgsValid });
const { mutate } = useFetchEndPoll(handleGoToResult);

const participants = data?.voterNames;
Expand All @@ -48,7 +52,8 @@ export default function DebateVotePage() {
</DefaultLayout>
);
}
if (!isValidPollId) {

if (!isArgsValid) {
return (
<DefaultLayout>
<DefaultLayout.ContentContainer>
Expand All @@ -59,6 +64,7 @@ export default function DebateVotePage() {
</DefaultLayout>
);
}

return (
<DefaultLayout>
<DefaultLayout.ContentContainer noPadding={true}>
Expand Down Expand Up @@ -108,21 +114,15 @@ export default function DebateVotePage() {
</main>

<DefaultLayout.StickyFooterWrapper>
<div className="flex w-full max-w-[800px] flex-row items-center justify-center gap-2 bg-default-white">
<div className="flex w-full max-w-[800px] flex-row items-center justify-center gap-2">
<GoToDebateEndButton tableId={tableId} className="flex-1" />
<button
type="button"
onClick={() => mutate(pollId)}
className="button enabled brand w-full rounded-full"
className="button enabled brand flex flex-1 flex-row rounded-full p-[24px]"
>
투표 결과 보기
</button>
<button
type="button"
onClick={handleGoHome}
className="button enabled neutral w-full rounded-full"
>
홈으로 돌아가기 →
</button>
</div>
</DefaultLayout.StickyFooterWrapper>
</div>
Expand Down
76 changes: 52 additions & 24 deletions src/page/DebateVoteResultPage/DebateVoteResultPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -55,7 +64,7 @@ export default function DebateVoteResultPage() {
}
};

if (!isValidPollId) {
if (!isArgsValid) {
return (
<DefaultLayout>
<DefaultLayout.ContentContainer>
Expand Down Expand Up @@ -96,38 +105,57 @@ export default function DebateVoteResultPage() {
</main>

<DefaultLayout.StickyFooterWrapper>
<div className="flex w-full max-w-[400px] flex-col items-center justify-center gap-2 bg-default-white md:max-w-[800px] md:flex-row">
<div className="flex w-full max-w-[400px] flex-col items-center justify-center gap-2 md:w-full md:max-w-[800px] md:flex-row">
<button
type="button"
onClick={openModal}
className="button enabled brand w-full rounded-full"
onClick={() => navigate(-1)}
className="button enabled neutral flex w-full flex-1 rounded-full p-[24px]"
disabled={isLoading}
>
세부 결과 확인하기
뒤로 가기 ←
</button>
<button
type="button"
onClick={handleGoHome}
className="button enabled neutral w-full rounded-full"
onClick={openModal}
className="button enabled brand flex w-full flex-1 rounded-full p-[24px]"
disabled={isLoading}
>
홈으로 돌아가기 →
세부 결과 확인하기
</button>
</div>
</DefaultLayout.StickyFooterWrapper>
</div>
</DefaultLayout.ContentContainer>
<ModalWrapper>
<VoteDetailResult
pros={{
name: data?.prosTeamName ?? '찬성팀',
count: data?.prosCount ?? 0,
}}
cons={{
name: data?.consTeamName ?? '반대팀',
count: data?.consCount ?? 0,
}}
onGoHome={handleGoHome}
/>
{isConfirmed ? (
<VoteDetailResult
pros={{
name: data?.prosTeamName ?? '찬성팀',
count: data?.prosCount ?? 0,
}}
cons={{
name: data?.consTeamName ?? '반대팀',
count: data?.consCount ?? 0,
}}
onGoHome={handleGoHome}
/>
) : (
<DialogModal
left={{
text: '아니오',
onClick: () => closeModal(),
}}
right={{
text: '네',
onClick: () => setIsConfirmed(true),
isBold: true,
}}
>
<div className="break-keep px-20 py-10 text-center text-xl font-bold">
정말로 세부 결과를 공개할까요?
</div>
</DialogModal>
)}
</ModalWrapper>
</DefaultLayout>
);
Expand Down
14 changes: 7 additions & 7 deletions src/page/DebateVoteResultPage/components/VoteDetailResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ export default function VoteDetailResult({
</div>

{/* 하단 CTA 바 */}
<div className="flex items-center justify-center bg-brand py-4">
<button
onClick={onGoHome}
className="flex items-center text-lg font-bold text-default-black transition hover:opacity-90"
>
<button
onClick={onGoHome}
className="flex w-full items-center justify-center bg-brand py-4 transition hover:opacity-90"
>
<div className="flex items-center text-lg font-bold text-default-black">
홈으로 돌아가기
</button>
</div>
</div>
</button>
</motion.section>
</main>
);
Expand Down
Loading