Conversation
Walkthrough서버 액션으로 데이터 페칭과 에러 재던지기를 중앙화(rethrowNextError)하고, 카트 UI를 컴포넌트 단위로 분리·옵션 편집(바텀시트)·디바운스 수량 입력을 추가했으며, 상품 상세는 관련 데이터(Promise.all) 병렬 조회와 도메인 타입으로 마이그레이션했습니다. (50자 이내) Changes
Sequence Diagram(s)mermaid (컴포넌트: CartOptionChangeSheet → 훅(useCartService) → 서버 액션(update) → 클라이언트 라우터 처리) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/components/product/product-image-slider.tsx (1)
18-18: 🛠️ Refactor suggestion | 🟠 Major코딩 가이드라인 위반:
export default function패턴 미사용🔧 수정 제안
-export function ProductImageSlider({ imageUrl }: ProductImageSliderProps) { +export default function ProductImageSlider({ imageUrl }: ProductImageSliderProps) {As per coding guidelines,
src/components/**/*.tsx: "export default function 패턴 (화살표 함수 금지)".src/app/actions/order.ts (1)
63-93:⚠️ Potential issue | 🟠 Major
fetchCartOrderItems/fetchDirectOrderItems비동기 에러 미처리
fetchCartOrderItems는getCartItems()를 (라인 75),fetchDirectOrderItems는getProductDetail()을 (라인 114) 호출할 때 try/catch가 없습니다. 이들 함수가 throw하면 에러가 그대로 전파되어 서버 액션을 거쳐 클라이언트에 내부 에러 메시지가 노출됩니다.같은 파일의 다른 함수들은
rethrowNextError()패턴으로 에러를 처리하므로 (라인 53-54), 이 두 함수도 동일한 패턴을 적용하거나notFound()/redirect()로 적절히 처리해야 합니다.fetchDirectOrderItems는 이미 JSON 파싱 에러 처리가 있으나 API 호출 에러는 미처리된 상태입니다.src/app/actions/cart.ts (1)
96-108:⚠️ Potential issue | 🟡 Minor
getCartCount의 제네릭 타입과 런타임 체크가 불일치.
api.get<{ count: number }>로 선언했지만typeof data === 'number'분기가 있어, 실제 응답 형태가 불확실함을 암시합니다. 제네릭 타입이{ count: number }라면number분기는 도달 불가(dead code)이고, bare number가 올 수 있다면 제네릭을number | { count: number }로 수정해야 합니다.제안: 타입을 확정하고 불필요한 분기 제거
API가
{ count: number }만 반환하는 경우:export async function getCartCount(): Promise<number> { try { const data = await api.get<{ count: number }>('/carts/count'); - - if (typeof data === 'number') { - return data; - } return data.count; } catch (error) {
🤖 Fix all issues with AI agents
In `@src/app/cart/page.tsx`:
- Around line 6-8: 세 컴포넌트 CartHeaderControl, CartItemList, CartSummaryFooter가 현재
named export로 작성되어 있으니 각 컴포넌트 파일에서 `export function <Name>()` 패턴을 `export
default function <Name>()`로 변경하고 해당 파일의 any other named exports가 있다면 이름을 유지하되
default로 내보내는지 확인한 뒤, 페이지 파일의 import 문을 named import에서 기본(default) import로 바꿔
`import CartHeaderControl from '@/components/cart/cart-header-control'`, `import
CartItemList from '@/components/cart/cart-item-list'`, `import CartSummaryFooter
from '@/components/cart/cart-summary-footer'` 형태로 업데이트하세요; 컴포넌트 내부/외부 참조가 있다면
호출부(예: JSX 사용처)에서 변경된 export 방식이 정상 동작하는지 확인하세요.
In `@src/app/product/`[id]/page.tsx:
- Line 4: The import of the mock fetchSizeAnalysis from '@/mocks/size' remains
and is used in this file (fetchSizeAnalysis), but other data-fetching functions
(getProductDetail, getSimilarProducts, getMyBodyInfoAction, getMyWishlist) were
migrated to server actions; either migrate the size analysis logic into a server
action and replace fetchSizeAnalysis usage with that new action (e.g., create
getSizeAnalysisAction() and call it from this page), or if you intentionally
want to keep the mock, remove the import of fetchSizeAnalysis and add an
explicit comment near getSizeOptionsAction/usage explaining why the mock is
retained (and ensure test-only guards or feature flags prevent it from
shipping); update references accordingly to use the new server action name or
the documented mock retention rationale.
In `@src/components/cart/cart-data-fetcher.tsx`:
- Line 6: The component is using a named export; change it to the required
default function pattern by converting the declaration to a default exported
function named CartDataFetcher (i.e., use "export default function
CartDataFetcher(...)") so it follows the src/components/**/*.tsx guideline (do
not use an arrow function), and ensure any imports or usages referencing
CartDataFetcher are updated if they relied on a named import.
In `@src/components/cart/cart-header-control.tsx`:
- Line 7: The component CartHeaderControl is using a named export but must
follow the project pattern of a default-exported function; change its
declaration from "export function CartHeaderControl()" to "export default
function CartHeaderControl()" (do not convert to an arrow function) and update
any imports elsewhere to use the default import form (e.g., import
CartHeaderControl from '...') so references remain correct.
In `@src/components/cart/cart-item-list.tsx`:
- Line 27: The component currently uses a named export "CartItemList"; change
its declaration to the required default-export function pattern by making it an
export default function named CartItemList (not an arrow function) so it matches
the src/components/**/*.tsx guideline; update any imports that rely on the named
export to use the default import form if needed.
In `@src/components/cart/cart-item.tsx`:
- Line 22: 현재 컴포넌트는 named export인 `export function CartItem`로 선언되어 있어
가이드라인(`src/components/**/*.tsx`: export default function 패턴, 화살표 함수 금지)을 위반합니다;
`CartItem` 컴포넌트를 화살표 함수가 아닌 `export default function CartItem(...) { ... }` 형태로
변경하고 파일 최종부에 default export가 아닌 선언 자체가 기본 export가 되도록 수정해 주세요(즉 `export function
CartItem` → `export default function CartItem` 및 함수 선언식으로 변환).
In `@src/components/cart/cart-option-change-sheet.tsx`:
- Line 26: The component is exported using a named export "export function
CartOptionChangeSheet" but the project guideline requires the "export default
function" pattern for files under src/components/**/*.tsx and forbids arrow
functions; change the declaration to a default export function (e.g., "export
default function CartOptionChangeSheet(...)") instead of a named export so the
file follows the required export style and retains the same identifier for
internal use.
- Around line 101-106: The onClick handler currently calls onConfirm(...) and
then onClose() without awaiting, causing a race when onConfirm returns a
Promise; change the onClick handler to an async function that awaits
onConfirm(item.cartId, currentColor, currentSize) before calling onClose(), and
wrap the await in a try/catch to handle and log/rethrow errors (or surface them
via an error callback) so unhandled rejections are avoided; update the handler
referencing onClick, onConfirm, onClose, item, currentColor and currentSize
accordingly.
In `@src/components/cart/cart-summary-footer.tsx`:
- Line 8: Change the named export function CartSummaryFooter to the required
default-export pattern used across components: replace "export function
CartSummaryFooter" with a default export function declaration (export default
function CartSummaryFooter(...)) so it follows the "export default function"
guideline (matching the pattern used in cart-header-control.tsx); ensure the
function name remains CartSummaryFooter and update any imports that referenced
the named export to use the default import if needed.
In `@src/components/product-option-sheet/use-product-option.ts`:
- Around line 68-93: The addItemToSelection callback mutates an item object when
incrementing quantity (newItems[existingIdx].quantity += 1), violating
immutability; instead, create a new item object when updating: copy the prev
array, replace the item at existingIdx with a shallow-cloned object that has
quantity: old.quantity + 1, then return the new array; ensure this change is
made inside addItemToSelection (and references like setSelectedItems,
existingIdx, newItems, and option) so no original item object is mutated.
In `@src/components/product/descriptions/product-description.tsx`:
- Line 13: The component currently uses a named export ("export function
ProductDescription") which violates the guideline requiring the "export default
function" pattern for files under src/components; change the declaration to a
default function export (e.g., export default function ProductDescription(...) {
... }) instead of a named or arrow function, keep the same function name and
props signature, and update any internal references/imports if needed to use the
default export.
In `@src/components/product/descriptions/recommended-products-carousel.tsx`:
- Line 54: The key fallback uses the falsy-coalescing operator
(similarProduct.id || i) which treats id === 0 as falsy and falls back to index;
in the JSX for the RecommendedProductsCarousel component replace the logical OR
with the nullish coalescing operator so the key becomes based on
similarProduct.id when it is 0 (use similarProduct.id ?? i), locating the prop
where key={similarProduct.id || i} and updating it to use ?? to preserve 0 as a
valid id.
- Around line 23-25: Change the named export to a default export for the
component by updating the declaration to "export default function
RecommendedProductsCarousel(...)" in RecommendedProductsCarousel, then update
any imports: in product-description.tsx replace the named import (e.g. import {
RecommendedProductsCarousel } ...) with a default import (import
RecommendedProductsCarousel ...), and update the re-export in product/index.tsx
to export the default (e.g. export { default as RecommendedProductsCarousel }
from '...') so all references use the default export.
In `@src/components/product/product-image-slider.tsx`:
- Around line 55-67: The component currently renders empty CarouselItem slides
when image URLs are falsy; update product-image-slider to filter out falsy
entries before mapping (use images.filter(Boolean) or similar) and map over that
filtered array in the images.map block so only valid Image components render; if
the filtered array is empty, render a fallback UI (single placeholder
CarouselItem/Image or a “no image” placeholder) and ensure any counter or
pagination logic uses the filtered array length instead of the original
Array(5).fill(...) source so the slide count and visuals stay consistent.
In `@src/mocks/product-data.ts`:
- Around line 87-90: The code can produce reviewRating = 0.0 even when
reviewCount > 0 and never reaches 5.0; update the reviewRating computation (the
symbol reviewRating that uses startId and i and the derived raw value) so that
when reviewCount > 0 you clamp the computed rating to a minimum of 1.0 (e.g.,
compute the raw rating from (((startId + i) * 53 + 7) % 50) / 10 and then set
reviewRating = Math.max(1.0, parsedRaw) after rounding to one decimal), ensuring
no positive-review product gets 0.0 while preserving the existing distribution.
🧹 Nitpick comments (16)
src/components/product/product-info.tsx (1)
9-10: 중복되는 복합 타입 — 공통 유틸리티 타입으로 추출 권장AI summary에 따르면
CompactProductHeader,ProductDescription,ProductDetailView등 여러 컴포넌트에서 동일한Omit + Partial<Pick>패턴을 반복 사용하고 있습니다.product.ts에 공통 타입을 한 번만 선언하면 변경 시 한 곳만 수정하면 됩니다.♻️ 제안: product.ts에 유틸리티 타입 추가
src/types/domain/product.ts에 추가:/** 조회수/구매수/리뷰수가 선택적인 Product 타입 */ export type ProductSummary = Omit<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'> & Partial<Pick<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'>>;이후 각 컴포넌트에서:
- product: Omit<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'> & - Partial<Pick<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'>>; + product: ProductSummary;#!/bin/bash # 동일한 Omit+Partial+Pick 패턴이 다른 컴포넌트에서도 반복되는지 확인 rg -n "Omit<Product" --type=ts --type=tsx -g '*.tsx' -g '*.ts'src/components/product/size/size-guide-section.tsx (1)
21-21: 코딩 가이드라인 위반:export default function패턴 미사용기존 코드이지만, 이 PR에서 수정하는 김에
export default function으로 전환하는 것을 권장합니다.As per coding guidelines,
src/components/**/*.tsx: "export default function 패턴 (화살표 함수 금지)".src/components/product/compact-product-header.tsx (1)
44-46:formatPrice유틸 사용 권장
src/lib/format.ts에formatPrice가 도입되었으므로,toLocaleString()대신 통일된 포맷 유틸을 사용하면 일관성이 높아집니다.♻️ 제안
+import { formatPrice } from '@/lib/format'; ... - {product.finalPrice.toLocaleString()}원 + {formatPrice(product.finalPrice)}원src/app/cart/page.tsx (1)
16-24: 서버 컴포넌트 에러 처리 패턴 확인
rethrowNextError가 digest 에러를 재throw한 후, 나머지 에러는console.error로 로깅하고 빈 배열로 폴백합니다. 사용자에게 장바구니가 비어있는 것처럼 보일 수 있으므로, 에러 상태를 UI에 전달하는 것도 고려해보세요.src/app/actions/user.ts (1)
11-13: API 응답 타입 불일치 방어 코드
points가 string으로 올 수 있다는 건 백엔드 API 계약이 불안정하다는 신호입니다. 장기적으로는 API 응답 스키마를 zod 등으로 검증하는 것이 더 안전합니다. 현재 방어 로직 자체는 동작에 문제없습니다.src/app/body-info/page.tsx (1)
3-3: 상대 경로 대신@/alias 사용 권장다른 import들은
@/alias를 사용하는데 이 줄만 상대 경로입니다. 일관성을 위해 통일하세요.♻️ 제안
-import { CloseButton } from '../../components/ui/close-button'; +import { CloseButton } from '@/components/ui/close-button';src/app/product/[id]/layout.tsx (1)
20-23:thumbnailImageUrl이 빈 문자열일 경우 OG 이미지 처리
product.thumbnailImageUrl이 빈 문자열이면openGraph.images에 빈 값이 들어가 잘못된 OG 태그가 생성될 수 있습니다.compact-product-header.tsx에서처럼 falsy 체크를 추가하는 것을 권장합니다.♻️ 제안
openGraph: { title: product.name, - images: [product.thumbnailImageUrl], + ...(product.thumbnailImageUrl && { + images: [product.thumbnailImageUrl], + }), },src/app/actions/body-info.ts (1)
24-29:ActionResponse의data?: unknown타입 강화 고려
data?: unknown은 범용적이지만, 소비하는 쪽에서 매번 타입 단언이 필요합니다. 제네릭으로 만들면 타입 안전성이 향상됩니다.♻️ 제안
-export type ActionResponse = { +export type ActionResponse<T = unknown> = { success: boolean; message: string; errors?: Record<string, string[]>; - data?: unknown; + data?: T; };src/components/product-option-sheet/use-product-option.ts (1)
56-56: 불필요한 alias:const options = initialOptions.이전에는 mock 데이터 fallback 로직이 있었으나 제거되면서 단순 alias만 남았습니다.
initialOptions를 직접 사용하거나, 파라미터명을options로 변경하는 것이 깔끔합니다.수정 제안 (파라미터명 변경)
export default function useProductOption({ productId, price, - options: initialOptions = [], + options = [], open: externalOpen, onOpenChange: externalOnOpenChange, }: UseProductOptionProps) { // ... - const options = initialOptions;src/components/product/descriptions/recommended-products-carousel.tsx (1)
29-30: 주석 처리된 dead code 제거 필요이전
products변수명을 참조하는 코드가 남아 있습니다. 빈 배열 가드가 필요하면similarProducts로 복원하고, 아니면 삭제하세요.♻️ 수정 제안
// 데이터가 빈 배열일 경우 렌더링 안 함 - // if (products.length === 0) return null; + if (similarProducts.length === 0) return null;src/app/product/[id]/page.tsx (1)
14-14:Number(id)가NaN일 경우 방어 처리 부재
id가 비숫자 문자열이면productId가NaN이 됩니다.getProductDetail에서 실패하여notFound()로 빠지긴 하지만, 명시적 검증이 더 안전합니다.🛡️ 수정 제안
const productId = Number(id); + if (Number.isNaN(productId)) notFound();src/components/cart/cart-item.tsx (1)
40-50: debounce 타이머 unmount 시 정리 누락컴포넌트가 언마운트될 때
debounceRef.current에 남아있는 타이머가 정리되지 않아, 언마운트 후onQuantityChange가 호출될 수 있습니다.🛡️ cleanup effect 추가 제안
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null); useEffect(() => { setInputValue(String(quantity)); }, [quantity]); + useEffect(() => { + return () => { + if (debounceRef.current) clearTimeout(debounceRef.current); + }; + }, []); + const debouncedChange = (val: number) => {src/components/product/descriptions/product-description.tsx (1)
16-19: 인라인 prop 타입이 복잡 — 별도 interface 추출 권장
Omit<...> & Partial<Pick<...>>조합이 인라인으로 선언되어 가독성이 떨어집니다.ProductDescriptionProps같은 별도 interface로 분리하면 재사용성과 가독성이 모두 향상됩니다.src/components/product/product-detail-view.tsx (1)
74-77: 하드코딩된availableOptions—product.options사용 가능
ProductDetailProps에options?: ProductOption[]가 선언되어 있지만,reviewProductInfo.availableOptions는 하드코딩된 sizes/colors를 사용합니다.product.options에서 동적으로 추출해야 실제 데이터와 일치합니다.♻️ 수정 제안
availableOptions: { - sizes: ['XS', 'S', 'M', 'L', 'XL'], - colors: ['Black', 'White', 'Navy', 'Gray', 'Beige'], + sizes: [...new Set(product.options?.map((o) => o.size) ?? [])], + colors: [...new Set(product.options?.map((o) => o.color) ?? [])], },src/components/cart/use-cart-service.ts (2)
37-46:UPDATE_OPTION에서 가격 재계산 미반영 확인옵션 변경 시
selectedColor/selectedSize만 업데이트하고totalPrice는 갱신하지 않습니다. 색상·사이즈별 가격이 동일하면 문제없지만, 다를 경우 서버 응답(revalidatePath) 전까지 UI에 이전 가격이 표시됩니다.현재 서버 실패 시
router.refresh()로 복구하므로 즉각적 문제는 아니지만, 옵션별 가격 차이가 있는 도메인이라면 고려 필요합니다.
187-194: checkout 시 URL 인코딩 검증 필요
items파라미터에 쉼표로 구분된 ID를 넣고 있는데, 대량의 장바구니 아이템이 있을 경우 URL 길이 제한에 근접할 수 있습니다. 현실적으로는 문제 없겠지만, 향후 확장 시 POST 기반 checkout이나 세션 저장 방식도 고려할 수 있습니다.
| import { CartHeaderControl } from '@/components/cart/cart-header-control'; | ||
| import { CartItemList } from '@/components/cart/cart-item-list'; | ||
| import { CartSummaryFooter } from '@/components/cart/cart-summary-footer'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find and examine the export patterns of cart components
echo "=== Locating cart components ==="
fd "cart-header-control|cart-item-list|cart-summary-footer" src/components --type f
echo -e "\n=== Examining export patterns ==="
fd "cart-header-control|cart-item-list|cart-summary-footer" src/components --type f --exec head -20 {}Repository: IT-Cotato/12th-OnGil-FE
Length of output: 1975
🏁 Script executed:
#!/bin/bash
# Check the export statement in CartItemList
echo "=== CartItemList export pattern ==="
rg "export" src/components/cart/cart-item-list.tsx -A 2 -B 1Repository: IT-Cotato/12th-OnGil-FE
Length of output: 166
CartHeaderControl, CartItemList, CartSummaryFooter를 default export로 변경
세 컴포넌트 모두 named export(export function ComponentName())를 사용 중입니다. 코딩 가이드라인에 따르면 src/components/**/*.tsx는 반드시 export default function 패턴을 사용해야 합니다. 각 컴포넌트 파일을 수정하고, 페이지의 import 문도 기본값 import로 업데이트해야 합니다.
🤖 Prompt for AI Agents
In `@src/app/cart/page.tsx` around lines 6 - 8, 세 컴포넌트 CartHeaderControl,
CartItemList, CartSummaryFooter가 현재 named export로 작성되어 있으니 각 컴포넌트 파일에서 `export
function <Name>()` 패턴을 `export default function <Name>()`로 변경하고 해당 파일의 any other
named exports가 있다면 이름을 유지하되 default로 내보내는지 확인한 뒤, 페이지 파일의 import 문을 named
import에서 기본(default) import로 바꿔 `import CartHeaderControl from
'@/components/cart/cart-header-control'`, `import CartItemList from
'@/components/cart/cart-item-list'`, `import CartSummaryFooter from
'@/components/cart/cart-summary-footer'` 형태로 업데이트하세요; 컴포넌트 내부/외부 참조가 있다면 호출부(예:
JSX 사용처)에서 변경된 export 방식이 정상 동작하는지 확인하세요.
| import { fetchUserBodyInfo, fetchSizeAnalysis } from '@/mocks/size'; | ||
| import { getProductDetail, getSimilarProducts } from '@/app/actions/product'; | ||
| import { getMyBodyInfoAction } from '@/app/actions/body-info'; | ||
| import { fetchSizeAnalysis } from '@/mocks/size'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# fetchSizeAnalysis 사용처 확인
echo "=== fetchSizeAnalysis 사용처 ==="
rg -n "fetchSizeAnalysis" --type ts --type tsx
echo -e "\n=== SizeAnalysis 관련 server action 확인 ==="
rg -n "SizeAnalysis" --type ts --type tsx src/app/actions/
echo -e "\n=== mocks/size 파일 내용 확인 ==="
find . -path "./src/mocks/size*" -type f | head -5
echo -e "\n=== src/app/product/[id]/page.tsx 라인 4 주변 확인 ==="
head -20 src/app/product/[id]/page.tsxRepository: IT-Cotato/12th-OnGil-FE
Length of output: 980
🏁 Script executed:
#!/bin/bash
# fetchSizeAnalysis 전체 검색
echo "=== fetchSizeAnalysis 모든 파일에서 검색 ==="
rg "fetchSizeAnalysis" -n 2>/dev/null || echo "No matches found"
echo -e "\n=== mocks/size.ts 내용 ==="
cat -n src/mocks/size.ts
echo -e "\n=== ProductDetailView 컴포넌트 확인 ==="
cat -n src/components/product/product-detail-view.tsx | head -50Repository: IT-Cotato/12th-OnGil-FE
Length of output: 3981
🏁 Script executed:
#!/bin/bash
# Server action 내 사이즈 관련 함수 검색
echo "=== app/actions 디렉토리 구조 ==="
find src/app/actions -type f -name "*.ts" | head -20
echo -e "\n=== 'size' 관련 server action 검색 ==="
rg "size|Size" src/app/actions/ -l
echo -e "\n=== 모든 app/actions 파일 목록 ==="
ls -la src/app/actions/Repository: IT-Cotato/12th-OnGil-FE
Length of output: 928
🏁 Script executed:
#!/bin/bash
# body-info.ts와 order.ts에서 사이즈 분석 관련 함수 확인
echo "=== body-info.ts 전체 내용 ==="
cat -n src/app/actions/body-info.ts
echo -e "\n=== order.ts에서 'size' 관련 부분 ==="
rg -n "size|Size" src/app/actions/order.ts -A 3Repository: IT-Cotato/12th-OnGil-FE
Length of output: 6091
fetchSizeAnalysis mock 의존성 아직 잔존
PR 목표인 mock 데이터 제거가 완료되지 않았습니다. fetchSizeAnalysis가 여전히 @/mocks/size에서 import되어 라인 36에서 활용 중인데, 다른 함수들(getProductDetail, getSimilarProducts, getMyBodyInfoAction, getMyWishlist)은 모두 server action으로 이미 마이그레이션되었습니다. getSizeOptionsAction()은 사이즈 옵션 조회만 처리하므로 fetchSizeAnalysis를 대체할 수 없습니다. 사이즈 분석 기능도 server action으로 마이그레이션하거나, 의도적으로 mock 유지 시 그 이유를 명시해야 합니다.
🤖 Prompt for AI Agents
In `@src/app/product/`[id]/page.tsx at line 4, The import of the mock
fetchSizeAnalysis from '@/mocks/size' remains and is used in this file
(fetchSizeAnalysis), but other data-fetching functions (getProductDetail,
getSimilarProducts, getMyBodyInfoAction, getMyWishlist) were migrated to server
actions; either migrate the size analysis logic into a server action and replace
fetchSizeAnalysis usage with that new action (e.g., create
getSizeAnalysisAction() and call it from this page), or if you intentionally
want to keep the mock, remove the import of fetchSizeAnalysis and add an
explicit comment near getSizeOptionsAction/usage explaining why the mock is
retained (and ensure test-only guards or feature flags prevent it from
shipping); update references accordingly to use the new server action name or
the documented mock retention rationale.
| export function RecommendedProductsCarousel({ | ||
| products, | ||
| similarProducts, | ||
| }: RecommendedProductsCarouselProps) { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "RecommendedProductsCarousel" --type=ts --type=tsx -g '!node_modules'Repository: IT-Cotato/12th-OnGil-FE
Length of output: 94
🏁 Script executed:
rg "RecommendedProductsCarousel" -t ts -g '!node_modules' -A 2 -B 2Repository: IT-Cotato/12th-OnGil-FE
Length of output: 2794
🏁 Script executed:
rg "from.*components/product" -t ts -A 1 | grep -i "recommended"Repository: IT-Cotato/12th-OnGil-FE
Length of output: 49
export default function 패턴 필수
src/components/**/*.tsx 코딩 가이드라인에 따라 named export 대신 default export를 사용해야 합니다. 이 변경 시 다음 3개 파일도 함께 수정이 필요합니다:
recommended-products-carousel.tsx: 라인 23 export 선언product-description.tsx: import 문 수정product/index.tsx: re-export 문 수정
♻️ 수정 범위
-export function RecommendedProductsCarousel({
+export default function RecommendedProductsCarousel({
similarProducts,
}: RecommendedProductsCarouselProps) {-import { RecommendedProductsCarousel } from './recommended-products-carousel';
+import RecommendedProductsCarousel from './recommended-products-carousel';-export { RecommendedProductsCarousel } from './descriptions/recommended-products-carousel';
+export { default as RecommendedProductsCarousel } from './descriptions/recommended-products-carousel';📝 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.
| export function RecommendedProductsCarousel({ | |
| products, | |
| similarProducts, | |
| }: RecommendedProductsCarouselProps) { | |
| export default function RecommendedProductsCarousel({ | |
| similarProducts, | |
| }: RecommendedProductsCarouselProps) { |
🤖 Prompt for AI Agents
In `@src/components/product/descriptions/recommended-products-carousel.tsx` around
lines 23 - 25, Change the named export to a default export for the component by
updating the declaration to "export default function
RecommendedProductsCarousel(...)" in RecommendedProductsCarousel, then update
any imports: in product-description.tsx replace the named import (e.g. import {
RecommendedProductsCarousel } ...) with a default import (import
RecommendedProductsCarousel ...), and update the re-export in product/index.tsx
to export the default (e.g. export { default as RecommendedProductsCarousel }
from '...') so all references use the default export.
| {images.map((src, index) => ( | ||
| <CarouselItem key={index} className="relative aspect-square w-full"> | ||
| <Image | ||
| src={src} | ||
| alt={`상품 이미지 ${index + 1}`} | ||
| fill | ||
| className="object-cover" | ||
| priority={index === 0} | ||
| sizes="(max-width: 768px) 100vw, 40vw" | ||
| /> | ||
| {src && ( | ||
| <Image | ||
| src={src} | ||
| alt={`상품 이미지 ${index + 1}`} | ||
| fill | ||
| className="object-cover" | ||
| priority={index === 0} | ||
| sizes="(max-width: 768px) 100vw, 40vw" | ||
| /> | ||
| )} | ||
| </CarouselItem> |
There was a problem hiding this comment.
imageUrl이 빈 문자열이면 빈 슬라이드 5개가 렌더링됩니다.
Array(5).fill(imageUrl)에서 imageUrl이 falsy이면 모든 CarouselItem이 빈 상태로 렌더링되고, 카운터는 1 / 5로 표시됩니다. 상위에서 guard하거나, 컴포넌트 레벨에서 fallback UI(placeholder 이미지 등)를 제공하는 것이 UX상 낫습니다.
🤖 Prompt for AI Agents
In `@src/components/product/product-image-slider.tsx` around lines 55 - 67, The
component currently renders empty CarouselItem slides when image URLs are falsy;
update product-image-slider to filter out falsy entries before mapping (use
images.filter(Boolean) or similar) and map over that filtered array in the
images.map block so only valid Image components render; if the filtered array is
empty, render a fallback UI (single placeholder CarouselItem/Image or a “no
image” placeholder) and ensure any counter or pagination logic uses the filtered
array length instead of the original Array(5).fill(...) source so the slide
count and visuals stay consistent.
| const reviewCount = ((startId + i) * 37 + 13) % 200; | ||
| const reviewRating = parseFloat( | ||
| ((((startId + i) * 53 + 7) % 50) / 10).toFixed(1), | ||
| ); |
There was a problem hiding this comment.
reviewRating 범위가 0.0~4.9로, 리뷰가 있는데 평점 0.0이 나올 수 있음
((startId + i) * 53 + 7) % 50 결과가 0이 되는 경우 reviewCount > 0인데 reviewRating = 0.0인 비정상 데이터가 생성됩니다. 또한 최대값이 4.9로 5.0에 도달하지 못합니다.
Mock 데이터라 치명적이지는 않지만, 하류 UI 컴포넌트에서 별점 0.0을 렌더링할 때 의도치 않은 결과가 나올 수 있습니다.
제안: 1.0~5.0 범위로 보정
- const reviewRating = parseFloat(
- ((((startId + i) * 53 + 7) % 50) / 10).toFixed(1),
- );
+ const reviewRating = parseFloat(
+ (((((startId + i) * 53 + 7) % 40) + 10) / 10).toFixed(1),
+ );이렇게 하면 10..49 / 10 = 1.0..4.9 범위로 최소 1.0이 보장됩니다.
🤖 Prompt for AI Agents
In `@src/mocks/product-data.ts` around lines 87 - 90, The code can produce
reviewRating = 0.0 even when reviewCount > 0 and never reaches 5.0; update the
reviewRating computation (the symbol reviewRating that uses startId and i and
the derived raw value) so that when reviewCount > 0 you clamp the computed
rating to a minimum of 1.0 (e.g., compute the raw rating from (((startId + i) *
53 + 7) % 50) / 10 and then set reviewRating = Math.max(1.0, parsedRaw) after
rounding to one decimal), ensuring no positive-review product gets 0.0 while
preserving the existing distribution.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/components/product-option-sheet/use-product-option.ts (2)
98-106:⚠️ Potential issue | 🟠 Major
stockStatus미검증 — 품절 옵션도 선택 가능합니다.
ProductOption에stockStatus: StockStatus필드가 존재하지만(src/types/domain/product.ts:29),addItemToSelection호출 전에 재고 상태를 확인하지 않습니다. 품절(OUT_OF_STOCK) 옵션이selectedItems에 추가되어 결제/장바구니 요청 시 서버 에러가 발생할 수 있습니다.수정 제안
if (targetOption) { + if (targetOption.stockStatus === 'OUT_OF_STOCK') { + alert('품절된 옵션입니다.'); + setCurrentSize(''); + return; + } addItemToSelection(targetOption); }
170-172:⚠️ Potential issue | 🟡 Minor
console.error잔존 — PR 체크리스트 위반.PR 템플릿 체크리스트에
console.log제거 항목이 있습니다. 프로덕션에서는 에러 리포팅 서비스(Sentry 등)로 대체하거나, 최소한 개발 환경 분기를 고려하세요.src/components/product/product-detail-view.tsx (1)
27-32: 🛠️ Refactor suggestion | 🟠 Major코딩 가이드라인 위반: 화살표 함수로 선언된 컴포넌트
ProductInquiryContent는 JSX를 반환하는 컴포넌트이지만const화살표 함수로 선언되어 있습니다. 가이드라인 및 learnings에 따르면const는 내부 로직과 훅에만 사용하고, 컴포넌트는 반드시function선언으로 작성해야 합니다.♻️ function 선언으로 변환
-const ProductInquiryContent = () => ( - <div className="rounded-lg bg-gray-50 py-20 text-center text-gray-500"> - <p>문의 영역입니다.</p> - <p className="mt-2 text-sm">이곳에 문의 리스트 컴포넌트가 들어갑니다.</p> - </div> -); +function ProductInquiryContent() { + return ( + <div className="rounded-lg bg-gray-50 py-20 text-center text-gray-500"> + <p>문의 영역입니다.</p> + <p className="mt-2 text-sm">이곳에 문의 리스트 컴포넌트가 들어갑니다.</p> + </div> + ); +}As per coding guidelines,
src/components/**/*.tsx: "export default function 패턴 (화살표 함수 금지)". Based on learnings, "Useconstonly for internal logic and hooks within components. Do not useconstfor component declarations."src/components/product/descriptions/product-description.tsx (1)
23-26:⚠️ Potential issue | 🟡 Minor상세 이미지 목 데이터를 실제 API 응답 데이터로 교체하세요
Array(10).fill()로 썸네일 이미지를 반복 복제하는 임시 로직이 프로덕션 코드에 남아 있습니다.productprops에서 실제 상세 이미지 배열을 받아 사용하거나, 필요시 별도 API 호출로 가져와야 합니다. 현재는 동일 이미지가 계속 노출됩니다.유사한 패턴이
src/components/product/product-image-slider.tsx에도 있으니 함께 처리하세요.
🧹 Nitpick comments (11)
src/components/product-option-sheet/use-product-option.ts (4)
82-92:Date.now()기반 ID — 빠른 연속 호출 시 충돌 가능.동일 옵션을 빠르게 두 번 추가하는 경우는
findIndex로 방어되지만, 서로 다른 옵션을 밀리초 단위로 추가하면 동일id가 생성될 수 있습니다.crypto.randomUUID()또는 카운터 사용을 권장합니다.수정 제안
- id: `${option.optionId}-${Date.now()}`, + id: crypto.randomUUID(),
58-66: 중복 제거 패턴 불일치 —SetvsindexOf.
availableColors는new Set으로 중복을 제거하고,availableSizes는.filter((val, idx, arr) => arr.indexOf(val) === idx)를 사용합니다. 일관성을 위해 동일 패턴을 적용하세요.수정 제안
- const availableSizes = options - .filter((o) => !currentColor || o.color === currentColor) - .map((o) => o.size) - .filter(Boolean) - .filter((val, idx, arr) => arr.indexOf(val) === idx); + const availableSizes = Array.from( + new Set( + options + .filter((o) => !currentColor || o.color === currentColor) + .map((o) => o.size) + .filter(Boolean), + ), + );
111-119:updateQuantity,removeItem,setIsOpen—useCallback미적용.
addItemToSelection은useCallback으로 감쌌지만 나머지 핸들러들은 매 렌더마다 새 참조가 생성됩니다. 자식 컴포넌트에 props로 전달될 경우 불필요한 리렌더링을 유발합니다.Also applies to: 121-123, 42-49
159-162: URL params에 JSON 직렬화 — 길이 제한 주의.
selections를JSON.stringify하여 query string에 넣고 있습니다. 선택 항목이 많아지면 URL 길이 제한(~2048 chars)에 도달할 수 있습니다.sessionStorage나 서버 상태를 통한 전달을 검토하세요.src/components/product/descriptions/product-description.tsx (2)
13-20: 인라인 props 타입이ProductDetailView와 중복됩니다.
product-detail-view.tsx의ProductDetailProps와 동일한Omit<Product, ...> & Partial<Pick<Product, ...>>패턴이 반복되고 있습니다. 하나의 도메인 타입으로 추출하면 두 곳 모두 일관성 있게 관리할 수 있습니다.♻️ 타입 추출 제안
src/types/domain/product.ts에 공유 타입을 정의:export type ProductSummary = Omit<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'> & Partial<Pick<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'>>;그런 다음 두 파일 모두에서 사용:
- product: Omit<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'> & - Partial<Pick<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'>>; + product: ProductSummary;
32-44: 이미지 리스트의key={idx}사용은 현재 구조에서 허용되나, 접근성 개선 여지가 있습니다.정적 배열이므로 인덱스 키는 괜찮습니다. 다만,
src가 falsy일 때 빈<div>만 렌더링되어 빈 영역이 레이아웃 공간을 차지합니다.aspect-3/4가 적용된 빈 컨테이너가 시각적 공백을 만들 수 있습니다.♻️ falsy src일 때 div 자체를 렌더링하지 않는 방안
- {visibleImages.map((src, idx) => ( - <div key={idx} className="relative aspect-3/4 w-full"> - {src && ( + {visibleImages.filter(Boolean).map((src, idx) => ( + <div key={idx} className="relative aspect-3/4 w-full"> + { <Image src={src} alt={`상세 설명 이미지 ${idx + 1}`} fill className="object-cover" sizes="(max-width: 768px) 100vw, 50vw" /> - )} + } </div> ))}src/components/product/product-detail-view.tsx (2)
74-77: 하드코딩된 sizes/colors 배열 —ProductOption[]데이터 활용 가능
optionsprop으로ProductOption[]을 받을 수 있는 구조인데,availableOptions의 sizes와 colors가 하드코딩되어 있습니다. 실제 옵션 데이터에서 추출하면 정확한 값을 반영할 수 있습니다.♻️ options에서 파생하는 방안
availableOptions: { - sizes: ['XS', 'S', 'M', 'L', 'XL'], - colors: ['Black', 'White', 'Navy', 'Gray', 'Beige'], + sizes: [...new Set(product.options?.map((o) => o.size) ?? [])], + colors: [...new Set(product.options?.map((o) => o.color) ?? [])], },
15-15: import 경로 불일치: 배럴 vs 직접 모듈 경로Lines 4-13에서는
@/components/product배럴을 사용하지만,ProductDescription만 직접 모듈 경로로 import하고 있습니다. 배럴에서 이미 re-export되므로 통일하는 것이 일관성에 좋습니다.♻️ 배럴 import로 통일
-import ProductDescription from '@/components/product/descriptions/product-description';Lines 4-13의 배럴 import에 추가:
import { ProductImageSlider, ProductInfo, ProductBottomBar, CompactProductHeader, ProductTab, ProductInteractionProvider, ProductStickyContainer, ProductHeader, + ProductDescription, } from '@/components/product';src/components/cart/cart-option-change-sheet.tsx (1)
39-49:useEffect내startTransition비동기 호출 시 클린업 누락
item이 빠르게 변경되면(예: 다른 상품 옵션 편집을 연속 클릭) 이전getProductOptions응답이 나중에 도착해setOptions가 잘못된 상품 옵션으로 덮어쓸 수 있습니다.useEffect클린업에서 stale 응답을 무시하는 패턴을 권장합니다.♻️ stale 응답 방지 패턴
useEffect(() => { if (!item) return; + let cancelled = false; setCurrentColor(item.selectedColor); setCurrentSize(item.selectedSize); startTransition(async () => { const fetched = await getProductOptions(item.productId); - setOptions(fetched); + if (!cancelled) setOptions(fetched); }); + + return () => { cancelled = true; }; }, [item]);src/components/cart/cart-item.tsx (2)
40-50: 컴포넌트 언마운트 시 debounce 타이머 클린업 누락
debounceRef의 타이머가 컴포넌트 언마운트 시 정리되지 않아, 삭제 등으로 카트 아이템이 제거된 후에도onQuantityChange가 실행될 수 있습니다. 불필요한 서버 액션 호출이나 stale 데이터 업데이트로 이어질 수 있습니다.♻️ useEffect 클린업 추가
+ useEffect(() => { + return () => { + if (debounceRef.current) clearTimeout(debounceRef.current); + }; + }, []); + useEffect(() => { setInputValue(String(quantity)); }, [quantity]);
128-146: 시니어 대상 앱에서 수량 입력 필드 터치 영역이 작을 수 있음
w-6(24px)은 시니어 친화적 UX 기준(최소 44px 권장, WCAG 2.5.5)에 비해 상당히 작습니다. 실제 렌더링에서 flex 컨테이너에 의해 확장될 수 있지만 확인이 필요합니다.w-12이상으로 넓히는 것을 고려해주세요.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/product/product-detail-view.tsx (1)
70-79:⚠️ Potential issue | 🟠 Major하드코딩된
availableOptions— mock 데이터 잔존 가능성커밋 메시지에서 "mock 데이터용 임시 로직 제거"를 언급했지만,
sizes: ['XS', 'S', 'M', 'L', 'XL']와colors: ['Black', 'White', 'Navy', 'Gray', 'Beige']가 하드코딩되어 있습니다.product.options(Line 46의ProductOption[])에서 실제 사이즈/색상을 추출해야 할 것으로 보입니다.제안: options에서 동적으로 추출
availableOptions: { - sizes: ['XS', 'S', 'M', 'L', 'XL'], - colors: ['Black', 'White', 'Navy', 'Gray', 'Beige'], + sizes: [...new Set(product.options?.map((o) => o.size) ?? [])], + colors: [...new Set(product.options?.map((o) => o.color) ?? [])], },
🤖 Fix all issues with AI agents
In `@src/components/product/product-image-slider.tsx`:
- Line 18: 컴포넌트 선언인 ProductImageSlider을 named export에서 default export로 변경하세요: 바꿀
대상은 function ProductImageSlider -> export default function ProductImageSlider({
imageUrls }: ProductImageSliderProps) (파일: ProductImageSlider), 그리고 해당 default로
바뀐 export에 맞춰 re-export를 수정하세요: src/components/product/index.tsx에서 named
re-export를 사용 중인 부분을 default re-export로 변경하여 import/export 불일치를 제거하세요.
🧹 Nitpick comments (7)
src/components/product/product-image-slider.tsx (1)
19-19: 불필요한 별칭 제거
const images = imageUrls는 단순 별칭으로 가독성에 기여하지 않습니다.제안
-export default function ProductImageSlider({ imageUrls }: ProductImageSliderProps) { - const images = imageUrls; +export default function ProductImageSlider({ imageUrls: images }: ProductImageSliderProps) {또는 그냥
imageUrls를 직접 사용하세요.src/components/product/descriptions/product-description.tsx (1)
16-21: 인라인 타입이ProductDetailProps와 중복됨 — 공유 타입 추출 권장
Omit<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'> & Partial<Pick<...>> & { imageUrls?: string[] }구조가product-detail-view.tsx의ProductDetailProps와 거의 동일합니다.src/types/domain/product.ts에 공유 타입을 정의하면 두 곳 모두 단순화됩니다.// src/types/domain/product.ts export type ProductDetailData = Omit<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'> & Partial<Pick<Product, 'viewCount' | 'purchaseCount' | 'reviewCount'>> & { imageUrls?: string[]; };src/components/product/product-detail-view.tsx (1)
27-32: 내부 플레이스홀더 컴포넌트도function선언 권장
const ProductInquiryContent = () => (...)패턴은 가이드라인의 화살표 함수 금지 규칙에 해당합니다. 내부 컴포넌트라도 일관성을 위해function선언이 낫습니다.제안
-const ProductInquiryContent = () => ( +function ProductInquiryContent() { + return ( <div className="rounded-lg bg-gray-50 py-20 text-center text-gray-500"> <p>문의 영역입니다.</p> <p className="mt-2 text-sm">이곳에 문의 리스트 컴포넌트가 들어갑니다.</p> </div> -); + ); +}As per coding guidelines,
src/components/**/*.tsx: "export default function 패턴 (화살표 함수 금지)". Based on learnings, "Do not useconstfor component declarations."src/components/product-option-sheet/use-product-option.ts (4)
104-108:alert()는 접근성(a11y) 측면에서 비권장
alert('품절된 옵션입니다.')는 네이티브 블로킹 다이얼로그로, 스크린 리더 사용자 경험이 좋지 않고 스타일링도 불가합니다. 토스트 알림이나 인라인 메시지로 대체하면 UX와 접근성 모두 개선됩니다.지금 당장은 아니더라도 추후 개선 대상으로 참고해 주세요.
56-56: 불필요한 별칭 할당
const options = initialOptions;는 의미 없는 중간 변수입니다. 이전에 더미 데이터 생성 로직이 있었던 흔적으로 보이는데, 리팩터링이 완료되었으므로 제거하거나 파라미터 이름 자체를options로 변경하는 게 깔끔합니다.제안: 파라미터 직접 사용
export default function useProductOption({ productId, price, - options: initialOptions = [], + options = [], open: externalOpen, onOpenChange: externalOnOpenChange, }: UseProductOptionProps) { ... - const options = initialOptions;
134-146: 다수 옵션의 병렬addToCart호출 — 부분 실패 시 정합성 문제
Promise.all은 하나라도 실패하면 전체가 reject됩니다. 3개 옵션 중 2개만 성공하면 사용자에게는 에러 메시지가 뜨지만, 서버에는 2개가 이미 추가된 상태입니다. 멱등성이 보장되지 않는다면Promise.allSettled로 변경하고 부분 실패를 핸들링하거나, 배치 API를 사용하는 것이 안전합니다.
162-165: URL 쿼리 파라미터에 JSON을 직접 넣는 방식 주의
selections를JSON.stringify하여 URL 파라미터로 전달하면, 옵션이 많을 경우 URL 길이 제한(~2048자)에 걸릴 수 있습니다. 또한 브라우저 히스토리에 주문 정보가 노출됩니다. 세션 스토리지나 서버 사이드 임시 저장을 검토해 보세요.
|
|
||
| export function ProductImageSlider({ imageUrl }: ProductImageSliderProps) { | ||
| const images = Array(5).fill(imageUrl); | ||
| export function ProductImageSlider({ imageUrls }: ProductImageSliderProps) { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the export pattern in product-image-slider.tsx
echo "=== product-image-slider.tsx export pattern ==="
rg -n 'export.*ProductImageSlider' --type=tsx src/components/product/
# Check re-export in index.tsx
echo -e "\n=== product/index.tsx re-export pattern ==="
cat src/components/product/index.tsx
# Check other component export patterns for reference
echo -e "\n=== Other component export patterns ==="
rg -n '^export (default )?function' --type=tsx src/components/product/ | head -20Repository: IT-Cotato/12th-OnGil-FE
Length of output: 2881
🏁 Script executed:
#!/bin/bash
# Check the actual content of product-image-slider.tsx
echo "=== product-image-slider.tsx content (first 30 lines) ==="
head -30 src/components/product/product-image-slider.tsx
# Check other components' export patterns
echo -e "\n=== product-card.tsx export pattern ==="
head -20 src/components/product/product-card.tsx | grep -E '^export|^import'
echo -e "\n=== product-info.tsx export pattern ==="
head -20 src/components/product/product-info.tsx | grep -E '^export|^import'
echo -e "\n=== product-filter-bar.tsx export pattern ==="
head -20 src/components/product/product-filter-bar.tsx | grep -E '^export|^import'
echo -e "\n=== product-list.tsx export pattern ==="
head -20 src/components/product/product-list.tsx | grep -E '^export|^import'Repository: IT-Cotato/12th-OnGil-FE
Length of output: 1625
🏁 Script executed:
#!/bin/bash
# Check more lines of product-image-slider.tsx to see the full implementation
echo "=== product-image-slider.tsx (lines 15-75) ==="
sed -n '15,75p' src/components/product/product-image-slider.tsx
# Verify if ProductImageSlider is used as default export anywhere
echo -e "\n=== Check if ProductImageSlider is imported as default ==="
rg 'import.*ProductImageSlider' --type=tsRepository: IT-Cotato/12th-OnGil-FE
Length of output: 1856
export default function 패턴 필수 적용
src/components/**/*.tsx 코딩 가이드라인에서 컴포넌트는 반드시 export default function을 사용해야 합니다. 현재 코드는 export function 패턴을 사용 중입니다.
이 변경 시 src/components/product/index.tsx의 re-export도 함께 수정이 필요합니다:
적용할 변경사항
-export function ProductImageSlider({ imageUrls }: ProductImageSliderProps) {
+export default function ProductImageSlider({ imageUrls }: ProductImageSliderProps) {-export { ProductImageSlider } from './product-image-slider';
+export { default as ProductImageSlider } from './product-image-slider';📝 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.
| export function ProductImageSlider({ imageUrls }: ProductImageSliderProps) { | |
| export default function ProductImageSlider({ imageUrls }: ProductImageSliderProps) { |
🤖 Prompt for AI Agents
In `@src/components/product/product-image-slider.tsx` at line 18, 컴포넌트 선언인
ProductImageSlider을 named export에서 default export로 변경하세요: 바꿀 대상은 function
ProductImageSlider -> export default function ProductImageSlider({ imageUrls }:
ProductImageSliderProps) (파일: ProductImageSlider), 그리고 해당 default로 바뀐 export에 맞춰
re-export를 수정하세요: src/components/product/index.tsx에서 named re-export를 사용 중인 부분을
default re-export로 변경하여 import/export 불일치를 제거하세요.
📝 개요
🚀 주요 변경 사항
📸 스크린샷 (선택)
✅ 체크리스트
이슈 해결 여부
PR 본문에 Closes #이슈번호 이라고 적으면, PR이 머지될 때 해당 이슈가 자동으로 닫힙니다