Skip to content

feat: 아이템 수정 상태 제약 해제 및 위시리스트 응답 구조 서버 기준으로 정리 - #424

Merged
iOdiO89 merged 10 commits into
devfrom
feat/416-item-edit
Aug 4, 2026
Merged

feat: 아이템 수정 상태 제약 해제 및 위시리스트 응답 구조 서버 기준으로 정리#424
iOdiO89 merged 10 commits into
devfrom
feat/416-item-edit

Conversation

@iOdiO89

@iOdiO89 iOdiO89 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

작업 요약

  • 위시·토너먼트 아이템을 status가 READY일 때도 수정할 수 있도록 변경합니다
  • 위시리스트 응답을 프론트에서 매핑하지 않고 서버 구조 그대로 사용합니다
  • 위시 응답에 refreshNeeded, reused 필드 타입을 추가합니다

작업 세부 내용

아이템 수정 화면 (item-edit-form)

  • 기존에는 status가 READY면 이미지·이름·가격 입력이 전부 disabled였고, 하단 CTA도 READY / FAILED 분기로 나뉘어 있었습니다.
  • 이제 상태와 무관하게 입력이 항상 열려 있고, CTA는 삭제하기 + 저장하기 한 벌로 통합했습니다.
  • 다시 불러오기READY이면서 onRefresh가 있을 때만 추가로 노출됩니다.

위시리스트 응답 구조 (getWishlist / useGetWishlist)

  • WishlistEntryTWishItemT 로 평탄화하던 mapWishlist를 제거하고 서버 응답({ wish, item })을 그대로 내려보냅니다.
  • 페이지네이션도 커스텀 WishlistPageT 대신 공통 ApiResponseT + pageResponse를 사용합니다.
  • 소비처(WishGridContent, wish-grid, ByWishContent 등)는 wish.id / item.name 형태로 접근하도록 맞췄습니다.

타입 정리

  • 공통 ApiResponseTpageResponse(nextCursor, hasNext)를 추가했습니다.
  • GetWishlistResponseTrefreshNeeded, reused를 추가했습니다. 이미지로 등록한 경우 null, 링크로 등록한 경우 boolean이라 주석으로 명시했습니다.
  • GetTournamentItemResponseT에서 sourceUrl, currency를 공통 필드로 올리고 FAILED를 미완성 상태 유니온에 합쳤습니다. 동일했던 PatchTournamentItemResponseT는 제거했습니다.

위시리스트 스켈레톤

  • 실제 카드에 rounded가 없어 스켈레톤의 rounded-2xl을 제거했습니다.
  • 스켈레톤 치수를 실제 카드에 맞췄습니다 (이미지 aspect-[201/166], 텍스트 영역 h-[124px]). 로딩 → 실제 카드 전환 시 리스트 높이가 튀지 않습니다.

연관 이슈

closes #416

Summary by CodeRabbit

  • 새 기능
    • 위시리스트 페이지네이션과 항목 상태 정보가 개선되었습니다.
    • 초대 링크에서 참여 여부와 만료 상태를 자동으로 안내합니다.
    • 회원은 토너먼트 초대 링크를 통해 자동 참여할 수 있습니다.
    • 결과 화면에서 영수증을 이미지로 저장·복사·공유할 수 있습니다.
  • 버그 수정
    • 영수증 아이콘 표시 오류와 일부 오류 화면 UI를 수정했습니다.
    • 위시 정보 편집 및 가격·이미지 저장 동작을 개선했습니다.
  • 스타일
    • 위시 관련 문구와 입력 안내, 토스트 위치 및 화면 스타일을 정리했습니다.

@iOdiO89 iOdiO89 self-assigned this Aug 3, 2026
@iOdiO89 iOdiO89 added feature New feature or request WEB labels Aug 3, 2026
@iOdiO89 iOdiO89 linked an issue Aug 3, 2026 that may be closed by this pull request
15 tasks
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
piki Ready Ready Preview Aug 4, 2026 2:34am

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다.

@github-actions
github-actions Bot requested a review from soyeong0115 August 3, 2026 07:42
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@iOdiO89, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f6e93499-596f-4bfe-9262-1e9db377b925

📥 Commits

Reviewing files that changed from the base of the PR and between 63fabec and b101606.

📒 Files selected for processing (22)
  • apps/web/e2e/helpers/apiResponse.ts
  • apps/web/e2e/mocks/wish.ts
  • apps/web/src/apis/getWishlist.ts
  • apps/web/src/app/archive/wish/[id]/_components/EditContent.tsx
  • apps/web/src/app/archive/wish/[id]/_hooks/usePatchWish.ts
  • apps/web/src/app/archive/wish/[id]/_types/wish.ts
  • apps/web/src/app/archive/wish/_components/WishCardSkeleton.tsx
  • apps/web/src/app/archive/wish/_components/WishContent.tsx
  • apps/web/src/app/archive/wish/_components/WishContentClient.tsx
  • apps/web/src/app/archive/wish/_components/WishGridContent.tsx
  • apps/web/src/app/archive/wish/_components/WishlistList.tsx
  • apps/web/src/app/archive/wish/_components/wish-grid/index.tsx
  • apps/web/src/app/tournament/[id]/create/by-wish/_components/ByWishContent.tsx
  • apps/web/src/app/tournament/[id]/item/[itemId]/_apis/patchTournamentItem.ts
  • apps/web/src/app/tournament/[id]/item/[itemId]/_components/EditContent.tsx
  • apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts
  • apps/web/src/app/tournament/[id]/item/[itemId]/_types/tournamentItem.ts
  • apps/web/src/components/common/item-edit-form/index.tsx
  • apps/web/src/hooks/useGetWishlist.ts
  • apps/web/src/types/api.ts
  • apps/web/src/types/item.ts
  • apps/web/src/types/wish.ts
