Conversation
📝 WalkthroughSummary by CodeRabbit릴리스 노트
Walkthrough결과 페이지에서 이미지별 투표·팩터 선택 및 바텀시트 기반 큐레이션 상호작용을 제거하고, 인라인 큐레이션 레이아웃으로 전환했습니다. 제품 카드에 가격·색상·저장수 표시와 전체 카드 링크/클릭영역 확장이 추가되었고 스타일·토큰·환경변수가 확장되었습니다. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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 |
빌드 결과빌드 성공 🎊 |
🎨 Storybook 빌드 완료!📚 Storybook: https://686a831b8e000345a949970a-scinueqkyt.chromatic.com/ 📊 빌드 정보
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a43b9c9c22
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| export const wrapper = style({ | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| alignItems: 'center', | ||
| minHeight: '66.7rem', | ||
| width: '100%', | ||
| height: 'calc(100dvh - 4.8rem)', // TitleNavBar height | ||
| overflow: 'hidden', | ||
| }); |
There was a problem hiding this comment.
Allow curation list to scroll within viewport
Setting the result page wrapper to a fixed 100dvh height with overflow: hidden means the page itself no longer scrolls. The new inline curation section can exceed the viewport on smaller screens, but resultSection doesn’t take the wrapper height, so the curation list isn’t constrained and gets clipped instead of scrollable (even though the curation content defines overflowY: auto). Users won’t be able to reach lower cards. Consider letting the wrapper scroll, or make resultSection flex to the wrapper height so the curation content can scroll inside.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/pages/generate/pages/result/components/DetectionHotspots.tsx (1)
93-101:⚠️ Potential issue | 🟠 Major중복 cache 저장으로 인한 루프/불필요 I/O 가능성
handleInferenceComplete에서saveEntry를 호출한 뒤, 아래 effect에서processedDetections가 존재하면 다시saveEntry를 호출합니다. 캐시 저장을 한 사이클에 한 번만 하도록 정리해 중복 저장/루프 위험을 줄여주세요.✅ 제안 수정 (saveEntry 단일화)
- const handleInferenceComplete = useCallback( - (result: ProcessedDetections, latestHotspots: FurnitureHotspot[]) => { - lastDetectionsRef.current = result; - saveEntry({ - processedDetections: result, - hotspots: latestHotspots, - }); - }, - [saveEntry] - ); + const handleInferenceComplete = useCallback( + (result: ProcessedDetections) => { + lastDetectionsRef.current = result; + }, + [] + );Based on learnings: Use
useDetectionCachehook'slastDetectionsRefto ensuresetCacheEntryis called only once per detection cycle, preventing infinite update loop.Also applies to: 150-156
src/pages/generate/pages/result/curationSheet/CurationSheet.tsx (1)
194-194:⚠️ Potential issue | 🟠 Majorprefetch staleTime을 실제 쿼리와 일치시켜야 함
useFurnitureCuration.ts의getGeneratedImageProducts쿼리는staleTime: 5 * 60 * 1000(5분)으로 설정되어 있으나,CurationSheet.tsx의 prefetch는staleTime: 30 * 1000(30초)로 설정되어 있습니다.같은 API에 대한 prefetch와 실제 쿼리의 staleTime이 다르면 캐시 일관성 문제가 발생합니다. prefetch 데이터가 30초 후 stale로 표시되어 불필요한 재요청이 발생할 수 있으므로, prefetch staleTime을
5 * 60 * 1000으로 변경하세요.src/shared/components/card/cardProduct/CardProduct.css.ts (1)
1-242:⚠️ Potential issue | 🟡 Minor.prettierrc 파일 생성 필요
프로젝트에
.prettierrc설정 파일이 없어요. 현재 코드는 일관되게 single quote를 사용하고 있는데, Prettier의 기본값은 double quote라 충돌합니다.
"singleQuote": true옵션을 포함한.prettierrc파일을 프로젝트 루트에 생성해 주세요.
🤖 Fix all issues with AI agents
In `@src/pages/generate/pages/result/components/DetectionHotspots.tsx`:
- Around line 122-127: The call to useFurnitureHotspots (which returns imgRef,
containerRef, hotspots, error) violates Prettier due to a missing trailing comma
on the last argument; update the invocation of useFurnitureHotspots(...) to add
a trailing comma after hotspotOptions so the argument list ends with a comma,
then run Prettier/ESLint to confirm the prettier/prettier error is resolved.
In `@src/pages/generate/pages/result/curationSheet/CurationSheet.tsx`:
- Around line 258-260: The current logic uses hasDetectionCodes to decide the
message and shows "가구를 분석 중이에요" even when there may simply be no detections;
update CurationSheet to accept and use a prop from the parent (e.g., a boolean
like isInferring or a status enum inferenceState) to distinguish processing vs
empty-result states, then change the conditional around hasDetectionCodes + the
new prop so renderStatus shows a loading message only when inference is actually
in progress and a different "no detections" message when inference finished but
hasDetectionCodes is false; refer to hasDetectionCodes and renderStatus to
locate and modify the code paths.
In `@src/shared/components/card/cardProduct/CardProduct.css.ts`:
- Around line 151-157: The borderRadius in the colorChip style should use a
semantic percentage value instead of a huge rem; update the colorChip constant
so its borderRadius is '50%' (replace '99.9rem') to ensure a true circular pill
and better responsiveness while keeping the rest of the properties (width,
height, border, boxSizing) unchanged.
In `@src/shared/components/card/cardProduct/CardProduct.tsx`:
- Around line 144-156: The overlay divs that stop event propagation around the
SaveButton (check the conditional using isLarge and the later similar block
around lines 221-231) should include an explicit role attribute to improve
accessibility; add role="presentation" to the div with
className={styles.saveBtnOverlay} that has the onClick and onKeyDown handlers so
the non-interactive wrapper is announced correctly while preserving SaveButton,
onToggleSave, disabled, and isSaved behavior.
| const { imgRef, containerRef, hotspots, error } = useFurnitureHotspots( | ||
| imageUrl, | ||
| mirrored, | ||
| shouldInferHotspots, | ||
| hotspotOptions | ||
| ); |
There was a problem hiding this comment.
Prettier 규칙 위반으로 ESLint 오류
정적 분석에서 prettier/prettier 오류가 발생했습니다. 마지막 인자에 trailing comma를 추가해 주세요.
✅ 제안 수정
const { imgRef, containerRef, hotspots, error } = useFurnitureHotspots(
imageUrl,
mirrored,
shouldInferHotspots,
- hotspotOptions
+ hotspotOptions,
);📝 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.
| const { imgRef, containerRef, hotspots, error } = useFurnitureHotspots( | |
| imageUrl, | |
| mirrored, | |
| shouldInferHotspots, | |
| hotspotOptions | |
| ); | |
| const { imgRef, containerRef, hotspots, error } = useFurnitureHotspots( | |
| imageUrl, | |
| mirrored, | |
| shouldInferHotspots, | |
| hotspotOptions, | |
| ); |
🧰 Tools
🪛 ESLint
[error] 126-126: Insert ,
(prettier/prettier)
🤖 Prompt for AI Agents
In `@src/pages/generate/pages/result/components/DetectionHotspots.tsx` around
lines 122 - 127, The call to useFurnitureHotspots (which returns imgRef,
containerRef, hotspots, error) violates Prettier due to a missing trailing comma
on the last argument; update the invocation of useFurnitureHotspots(...) to add
a trailing comma after hotspotOptions so the argument list ends with a comma,
then run Prettier/ESLint to confirm the prettier/prettier error is resolved.
| if (!hasDetectionCodes) { | ||
| return renderStatus('가구를 분석 중이에요', '잠시만 기다려 주세요'); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
감지 진행 중 상태 메시지 개선 고려
hasDetectionCodes가 false일 때 "가구를 분석 중이에요" 메시지가 표시돼요. 실제로 추론이 진행 중인지, 아니면 감지된 가구가 없는 것인지 구분이 어려울 수 있어요. 상위 컴포넌트에서 추론 상태를 전달받아 더 정확한 피드백을 제공하는 것을 고려해 주세요.
🧰 Tools
🪛 ESLint
[error] 259-259: Replace '가구를·분석·중이에요',·'잠시만·기다려·주세요' with "가구를·분석·중이에요",·"잠시만·기다려·주세요"
(prettier/prettier)
🤖 Prompt for AI Agents
In `@src/pages/generate/pages/result/curationSheet/CurationSheet.tsx` around lines
258 - 260, The current logic uses hasDetectionCodes to decide the message and
shows "가구를 분석 중이에요" even when there may simply be no detections; update
CurationSheet to accept and use a prop from the parent (e.g., a boolean like
isInferring or a status enum inferenceState) to distinguish processing vs
empty-result states, then change the conditional around hasDetectionCodes + the
new prop so renderStatus shows a loading message only when inference is actually
in progress and a different "no detections" message when inference finished but
hasDetectionCodes is false; refer to hasDetectionCodes and renderStatus to
locate and modify the code paths.
빌드 결과빌드 성공 🎊 |
빌드 결과빌드 성공 🎊 |
빌드 결과빌드 성공 🎊 |
빌드 결과빌드 성공 🎊 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@src/pages/generate/pages/result/curationSheet/CurationSheet.css.ts`:
- Around line 83-92: The current grid style gridbox uses a fixed-width
declaration via gridTemplateColumns: 'repeat(2, 16.4rem)' which causes
horizontal overflow on small viewports; update gridTemplateColumns in the
gridbox style to use responsive units instead (for example use 'repeat(2, 1fr)'
for equal column distribution or 'repeat(auto-fill, minmax(16rem, 1fr))' for a
flexible minimum-width grid) and keep columnGap/rowGap/justify settings intact
so the layout becomes responsive like GeneratedImagesSection and FloorPlanList.
In `@src/pages/generate/pages/result/ResultPage.css.ts`:
- Around line 9-24: The hardcoded `4.8rem` in the wrapper style should be
extracted to a shared layout token and referenced in the calc to avoid magic
numbers; create a constant (e.g., TITLE_NAV_BAR_HEIGHT = '4.8rem') in a shared
tokens module (or top of this file) and update wrapper.height to use
`calc(100dvh - ${TITLE_NAV_BAR_HEIGHT})`; ensure any other places that rely on
TitleNavBar height import and use the same token so changes are centralized
(check wrapper and any other styles referencing TitleNavBar height).
In `@src/shared/components/card/cardProduct/CardProduct.tsx`:
- Around line 107-117: When enableWholeCardLink && linkHref is true, replace the
outer div with a native anchor element so the card uses semantic link behavior
(supports Ctrl/Cmd+click, proper focus, no ARIA role hack). Concretely, render
<a href={linkHref}> with the same className (styles.wrapper({ size }) and
styles.clickable), move onClick={handleWrapperClick} onto the anchor, remove
role/tabIndex/aria-label that mimic link semantics, and stop using
handleWrapperKeyDown for keyboard activation; otherwise keep the plain div
branch for non-link cards. Also ensure inner interactive children remain
accessible (avoid nesting anchors) and keep title available for accessible
labeling if needed.
| export const gridbox = style({ | ||
| width: '100%', | ||
| height: 'fit-content', | ||
| display: 'grid', | ||
| gridTemplateColumns: 'repeat(auto-fill, minmax(16.6rem, 1fr))', | ||
| columnGap: '1.1rem', | ||
| justifyItems: 'center', | ||
| gridTemplateColumns: 'repeat(2, 16.4rem)', | ||
| columnGap: '0.7rem', | ||
| rowGap: 0, | ||
| justifyContent: 'space-between', | ||
| justifyItems: 'start', | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for responsive patterns in curation-related files
rg -n -C3 '@media|minWidth|maxWidth|breakpoint|container' src/pages/generate/pages/result/curationSheet/Repository: TEAM-HOUME/HOUME-CLIENT
Length of output: 1978
🏁 Script executed:
#!/bin/bash
# Read the full CurationSheet.css.ts file to understand the context
cat -n src/pages/generate/pages/result/curationSheet/CurationSheet.css.tsRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 5104
🏁 Script executed:
#!/bin/bash
# Search for media queries and responsive utilities in the entire source
fd -e "css.ts" src/ | head -20 | xargs grep -l '@media\|selectors.*@media'Repository: TEAM-HOUME/HOUME-CLIENT
Length of output: 390
🏁 Script executed:
#!/bin/bash
# Search for layoutVars definition
rg -n "layoutVars" src/ | head -20Repository: TEAM-HOUME/HOUME-CLIENT
Length of output: 626
🏁 Script executed:
#!/bin/bash
# Search for media queries in CSS files
fd -type f -name "*.css.ts" src/ -exec grep -l "@media" {} \;Repository: TEAM-HOUME/HOUME-CLIENT
Length of output: 237
🏁 Script executed:
#!/bin/bash
# Check if there are viewport/screen size considerations in the codebase
rg -n "viewport|screen|device|mobile|tablet|desktop" src/pages/generate/pages/result/curationSheet/ -iRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 49
🏁 Script executed:
#!/bin/bash
# Read the layoutVars definition
sed -n '27,60p' src/shared/styles/global.css.tsRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 710
🏁 Script executed:
#!/bin/bash
# Search for media queries in all CSS files
find src -name "*.css.ts" -type f -exec grep -l "@media" {} \;Repository: TEAM-HOUME/HOUME-CLIENT
Length of output: 98
🏁 Script executed:
#!/bin/bash
# Check the full global.css.ts to understand layout constraints
wc -l src/shared/styles/global.css.tsRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 102
🏁 Script executed:
#!/bin/bash
# Check if there are media queries anywhere in the codebase
rg -n "@media" src/Repository: TEAM-HOUME/HOUME-CLIENT
Length of output: 116
🏁 Script executed:
#!/bin/bash
# Search for any responsive grid handling or container queries
rg -n "gridTemplate|container.*query" src/ -iRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 1012
🏁 Script executed:
#!/bin/bash
# Check if CurationSheet component has any responsive logic
grep -n "gridbox" src/pages/generate/pages/result/curationSheet/CurationSheet.tsxRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 109
🏁 Script executed:
#!/bin/bash
# Check the media query in global.css.ts
sed -n '107,130p' src/shared/styles/global.css.tsRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 497
🏁 Script executed:
#!/bin/bash
# Check how gridbox is being used and if there's overflow handling
grep -B5 -A10 "gridbox" src/pages/generate/pages/result/curationSheet/CurationSheet.tsxRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 435
🏁 Script executed:
#!/bin/bash
# Calculate the actual width constraints
python3 << 'EOF'
# Layout constraints
max_width_px = 440
min_width_px = 375
padding_left_right = 32 + 32 # 2rem on each side = 32px
# Grid sizing
column_width_rem = 16.4
num_columns = 2
gap_rem = 0.7
gap_px = gap_rem * 16 # approximate 1rem = 16px
# Calculate required width
required_width = (column_width_rem * num_columns * 16) + gap_px
available_width_max = max_width_px - padding_left_right
available_width_min = min_width_px - padding_left_right
print(f"Max available width (440px viewport): {available_width_max}px")
print(f"Min available width (375px viewport): {available_width_min}px")
print(f"Required width for grid: {required_width}px")
print(f"Overflow on 440px screen: {required_width - available_width_max}px")
print(f"Overflow on 375px screen: {required_width - available_width_min}px")
EOFRepository: TEAM-HOUME/HOUME-CLIENT
Length of output: 255
고정 너비 그리드 레이아웃 오버플로우 - 반드시 수정 필요
gridTemplateColumns: 'repeat(2, 16.4rem)'는 고정 너비를 사용하고 있어서 실제 오버플로우가 발생해요. 앱의 최소 지원 너비(375px)에서 약 225px, 최대 너비(440px)에서도 약 160px의 오버플로우가 발생합니다.
다른 그리드 컴포넌트들(GeneratedImagesSection, FloorPlanList 등)처럼 반응형 단위를 사용해 주세요:
repeat(2, 1fr)(동일 너비 분배)repeat(auto-fill, minmax(16rem, 1fr))(유연한 너비)
🧰 Tools
🪛 ESLint
[error] 84-84: Replace '100%' with "100%"
(prettier/prettier)
[error] 85-85: Replace 'fit-content' with "fit-content"
(prettier/prettier)
[error] 86-86: Replace 'grid' with "grid"
(prettier/prettier)
[error] 87-87: Replace 'repeat(2,·16.4rem)' with "repeat(2,·16.4rem)"
(prettier/prettier)
[error] 88-88: Replace '0.7rem' with "0.7rem"
(prettier/prettier)
[error] 90-90: Replace 'space-between' with "space-between"
(prettier/prettier)
[error] 91-91: Replace 'start' with "start"
(prettier/prettier)
🤖 Prompt for AI Agents
In `@src/pages/generate/pages/result/curationSheet/CurationSheet.css.ts` around
lines 83 - 92, The current grid style gridbox uses a fixed-width declaration via
gridTemplateColumns: 'repeat(2, 16.4rem)' which causes horizontal overflow on
small viewports; update gridTemplateColumns in the gridbox style to use
responsive units instead (for example use 'repeat(2, 1fr)' for equal column
distribution or 'repeat(auto-fill, minmax(16rem, 1fr))' for a flexible
minimum-width grid) and keep columnGap/rowGap/justify settings intact so the
layout becomes responsive like GeneratedImagesSection and FloorPlanList.
| return ( | ||
| <div className={styles.wrapper({ size })} onClick={onCardClick}> | ||
| <section className={styles.imgSection({ size })}> | ||
| <div | ||
| className={`${styles.wrapper({ size })} ${ | ||
| enableWholeCardLink ? styles.clickable : '' | ||
| }`} | ||
| onClick={handleWrapperClick} | ||
| onKeyDown={handleWrapperKeyDown} | ||
| role={enableWholeCardLink && linkHref ? 'link' : undefined} | ||
| tabIndex={enableWholeCardLink && linkHref ? 0 : undefined} | ||
| aria-label={enableWholeCardLink ? `${title} 상품 링크로 이동` : undefined} | ||
| > |
There was a problem hiding this comment.
div에 role="link" 사용 대신 <a> 태그 권장
div에 role="link", tabIndex, aria-label을 적용하고 있지만, 시맨틱하게는 <a> 태그를 사용하는 것이 더 적절해요. 스크린 리더와 브라우저가 네이티브 링크 동작(예: Ctrl+Click으로 새 탭 열기)을 지원하고, Biome 정적 분석 경고도 해결돼요.
♿ 접근성 개선을 위한 리팩터링 제안
+ const WrapperComponent = enableWholeCardLink && linkHref ? 'a' : 'div';
+ const wrapperProps = enableWholeCardLink && linkHref
+ ? {
+ href: linkHref,
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ 'aria-label': `${title} 상품 링크로 이동`,
+ }
+ : {};
return (
- <div
+ <WrapperComponent
className={`${styles.wrapper({ size })} ${
enableWholeCardLink ? styles.clickable : ''
}`}
onClick={handleWrapperClick}
- onKeyDown={handleWrapperKeyDown}
- role={enableWholeCardLink && linkHref ? 'link' : undefined}
- tabIndex={enableWholeCardLink && linkHref ? 0 : undefined}
- aria-label={enableWholeCardLink ? `${title} 상품 링크로 이동` : undefined}
+ {...wrapperProps}
>🧰 Tools
🪛 ESLint
[error] 110-110: Replace '' with ""
(prettier/prettier)
[error] 114-114: Replace 'link' with "link"
(prettier/prettier)
🤖 Prompt for AI Agents
In `@src/shared/components/card/cardProduct/CardProduct.tsx` around lines 107 -
117, When enableWholeCardLink && linkHref is true, replace the outer div with a
native anchor element so the card uses semantic link behavior (supports
Ctrl/Cmd+click, proper focus, no ARIA role hack). Concretely, render <a
href={linkHref}> with the same className (styles.wrapper({ size }) and
styles.clickable), move onClick={handleWrapperClick} onto the anchor, remove
role/tabIndex/aria-label that mimic link semantics, and stop using
handleWrapperKeyDown for keyboard activation; otherwise keep the plain div
branch for non-link cards. Also ensure inner interactive children remain
accessible (avoid nesting anchors) and keep title available for accessible
labeling if needed.
빌드 결과빌드 성공 🎊 |
빌드 결과빌드 성공 🎊 |
빌드 결과빌드 성공 🎊 |
📌 Summary
결과 페이지의 큐레이션 영역을 바텀시트에서 인라인 섹션으로 전환하고, Figma 기준으로 필터 칩/그리드/카드 UI를 정합화했습니다.
Storybook 빌드 오류(vanilla-extract selector)와 카드 내부 버튼 키보드 이벤트 전파 이슈도 함께 수정했습니다.
📄 Tasks
🔍 To Reviewer
pnpm build-storybook기준으로는 정상 빌드됩니다.📸 Screenshot
pages/generate/FilterChip,CardProduct스토리에서 확인