Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
530 changes: 0 additions & 530 deletions .cursorrules

This file was deleted.

8 changes: 5 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ apps/web/src/
│ └── {component-name}/ # 폴더명: kebab-case
│ ├── index.tsx # 컴포넌트 본체 (default export)
│ ├── {componentName}.style.ts # cva variants (스타일 분리 시)
│ └── {componentName}.const.ts # 상수/타입 (필요 시)
│ ├── {componentName}.const.ts # 상수 (필요 시)
│ └── {componentName}.types.ts # 타입 (필요 시)
├── apis/ # API 호출 함수 (HTTP 메서드 prefix 컨벤션)
├── hooks/ # 커스텀 훅
├── utils/ # 공통 유틸리티 함수
Expand Down Expand Up @@ -170,7 +171,8 @@ apps/web/src/
| **대표 컴포넌트** | `index.tsx` (default export) | `button/index.tsx` |
| **보조 컴포넌트** | PascalCase | `UserProfile.tsx`, `ButtonLink.tsx` |
| **스타일 (cva)** | camelCase + `.style.ts` | `button.style.ts`, `stateChip.style.ts` |
| **상수/타입** | camelCase + `.const.ts` | `userProfile.const.ts` |
| **상수** | camelCase + `.const.ts` | `joinErrorDialog.const.ts` |
| **타입** | camelCase + `.types.ts` | `userProfile.types.ts` |

- **폴더명**: kebab-case (`button/`, `wish-card/`, `state-chip/`)

Expand Down Expand Up @@ -198,7 +200,7 @@ import Button from '@/components/common/Button/Button';
| **폴더** | kebab-case | `wish-card/`, `state-chip/` |
| **공통 컴포넌트 본체** | `index.tsx` | `components/common/button/index.tsx` |
| **보조 컴포넌트 파일** | PascalCase | `UserProfile.tsx`, `ButtonLink.tsx` |
| **스타일/상수 파일** | camelCase | `button.style.ts`, `userProfile.const.ts` |
| **스타일/상수/타입 파일** | camelCase | `button.style.ts`, `userProfile.types.ts` |
| **일반 파일** (훅, 유틸) | camelCase | `useAuth.ts`, `formatDate.ts` |
| **타입** | T suffix | `UserT`, `ProductT` |
| **API 함수** | HTTP 메서드 prefix | `getUser`, `postWishlist`, `patchProfile`, `deleteItem` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ import { useQueryAction } from '@/hooks/useQueryAction';
import { useSSEFallback } from '@/hooks/useSSEFallback';
import { hasParsingItems } from '@/utils/item';

import { type JoinConfirmPayloadT, consumeJoinConfirmFor } from '../../../join/_utils/joinSession';
import { useGetTournament } from '../../_common/_hooks/useGetTournament';
import { PREV_ITEM_COUNT_KEY } from '../_consts/tournamentItemBasket';
import { useCountdown } from '../_hooks/useCountdown';
import { usePostTournamentStart } from '../_hooks/usePostTournamentStart';
import { hasSentInvite } from '../_utils/inviteSentSession';
import { hasSentInvite } from '@/utils/inviteSentSession';
import DepositClosedDialog from './deposit-closed-dialog/DepositClosedDialog';
import MemberJoinConfirmDialog from './member-join-confirm-dialog/MemberJoinConfirmDialog';
import OwnerStartedDialog from './owner-started-dialog/OwnerStartedDialog';
import ParticipantPanel from './participant-panel/ParticipantPanel';
import TournamentHeader from './tournament-header/TournamentHeader';
Expand Down Expand Up @@ -112,9 +110,6 @@ function TournamentCreateClient({ tournamentId }: TournamentCreateClientProps) {
(pending?.participants ?? []).map(p => [p.userId, p.profileImage])
);

const [confirmPayload, setConfirmPayload] = useState<JoinConfirmPayloadT | null>(() =>
consumeJoinConfirmFor(tournamentId)
);
const isParticipant = !tournamentData.isOwner;
// 참여자는 주최자가 ROOT 를 시작한 후(ownerStarted=true) 부터 본인 CLONE 시작 가능.
const isWaitingForOwnerStart = isParticipant && pending?.ownerStarted === false;
Expand Down Expand Up @@ -182,8 +177,6 @@ function TournamentCreateClient({ tournamentId }: TournamentCreateClientProps) {
if (!open) setHasDismissedOwnerStarted(true);
};

const handleCloseConfirm = () => setConfirmPayload(null);

return (
<div className="flex h-full min-h-0 flex-col bg-bg-layer-basement pt-padding-top pb-bottom-cta">
<div className="px-5">
Expand Down Expand Up @@ -262,21 +255,6 @@ function TournamentCreateClient({ tournamentId }: TournamentCreateClientProps) {
onConfirm={() => setIsWelcomeOpen(false)}
/>
)}

