feat: 친구 초대 및 토너먼트 공유 플로우 UI 구현 - #142
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Walkthrough로그인/공통 코드의 포맷 정리와 Web Share 유틸 및 참여자 목업을 추가하고, 토너먼트 생성 페이지에 카운트다운·참여자 패널·초대 다이얼로그·시작·종료 확인을 구현하며 결과 화면에 플레이 링크 공유 다이얼로그를 연결합니다. ChangesUI 정리 및 포맷 정리
토너먼트 초대·카운트다운·공유 플로우
결과 공유 플로우
Sequence Diagram(s)sequenceDiagram
participant User
participant TournamentCreateClient as TournamentCreateClient
participant ParticipantPanel as ParticipantPanel
participant InviteFriendsDialog as InviteFriendsDialog
participant share as WebShare
participant TournamentStartButton as TournamentStartButton
participant ConfirmStartDialog as ConfirmStartDialog
participant ResultClient as ResultClient
participant PlateShareDialog as PlateShareDialog
User->>TournamentCreateClient: 생성 페이지 접근
TournamentCreateClient->>ParticipantPanel: participants, inviteUrl 전달
User->>ParticipantPanel: 친구 초대 클릭
ParticipantPanel->>InviteFriendsDialog: open, inviteUrl
InviteFriendsDialog->>share: share(inviteUrl)
share-->>InviteFriendsDialog: shared/copied/failed
User->>TournamentStartButton: 시작 클릭
TournamentStartButton->>ConfirmStartDialog: 참여자 있으면 다이얼로그 오픈
User->>ConfirmStartDialog: 확인 -> start mutation 실행
User->>ResultClient: 결과 확인
User->>ResultClient: 플레이 링크 공유 클릭
ResultClient->>PlateShareDialog: plateUrl 전달, open
PlateShareDialog->>share: share(plateUrl)
share-->>PlateShareDialog: shared/copied/failed
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
No description provided. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
apps/web/src/app/tournament/[id]/result/_components/ResultClient.tsx (1)
37-37: ⚡ Quick win하드코딩된 공유 도메인 URL.
plateUrl이https://piki.today/...로 하드코딩되어 있어 환경(local/dev/staging)에 따라 잘못된 링크가 공유될 수 있습니다. 환경 변수(예:NEXT_PUBLIC_BASE_URL)나 런타임 origin 기반으로 구성하는 것을 권장합니다.임시 URL을 환경 변수 기반으로 전환하는 작업을 도와드릴까요? 필요하시면 이슈를 생성하겠습니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/app/tournament/`[id]/result/_components/ResultClient.tsx at line 37, The plateUrl is hardcoded to "https://piki.today/…" in ResultClient.tsx (const plateUrl) which breaks non-production environments; change it to build the base using an environment variable (NEXT_PUBLIC_BASE_URL) or, since this is client code, derive origin at runtime via window.location.origin and fall back to NEXT_PUBLIC_BASE_URL, then concatenate `/tournament/${tournamentId}/plate`; update the reference in the ResultClient component where plateUrl is used and ensure tournamentId remains the dynamic segment.apps/web/src/app/tournament/[id]/result/_components/ReceiptPaper.tsx (1)
138-138: 💤 Low value
이미지 공유액션이 동작하지 않는데도 클릭 가능한 외형(cursor-pointer)을 보입니다.
onClick이 전달되지 않은 경우(현재이미지 공유)에도 버튼이 항상cursor-pointer를 적용해 사용자에게 클릭 가능한 것처럼 보이지만 아무 동작도 하지 않습니다. 핸들러 유무에 따라 커서/비활성 처리를 분기하는 것을 권장합니다.♻️ 제안
-function ShareAction({ icon, label, onClick }: ShareActionProps) { +function ShareAction({ icon, label, onClick }: ShareActionProps) { return ( - <button type="button" onClick={onClick} className="flex cursor-pointer items-center gap-2"> + <button + type="button" + onClick={onClick} + disabled={!onClick} + className={cn( + 'flex items-center gap-2', + onClick ? 'cursor-pointer' : 'cursor-default opacity-60' + )} + >Also applies to: 211-219
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/app/tournament/`[id]/result/_components/ReceiptPaper.tsx at line 138, The ShareAction item (rendered as <ShareAction icon={<ImageIconOutline ... />} label="이미지 공유" /> in ReceiptPaper.tsx) shows a clickable cursor even when no onClick handler is provided; update ShareAction so its interactive styling and pointer behavior are conditional on the presence of an onClick prop: remove or change cursor-pointer when onClick is undefined, add a disabled/aria-disabled state and visually dim the control (and/or disable pointer events) when no handler exists, and ensure the same conditional logic is applied for all instances noted (lines ~211-219 and the current line).apps/web/src/app/tournament/[id]/result/_components/plate-share-dialog/PlateShareDialog.tsx (1)
57-66: ⚡ Quick win
변경버튼이 동작하지 않고,7일 후 마감문구와expiresLabel기본값이 일치하지 않습니다.PR 목표상 만료 기한을 캘린더/시간으로 선택하는 기능이 요구되지만,
변경버튼에는onClick핸들러가 없어 비동작 상태입니다. 또한7일 후 마감은 하드코딩이고expiresLabel기본값'2026.05.24까지'는 현재 시점 기준 이미 지난 날짜라 표시가 모순됩니다. 실제 만료 시각으로부터 두 문구를 함께 계산하도록 정리하는 것을 권장합니다.만료 기한 선택(캘린더/시간) 기능 구현 또는 추적 이슈 생성을 도와드릴까요?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/app/tournament/`[id]/result/_components/plate-share-dialog/PlateShareDialog.tsx around lines 57 - 66, PlateShareDialog: the "변경" button has no onClick and the displayed "7일 후 마감" is hardcoded while expiresLabel default ('2026.05.24까지') is stale; wire the button (the <button> with className including "변경") to an onClick that opens your expiry selector (or triggers a handler like onOpenExpiryPicker), replace the hardcoded "7일 후 마감" with a computed relative label derived from the shared expiry state (e.g., expiresAt or expiryDate used by PlateShareDialog) and compute expiresLabel from the same expiresAt value (using a date util like date-fns/dayjs) so both the relative text and the formatted expiresLabel are always consistent and reflect the actual default expiry instead of a past hardcoded date; if selector implementation is out of scope, at least add the onClick and create a tracking TODO/open-issue to implement the calendar/time picker.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/app/tournament/`[id]/create/_apis/getTournament.ts:
- Around line 17-24: withMockParticipants currently unconditionally replaces
real pending.participants with MOCK_TOURNAMENT_PARTICIPANTS when count < 2,
which breaks real UX; change it to preserve the real API response and only
inject mocks behind an explicit dev/story flag or wrapper (e.g., check a dev
flag like process.env.NODE_ENV !== 'production' or a passed-in useMock boolean),
so in withMockParticipants (and the other helper using
MOCK_TOURNAMENT_PARTICIPANTS) only return the mocked participants when that flag
is true; otherwise return the original data unchanged, or move mock injection
into a dev-only wrapper used by stories/tests.
In
`@apps/web/src/app/tournament/`[id]/create/_components/invite-friends/InviteFriendsDialog.tsx:
- Around line 43-59: The expiration card in InviteFriendsDialog is hardcoded and
the "변경" button has no handler; update InviteFriendsDialog to accept a
depositDeadline prop (e.g., Date or ISO string) and an optional onChangeDeadline
callback prop, compute/display the dynamic relative label (e.g., "30분 후 마감") and
formatted absolute time from depositDeadline instead of the static text, and
wire the button's onClick to onChangeDeadline (or conditionally hide/disable the
button when onChangeDeadline is not provided) so the UI reflects the real
deadline and the button is functional.
In `@apps/web/src/app/tournament/`[id]/create/_hooks/useCountdown.ts:
- Around line 18-28: The countdown hook calls formatRemaining even when deadline
yields NaN, causing "NaN:NaN:NaN" to show; update useCountdown to first validate
target (computed from deadline) with Number.isFinite or isFinite and, if
invalid, keep remaining as null and skip starting the interval; modify the
effect around target/ tick so formatRemaining(target - Date.now()) is only
called when target is a finite number (referencing the target variable,
useEffect, tick function, setRemaining, and formatRemaining) and ensure the
returned isExpired logic still handles remaining === null.
---
Nitpick comments:
In
`@apps/web/src/app/tournament/`[id]/result/_components/plate-share-dialog/PlateShareDialog.tsx:
- Around line 57-66: PlateShareDialog: the "변경" button has no onClick and the
displayed "7일 후 마감" is hardcoded while expiresLabel default ('2026.05.24까지') is
stale; wire the button (the <button> with className including "변경") to an
onClick that opens your expiry selector (or triggers a handler like
onOpenExpiryPicker), replace the hardcoded "7일 후 마감" with a computed relative
label derived from the shared expiry state (e.g., expiresAt or expiryDate used
by PlateShareDialog) and compute expiresLabel from the same expiresAt value
(using a date util like date-fns/dayjs) so both the relative text and the
formatted expiresLabel are always consistent and reflect the actual default
expiry instead of a past hardcoded date; if selector implementation is out of
scope, at least add the onClick and create a tracking TODO/open-issue to
implement the calendar/time picker.
In `@apps/web/src/app/tournament/`[id]/result/_components/ReceiptPaper.tsx:
- Line 138: The ShareAction item (rendered as <ShareAction
icon={<ImageIconOutline ... />} label="이미지 공유" /> in ReceiptPaper.tsx) shows a
clickable cursor even when no onClick handler is provided; update ShareAction so
its interactive styling and pointer behavior are conditional on the presence of
an onClick prop: remove or change cursor-pointer when onClick is undefined, add
a disabled/aria-disabled state and visually dim the control (and/or disable
pointer events) when no handler exists, and ensure the same conditional logic is
applied for all instances noted (lines ~211-219 and the current line).
In `@apps/web/src/app/tournament/`[id]/result/_components/ResultClient.tsx:
- Line 37: The plateUrl is hardcoded to "https://piki.today/…" in
ResultClient.tsx (const plateUrl) which breaks non-production environments;
change it to build the base using an environment variable (NEXT_PUBLIC_BASE_URL)
or, since this is client code, derive origin at runtime via
window.location.origin and fall back to NEXT_PUBLIC_BASE_URL, then concatenate
`/tournament/${tournamentId}/plate`; update the reference in the ResultClient
component where plateUrl is used and ensure tournamentId remains the dynamic
segment.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9a200f4e-9fa2-4deb-8f80-b2fe66dfbd8d
⛔ Files ignored due to path filters (3)
apps/web/src/app/tournament/[id]/create/_assets/confirm-exit-basket.svgis excluded by!**/*.svgapps/web/src/app/tournament/[id]/create/_assets/confirm-start-face.svgis excluded by!**/*.svgapps/web/src/assets/icons/fill/timer.svgis excluded by!**/*.svg
📒 Files selected for processing (30)
apps/web/src/app/auth/callback/[provider]/_components/CallbackHandler.tsxapps/web/src/app/login/_components/LoginButtons.tsxapps/web/src/app/login/_components/SocialLoginButton.tsxapps/web/src/app/login/page.tsxapps/web/src/app/tournament/[id]/create/_apis/getTournament.tsapps/web/src/app/tournament/[id]/create/_components/TournamentCreateClient.tsxapps/web/src/app/tournament/[id]/create/_components/deposit-countdown/DepositCountdown.tsxapps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriends.tsxapps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsxapps/web/src/app/tournament/[id]/create/_components/participant-panel/ParticipantChip.tsxapps/web/src/app/tournament/[id]/create/_components/participant-panel/ParticipantPanel.tsxapps/web/src/app/tournament/[id]/create/_components/tournament-header/ConfirmExitDialog.tsxapps/web/src/app/tournament/[id]/create/_components/tournament-header/TournamentHeader.tsxapps/web/src/app/tournament/[id]/create/_components/tournament-item-basket-status/TournamentItemBasketStatus.tsxapps/web/src/app/tournament/[id]/create/_components/tournament-item-basket/TournamentItemBasketCarousel.tsxapps/web/src/app/tournament/[id]/create/_components/tournament-start-button/ConfirmStartDialog.tsxapps/web/src/app/tournament/[id]/create/_components/tournament-start-button/TournamentStartButton.tsxapps/web/src/app/tournament/[id]/create/_hooks/useCountdown.tsapps/web/src/app/tournament/[id]/create/_hooks/useGetTournamentItem.tsapps/web/src/app/tournament/[id]/create/_hooks/usePostTournamentItemLink.tsapps/web/src/app/tournament/[id]/create/by-wish/_components/WishSelectHeader.tsxapps/web/src/app/tournament/[id]/create/page.tsxapps/web/src/app/tournament/[id]/result/_components/ReceiptDrawMachine.tsxapps/web/src/app/tournament/[id]/result/_components/ReceiptPaper.tsxapps/web/src/app/tournament/[id]/result/_components/ResultClient.tsxapps/web/src/app/tournament/[id]/result/_components/plate-share-dialog/PlateShareDialog.tsxapps/web/src/components/common/get-item-dialog/index.tsxapps/web/src/mocks/deposit.tsapps/web/src/mocks/participants.tsapps/web/src/utils/share.ts
💤 Files with no reviewable changes (1)
- apps/web/src/app/tournament/[id]/create/_components/tournament-item-basket-status/TournamentItemBasketStatus.tsx
| const withMockParticipants = (data: GetTournamentResponseT): GetTournamentResponseT => { | ||
| if (!data.pending) return data; | ||
| if (data.pending.participants && data.pending.participants.length >= 2) return data; | ||
| return { | ||
| ...data, | ||
| pending: { ...data.pending, participants: MOCK_TOURNAMENT_PARTICIPANTS }, | ||
| }; | ||
| }; |
There was a problem hiding this comment.
실제 응답을 API 레이어에서 항상 mock 참가자로 덮어쓰면 안 됩니다.
지금 로직은 pending.participants가 2명 미만인 모든 케이스를 MOCK_TOURNAMENT_PARTICIPANTS로 치환합니다. 이 값이 이제 친구 여부의 단일 소스라서, 혼자 진행 중인 실제 토너먼트도 참여자 패널·시작 확인·나가기 확인 분기가 전부 “친구가 있는 상태”로 동작하게 됩니다. mock 주입은 개발 플래그나 스토리 전용 경로로 분리하고, 실 API 응답 자체는 보존하는 편이 안전합니다.
Also applies to: 34-41
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/app/tournament/`[id]/create/_apis/getTournament.ts around lines
17 - 24, withMockParticipants currently unconditionally replaces real
pending.participants with MOCK_TOURNAMENT_PARTICIPANTS when count < 2, which
breaks real UX; change it to preserve the real API response and only inject
mocks behind an explicit dev/story flag or wrapper (e.g., check a dev flag like
process.env.NODE_ENV !== 'production' or a passed-in useMock boolean), so in
withMockParticipants (and the other helper using MOCK_TOURNAMENT_PARTICIPANTS)
only return the mocked participants when that flag is true; otherwise return the
original data unchanged, or move mock injection into a dev-only wrapper used by
stories/tests.
| <div className="flex w-full items-center justify-between rounded-xl border border-border-neutral-muted bg-bg-layer-default px-4 py-5"> | ||
| <div className="flex items-center gap-4"> | ||
| <div className="flex size-11 items-center justify-center rounded-3xl bg-blue-50"> | ||
| <StopwatchIconFill className="size-6 text-text-accent" /> | ||
| </div> | ||
| <div className="flex flex-col gap-0.5"> | ||
| <p className="body-2-semibold text-text-accent">30분 후 마감</p> | ||
| <p className="heading-1 text-text-neutral-primary">오늘 13:52까지</p> | ||
| </div> | ||
| </div> | ||
| <button | ||
| type="button" | ||
| className="cursor-pointer body-2-medium text-text-neutral-tertiary underline" | ||
| > | ||
| 변경 | ||
| </button> | ||
| </div> |
There was a problem hiding this comment.
만료 카드가 정적 하드코딩이며 "변경" 버튼이 동작하지 않습니다.
30분 후 마감 / 오늘 13:52까지가 실제 depositDeadline과 무관하게 고정되어 있고, 변경 버튼에는 onClick 핸들러가 없어 클릭해도 아무 동작이 없습니다. 이슈 #139의 "만료 연장/새로고침" 요구사항과도 어긋납니다. 실제 마감 시각을 prop으로 전달받아 표시하고, 변경 버튼에 동작을 연결하거나 임시로 숨기는 것을 권장합니다.
원하시면 마감 시각을 prop으로 받아 포맷팅해 표시하는 구현 초안을 만들어 드리겠습니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@apps/web/src/app/tournament/`[id]/create/_components/invite-friends/InviteFriendsDialog.tsx
around lines 43 - 59, The expiration card in InviteFriendsDialog is hardcoded
and the "변경" button has no handler; update InviteFriendsDialog to accept a
depositDeadline prop (e.g., Date or ISO string) and an optional onChangeDeadline
callback prop, compute/display the dynamic relative label (e.g., "30분 후 마감") and
formatted absolute time from depositDeadline instead of the static text, and
wire the button's onClick to onChangeDeadline (or conditionally hide/disable the
button when onChangeDeadline is not provided) so the UI reflects the real
deadline and the button is functional.
| const target = typeof deadline === 'object' ? deadline.getTime() : new Date(deadline).getTime(); | ||
| const [remaining, setRemaining] = useState<string | null>(null); | ||
|
|
||
| useEffect(() => { | ||
| const tick = () => setRemaining(formatRemaining(target - Date.now())); | ||
| tick(); | ||
| const id = setInterval(tick, 1000); | ||
| return () => clearInterval(id); | ||
| }, [target]); | ||
|
|
||
| return { remaining, isExpired: remaining === '00:00:00' }; |
There was a problem hiding this comment.
유효하지 않은 deadline이 들어오면 NaN:NaN:NaN이 그대로 노출됩니다.
new Date(deadline).getTime()가 NaN인 경우에도 바로 formatRemaining()을 호출해서 문자열을 만들고 있습니다. DepositCountdown 쪽 fallback은 null만 처리하므로, 잘못된 API 값이나 빈 값이 들어오면 사용자에게 깨진 타이머가 보입니다. target이 finite한지 먼저 검사해서 invalid input일 때는 remaining: null로 유지하는 분기가 필요합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/app/tournament/`[id]/create/_hooks/useCountdown.ts around lines
18 - 28, The countdown hook calls formatRemaining even when deadline yields NaN,
causing "NaN:NaN:NaN" to show; update useCountdown to first validate target
(computed from deadline) with Number.isFinite or isFinite and, if invalid, keep
remaining as null and skip starting the interval; modify the effect around
target/ tick so formatRemaining(target - Date.now()) is only called when target
is a finite number (referencing the target variable, useEffect, tick function,
setRemaining, and formatRemaining) and ensure the returned isExpired logic still
handles remaining === null.
* Squashed commit of the following: commit 52c225d Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 21:52:08 2026 +0900 chore: format commit 4f45210 Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 21:31:28 2026 +0900 refactor: 외부 라우트 import 를 절대경로로 변경 commit de4f8b4 Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 19:00:18 2026 +0900 fix: 친구 토너먼트 결과보기 카드 노출 조건 단순화 + 에러 안내 commit 143ca1e Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 18:42:01 2026 +0900 fix: 플레이 링크 진입 후 CLONE 상태에 따라 라우팅 분기 commit e8cfd72 Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 18:39:49 2026 +0900 fix: 비로그인 진입 시 PlayClient 게스트 발급 회복 (401/400 둘 다 처리) commit 3bcfaa3 Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 18:31:34 2026 +0900 fix: 플레이 링크 진입 시 토너먼트 상태에 따라 적절 화면 라우팅 commit 31cf810 Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 18:28:26 2026 +0900 fix: 결승 직후 토너먼트 캐시 시드 제거 (그룹 결과 카드 즉시 노출) commit 8f6cc22 Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 16:27:51 2026 +0900 chore: from-play-link idempotent 동작 주석 갱신 commit 534dbed Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 14:07:22 2026 +0900 fix: 결과 페이지에서 토너먼트 캐시를 권위 응답으로 강제 덮어쓰기 commit eec26db Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 04:26:29 2026 +0900 chore : format commit 7c0bb2b Author: joyeongchan <tigerbone@naver.com> Date: Tue Jun 9 04:22:59 2026 +0900 fix: 그룹 결과 카드를 ROOT 토너먼트에서만 노출 commit e813384 Author: joyeongchan <tigerbone@naver.com> Date: Mon Jun 8 20:56:22 2026 +0900 feat: ownerStarted/isRoot 기반 참여자 대기·플레이 링크 공유 분기 commit 6d7805a Author: joyeongchan <tigerbone@naver.com> Date: Mon Jun 8 20:43:08 2026 +0900 fix: 친구 토너먼트 결과보기 카드에 아바타 그룹 추가 (시안 일치) commit 02ae3d4 Author: joyeongchan <tigerbone@naver.com> Date: Mon Jun 8 20:36:39 2026 +0900 refactor: PlateShareDialog 시안 일치 (스톱워치/체크리스트 제거) commit 9810007 Author: joyeongchan <tigerbone@naver.com> Date: Mon Jun 8 19:24:41 2026 +0900 feat: 참여자 토너먼트 진행 (CLONE 구조 대응) commit 0990df0 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 05:18:02 2026 +0900 fix: refresh/guest/play-link POST body를 빈 객체로 통일 commit c5e70d6 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 05:12:06 2026 +0900 fix: 비회원 게스트 참여 시 inviteCode 전달 commit 9d55b3a Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 04:31:11 2026 +0900 feat: 참여자 화면이 status 변화 감지해 자동 라우팅 commit bca0b40 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 04:08:54 2026 +0900 fix: 결과 화면 하단 단일 CTA로 정리 commit f654e73 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 04:05:54 2026 +0900 fix: body에 suppressHydrationWarning 추가 (확장 프로그램 대응) commit bb1bc17 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 04:00:31 2026 +0900 feat: 그룹 결과 화면 1st 강조 + Others 축약 형태로 재구성 commit 57d088b Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:55:22 2026 +0900 fix: 회원 프로필 이미지 정사각형 컨테이너로 렌더링 commit 1189b79 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:53:27 2026 +0900 fix: 비회원 참가자 프로필을 기본 SVG로 표시 (홈/토너먼트 일관 적용) commit a73264d Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:51:38 2026 +0900 fix: 비회원 참가자 프로필을 기본 SVG로 표시 commit a3b7ce1 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:43:26 2026 +0900 feat: 친구 초대 링크 진입 라우트 추가 commit 5c13804 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:22:42 2026 +0900 fix: 플레이 링크 공유 주최자 분기 + 기존 링크 재사용 commit 3726ce2 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:15:03 2026 +0900 fix: WishGrid 리스트 항목에 누락된 key prop 추가 commit fd45030 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:12:06 2026 +0900 fix: 참여자 mock 제거 및 친구 없을 때 카운트다운/시작 확인 분기 commit 4488d2c Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 03:03:53 2026 +0900 fix: 주최자는 초대 만료와 무관하게 담기 가능하도록 수정 commit 7307ee7 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 02:35:08 2026 +0900 feat: 그룹 결과 보기 화면 추가 및 결과 진입 카드 연동 commit ea2ddad Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 02:19:01 2026 +0900 feat: 플레이 링크 진입 시 토너먼트 자동 복제 및 라우팅 commit d970c4a Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 01:43:30 2026 +0900 chore: prettier commit 8460097 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 01:27:39 2026 +0900 feat: 플레이 링크 만료 시각 서버 응답 기반으로 표시 commit 9f032ee Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 01:21:19 2026 +0900 feat: 초대 코드 검증 API 연동 및 미리보기 흐름 실 데이터화 commit 939b758 Author: joyeongchan <tigerbone@naver.com> Date: Sun Jun 7 00:03:57 2026 +0900 refactor: 담기 마감을 초대 코드 만료 시간으로 통일 commit 03515cb Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 03:33:11 2026 +0900 feat: 친구 초대 다이얼로그 동적 데이터 연동 (만료시간/링크) commit 77a1806 Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 03:25:24 2026 +0900 feat: 비회원 게스트 토너먼트 참여 API 연동 commit 76a9a4e Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 03:16:41 2026 +0900 feat: 플레이 링크 생성 API 연동 및 공유 URL 동적 구성 commit 3622c24 Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 03:04:28 2026 +0900 refactor: 주최자 분기를 tournamentData.isOwner로 통일 commit 9678e2a Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 02:56:28 2026 +0900 feat: 닉네임 중복 체크 API 연동 commit 118eec3 Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 02:36:24 2026 +0900 docs: 소셜 토너먼트 API 연동 계획 문서 추가 commit 8b7d832 Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 02:20:07 2026 +0900 chore: 슬랙봇 임시완화 복구 commit c38bc5f Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 02:19:24 2026 +0900 chore: 슬랙봇 누락 commit 0a4624d Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 02:14:13 2026 +0900 chore: prettier format commit 496717d Merge: b2cb0f7 c858551 Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 02:11:22 2026 +0900 merge: dev 머지 + components/common 경로 리네임 반영 commit b2cb0f7 Author: joyeongchan <tigerbone@naver.com> Date: Sat Jun 6 01:55:52 2026 +0900 chore: format commit ae1c2b8 Author: joyeongchan <tigerbone@naver.com> Date: Thu Jun 4 04:12:40 2026 +0900 feat: 홈 초대 코드 다이얼로그 + 형식/불일치 에러 분기 구현 commit 2a112f2 Author: joyeongchan <tigerbone@naver.com> Date: Thu Jun 4 02:54:50 2026 +0900 feat: 참여자 패널 친구 유무에 따른 UI 분기 commit a2a860b Author: joyeongchan <tigerbone@naver.com> Date: Thu Jun 4 02:29:23 2026 +0900 chore: mock 담기 종료 시간 1분 조정 commit 0590e74 Author: joyeongchan <tigerbone@naver.com> Date: Thu Jun 4 02:22:10 2026 +0900 feat: 초대 참여자에게 시작 버튼 비활성 + 안내 툴팁 표시 commit 43a8960 Author: joyeongchan <tigerbone@naver.com> Date: Thu Jun 4 02:05:46 2026 +0900 fix: 담기 종료 후 슬롯 UI 정리 + 캐러셀 memo 처리 commit e3a7d8b Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 22:28:59 2026 +0900 feat: 담기 종료 이후 상태별 UI 분기 처리 commit efb5d97 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 20:09:47 2026 +0900 feat: 회원/비회원 초대 참여 분기 + 회원용 확인 다이얼로그 추가 commit 3839f69 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 20:01:12 2026 +0900 fix: 초대 환영 바텀시트 대상 토너먼트에서만 노출 commit a5575e2 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 19:56:43 2026 +0900 feat: 초대 참여 후 환영 바텀시트 자동 노출 commit 06088a1 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 19:45:29 2026 +0900 fix: 초대 참여하기 화면 풀스크린 페이지로 변경 commit 1b11188 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 19:42:40 2026 +0900 chore: 임시 mock 초대 코드 111111로 변경 commit 2ca2217 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 19:39:20 2026 +0900 feat: 초대 참여 닉네임 확인 화면 UI 구현 commit 6eb6e7f Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 18:43:26 2026 +0900 style: 초대 코드 화면 타이포·간격 시안 매칭 commit c012c39 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 18:41:25 2026 +0900 fix: 홈 초대 토너먼트 입장 버튼 라우팅 연결 commit 46e1b95 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 18:37:11 2026 +0900 fix: 초대 코드 에러 헬퍼 텍스트 디자인에 맞게 수정 commit 46f7399 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 17:51:21 2026 +0900 refactor: 초대 코드 페이지 경로 invite → join 변경 commit 3b4f985 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 17:48:29 2026 +0900 feat: 초대 코드 입력 화면 UI 구현 commit 3273be5 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 16:31:06 2026 +0900 refactor: 익명 핸들러 분리 + 사용 안 하는 InviteFriends 제거 commit 8cf4580 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 04:26:02 2026 +0900 chore: format commit 229ab7a Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 04:25:00 2026 +0900 feat: 결과 화면 플레이트 공유 다이얼로그 구현 commit 4841629 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 04:06:52 2026 +0900 refactor: 친구 초대/참여자 패널 아이콘 색상 토큰 정리 commit c3ceccd Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 04:03:44 2026 +0900 fix: 토너먼트 시작/뒤로가기 모달 아이콘 디자인 교체 commit 84c3dd4 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 03:59:28 2026 +0900 fix: 친구 mock 머지 임계값을 2명 이상으로 조정 commit 3fd0f3c Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 03:44:21 2026 +0900 refactor: 친구 포함 여부 판단을 tournamentData participants로 변경 commit c60ac1d Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 03:42:12 2026 +0900 feat: 친구 포함 토너먼트 시작 확인 모달 추가 commit cf30ac6 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 03:34:03 2026 +0900 feat: 후보 담기 마감 카운트다운 UI 구현 commit a71c8c3 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 03:21:44 2026 +0900 feat: 토너먼트 참여자 패널 collapsed/expanded UI 구현 commit ecdfe2a Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 03:09:26 2026 +0900 fix: 초대 링크 공유 토스트 메시지 통일 commit 11ecd7b Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 03:06:15 2026 +0900 feat: 친구 초대 링크 공유 시트 연동 / 임시 더미 url commit 6274dd7 Author: joyeongchan <tigerbone@naver.com> Date: Wed Jun 3 02:59:52 2026 +0900 feat: 토너먼트 친구 초대 바텀시트 다이얼로그 구현 * fix: 코드 검증 중 입력 변경 시 race condition 방지 * fix: PlayClient 의 goToTournament 호출에 await 추가 (무한 로딩 방지) * feat: 게스트도 친구 토너먼트 결과보기 (sourceTournamentId 활용) * refactor: InviteClient 의 의미 없는 Axios 에러 분기 제거 * refactor: play _apis/_types 를 [id] 라우트 내부로 이동 * refactor: 토너먼트 응답 타입/훅 중복 제거 및 _common 으로 통합 * fix: 토너먼트 prefetch queryKey 의 id 타입 number 로 통일 * refactor: create 자식 컴포넌트의 중복 useGetTournament 호출 제거 * refactor: result 페이지 영수증 포맷 유틸을 _utils 로 추출 * chore: TournamentItemBasket 의 사용 변수에서 _ prefix 제거 * refactor: JoinPreviewClient 의 중복 null 체크 제거 및 tournamentId 타입 좁히기 * chore: format
작업 요약
HH:MM:SS 후 담기 종료)작업 세부 내용
친구 초대 다이얼로그
InviteFriendsDialog신규 — 만료 시간 카드 + 안내 체크 박스 +초대 링크 보내기링크를 성공적으로 공유했어요.)참여자 패널
ParticipantPanel신규 — collapsed(나 · 닉네임 ... 외 N명+ chevron) / expanded(chip 그리드 ++초대 버튼) 토글ParticipantChip신규 — 아바타 + 닉네임 +N개InviteFriends카드 →ParticipantPanel로 교체후보 담기 카운트다운
useCountdown훅 — deadline →HH:MM:SS, SSR hydration mismatch 회피DepositCountdown컴포넌트 —TimerIconFill+00:37:43 후 담기 종료currentColor적용)시작 / 뒤로가기 확인 모달
ConfirmStartDialog—토너먼트를 정말 바로 시작할까요?(돌아가기 / 바로 시작할래요)ConfirmExitDialog—담기를 잠깐 멈출까요?(계속 담기 / 나가기)tournamentData.pending.participants.length > 1일 때만 노출 분기TournamentHeader에 백버튼 추가 + 친구 분기 적용confirm-start-face.svg,confirm-exit-basket.svg)결과 화면 플레이 공유
PlateShareDialog신규 —토너먼트 플레이 공유+ 만료 카드(7일 후 마감) +플레이 링크 보내기🔗 플레이 링크 공유액션 클릭 시 다이얼로그 오픈결과 저장하기CTA는 기존 동작 유지정리
mocks/폴더로 분리 (participants.ts,deposit.ts)tournamentData.pending.participants단일 진실 원천으로 통일text-icon-neutral-*)연관 이슈
closes #139
Summary by CodeRabbit
New Features
Style
Refactor