From fa36925951097812e08554cdfe78611adc250c67 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Wed, 12 Aug 2026 15:45:26 +0900 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20=EC=8B=9C=EC=9E=91=EB=90=9C=20?= =?UTF-8?q?=ED=86=A0=EB=84=88=EB=A8=BC=ED=8A=B8=EC=97=90=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=C2=B7=EC=9C=84=EC=8B=9C=EB=A1=9C=20=EB=8B=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=8B=9C=20=EC=95=88=EB=82=B4=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts | 1 + apps/web/src/hooks/usePostTournamentOCR.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts b/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts index a59f2937..130bd47f 100644 --- a/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts +++ b/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts @@ -35,6 +35,7 @@ export const usePostTournamentItemsByWish = (tournamentId: number, previousItemC /** 토너먼트가 시작됐거나 삭제, 존재하지 않는 경우 */ if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING || code === ERROR_CODE.TOURNAMENT_NOT_FOUND) { + toast.error(getApiErrorMessage(error)); queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); router.replace(ROUTES.TOURNAMENT_CREATE(tournamentId)); return; diff --git a/apps/web/src/hooks/usePostTournamentOCR.ts b/apps/web/src/hooks/usePostTournamentOCR.ts index bc932702..b16a7e4c 100644 --- a/apps/web/src/hooks/usePostTournamentOCR.ts +++ b/apps/web/src/hooks/usePostTournamentOCR.ts @@ -29,6 +29,7 @@ export const usePostTournamentOCR = (tournamentId: number) => { /** 토너먼트가 시작된 경우 */ if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING) { + toast.error(getApiErrorMessage(error)); queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); return; } From f4de8ed1d8def41a98c55309629ed0f79edbd950 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Wed, 12 Aug 2026 15:56:20 +0900 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=EC=82=AD=EC=A0=9C=EB=90=9C=20?= =?UTF-8?q?=ED=86=A0=EB=84=88=EB=A8=BC=ED=8A=B8=20NOT=5FFOUND=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=ED=99=88=20=ED=8F=B4=EB=B0=B1+=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EC=95=A1=EC=85=98=20=ED=86=A0=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A1=9C=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_hooks/usePostTournamentItemsByWish.ts | 13 +++++++++++-- .../[itemId]/_hooks/usePatchTournamentItem.ts | 16 +++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts b/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts index 130bd47f..5c3085c3 100644 --- a/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts +++ b/apps/web/src/app/tournament/[id]/create/by-wish/_hooks/usePostTournamentItemsByWish.ts @@ -4,6 +4,7 @@ import { useRouter } from 'next/navigation'; import { toast } from 'sonner'; import { PREV_ITEM_COUNT_KEY } from '@/app/tournament/[id]/create/_consts/tournamentItemBasket'; +import { QUERY_ACTION } from '@/consts/queryAction'; import { ROUTES } from '@/consts/route'; import { useBackWithFallback } from '@/hooks/useBackWithFallback'; import { getApiErrorCode, isGlobalNetError } from '@/utils/apiError'; @@ -33,14 +34,22 @@ export const usePostTournamentItemsByWish = (tournamentId: number, previousItemC const code = getApiErrorCode(error); - /** 토너먼트가 시작됐거나 삭제, 존재하지 않는 경우 */ - if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING || code === ERROR_CODE.TOURNAMENT_NOT_FOUND) { + /** 토너먼트가 시작된 경우 */ + if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING) { toast.error(getApiErrorMessage(error)); queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); router.replace(ROUTES.TOURNAMENT_CREATE(tournamentId)); return; } + /** 토너먼트가 삭제된 경우 */ + if (code === ERROR_CODE.TOURNAMENT_NOT_FOUND) { + router.replace( + `${ROUTES.HOME}?${QUERY_ACTION.KEY}=${QUERY_ACTION.VALUE.TOURNAMENT_NOT_FOUND}` + ); + return; + } + /** * 400: 아이템 32개 초과 * 403: 토너먼트 참여 권한 없음·위시에 없는 아이템 diff --git a/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts b/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts index 92351cde..a26f0ed8 100644 --- a/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts +++ b/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts @@ -3,6 +3,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useRouter } from 'next/navigation'; import { toast } from 'sonner'; +import { QUERY_ACTION } from '@/consts/queryAction'; import { ROUTES } from '@/consts/route'; import { useBackWithFallback } from '@/hooks/useBackWithFallback'; import type { PatchItemRequestT } from '@/types/item'; @@ -37,16 +38,21 @@ export const usePatchTournamentItem = (tournamentId: number, tournamentItemId: n const code = getApiErrorCode(error); - /** 토너먼트가 시작됐거나 삭제, 존재하지 않는 경우 */ - if ( - code === ERROR_CODE.TOURNAMENT_NOT_PENDING || - code === ERROR_CODE.TOURNAMENT_NOT_FOUND - ) { + /** 토너먼트가 시작된 경우 */ + if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING) { queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); router.replace(ROUTES.TOURNAMENT_CREATE(tournamentId)); return; } + /** 토너먼트가 삭제된 경우 */ + if (code === ERROR_CODE.TOURNAMENT_NOT_FOUND) { + router.replace( + `${ROUTES.HOME}?${QUERY_ACTION.KEY}=${QUERY_ACTION.VALUE.TOURNAMENT_NOT_FOUND}` + ); + return; + } + /** * 400: 상품 이름·가격 미입력 * 403: 토너먼트 참여 권한 없음 From 8e1c225eb763ce6a66c2b78700ab0b855cd6af5c Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Wed, 12 Aug 2026 16:36:54 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20=EA=B3=B5=EC=9C=A0=20=EB=8B=A4?= =?UTF-8?q?=EC=9D=B4=EC=96=BC=EB=A1=9C=EA=B7=B8=EA=B0=80=20=EC=93=B0?= =?UTF-8?q?=EB=8A=94=20usePostTournamentItemLink=EB=A5=BC=20src/hooks?= =?UTF-8?q?=EB=A1=9C=20=EB=A0=88=EB=B2=A8=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[id]/create/_apis => apis}/postTournamentItemLink.ts | 4 ++-- apps/web/src/app/tournament/[id]/create/_types/tournament.ts | 3 --- apps/web/src/components/get-item-dialog/ByLinkDialog.tsx | 2 +- .../[id]/create/_hooks => hooks}/usePostTournamentItemLink.ts | 3 +-- apps/web/src/types/tournament.ts | 4 ++++ 5 files changed, 8 insertions(+), 8 deletions(-) rename apps/web/src/{app/tournament/[id]/create/_apis => apis}/postTournamentItemLink.ts (75%) delete mode 100644 apps/web/src/app/tournament/[id]/create/_types/tournament.ts rename apps/web/src/{app/tournament/[id]/create/_hooks => hooks}/usePostTournamentItemLink.ts (96%) diff --git a/apps/web/src/app/tournament/[id]/create/_apis/postTournamentItemLink.ts b/apps/web/src/apis/postTournamentItemLink.ts similarity index 75% rename from apps/web/src/app/tournament/[id]/create/_apis/postTournamentItemLink.ts rename to apps/web/src/apis/postTournamentItemLink.ts index 5d098526..043a2786 100644 --- a/apps/web/src/app/tournament/[id]/create/_apis/postTournamentItemLink.ts +++ b/apps/web/src/apis/postTournamentItemLink.ts @@ -1,8 +1,8 @@ -import { clientApi } from '@/apis/client'; import { ENDPOINTS } from '@/consts/api'; import type { ApiResponseT } from '@/types/api'; +import type { PostTournamentItemLinkResponseT } from '@/types/tournament'; -import type { PostTournamentItemLinkResponseT } from '../_types/tournament'; +import { clientApi } from './client'; export const postTournamentItemLink = async (tournamentId: number, url: string) => { const { data } = await clientApi.post>( diff --git a/apps/web/src/app/tournament/[id]/create/_types/tournament.ts b/apps/web/src/app/tournament/[id]/create/_types/tournament.ts deleted file mode 100644 index b4175a82..00000000 --- a/apps/web/src/app/tournament/[id]/create/_types/tournament.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type PostTournamentItemLinkResponseT = { - tournamentItemId: number; -}; diff --git a/apps/web/src/components/get-item-dialog/ByLinkDialog.tsx b/apps/web/src/components/get-item-dialog/ByLinkDialog.tsx index 2117ec69..20ee6099 100644 --- a/apps/web/src/components/get-item-dialog/ByLinkDialog.tsx +++ b/apps/web/src/components/get-item-dialog/ByLinkDialog.tsx @@ -3,11 +3,11 @@ import { useParams } from 'next/navigation'; import { useState } from 'react'; -import { usePostTournamentItemLink } from '@/app/tournament/[id]/create/_hooks/usePostTournamentItemLink'; import { LinkIconFill } from '@/assets/icons'; import Button from '@/components/button'; import { Dialog, DialogContent, DialogDescription, DialogTitle } from '@/components/dialog'; import Input from '@/components/input'; +import { usePostTournamentItemLink } from '@/hooks/usePostTournamentItemLink'; import { usePostWishLink } from '@/hooks/usePostWishLink'; import type { ItemTypeT } from '@/types/item'; import { isGlobalNetError } from '@/utils/apiError'; diff --git a/apps/web/src/app/tournament/[id]/create/_hooks/usePostTournamentItemLink.ts b/apps/web/src/hooks/usePostTournamentItemLink.ts similarity index 96% rename from apps/web/src/app/tournament/[id]/create/_hooks/usePostTournamentItemLink.ts rename to apps/web/src/hooks/usePostTournamentItemLink.ts index 155279f8..96b31507 100644 --- a/apps/web/src/app/tournament/[id]/create/_hooks/usePostTournamentItemLink.ts +++ b/apps/web/src/hooks/usePostTournamentItemLink.ts @@ -3,13 +3,12 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useRouter } from 'next/navigation'; import { toast } from 'sonner'; +import { postTournamentItemLink } from '@/apis/postTournamentItemLink'; import { QUERY_ACTION } from '@/consts/queryAction'; import { ROUTES } from '@/consts/route'; import { getApiErrorCode, getApiErrorStatus, isGlobalNetError } from '@/utils/apiError'; import { getApiErrorMessage } from '@/utils/getApiErrorMessage'; -import { postTournamentItemLink } from '../_apis/postTournamentItemLink'; - type UsePostTournamentItemLinkOptionsT = { /** 입력 폼처럼 에러를 화면 안에서 안내하는 경우 false — 4xx 토스트를 끈다 */ showErrorToast?: boolean; diff --git a/apps/web/src/types/tournament.ts b/apps/web/src/types/tournament.ts index d1e9333a..8c158bc4 100644 --- a/apps/web/src/types/tournament.ts +++ b/apps/web/src/types/tournament.ts @@ -56,6 +56,10 @@ export type PostCreateTournamentResponseT = { tournamentId: number; }; +export type PostTournamentItemLinkResponseT = { + tournamentItemId: number; +}; + /** 초대 코드 / 토너먼트 미리보기 응답 */ export type GetInvitePreviewResponseT = { tournamentId: number; From 8249bdb6d3b179dddad8f555affd763acecdd628 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Wed, 12 Aug 2026 16:37:10 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20=EC=8B=9C=EC=9E=91=EB=90=9C=20?= =?UTF-8?q?=ED=86=A0=EB=84=88=EB=A8=BC=ED=8A=B8=20=EC=95=88=EB=82=B4=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20NOT=5FPENDING=20=EB=B6=84=EA=B8=B0?= =?UTF-8?q?=EC=97=90=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tournament/[id]/_common/_hooks/useDeleteTournamentItem.ts | 1 + .../app/tournament/[id]/create/_hooks/usePatchInviteExpiry.ts | 1 + .../[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts | 1 + apps/web/src/hooks/usePostTournamentItemLink.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/apps/web/src/app/tournament/[id]/_common/_hooks/useDeleteTournamentItem.ts b/apps/web/src/app/tournament/[id]/_common/_hooks/useDeleteTournamentItem.ts index 1824fc5e..5d006d3a 100644 --- a/apps/web/src/app/tournament/[id]/_common/_hooks/useDeleteTournamentItem.ts +++ b/apps/web/src/app/tournament/[id]/_common/_hooks/useDeleteTournamentItem.ts @@ -36,6 +36,7 @@ export const useDeleteTournamentItem = (tournamentId: number, tournamentItemId: /** 토너먼트가 시작된 경우 */ if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING) { + toast.error(getApiErrorMessage(error)); queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); if (pathname !== ROUTES.TOURNAMENT_CREATE(tournamentId)) router.replace(ROUTES.TOURNAMENT_CREATE(tournamentId)); diff --git a/apps/web/src/app/tournament/[id]/create/_hooks/usePatchInviteExpiry.ts b/apps/web/src/app/tournament/[id]/create/_hooks/usePatchInviteExpiry.ts index acce0ff7..21f5d0f7 100644 --- a/apps/web/src/app/tournament/[id]/create/_hooks/usePatchInviteExpiry.ts +++ b/apps/web/src/app/tournament/[id]/create/_hooks/usePatchInviteExpiry.ts @@ -31,6 +31,7 @@ export const usePatchInviteExpiry = (tournamentId: number) => { /** 토너먼트가 시작된 경우 */ if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING) { + toast.error(getApiErrorMessage(error)); queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); return; } diff --git a/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts b/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts index a26f0ed8..34abcd70 100644 --- a/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts +++ b/apps/web/src/app/tournament/[id]/item/[itemId]/_hooks/usePatchTournamentItem.ts @@ -40,6 +40,7 @@ export const usePatchTournamentItem = (tournamentId: number, tournamentItemId: n /** 토너먼트가 시작된 경우 */ if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING) { + toast.error(getApiErrorMessage(error)); queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); router.replace(ROUTES.TOURNAMENT_CREATE(tournamentId)); return; diff --git a/apps/web/src/hooks/usePostTournamentItemLink.ts b/apps/web/src/hooks/usePostTournamentItemLink.ts index 96b31507..80091343 100644 --- a/apps/web/src/hooks/usePostTournamentItemLink.ts +++ b/apps/web/src/hooks/usePostTournamentItemLink.ts @@ -34,6 +34,7 @@ export const usePostTournamentItemLink = ( /** 토너먼트가 시작된 경우 */ if (code === ERROR_CODE.TOURNAMENT_NOT_PENDING) { + if (showErrorToast) toast.error(getApiErrorMessage(error)); queryClient.invalidateQueries({ queryKey: ['tournament', tournamentId] }); return; } From e393e1674c1891446bd7d46296414bc3b7927861 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 13 Aug 2026 09:34:19 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=EC=B4=88=EB=8C=80=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=EA=B0=80=20=EC=97=86=EB=8A=94=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EC=9D=98=20=EA=B3=B5=EC=9C=A0=20=EB=B2=84=ED=8A=BC=20=EB=AC=B4?= =?UTF-8?q?=EB=B0=98=EC=9D=91=EC=97=90=20=EC=95=88=EC=A0=84=EB=A7=9D=20?= =?UTF-8?q?=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/invite-friends/InviteFriendsDialog.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx b/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx index 0f3bb745..2b9d7597 100644 --- a/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx +++ b/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx @@ -103,7 +103,11 @@ function InviteFriendsDialog({ }; const handleSendInviteLink = async () => { - if (!inviteUrl) return; + /** 이미 시작된 토너먼트인 경우 */ + if (!inviteUrl) { + toast.error('이미 시작된 토너먼트에는 친구를 초대할 수 없어요.'); + return; + } const result = await share({ title: 'piki 토너먼트 초대', From 3bdf4a58e8270ea0dba5d8dd5d75f1b65564e8f1 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 13 Aug 2026 13:52:02 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20=EC=B4=88=EB=8C=80=20=EC=95=88?= =?UTF-8?q?=EC=A0=84=EB=A7=9D=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=EB=A5=BC=20=EA=B3=B5=EC=9A=A9=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=B9=B4=ED=83=88=EB=A1=9C=EA=B7=B8=EB=A1=9C=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) --- .../create/_components/invite-friends/InviteFriendsDialog.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx b/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx index 2b9d7597..d1a459eb 100644 --- a/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx +++ b/apps/web/src/app/tournament/[id]/create/_components/invite-friends/InviteFriendsDialog.tsx @@ -1,5 +1,6 @@ 'use client'; +import { ERROR_CODE, ERROR_MESSAGE_MAP } from '@piki/core'; import { useEffect, useMemo, useState } from 'react'; import { toast } from 'sonner'; @@ -105,7 +106,7 @@ function InviteFriendsDialog({ const handleSendInviteLink = async () => { /** 이미 시작된 토너먼트인 경우 */ if (!inviteUrl) { - toast.error('이미 시작된 토너먼트에는 친구를 초대할 수 없어요.'); + toast.error(ERROR_MESSAGE_MAP[ERROR_CODE.TOURNAMENT_NOT_PENDING]); return; }