{confirmPayload && (
<MemberJoinConfirmDialog
open
onOpenChange={open => {
if (!open) handleCloseConfirm();
}}
nickname={confirmPayload.nickname}
profileType={confirmPayload.profileType}
tournamentName={confirmPayload.tournamentName}
itemCount={confirmPayload.itemCount}
participantCount={confirmPayload.participantCount}
onConfirm={handleCloseConfirm}
/>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function DepositCountdown({ deadline, showLabel = true }: DepositCountdownProps)
const { remaining } = useCountdown(deadline);

return (
<div className="flex items-center justify-center gap-1 rounded-lg bg-sky-blue-50 py-1 pr-3 pl-2.5 text-text-accent/88">
<div className="flex items-center justify-center gap-1 rounded-lg bg-sky-blue-50 py-1.5 pr-3 pl-2.5 text-text-accent/88">
<TimerIconFill className="size-5 text-sky-blue-400" />
<p className="body-2-semibold">
{remaining ?? '--:--:--'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { parseServerLocalDateTime } from '@/utils/formatDate';
import { share } from '@/utils/share';

import { usePatchInviteExpiry } from '../../_hooks/usePatchInviteExpiry';
import { markInviteSent } from '../../_utils/inviteSentSession';
import { markInviteSent } from '@/utils/inviteSentSession';
import InviteExpiresPicker from './InviteExpiresPicker';

type InviteFriendsDialogProps = {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import UserProfile from '@/components/user-profile-group/UserProfile';
import type { UserT } from '@/components/user-profile-group/userProfile.const';
import type { UserT } from '@/components/user-profile-group/userProfile.types';
import { useGetMe } from '@/hooks/useGetMe';

type ParticipantChipProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useState } from 'react';

import { AddIconOutline, ChevronDownIconOutline, ChevronUpIconOutline } from '@/assets/icons';
import UserProfileGroup from '@/components/user-profile-group';
import type { UserT } from '@/components/user-profile-group/userProfile.const';
import type { UserT } from '@/components/user-profile-group/userProfile.types';
import { ROUTES } from '@/consts/route';
import { Z_INDEX } from '@/consts/zIndex';
import { cn } from '@/utils/cn';
Expand Down Expand Up @@ -54,9 +54,7 @@ function ParticipantPanel({
const [isInviteDialogOpen, setIsInviteDialogOpen] = useState(false);

const hasFriends = participants.length > 1;
const profileImageUrls = participants.flatMap(({ user }) =>
user.imageUrl ? [user.imageUrl] : []
);
const profileImageUrls = participants.map(({ user }) => user.imageUrl);
const inviteUrl = inviteCode ? buildInviteUrl(tournamentId, inviteCode) : '';

const handleToggleExpand = () => setIsExpanded(prev => !prev);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ROUTES } from '@/consts/route';
import { logAnalyticsEvent } from '@/utils/analytics';
import { getApiErrorCode, getApiErrorStatus, isGlobalNetError } from '@/utils/apiError';
import { getApiErrorMessage } from '@/utils/getApiErrorMessage';
import { clearInviteSent } from '@/utils/inviteSentSession';

import { postTournamentStart } from '../_apis/postTournamentStart';

Expand All @@ -21,6 +22,7 @@ export const usePostTournamentStart = (tournamentId: number) => {
// - 주최자: ROOT ID (요청 tournamentId 와 동일)
// - 참여자: 새로 생성된 CLONE ID (이후 본인 인스턴스로 진행)
onSuccess: ({ tournamentId: nextTournamentId }) => {
clearInviteSent(tournamentId);
logAnalyticsEvent(ANALYTICS_EVENT.TOURNAMENT_START, {
tournament_id: nextTournamentId,
source_tournament_id: tournamentId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import Link from 'next/link';
import { useEffect } from 'react';

import ResultGuestBannerGroupIllustration from '@/assets/images/result-guest-banner-group.svg';
import UserProfileGreenIcon from '@/assets/images/user-profile-green.svg';
import UserProfileYellowIcon from '@/assets/images/user-profile-yellow.svg';
import ResultGuestBannerIllustration from '@/assets/images/result-guest-banner-illustration.svg';
import { ANALYTICS_EVENT } from '@/consts/analytics';
import { ROUTES } from '@/consts/route';
import { logAnalyticsEvent } from '@/utils/analytics';
Expand All @@ -31,39 +29,9 @@ function ResultGuestBanner() {
<p className="body-1-semibold text-text-neutral-secondary">가입하고 토너먼트 주최하기</p>
</div>

{/* 노란 이모지 — 그룹 일러스트 뒤에 위치 */}
<UserProfileYellowIcon
<ResultGuestBannerIllustration
aria-hidden
style={{
position: 'absolute',
right: '21.59px',
top: '15px',
width: '21.396px',
height: '21.396px',
transform: 'rotate(12.047deg)',
}}
/>
{/* 그룹 일러스트 (블루 카드 + 하트 + 스파클) */}
<ResultGuestBannerGroupIllustration
aria-hidden
style={{
position: 'absolute',
right: '19.27px',
top: '14.25px',
height: '52.087px',
width: '77.711px',
}}
/>
{/* 초록 이모지 — 그룹 일러스트 앞에 위치 */}
<UserProfileGreenIcon
aria-hidden
style={{
position: 'absolute',
right: '84.5px',
top: '39.63px',
width: '22px',
height: '23px',
}}
className="absolute top-[14.25px] right-[18px] h-[53px] w-[87px]"
/>
</Link>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Button from '@/components/button';
import { Drawer, DrawerContent, DrawerDescription, DrawerTitle } from '@/components/drawer';
import Spinner from '@/components/spinner';
import { ANALYTICS_EVENT } from '@/consts/analytics';
import { ROUTES } from '@/consts/route';
import { logAnalyticsEvent } from '@/utils/analytics';
import { share } from '@/utils/share';

Expand All @@ -21,8 +22,9 @@ type PlateShareDialogProps = {
};

const buildPlayLinkUrl = (tournamentId: number) => {
if (typeof window === 'undefined') return `/play/${tournamentId}`;
return `${window.location.origin}/play/${tournamentId}`;
const path = ROUTES.PLAY_FROM_LINK(tournamentId);
if (typeof window === 'undefined') return path;
return `${window.location.origin}${path}`;
};

function PlateShareDialog({
Expand Down
35 changes: 0 additions & 35 deletions apps/web/src/app/tournament/join/_utils/joinSession.ts

This file was deleted.

24 changes: 0 additions & 24 deletions apps/web/src/assets/images/result-guest-banner-group.svg

This file was deleted.

Loading
Loading