diff --git a/apps/web/src/app/invite/[id]/_components/InviteClient.tsx b/apps/web/src/app/invite/[id]/_components/InviteClient.tsx index d889750d..b9be1e69 100644 --- a/apps/web/src/app/invite/[id]/_components/InviteClient.tsx +++ b/apps/web/src/app/invite/[id]/_components/InviteClient.tsx @@ -69,6 +69,15 @@ function InviteClient({ tournamentId, inviteCode }: InviteClientProps) { return; } + /** + * 이미 참여한 유저(멤버·게스트 공통)가 같은 링크로 재진입하면 join 플로우를 건너뛰고 + * 토너먼트로 바로 진입. preview 응답의 joined 로 판별 — 별도 조회 없이 preview 한 번으로 끝난다. + */ + if (preview.joined) { + router.replace(ROUTES.TOURNAMENT_CREATE(tournamentId)); + return; + } + const user = await getMe().catch(() => null); if (user?.identityType === 'MEMBER') { await joinAsMemberAndGoToCreate(); diff --git a/apps/web/src/app/tournament/join/_types/join.ts b/apps/web/src/app/tournament/join/_types/join.ts index 1673c672..b32ebe75 100644 --- a/apps/web/src/app/tournament/join/_types/join.ts +++ b/apps/web/src/app/tournament/join/_types/join.ts @@ -4,6 +4,8 @@ export type GetInvitePreviewResponseT = { tournamentName: string; itemCount: number; participantCount: number; + /** 요청자(게스트/회원)가 이미 이 토너먼트에 참여 중인지. 미인증·미참여면 false */ + joined: boolean; }; export type PostJoinRequestT = {