📝 Walkthrough

Walkthrough

위시리스트 응답과 아이템 수정 계약을 갱신했습니다. 초대 진입과 회원 자동 참여 흐름을 서버 및 상태 기반으로 변경했습니다. 영수증 공유를 다이얼로그 중심으로 재구성했습니다. 오류 화면과 공통 문구도 보정했습니다.

Changes

위시리스트 및 아이템 흐름

Layer / File(s) Summary
위시리스트 및 아이템 응답 계약
apps/web/src/types/api.ts, apps/web/src/types/wish.ts, apps/web/src/types/item.ts, apps/web/src/app/.../_types/*
ApiResponseTpageResponse를 추가했습니다. 위시리스트 항목에 refreshNeededreused를 추가했습니다. 가격 필드를 currentPrice에서 price로 변경했습니다.
위시리스트 데이터 흐름 전환
apps/web/src/apis/getWishlist.ts, apps/web/src/hooks/useGetWishlist.ts, apps/web/src/app/archive/wish/_components/*, apps/web/e2e/mocks/wish.ts
API 원본 배열과 페이지 메타데이터를 사용하도록 변경했습니다. 화면은 wish.id와 중첩된 item을 사용합니다.
아이템 수기 수정 흐름
apps/web/src/components/common/item-edit-form/index.tsx, apps/web/src/app/archive/wish/[id]/..., apps/web/src/app/tournament/[id]/item/[itemId]/...
상태와 관계없이 편집 입력과 저장 CTA를 표시합니다. 변경된 가격과 선택적 이미지를 FormData에 전달합니다. PATCH API는 응답 본문을 반환하지 않습니다.

초대 및 토너먼트 참여 흐름

Layer / File(s) Summary
초대 미리보기 계약과 API
apps/web/src/types/tournament.ts, apps/web/src/apis/getInvitePreviewByCode.ts, apps/web/src/app/home/_components/InviteTournamentDialog.tsx, apps/web/src/app/tournament/join/_apis/getInvitePreview.ts
공용 초대 미리보기 타입을 추가했습니다. 서버에서는 serverApi, 클라이언트에서는 clientApi를 사용합니다.
초대 페이지 서버 진입 처리
apps/web/src/app/invite/[id]/page.tsx, apps/web/src/app/invite/[id]/_components/InviteInvalid.tsx
초대 코드 오류, 만료, 토너먼트 불일치, 기존 참여 여부에 따라 화면과 리다이렉트를 서버에서 결정합니다.
회원 자동 참여 상태 처리
apps/web/src/app/tournament/join/[id]/_components/JoinPreviewClient.tsx
회원은 닉네임 입력 없이 자동 참여합니다. 참여 중, 재시도 가능, 참여 차단 상태별 UI를 표시합니다.

영수증 공유 흐름

Layer / File(s) Summary
영수증 렌더링과 캡처 레이어
apps/web/src/app/tournament/[id]/result/_components/ReceiptDrawMachine.tsx, .../receipt-share-dialog/ReceiptShareCaptureLayer.tsx
기존 영수증 컴포넌트의 imperative ref를 제거했습니다. 공유용 캡처 레이어를 추가했습니다.
영수증 공유 다이얼로그
apps/web/src/app/tournament/[id]/result/_components/ResultClient.tsx, .../receipt-share-dialog/ReceiptShareDialog.tsx
공유 버튼과 SHARE_RECEIPT 액션이 다이얼로그를 엽니다. 이미지 미리보기와 저장·복사·채팅방 공유를 제공합니다.
영수증 이미지 처리 유틸리티
apps/web/src/app/tournament/[id]/result/_utils/shareReceiptImage.ts
캡처, 다운로드, 클립보드 복사, 파일 공유를 별도 함수로 분리했습니다.
영수증 아이콘 연결
apps/web/src/assets/icons/{fill,outline}/index.ts, apps/web/src/app/archive/tournament/..., apps/web/src/components/tournament-card/MorePopover.tsx
오타가 있는 영수증 아이콘 export와 사용처를 수정했습니다.

공통 화면 및 문구 보정

Layer / File(s) Summary
오류 및 404 화면
apps/web/src/app/error.tsx, apps/web/src/app/global-error.tsx, apps/web/src/app/not-found.tsx
경고 아이콘, 공통 버튼 스타일, 새 레이아웃과 안내 문구를 적용했습니다.
공통 UI 및 문구 보정
apps/web/src/components/common/*, apps/web/src/components/get-item-dialog/index.tsx, apps/web/src/components/input/index.tsx, apps/web/src/components/toast/index.tsx, apps/web/src/app/home/*, apps/web/src/app/mypage/withdraw/page.tsx
placeholder, 토스트 위치, 위시 및 토너먼트 관련 문구를 변경했습니다.
E2E 표시 검증
apps/web/e2e/specs/home/home.spec.ts
홈 토너먼트 목록 제목 검증 문구를 변경했습니다.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ResultClient
  participant ReceiptShareDialog
  participant ReceiptShareCaptureLayer
  participant shareReceiptImage
  ResultClient->>ReceiptShareDialog: 영수증 공유 요청
  ReceiptShareDialog->>ReceiptShareCaptureLayer: 캡처용 영수증 렌더링
  ReceiptShareDialog->>shareReceiptImage: 이미지 Blob 생성
  shareReceiptImage-->>ReceiptShareDialog: Blob 반환
  ReceiptShareDialog->>shareReceiptImage: 저장·복사·파일 공유 실행
  ReceiptShareDialog-->>ResultClient: 공유 결과 반영
Loading
sequenceDiagram
  participant InvitePage
  participant getInvitePreviewByCode
  participant InviteAPI
  participant InviteInvalid
  participant JoinPreviewClient
  InvitePage->>getInvitePreviewByCode: 초대 코드 미리보기 요청
  getInvitePreviewByCode->>InviteAPI: 서버 또는 클라이언트 API 호출
  InviteAPI-->>getInvitePreviewByCode: 미리보기 데이터 반환
  getInvitePreviewByCode-->>InvitePage: joined와 tournamentId 전달
  InvitePage->>InviteInvalid: 오류 상태 표시
  InvitePage->>JoinPreviewClient: 미참여 사용자 이동
  JoinPreviewClient->>InviteAPI: 회원 자동 참여 요청
Loading

Possibly related PRs

  • TeamPiKi/client#421: getWishlist.ts, WishContent.tsx, useGetWishlist.ts의 페이지네이션 변경과 직접 연결됩니다.
  • TeamPiKi/client#418: 영수증 공유 컴포넌트와 이미지 처리 유틸리티 변경이 직접 겹칩니다.
  • TeamPiKi/client#412: 초대 페이지와 초대 참여 흐름 변경이 직접 연결됩니다.

Suggested labels: refactor

Suggested reviewers: soyeong0115

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 초대 플로우, 영수증 공유, 오류 화면, 입력·토스트 스타일 등 연결 이슈와 직접 관련이 없는 변경이 포함되어 있습니다. 연결 이슈와 무관한 초대 플로우, 영수증 공유, 오류 화면 및 전역 스타일 변경을 별도 PR로 분리하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive READY 상태 수정, 선택 이미지 저장, 타입 변경은 확인되지만 변경 필드 전송과 오류 처리는 요약만으로 검증할 수 없습니다. 변경 필드만 전송하는 로직, FAILED 사전 검증, 403/404 유지 및 ITEM-003~005 토스트 처리를 diff 또는 테스트로 확인하세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 READY 상태 수정 허용과 위시리스트 응답 구조 변경이라는 주요 변경을 명확하게 요약합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/416-item-edit

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/components/common/item-edit-form/index.tsx (1)

110-146: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

기존 READY 전용 BottomCta를 제거하세요.

itemStatus === 'READY' && onRefresh 조건에서 기존 BottomCta가 먼저 렌더링됩니다. 그 다음 공통 BottomCta도 렌더링됩니다. READY 항목에서 삭제 버튼과 고정 CTA 컨테이너가 중복됩니다.

Lines 98-111의 기존 CTA 블록을 제거하세요. 공통 BottomCta만 유지하세요.

🤖 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/components/common/item-edit-form/index.tsx` around lines 110 -
146, Remove the existing READY-specific BottomCta block near the preceding
conditional render, including its duplicate delete/fixed CTA controls. Keep only
the shared BottomCta containing the delete, conditional refresh, and save
buttons, preserving its current conditions and handlers.
🧹 Nitpick comments (2)
apps/web/src/app/archive/wish/_components/wish-grid/index.tsx (2)

10-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

프로젝트 모듈 import를 절대 경로로 변경하세요.

Line 10../../_utils/wishScroll은 같은 디렉터리 밖의 프로젝트 모듈을 상대 경로로 import합니다. @/app/archive/wish/_utils/wishScroll을 사용하세요.

수정 예시
-import { saveWishScroll } from '../../_utils/wishScroll';
+import { saveWishScroll } from '`@/app/archive/wish/_utils/wishScroll`';

As per coding guidelines, relative imports are only allowed for files in the same directory.

🤖 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/archive/wish/_components/wish-grid/index.tsx` at line 10,
Update the saveWishScroll import in the wish-grid module from the relative path
to the project alias path `@/app/archive/wish/_utils/wishScroll`, keeping the
imported symbol and behavior unchanged.

Source: Coding guidelines


34-41: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Linkcursor-pointer를 추가하세요.

Line 34Line 81Link는 클릭 요소입니다. 두 요소에 cursor-pointer를 추가하세요.

수정 예시
 <Link
+  className="cursor-pointer"
   href={ROUTES.WISH_EDIT(wish.id)}

As per coding guidelines, clickable elements require cursor-pointer.

Also applies to: 81-94

🤖 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/archive/wish/_components/wish-grid/index.tsx` around lines
34 - 41, Update both Link elements rendering the wish cards, including the one
wrapping WishFailedCard and the corresponding Link near the second card, to
include the cursor-pointer styling while preserving their existing click
behavior and attributes.

Source: Coding guidelines

🤖 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/archive/wish/`[id]/_components/ItemEditForm.tsx:
- Around line 10-16: Keep initialImageUrl required as a string in
ItemEditFormProps and update ItemEditFormBase to handle null or empty image
values internally, including rendering and validation, so callers do not need to
convert wishData.item.imageUrl with an empty-string fallback.

In `@apps/web/src/components/common/item-edit-form/index.tsx`:
- Around line 136-145: Update isValid and handleSave in the item edit form so
selectedImage is required only when the item status is FAILED; for READY and
in-progress items, allow saving without an image and pass only the changed valid
fields to onSave. Remove the unconditional !selectedImage guard from handleSave,
while preserving the existing loading and deletion restrictions.

In `@apps/web/src/types/wish.ts`:
- Around line 8-22: Update GetWishlistResponseT so its item field uses the same
status-based union as GetWishResponseT, including PENDING, PROCESSING, and
FAILED variants with name, currentPrice, currency, and imageUrl nullable.
Preserve the existing response fields and align the union with the
detail-response type so WishGrid can pass each variant to WishCard safely.

---

Outside diff comments:
In `@apps/web/src/components/common/item-edit-form/index.tsx`:
- Around line 110-146: Remove the existing READY-specific BottomCta block near
the preceding conditional render, including its duplicate delete/fixed CTA
controls. Keep only the shared BottomCta containing the delete, conditional
refresh, and save buttons, preserving its current conditions and handlers.

---

Nitpick comments:
In `@apps/web/src/app/archive/wish/_components/wish-grid/index.tsx`:
- Line 10: Update the saveWishScroll import in the wish-grid module from the
relative path to the project alias path `@/app/archive/wish/_utils/wishScroll`,
keeping the imported symbol and behavior unchanged.
- Around line 34-41: Update both Link elements rendering the wish cards,
including the one wrapping WishFailedCard and the corresponding Link near the
second card, to include the cursor-pointer styling while preserving their
existing click behavior and attributes.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3c2de044-34b2-403b-a5d7-f0a942980db8

📥 Commits

Reviewing files that changed from the base of the PR and between 8853d12 and 9d15b2d.

📒 Files selected for processing (20)
  • apps/web/e2e/helpers/apiResponse.ts
  • apps/web/e2e/mocks/wish.ts
  • apps/web/src/apis/getWishlist.ts
  • apps/web/src/app/archive/wish/[id]/_components/EditContent.tsx
  • apps/web/src/app/archive/wish/[id]/_components/ItemEditForm.tsx
  • apps/web/src/app/archive/wish/[id]/_types/wish.ts
  • apps/web/src/app/archive/wish/_components/WishCardSkeleton.tsx
  • apps/web/src/app/archive/wish/_components/WishContent.tsx
  • apps/web/src/app/archive/wish/_components/WishContentClient.tsx
  • apps/web/src/app/archive/wish/_components/WishGridContent.tsx
  • apps/web/src/app/archive/wish/_components/WishlistList.tsx
  • apps/web/src/app/archive/wish/_components/wish-grid/index.tsx
  • apps/web/src/app/tournament/[id]/create/by-wish/_components/ByWishContent.tsx
  • apps/web/src/app/tournament/[id]/item/[itemId]/_apis/patchTournamentItem.ts
  • apps/web/src/app/tournament/[id]/item/[itemId]/_components/EditContent.tsx
  • apps/web/src/app/tournament/[id]/item/[itemId]/_types/tournamentItem.ts
  • apps/web/src/components/common/item-edit-form/index.tsx
  • apps/web/src/hooks/useGetWishlist.ts
  • apps/web/src/types/api.ts
  • apps/web/src/types/wish.ts

Comment thread apps/web/src/app/archive/wish/[id]/_components/ItemEditForm.tsx
Comment thread apps/web/src/components/common/item-edit-form/index.tsx
Comment thread apps/web/src/types/wish.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (5)
apps/web/e2e/specs/home/home.spec.ts (1)

13-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

E2E 테스트 제목도 새 문구와 일치시키세요.

현재 assertion은 최근 토너먼트를 검증하지만 테스트 제목은 최근 생성한 토너먼트를 사용합니다. 테스트 리포트의 의미를 일치시키려면 관련 테스트 제목을 새 용어로 변경하세요.

🤖 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/e2e/specs/home/home.spec.ts` at line 13, Update the related E2E test
title in home.spec.ts to use the same “최근 토너먼트” wording asserted by getByRole,
replacing the existing “최근 생성한 토너먼트” title while leaving the assertion
unchanged.
apps/web/src/app/error.tsx (1)

22-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

최상위 화면 컨테이너를 <main>으로 변경하세요.

세 화면은 실제 화면 컨테이너에 <div>를 사용합니다. 화면의 주 콘텐츠 영역에는 semantic <main>을 사용하세요.

  • apps/web/src/app/error.tsx#L22-L44: 최상위 <div><main>으로 변경하세요.
  • apps/web/src/app/global-error.tsx#L25-L50: 최상위 <div><main>으로 변경하세요.
  • apps/web/src/app/not-found.tsx#L9-L24: 최상위 <div><main>으로 변경하세요.

As per coding guidelines, containers in apps/web/src/**/*.tsx must use semantic <main> tags.

