feat: 위시 단건 조회 응답에 가격 이력 추가 및 응답 타입 서버 계약 기준으로 정리 - #435
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 55 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 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 configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthrough공통 API 응답에 페이지네이션 메타데이터를 추가했습니다. 위시리스트 항목과 가격 이력 타입을 확장했습니다. 위시리스트 페이지는 무한 조회 데이터를 사전 조회하고, 클라이언트 화면에서 선택·삭제·추가 상태를 관리합니다. Changes위시리스트 페이지네이션 및 데이터 모델
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ArchiveWishPage
participant ReactQueryClient
participant getWishlist
participant WishContent
ArchiveWishPage->>ReactQueryClient: 무한 조회 사전 실행
ReactQueryClient->>getWishlist: 커서 기반 위시리스트 요청
getWishlist-->>ReactQueryClient: 목록과 pageResponse 반환
ReactQueryClient-->>ArchiveWishPage: dehydrated query state 반환
ArchiveWishPage->>WishContent: HydrationBoundary로 화면 렌더링
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
|
Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다. |
- WishContent.tsx: 브랜치의 client wrapper 삭제 리팩터링 유지 - page.tsx: dev 의 GetWishlistApiResponseT 로 prefetch 타입 정리
서버 ApiResponseBody 는 pageResponse 를 non-null 기본값(EMPTY)으로 모든 응답에 항상 포함한다. 엔드포인트별 intersection 중복을 제거하고 ApiResponseT 로 되돌린다.
3b9eb7f to
1d3d2bc
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (7)
apps/web/src/apis/getWishlist.ts (1)
9-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
getWishlist응답 타입 이름을 API 명명 규칙에 맞춰 주세요.현재
GetWishlistApiResponseT는 함수명getWishlist에서 파생한{PascalCaseFunctionName}ResponseT규칙과 다릅니다.apps/web/src/types/wish.ts의 항목 타입과 이름이 충돌하면 해당 import를 별칭으로 바꾸고, 이 모듈의 wrapper 타입을GetWishlistResponseT로 변경해 주세요.apps/web/src/app/archive/wish/page.tsx의 import도 함께 갱신해야 합니다.As per coding guidelines, API 요청 및 응답 타입은
{PascalCaseFunctionName}RequestT및{PascalCaseFunctionName}ResponseT형식을 사용해야 합니다.🤖 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/apis/getWishlist.ts` at line 9, Rename the API wrapper type in getWishlist to GetWishlistResponseT to follow the function-based naming convention. Resolve any collision with the item type imported from apps/web/src/types/wish.ts by aliasing that import, and update all references, including the import in the archive wish page.Source: Coding guidelines
apps/web/src/app/archive/wish/_components/WishContent.tsx (4)
75-75: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value고정 너비
w-[110px]를 제거하십시오.코딩 가이드라인은 모바일 레이아웃에서 고정 너비를 피하도록 요구합니다. 이 버튼은 체크박스와 "전체선택" 텍스트만 포함합니다. 콘텐츠 너비로 충분합니다. 큰 글꼴 설정에서 고정 너비는 텍스트를 넘치게 만듭니다.
♻️ 제안 수정
- className="flex w-[110px] cursor-pointer items-center gap-2" + className="flex cursor-pointer items-center gap-2"가이드라인 근거: "avoid fixed widths in mobile layouts in favor of
w-fullwithpx-5and optionalmax-w-*".🤖 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/WishContent.tsx` at line 75, Remove the fixed w-[110px] width from the button className in WishContent, allowing its checkbox and “전체선택” text to size naturally without overflow on larger fonts.Source: Coding guidelines
10-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value상위 디렉터리 상대 경로를 절대 경로로 변경하십시오.
코딩 가이드라인은 상대 경로를 동일 디렉터리 파일에만 허용합니다.
../_hooks/는 상위 디렉터리를 참조합니다.@/*절대 경로를 사용하십시오. 12-15행의./import는 동일 디렉터리이므로 그대로 두십시오.♻️ 제안 수정
-import { useDeleteWishes } from '../_hooks/useDeleteWishes'; -import { useShareIntentWish } from '../_hooks/useShareIntentWish'; +import { useDeleteWishes } from '`@/app/archive/wish/_hooks/useDeleteWishes`'; +import { useShareIntentWish } from '`@/app/archive/wish/_hooks/useShareIntentWish`';절대 경로 import이므로 8행 아래
@/그룹으로 이동시키십시오.가이드라인 근거: "Use
@/*absolute imports for project modules and relative imports only 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/WishContent.tsx` around lines 10 - 11, Update the useDeleteWishes and useShareIntentWish imports in WishContent.tsx to use the `@/`* absolute path alias instead of ../_hooks/ relative paths, and place them with the existing `@/`* import group. Leave the same-directory ./ imports unchanged.Source: Coding guidelines
124-136: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
onOpenChange의 pending 가드가 중복입니다.
apps/web/src/components/common/confirm-dialog/index.tsx35-38행의handleOpenChange가 이미 동일한 가드를 수행합니다.isPending을 prop으로 전달하므로, 호출부의 가드는 효과가 없습니다.♻️ 제안 수정
- onOpenChange={open => { - if (!open && isDeleteWishesPending) return; - setIsDeleteDialogOpen(open); - }} + onOpenChange={setIsDeleteDialogOpen}🤖 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/WishContent.tsx` around lines 124 - 136, Remove the redundant pending-state guard from the onOpenChange handler in WishContent’s ConfirmDialog usage, and pass setIsDeleteDialogOpen directly while retaining isPending={isDeleteWishesPending} so ConfirmDialog.handleOpenChange remains responsible for blocking changes during deletion.
39-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win상태 문자열 리터럴 대신
ITEM_STATUS상수를 사용하고 조건을 단순화하십시오.
apps/web/src/consts/item.ts는PENDING,PROCESSING,READY,FAILED네 가지 상태만 정의합니다. 현재 조건은 그중 세 개를 제외하므로READY만 남습니다. 긍정 조건 하나로 표현하면 의도가 명확해집니다.또한 리터럴을 직접 비교하면 상태 값이 변경될 때 타입 검사기가 불일치를 잡지 못합니다.
apps/web/src/app/archive/wish/[id]/_types/wish.ts의ItemT도READY분기에서만name과price를 non-null로 정의합니다. 선택 가능 조건과 의미가 일치합니다.♻️ 제안 수정
+import { ITEM_STATUS } from '`@/consts/item`';const { wishlistData } = useGetWishlist(); const selectableIds = wishlistData - .filter( - ({ item }) => - item.status !== 'FAILED' && item.status !== 'PENDING' && item.status !== 'PROCESSING' - ) + .filter(({ item }) => item.status === ITEM_STATUS.READY) .map(({ wish }) => wish.id);🤖 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/WishContent.tsx` around lines 39 - 44, Update the selectableIds filter in WishContent to use the ITEM_STATUS constant and positively retain only the READY status, replacing the three literal exclusions. Keep the existing mapping to wish.id unchanged.apps/web/src/app/archive/wish/[id]/_types/wish.ts (1)
7-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
| null이 중복입니다.
PriceHistorySourceT는 정의 자체에null을 포함합니다(apps/web/src/types/item.ts34행). 따라서PriceHistorySourceT | null은PriceHistorySourceT와 동일한 타입입니다. 중복 표기는 독자가 별도의 nullable 계층이 있다고 오해하게 만듭니다.
item.source가PriceHistorySourceT와 다른 값 집합을 가진다면, 별도 타입을 정의하십시오.♻️ 중복 nullable 제거
- source: PriceHistorySourceT | null; + source: PriceHistorySourceT;🤖 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/`[id]/_types/wish.ts at line 7, Remove the redundant | null from the source field declaration in the wish type, using PriceHistorySourceT directly. Preserve the existing type behavior; only introduce a separate type if item.source is intentionally meant to support values outside PriceHistorySourceT.apps/web/src/app/archive/wish/page.tsx (1)
12-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value공유 옵션 팩토리로 위시리스트 무한 쿼리 설정을 한 곳에 두세요.
queryClient.prefetchInfiniteQuery와useGetWishlist가 동일한queryKey,queryFn,initialPageParam,getNextPageParam을 직접 정의하고 있습니다. TanStack Query v5infiniteQueryOptions팩토리가 현재 구조와 타입 추론에 적합하지만, 현재 코드에서 프론트엔드 재시도/하이드레이션 오류가 발생한다는 사실은 없습니다.🤖 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/page.tsx` around lines 12 - 18, Extract the shared wishlist infinite-query configuration into an infiniteQueryOptions factory, then reuse it in both prefetchInfiniteQuery and useGetWishlist. Keep queryKey, queryFn, initialPageParam, and getNextPageParam defined only in the factory so TanStack Query v5 preserves consistent options and type inference.
🤖 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.
Nitpick comments:
In `@apps/web/src/apis/getWishlist.ts`:
- Line 9: Rename the API wrapper type in getWishlist to GetWishlistResponseT to
follow the function-based naming convention. Resolve any collision with the item
type imported from apps/web/src/types/wish.ts by aliasing that import, and
update all references, including the import in the archive wish page.
In `@apps/web/src/app/archive/wish/_components/WishContent.tsx`:
- Line 75: Remove the fixed w-[110px] width from the button className in
WishContent, allowing its checkbox and “전체선택” text to size naturally without
overflow on larger fonts.
- Around line 10-11: Update the useDeleteWishes and useShareIntentWish imports
in WishContent.tsx to use the `@/`* absolute path alias instead of ../_hooks/
relative paths, and place them with the existing `@/`* import group. Leave the
same-directory ./ imports unchanged.
- Around line 124-136: Remove the redundant pending-state guard from the
onOpenChange handler in WishContent’s ConfirmDialog usage, and pass
setIsDeleteDialogOpen directly while retaining isPending={isDeleteWishesPending}
so ConfirmDialog.handleOpenChange remains responsible for blocking changes
during deletion.
- Around line 39-44: Update the selectableIds filter in WishContent to use the
ITEM_STATUS constant and positively retain only the READY status, replacing the
three literal exclusions. Keep the existing mapping to wish.id unchanged.
In `@apps/web/src/app/archive/wish/`[id]/_types/wish.ts:
- Line 7: Remove the redundant | null from the source field declaration in the
wish type, using PriceHistorySourceT directly. Preserve the existing type
behavior; only introduce a separate type if item.source is intentionally meant
to support values outside PriceHistorySourceT.
In `@apps/web/src/app/archive/wish/page.tsx`:
- Around line 12-18: Extract the shared wishlist infinite-query configuration
into an infiniteQueryOptions factory, then reuse it in both
prefetchInfiniteQuery and useGetWishlist. Keep queryKey, queryFn,
initialPageParam, and getNextPageParam defined only in the factory so TanStack
Query v5 preserves consistent options and type inference.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 37db91ed-5cce-4561-83ff-aacd82b4b760
📒 Files selected for processing (9)
apps/web/e2e/helpers/apiResponse.tsapps/web/src/apis/getWishlist.tsapps/web/src/app/archive/wish/[id]/_types/wish.tsapps/web/src/app/archive/wish/_components/WishContent.tsxapps/web/src/app/archive/wish/_components/WishContentClient.tsxapps/web/src/app/archive/wish/page.tsxapps/web/src/app/notification/_apis/getNotifications.tsapps/web/src/types/api.tsapps/web/src/types/item.ts
💤 Files with no reviewable changes (1)
- apps/web/src/app/archive/wish/_components/WishContentClient.tsx
작업 요약
작업 세부 내용
서버 레포의 응답 DTO를 직접 대조하며 작업했습니다.
가격 이력(priceHistory) 타입 추가
서버가
GET /wishlists/{id}/history를 없애고 가격 이력을 단건 조회 응답에 흡수시켜, 그에 맞춰 타입을 추가했습니다.types/item.ts에PriceHistoryT,PriceHistorySourceT추가GetWishResponseT에priceHistory필드 추가 (최신순, 최대 50건)source는 값의 출처를 나타내는 맥락 표시입니다 —SERVER(파서) /SERVER_LLM(LLM) /MANUAL(수기)editedByMe는 수기 값 한정으로, 같은 상품을 담은 다른 사용자가 입력한 값이면false입니다위시 단건 조회·수정 응답 타입 정정
서버 응답 DTO(
WishDetailResponse/WishItemResponse)와 대조해 어긋난 부분을 고쳤습니다.PENDING을 값이 있는 갈래에서 값이 없는 갈래로 이동 — 서버는PENDING·PROCESSING동안name·price·imageUrl이 비어 있습니다. 특히 "다시 불러오기" 를 누르면 활성 스냅샷이 즉시 빈PENDING으로 교체되므로 실제로 닿는 경로입니다READY의currency를string | null로 변경 —READY가 보장하는 건name·price·imageUrl·extractedAt네 개뿐이고,currency는 ISO 4217 정규화에 실패하면null로 내려옵니다item.source추가 — 지금 화면에 보이는 값의 출처입니다. 수기 배지 노출에 쓸 수 있고, 출처 기록 도입 전 데이터는null입니다sourcePlatform추가,sourceUrl은 status 와 무관하므로 공통부로 옮기고// 확인필주석을 정리했습니다PatchWishResponseT를GetWishResponseT별칭에서 분리 — 수정 응답은 조회와 다른 DTO 라서priceHistory가 없고, 대신 등록 전용 필드인refreshNeeded·reused가 항상null로 옵니다내 위시 페이지 client wrapper 제거
page → WishContent(RSC) → WishContentClient(client)3중 구조에서 가운데 한 겹이 하는 일이 prefetch 뿐이라,page(RSC) → WishContent(client)2중 구조로 줄였습니다.HydrationBoundary를page.tsx로 이동WishContentClient.tsx삭제하고 내용을WishContent.tsx로 통합연관 이슈
related to #416
Summary by CodeRabbit