🤖 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/error.tsx` around lines 22 - 44, Replace the top-level
screen container with a semantic main element in apps/web/src/app/error.tsx
lines 22-44, apps/web/src/app/global-error.tsx lines 25-50, and
apps/web/src/app/not-found.tsx lines 9-24; preserve each screen’s existing
contents, styling, and behavior.

Source: Coding guidelines

apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareCaptureLayer.tsx (2)

5-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

상위 디렉터리 상대경로 import를 @/ 절대경로로 통일하세요. 두 신규 파일 모두 ../../../../로 상위 디렉터리 모듈을 가져옵니다. 코딩 가이드라인은 프로젝트 모듈에 @/* 절대경로를 쓰고 상대경로는 동일 디렉터리 파일에만 쓰도록 정합니다.

  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareCaptureLayer.tsx#L5-L6: ../../../_common/_types/tournament../ReceiptPaper@/ 절대경로로 바꾸세요.
  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx#L14-L20: ../../../_common/_types/tournament../../_utils/shareReceiptImage@/ 절대경로로 바꾸세요. 같은 디렉터리인 ./ReceiptShareCaptureLayer는 그대로 두세요.
🤖 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/receipt-share-dialog/ReceiptShareCaptureLayer.tsx
around lines 5 - 6, 상위 디렉터리 모듈의 상대경로 import를 프로젝트의 `@/` 절대경로로 통일하세요.
ReceiptShareCaptureLayer.tsx의 RankedProductT와 ReceiptPaper import,
ReceiptShareDialog.tsx의 RankedProductT와 shareReceiptImage import를 변경하고, 동일 디렉터리의
./ReceiptShareCaptureLayer import는 그대로 유지하세요.

Source: Coding guidelines


1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

forwardRef 대신 ref prop을 사용하세요.

React 19에서 ref는 일반 prop입니다. ReceiptShareCaptureLayer의 타입에 ref?: React.Ref<HTMLDivElement>를 두고 정규 function 컴포넌트로 작성하세요.

♻️ 제안 리팩터
-import { forwardRef } from 'react';
-
 import PikiLogoCart from '`@/assets/images/piki-logo-cart.svg`';
type ReceiptShareCaptureLayerProps = {
+  ref?: React.Ref<HTMLDivElement>;
  tournamentId: number;
  tournamentName: string;
  result: RankedProductT[];
  date: Date;
};

-const ReceiptShareCaptureLayer = forwardRef<HTMLDivElement, ReceiptShareCaptureLayerProps>(
-  function ReceiptShareCaptureLayer({ tournamentId, tournamentName, result, date }, ref) {
-    return (
+function ReceiptShareCaptureLayer({
+  ref,
+  tournamentId,
+  tournamentName,
+  result,
+  date,
+}: ReceiptShareCaptureLayerProps) {
+  return (
🤖 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/receipt-share-dialog/ReceiptShareCaptureLayer.tsx
at line 1, Replace the forwardRef-based ReceiptShareCaptureLayer implementation
with a regular function component that accepts ref?: React.Ref<HTMLDivElement>
in its props, removes the forwardRef import and wrapper, and passes the ref to
the same underlying div.

Source: Coding guidelines

apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx (1)

81-111: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

캡처에 실패하면 다이얼로그가 스켈레톤 상태로 고정됩니다.

capture가 실패하면 toast.error만 표시합니다. previewUrlimageBlob은 계속 null이므로 미리보기는 Skeleton으로 남고 세 버튼은 계속 비활성 상태입니다. 사용자는 다이얼로그를 닫았다 다시 여는 방법 외에 재시도 수단이 없습니다.

실패 상태를 저장하고, 실패 시 안내 문구와 다시 시도 버튼을 노출하는 방법을 권장합니다.

Also applies to: 184-195

🤖 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/receipt-share-dialog/ReceiptShareDialog.tsx
around lines 81 - 111, Update the ReceiptShareDialog capture flow to store an
explicit capture failure state instead of only showing a toast. Set that state
in the catch path of capture, render an explanatory failure message and retry
action when it is active, and have retry invoke the capture flow again while
clearing the failure state; keep the existing skeleton, preview, and button
behavior for loading and successful captures.
🤖 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/invite/`[id]/_components/InviteInvalid.tsx:
- Line 22: InviteInvalid 화면의 주요 제목인 `초대 링크가 유효하지 않아요`를 감싸는 요소를 `p`에서 `h1`로
변경하세요. 기존 `heading-1-bold text-text-neutral-primary` 클래스와 제목 텍스트는 그대로 유지하세요.
- Around line 30-34: Update the home navigation CTA in InviteInvalid to remove
the nested Link/Button interactive elements; replace them with ButtonLink or a
single Link styled as the existing primary large full-width button while
preserving ROUTES.HOME and the current label.

In `@apps/web/src/app/invite/`[id]/page.tsx:
- Around line 30-33: Update the catch block in the invite page around
InviteInvalid so only Axios errors with status 400 or 409 return the
invalid-invite screen; rethrow network failures, 5xx responses, and all other
unexpected errors for the error boundary to handle. Preserve
showExpiredDialog=true only for status 409 and false for status 400.

In `@apps/web/src/app/tournament/`[id]/result/_utils/shareReceiptImage.ts:
- Around line 128-134: Update the share result flow around the share utility and
ReceiptShareDialog.handleShareToChat so non-AbortError exceptions from
navigator.share return a new 'failed' status instead of 'unsupported'; preserve
'cancelled' for AbortError and reserve 'unsupported' for capability checks.
Handle 'failed' in the dialog by showing the existing general error toast, while
keeping the unsupported message only for genuinely unsupported environments.
- Around line 20-21: Update isDownloadSupported and the saveReceiptImage flow so
support is not inferred solely from the anchor download property, which may be
present without functioning in iOS WKWebView. Ensure
ReceiptShareDialog.handleSave does not show a definitive success toast based
only on invoking the save command; report an attempted save instead unless an
app bridge or other reliable result confirms that storage completed.

In `@apps/web/src/app/tournament/join/`[id]/_components/JoinPreviewClient.tsx:
- Around line 79-83: Update the 409 handling in the postJoin onError callback to
inspect error.response?.data.code instead of treating every conflict as
LINK_EXPIRED. Route each recognized code to its corresponding dialog and use a
cause-neutral blocked screen when the cause cannot be distinguished, while
preserving the existing auto-join blocked state.

In `@apps/web/src/types/item.ts`:
- Around line 19-22: PatchItemRequestT in apps/web/src/types/item.ts lines 19-22
must make name and price optional to represent partial updates. In
apps/web/src/app/archive/wish/[id]/_hooks/usePatchWish.ts lines 17-21 and
apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts
lines 18-22, append each FormData field only when its corresponding value is not
undefined, so mutations send only changed fields.

---

Nitpick comments:
In `@apps/web/e2e/specs/home/home.spec.ts`:
- Line 13: Update the related E2E test title in home.spec.ts to use the same “최근
토너먼트” wording asserted by getByRole, replacing the existing “최근 생성한 토너먼트” title
while leaving the assertion unchanged.

In `@apps/web/src/app/error.tsx`:
- Around line 22-44: Replace the top-level screen container with a semantic main
element in apps/web/src/app/error.tsx lines 22-44,
apps/web/src/app/global-error.tsx lines 25-50, and
apps/web/src/app/not-found.tsx lines 9-24; preserve each screen’s existing
contents, styling, and behavior.

In
`@apps/web/src/app/tournament/`[id]/result/_components/receipt-share-dialog/ReceiptShareCaptureLayer.tsx:
- Around line 5-6: 상위 디렉터리 모듈의 상대경로 import를 프로젝트의 `@/` 절대경로로 통일하세요.
ReceiptShareCaptureLayer.tsx의 RankedProductT와 ReceiptPaper import,
ReceiptShareDialog.tsx의 RankedProductT와 shareReceiptImage import를 변경하고, 동일 디렉터리의
./ReceiptShareCaptureLayer import는 그대로 유지하세요.
- Line 1: Replace the forwardRef-based ReceiptShareCaptureLayer implementation
with a regular function component that accepts ref?: React.Ref<HTMLDivElement>
in its props, removes the forwardRef import and wrapper, and passes the ref to
the same underlying div.

In
`@apps/web/src/app/tournament/`[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx:
- Around line 81-111: Update the ReceiptShareDialog capture flow to store an
explicit capture failure state instead of only showing a toast. Set that state
in the catch path of capture, render an explanatory failure message and retry
action when it is active, and have retry invoke the capture flow again while
clearing the failure state; keep the existing skeleton, preview, and button
behavior for loading and successful captures.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8cfeb615-582e-4644-ab35-e14fd54e3ba2

📥 Commits

Reviewing files that changed from the base of the PR and between 9d15b2d and 63fabec.

⛔ Files ignored due to path filters (3)
  • apps/web/src/assets/icons/fill/receipt.svg is excluded by !**/*.svg
  • apps/web/src/assets/icons/outline/receipt.svg is excluded by !**/*.svg
  • apps/web/src/assets/images/basket-not-found.svg is excluded by !**/*.svg
📒 Files selected for processing (40)
  • apps/web/e2e/mocks/wish.ts
  • apps/web/e2e/specs/home/home.spec.ts
  • apps/web/src/apis/getInvitePreviewByCode.ts
  • apps/web/src/app/archive/tournament/_components/TournamentStatusTab.tsx
  • apps/web/src/app/archive/wish/[id]/_components/EditContent.tsx
  • apps/web/src/app/archive/wish/[id]/_hooks/usePatchWish.ts
  • apps/web/src/app/archive/wish/[id]/_types/wish.ts
  • apps/web/src/app/archive/wish/_components/WishGridContent.tsx
  • apps/web/src/app/archive/wish/_components/wish-grid/index.tsx
  • apps/web/src/app/error.tsx
  • apps/web/src/app/global-error.tsx
  • apps/web/src/app/home/_components/CreateTournamentDialog.tsx
  • apps/web/src/app/home/_components/InviteTournamentDialog.tsx
  • apps/web/src/app/home/_components/tournament-list/index.tsx
  • apps/web/src/app/invite/[id]/_components/InviteClient.tsx
  • apps/web/src/app/invite/[id]/_components/InviteInvalid.tsx
  • apps/web/src/app/invite/[id]/page.tsx
  • apps/web/src/app/mypage/withdraw/page.tsx
  • apps/web/src/app/not-found.tsx
  • apps/web/src/app/tournament/[id]/create/by-wish/_components/ByWishContent.tsx
  • apps/web/src/app/tournament/[id]/item/[itemId]/_components/EditContent.tsx
  • apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts
  • apps/web/src/app/tournament/[id]/result/_components/ReceiptDrawMachine.tsx
  • apps/web/src/app/tournament/[id]/result/_components/ResultClient.tsx
  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareCaptureLayer.tsx
  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx
  • apps/web/src/app/tournament/[id]/result/_utils/shareReceiptImage.ts
  • apps/web/src/app/tournament/join/[id]/_components/JoinPreviewClient.tsx
  • apps/web/src/app/tournament/join/_apis/getInvitePreview.ts
  • apps/web/src/app/tournament/join/_types/join.ts
  • apps/web/src/assets/icons/fill/index.ts
  • apps/web/src/assets/icons/outline/index.ts
  • apps/web/src/components/common/create-tournament-dialog/index.tsx
  • apps/web/src/components/common/item-edit-form/index.tsx
  • apps/web/src/components/get-item-dialog/index.tsx
  • apps/web/src/components/input/index.tsx
  • apps/web/src/components/toast/index.tsx
  • apps/web/src/components/tournament-card/MorePopover.tsx
  • apps/web/src/types/item.ts
  • apps/web/src/types/tournament.ts
💤 Files with no reviewable changes (2)
  • apps/web/src/app/tournament/join/_types/join.ts
  • apps/web/src/app/invite/[id]/_components/InviteClient.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/web/src/app/archive/wish/[id]/_components/EditContent.tsx
  • apps/web/src/app/archive/wish/_components/WishGridContent.tsx
  • apps/web/src/app/tournament/[id]/item/[itemId]/_components/EditContent.tsx
  • apps/web/src/app/tournament/[id]/create/by-wish/_components/ByWishContent.tsx
  • apps/web/src/app/archive/wish/_components/wish-grid/index.tsx

<>
<main className="flex min-h-dvh flex-col items-center justify-center gap-6 bg-bg-layer-basement px-5 pt-padding-top">
<div className="flex flex-col items-center gap-2">
<p className="heading-1-bold text-text-neutral-primary">초대 링크가 유효하지 않아요</p>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

주요 화면 제목을 h1으로 변경하세요.

초대 링크가 유효하지 않아요는 이 화면의 주요 제목입니다. 현재 p 요소라서 문서 구조와 보조 기술의 제목 탐색에 포함되지 않습니다.

As per coding guidelines, "제목에는 <h1> 또는 <h2>를 사용한다."

🤖 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/invite/`[id]/_components/InviteInvalid.tsx at line 22,
InviteInvalid 화면의 주요 제목인 `초대 링크가 유효하지 않아요`를 감싸는 요소를 `p`에서 `h1`로 변경하세요. 기존
`heading-1-bold text-text-neutral-primary` 클래스와 제목 텍스트는 그대로 유지하세요.

Source: Coding guidelines

Comment on lines +30 to +34
<Link href={ROUTES.HOME} className="w-full max-w-80">
<Button size="lg" variant="primary" className="w-full">
홈으로 가기
</Button>
</Link>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

중첩된 인터랙티브 요소를 제거하세요.

Link 내부의 Button<a> 내부에 <button>을 생성합니다. 이 구조는 유효하지 않은 HTML이며 키보드와 클릭 동작을 불안정하게 만듭니다.

ButtonLink 또는 버튼 스타일을 적용한 단일 Link로 홈 이동 CTA를 구현하세요.

🤖 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/invite/`[id]/_components/InviteInvalid.tsx around lines 30 -
34, Update the home navigation CTA in InviteInvalid to remove the nested
Link/Button interactive elements; replace them with ButtonLink or a single Link
styled as the existing primary large full-width button while preserving
ROUTES.HOME and the current label.

Comment on lines +30 to +33
} catch (error) {
/** 409(만료·비활성 초대)는 만료 다이얼로그 노출, 그 외(400 코드 불일치 등)는 안내 화면만 */
const isExpired = isAxiosError<ApiErrorResponseT>(error) && error.response?.status === 409;
return <InviteInvalid showExpiredDialog={isExpired} />;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline 'apps/web/src/app/invite/[id]/page.tsx' --items all
rg -n -C 5 --glob '*.{ts,tsx}' \
  'getInvitePreviewByCode|interceptors|validateStatus|AxiosError' apps/web/src

Repository: TeamPiKi/client

Length of output: 45260


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- page snippet ---\n'
sed -n '1,80p' 'apps/web/src/app/invite/[id]/page.tsx'

printf '\n--- getInvitePreviewByCode ---\n'
sed -n '1,80p' apps/web/src/apis/getInvitePreviewByCode.ts

printf '\n--- serverApi interceptor ---\n'
sed -n '1,90p' apps/web/src/apis/server.ts

printf '\n--- error boundary/global query error handling mentions ---\n'
rg -n -C 3 --glob '*.{ts,tsx}' 'ErrorBoundary|onError|globalError|fallback|getApiErrorMessage|setExtra|captureError' apps/web/src

Repository: TeamPiKi/client

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- page snippet ---'
sed -n '1,80p' 'apps/web/src/app/invite/[id]/page.tsx'

printf '%s\n' ''
printf '%s\n' '--- getInvitePreviewByCode ---'
sed -n '1,80p' apps/web/src/apis/getInvitePreviewByCode.ts

printf '%s\n' ''
printf '%s\n' '--- serverApi interceptor ---'
sed -n '1,90p' apps/web/src/apis/server.ts

printf '%s\n' ''
printf '%s\n' '--- error boundary/global query error handling mentions ---'
rg -n -C 3 --glob '*.{ts,tsx}' 'ErrorBoundary|onError|globalError|fallback|getApiErrorMessage|setExtra|captureError' apps/web/src

Repository: TeamPiKi/client

Length of output: 49012


예상하지 않은 요청 실패를 오류 화면으로 전파하세요.

Line 30의 catch는 네트워크 오류와 5xx 응답도 InviteInvalid로 변환합니다. 400과 409만 InviteInvalid로 처리하고, 그 외 오류는 다시 throw해서 오류 경계에서 처리하세요.

수정 예시
   } catch (error) {
-    /** 409(만료·비활성 초대)는 만료 다이얼로그 노출, 그 외(400 코드 불일치 등)는 안내 화면만 */
-    const isExpired = isAxiosError<ApiErrorResponseT>(error) && error.response?.status === 409;
-    return <InviteInvalid showExpiredDialog={isExpired} />;
+    if (!isAxiosError<ApiErrorResponseT>(error)) throw error;
+
+    const status = error.response?.status;
+    if (status !== 400 && status !== 409) throw error;
+
+    return <InviteInvalid showExpiredDialog={status === 409} />;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (error) {
/** 409(만료·비활성 초대)는 만료 다이얼로그 노출, 그 외(400 코드 불일치 등)는 안내 화면만 */
const isExpired = isAxiosError<ApiErrorResponseT>(error) && error.response?.status === 409;
return <InviteInvalid showExpiredDialog={isExpired} />;
} catch (error) {
if (!isAxiosError<ApiErrorResponseT>(error)) throw error;
const status = error.response?.status;
if (status !== 400 && status !== 409) throw error;
return <InviteInvalid showExpiredDialog={status === 409} />;
🤖 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/invite/`[id]/page.tsx around lines 30 - 33, Update the catch
block in the invite page around InviteInvalid so only Axios errors with status
400 or 409 return the invalid-invite screen; rethrow network failures, 5xx
responses, and all other unexpected errors for the error boundary to handle.
Preserve showExpiredDialog=true only for status 409 and false for status 400.

Comment thread apps/web/src/app/tournament/[id]/result/_utils/shareReceiptImage.ts
Comment thread apps/web/src/app/tournament/[id]/result/_utils/shareReceiptImage.ts
Comment on lines 79 to 83
onError: error => {
if (isAxiosError<ApiErrorResponseT>(error) && error.response?.status === 409) {
setAutoJoinStatus('blocked');
setIsTournamentErrorDialogOpen(true);
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline 'apps/web/src/app/tournament/join/[id]/_components/JoinPreviewClient.tsx' --items all
rg -n -C 6 --glob '*.{ts,tsx}' \
  'postJoinMutation|postJoin|LINK_EXPIRED|ALREADY_STARTED|ALREADY_ENDED|ApiErrorResponseT' apps/web/src

Repository: TeamPiKi/client

Length of output: 50371


409 응답의 code를 구분하고 적절한 다이얼로그로 연결하세요.

postJoin의 모든 409를 LINK_EXPIRED로 처리하면 이미 참여한 경우나 토너먼트 상태 변경까지 링크 만료 안내로 표시됩니다. error.response?.data.code를 확인해 원인에 맞는 UI를 보여주거나, 서버에서 분리가 불가능한 경우에는 원인 중립적인 차단 화면을 사용하세요.

🤖 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/join/`[id]/_components/JoinPreviewClient.tsx
around lines 79 - 83, Update the 409 handling in the postJoin onError callback
to inspect error.response?.data.code instead of treating every conflict as
LINK_EXPIRED. Route each recognized code to its corresponding dialog and use a
cause-neutral blocked screen when the cause cannot be distinguished, while
preserving the existing auto-join blocked state.

Comment thread apps/web/src/types/item.ts Outdated
@iOdiO89
iOdiO89 merged commit 28adc48 into dev Aug 4, 2026
7 checks passed
@iOdiO89
iOdiO89 deleted the feat/416-item-edit branch August 4, 2026 02:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request WEB

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 위시/토너먼트 아이템 수기 수정 상시 허용 대응

1 participant