삐봇 테스트#1269
Conversation
|
Warning Review limit reached
More reviews will be available in 48 minutes and 25 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
개요홈페이지 구조를 데스크톱과 모바일로 완전히 분리하고 모바일 환경을 리디자인합니다. 날씨 및 매장 카운트 API를 추가하고, 새로운 모바일 홈 컴포넌트, 하단 네비게이션, 모바일 카페테리아 UI를 도입하며, Zustand 기반 홈 실험 상태 관리를 추가합니다. 변경사항홈페이지 모바일 리디자인 및 구조 재구성
시퀀스 다이어그램sequenceDiagram
participant User as 사용자
participant HomePage as HomePage 컴포넌트
participant MediaQuery as useMediaQuery()
participant ExperimentStore as useHomeExperimentVariant()
participant DesktopHome as DesktopHome
participant MobileHome as MobileHome
participant MobileHomeRedesign as MobileHomeRedesign
User->>HomePage: 페이지 접속
HomePage->>MediaQuery: 모바일 여부 확인
alt 데스크톱
MediaQuery-->>HomePage: false
HomePage->>DesktopHome: props 전달
DesktopHome-->>User: 데스크톱 레이아웃 렌더링
else 모바일
MediaQuery-->>HomePage: true
HomePage->>ExperimentStore: variant 조회
alt redesign 변형
ExperimentStore-->>HomePage: 'redesign'
HomePage->>MobileHome: variant='redesign' 전달
MobileHome->>MobileHomeRedesign: props 전달 (variant 제외)
MobileHomeRedesign-->>User: 신규 모바일 홈 렌더링
else legacy 변형
ExperimentStore-->>HomePage: 'legacy'
HomePage->>MobileHome: variant='legacy' 전달
MobileHome->>MobileHome: variant 확인
MobileHome-->>User: 레거시 모바일 홈 렌더링
end
end
예상 코드 리뷰 난이도🎯 4 (복잡함) | ⏱️ ~50분 관련 PR
추천 레이블
추천 리뷰어
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 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: 7
🧹 Nitpick comments (2)
src/api/weather/queries.ts (1)
9-15: 날씨 데이터의 신선도(staleTime/refetch) 설정 검토.
weatherQueries.info()에staleTime/refetchInterval등이 없어 React Query 기본값(staleTime: 0)으로 동작합니다. 날씨는 시간에 민감하지만 매 마운트/포커스마다 재요청하면 불필요한 호출이 발생할 수 있습니다. 갱신 주기에 맞춰 명시적으로 설정하는 것을 고려해보세요. (다른 도메인 쿼리와의 일관성 차원에서 선택사항)♻️ 예시
info: () => queryOptions({ queryKey: weatherQueryKeys.info(), queryFn: getWeatherInfo, + staleTime: 1000 * 60 * 10, // 예: 10분 }),🤖 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 `@src/api/weather/queries.ts` around lines 9 - 15, weatherQueries.info currently returns queryOptions(...) with no staleTime/refetchInterval so it uses React Query defaults; update the object returned by weatherQueries.info to pass explicit staleTime and/or refetchInterval to queryOptions (alongside queryKey: weatherQueryKeys.info() and queryFn: getWeatherInfo) to avoid unnecessary refetches on every mount/focus—for example choose a staleTime that matches your weather update cadence (e.g., several minutes) and, if needed, a background refetchInterval for periodic updates; modify the weatherQueries.info factory to include these fields so weather data freshness is controlled consistently with other domain queries.src/components/layout/Header/MobileHomeRedesignHeader/index.tsx (1)
13-13: ⚡ Quick win알림 아이콘은 시맨틱 컨트롤로 감싸주세요.
현재는 SVG 단독 렌더링이라 키보드 포커스/조작이 불가능합니다. 알림 진입 의도가 있다면
button(또는Link)으로 감싸고aria-label을 버튼에 두는 쪽이 안전합니다.예시 수정
- <NotificationBellIcon aria-label="알림" /> + <button type="button" aria-label="알림" className={styles.header__notificationButton}> + <NotificationBellIcon aria-hidden /> + </button>As per coding guidelines,
src/components/**에서는 “접근성(a11y) 관련 속성이 적절히 사용되고 있는지 확인”해야 합니다.🤖 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 `@src/components/layout/Header/MobileHomeRedesignHeader/index.tsx` at line 13, Wrap the standalone NotificationBellIcon SVG in a semantic control (e.g., a <button> or <Link>) so it becomes keyboard-focusable and operable; move the aria-label from the SVG to the wrapping control (e.g., aria-label="알림" on the button), set type="button" if using button, and mark the inner SVG as decorative (aria-hidden="true") or remove its own aria attributes; ensure the click handler/props wired to NotificationBellIcon (if any) are attached to the wrapper so interaction logic remains intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.vscode/settings.json:
- Around line 11-12: Replace the incorrect VS Code setting key
"js/ts.tsdk.promptToUseWorkspaceVersion" with the correct official key
"typescript.enablePromptUseWorkspaceTsdk" so the workspace TypeScript SDK prompt
behavior works; leave "js/ts.tsdk.path" as-is and update the JSON entry name
accordingly.
In `@src/api/dinings/entity.ts`:
- Line 16: The kcal field was changed to non-nullable which can break client
type-safety if backend may return null; restore the original nullable contract
by changing the kcal declaration back to number | null in the dining entity
(kcal) or, if you prefer a non-nullable client model, add a
parsing/normalization step (e.g., in the DTO/mapper that constructs the dining
entity) that converts backend nulls to a deterministic value (like 0 or
undefined) before populating the kcal property so the runtime and the TypeScript
type remain consistent.
In `@src/components/cafeteria/components/CafeteriaInfo/index.tsx`:
- Line 50: The weekend filter currently only checks for schedule.day_of_week ===
'토요일' which misses API values like '주말'; update the predicate in the weekend
computation (the cafeteriaInfo.opens.filter call that assigns weekend) to accept
both '토요일' and '주말' (e.g., check against an allowed set or normalize
day_of_week) and apply the same change to the other similar occurrence around
the 91-91 region so both places handle alternate values consistently.
In `@src/components/IndexComponents/IndexMobileCafeteria/index.tsx`:
- Around line 110-124: The tab buttons rendered from availableDinings are only
visually marked via the --active class so screen readers can't tell which is
selected; update the button JSX in the map (the element that uses
availableDinings, activePlace and handleTabClick) to expose the state by adding
accessibility attributes—either add aria-pressed={dining.place === activePlace}
on each button, or convert to the tab pattern by adding role="tab" and
aria-selected={dining.place === activePlace} (and ensure the container has
role="tablist" if you choose the tab pattern); keep the existing class toggle
and onClick handler (handleTabClick) intact.
- Around line 32-35: The current render uses a truthy check on dining.price_cash
which will output a raw "0" when price_cash is 0; update the conditional in the
span of the IndexMobileCafeteria render so you explicitly test for
null/undefined (e.g., dining.price_cash != null) rather than using &&; replace
the {dining.price_cash && `₩${dining.price_cash.toLocaleString()} · `} usage
with a ternary or explicit null check so 0 is formatted with toLocaleString()
(or handled as a free meal text) and then still render
<strong>{dining.kcal}kcal</strong> as before.
In `@src/components/layout/HomeLayout/HomeLayout.module.scss`:
- Line 3: Update the min-height declaration in HomeLayout.module.scss so mobile
viewport changes don't cause layout jumps: keep the existing fallback then
override with dynamic viewport units by adding a 100dvh rule after the 100vh one
(e.g., leave min-height: 100vh; then add min-height: 100dvh;), targeting the
same selector where min-height is defined in HomeLayout.module.scss.
In `@src/components/layout/MobileBottomNavigation/index.tsx`:
- Line 48: The current active-tab check in MobileBottomNavigation (the isActive
assignment using pathname, resolvedHref and key === 'profile') only does exact
matches; change it to also treat section tabs as active when the current
pathname is a prefix of the tab's route. Update the isActive logic (in index.tsx
where isActive is computed using pathname, resolvedHref, and key) to return true
when pathname === resolvedHref OR pathname.startsWith(resolvedHref + '/') (and
preserve the special-case profile check using ROUTES.AuthModifyInfo()), ensuring
you normalize trailing slashes if needed so nested routes under a tab remain
active.
---
Nitpick comments:
In `@src/api/weather/queries.ts`:
- Around line 9-15: weatherQueries.info currently returns queryOptions(...) with
no staleTime/refetchInterval so it uses React Query defaults; update the object
returned by weatherQueries.info to pass explicit staleTime and/or
refetchInterval to queryOptions (alongside queryKey: weatherQueryKeys.info() and
queryFn: getWeatherInfo) to avoid unnecessary refetches on every mount/focus—for
example choose a staleTime that matches your weather update cadence (e.g.,
several minutes) and, if needed, a background refetchInterval for periodic
updates; modify the weatherQueries.info factory to include these fields so
weather data freshness is controlled consistently with other domain queries.
In `@src/components/layout/Header/MobileHomeRedesignHeader/index.tsx`:
- Line 13: Wrap the standalone NotificationBellIcon SVG in a semantic control
(e.g., a <button> or <Link>) so it becomes keyboard-focusable and operable; move
the aria-label from the SVG to the wrapping control (e.g., aria-label="알림" on
the button), set type="button" if using button, and mark the inner SVG as
decorative (aria-hidden="true") or remove its own aria attributes; ensure the
click handler/props wired to NotificationBellIcon (if any) are attached to the
wrapper so interaction logic remains intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ec6cd92a-be19-438a-b69b-dea9cc13bc41
⛔ Files ignored due to path filters (30)
.yarn/cache/@esbuild-darwin-arm64-npm-0.27.2-d675c4a521-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@esbuild-linux-x64-npm-0.27.2-11f1a3d9db-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@img-sharp-darwin-arm64-npm-0.34.3-8944698b4c-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@img-sharp-libvips-darwin-arm64-npm-1.2.0-2d65006be7-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@img-sharp-libvips-linux-x64-npm-1.2.0-91cf635ac8-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@img-sharp-linux-x64-npm-0.34.3-aa297ca1ca-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@next-swc-darwin-arm64-npm-15.5.18-ac1ed6c8cc-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@rollup-rollup-darwin-arm64-npm-4.59.0-db3495ba42-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@rollup-rollup-linux-x64-gnu-npm-4.59.0-da6c703f69-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@sentry-cli-darwin-npm-2.45.0-76059cfa9f-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@sentry-cli-darwin-npm-2.58.5-1f667e3b9d-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@sentry-cli-linux-x64-npm-2.45.0-6e5f26280b-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@sentry-cli-linux-x64-npm-2.58.5-7cea7778bc-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@unrs-resolver-binding-darwin-arm64-npm-1.11.1-c78d4bd2cb-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**.yarn/cache/@unrs-resolver-binding-linux-x64-gnu-npm-1.11.1-93a00570de-10.zipis excluded by!**/.yarn/**,!**/*.zip,!.yarn/**and included by**src/assets/svg/common/arrow-right-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/bbico-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/bus-time-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/category-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/clipboard-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/fork-knife-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/home-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/koin-title-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/notification-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/notification-on-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/qr-code-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/route-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/sun-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/user-icon.svgis excluded by!**/*.svgand included by**src/assets/svg/common/van-icon.svgis excluded by!**/*.svgand included by**
📒 Files selected for processing (31)
.vscode/settings.jsonsrc/api/dinings/entity.tssrc/api/index.tssrc/api/store/APIDetail.tssrc/api/store/entity.tssrc/api/store/index.tssrc/api/store/queries.tssrc/api/weather/APIDetail.tssrc/api/weather/entity.tssrc/api/weather/index.tssrc/api/weather/queries.tssrc/components/IndexComponents/HomePage/DesktopHome.tsxsrc/components/IndexComponents/HomePage/HomePage.module.scsssrc/components/IndexComponents/HomePage/MobileHome.tsxsrc/components/IndexComponents/HomePage/MobileHomeLegacy.tsxsrc/components/IndexComponents/HomePage/MobileHomeRedesign.module.scsssrc/components/IndexComponents/HomePage/MobileHomeRedesign.tsxsrc/components/IndexComponents/HomePage/index.tsxsrc/components/IndexComponents/HomePage/types.tssrc/components/IndexComponents/IndexMobileCafeteria/IndexMobileCafeteria.module.scsssrc/components/IndexComponents/IndexMobileCafeteria/index.tsxsrc/components/cafeteria/components/CafeteriaInfo/index.tsxsrc/components/layout/Footer/index.tsxsrc/components/layout/Header/MobileHomeRedesignHeader/MobileHomeRedesignHeader.module.scsssrc/components/layout/Header/MobileHomeRedesignHeader/index.tsxsrc/components/layout/HomeLayout/HomeLayout.module.scsssrc/components/layout/HomeLayout/index.tsxsrc/components/layout/MobileBottomNavigation/MobileBottomNavigation.module.scsssrc/components/layout/MobileBottomNavigation/index.tsxsrc/pages/index.tsxsrc/utils/zustand/homeExperiment.ts
💤 Files with no reviewable changes (1)
- src/components/IndexComponents/HomePage/HomePage.module.scss
| "js/ts.tsdk.path": ".yarn/sdks/typescript/lib", | ||
| "js/ts.tsdk.promptToUseWorkspaceVersion": true, |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
VS Code 공식 설정에서 TypeScript SDK 경로/워크스페이스 버전 프롬프트에 해당하는 정확한 setting key가 무엇인지 확인해줘. (typescript.tsdk, typescript.enablePromptUseWorkspaceTsdk, js/ts.tsdk.path, js/ts.tsdk.promptToUseWorkspaceVersion 비교)
💡 Result:
정확한 setting key는 다음과 같습니다. 1) VS Code 공식 설정에서 “워크스페이스 tsdk 버전 사용을 위한 프롬프트”를 제어하는 key - typescript.enablePromptUseWorkspaceTsdk [1][2] 2) VS Code 공식 설정에서 “워크스페이스 tsdk 경로(= tsserver.js가 있는 디렉터리)”를 지정하는 key - js/ts.tsdk.path [3][4] - (참고) 질문에 적어주신 typescript.tsdk도 관련 설정이지만, 문서상 경로 지정은 js/ts.tsdk.path로 설명됩니다. 또한 docs에서도 “tsdk 경로만으로는 IntelliSense에 실제 적용이 바로 되지 않고 TypeScript: Select TypeScript Version 명령으로 실제 사용을 시작해야” 한다고 명시합니다. [3][4] 3) 질문에 적어주신 js/ts.tsdk.promptToUseWorkspaceVersion - 해당 key는 VS Code 공식 문서/근거 자료에서 확인되지 않았습니다. (반대로, 대신 typescript.enablePromptUseWorkspaceTsdk가 프롬프트 관련 설정으로 명시됩니다.) [1][2] 요약(비교) - typescript.tsdk: “workspace에 존재하는 TypeScript SDK를 사용하기 위한 설정”으로 언급되지만, 프롬프트 제어 key는 enablePromptUseWorkspaceTsdk입니다. [1][2] - typescript.enablePromptUseWorkspaceTsdk: “워크스페이스 tsdk 버전 사용을 위한 프롬프트”의 정확한 setting key입니다. [1][2] - js/ts.tsdk.path: workspace의 tsserver.js/lib 위치(= tsdk 경로)를 지정하는 key입니다. [3][4] - js/ts.tsdk.promptToUseWorkspaceVersion: 공식 문서상 근거로 확인되지 않았습니다. (프롬프트는 enablePromptUseWorkspaceTsdk로 제어됩니다.) [1][2]
Citations:
- 1: Revisit notification to ask for TypeScript version in workspace microsoft/vscode#245324
- 2: Combine workspace trust with enablePromptUseWorkspaceTsdk microsoft/vscode#135713
- 3: https://code.visualstudio.com/docs/typescript/typescript-transpiling
- 4: https://github.com/microsoft/vscode-docs/blob/main/docs/typescript/typescript-transpiling.md
VS Code TypeScript SDK 설정 키 불일치 수정 필요
.vscode/settings.json11-12의js/ts.tsdk.path는 문서에 맞는 TypeScript SDK 경로 지정 키입니다.- 그러나
js/ts.tsdk.promptToUseWorkspaceVersion는 VS Code 공식 설정 키로 확인되지 않아 워크스페이스 tsdk “프롬프트/사용” 관련 동작이 누락될 수 있습니다.typescript.enablePromptUseWorkspaceTsdk로 교체하세요.
🤖 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 @.vscode/settings.json around lines 11 - 12, Replace the incorrect VS Code
setting key "js/ts.tsdk.promptToUseWorkspaceVersion" with the correct official
key "typescript.enablePromptUseWorkspaceTsdk" so the workspace TypeScript SDK
prompt behavior works; leave "js/ts.tsdk.path" as-is and update the JSON entry
name accordingly.
| price_card: number | null; | ||
| price_cash: number | null; | ||
| kcal: number | null; | ||
| kcal: number; |
There was a problem hiding this comment.
kcal nullable 제거는 API 계약 불일치 위험이 있습니다.
기존 nullable을 non-null로 바꾸면, 서버가 null을 반환하는 순간 클라이언트 타입 안정성이 깨집니다. 백엔드 계약이 확정되지 않았다면 number | null을 유지하거나, 파싱 레이어에서 null을 명시적으로 정규화해 주세요.
As per coding guidelines "src/api/**: 2. 요청/응답 타입이 명확하게 정의되어 있는지 확인해주세요."
🤖 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 `@src/api/dinings/entity.ts` at line 16, The kcal field was changed to
non-nullable which can break client type-safety if backend may return null;
restore the original nullable contract by changing the kcal declaration back to
number | null in the dining entity (kcal) or, if you prefer a non-nullable
client model, add a parsing/normalization step (e.g., in the DTO/mapper that
constructs the dining entity) that converts backend nulls to a deterministic
value (like 0 or undefined) before populating the kcal property so the runtime
and the TypeScript type remain consistent.
| export default function CafeteriaInfo({ cafeteriaInfo, closeInfo }: CafeteriaInfoProps) { | ||
| const weekday = cafeteriaInfo.opens.filter((schedule) => schedule.day_of_week === '평일'); | ||
| const weekend = cafeteriaInfo.opens.filter((schedule) => schedule.day_of_week === '주말'); | ||
| const weekend = cafeteriaInfo.opens.filter((schedule) => schedule.day_of_week === '토요일'); |
There was a problem hiding this comment.
요일 값 전환기 호환 처리가 있으면 더 안전합니다.
현재는 토요일만 필터링해서, API가 아직 주말 값을 보내는 구간이면 운영시간이 비어 보일 수 있습니다. 전환기라면 주말도 함께 허용하는 게 안전합니다.
예시 수정
- const weekend = cafeteriaInfo.opens.filter((schedule) => schedule.day_of_week === '토요일');
+ const weekend = cafeteriaInfo.opens.filter(
+ (schedule) => schedule.day_of_week === '토요일' || schedule.day_of_week === '주말',
+ );As per coding guidelines "src/**: 가독성·안정성(Null/에러 처리)·테스트/유지보수 용이성·브라우저/접근성 이슈 등을 검토해주세요."
Also applies to: 91-91
🤖 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 `@src/components/cafeteria/components/CafeteriaInfo/index.tsx` at line 50, The
weekend filter currently only checks for schedule.day_of_week === '토요일' which
misses API values like '주말'; update the predicate in the weekend computation
(the cafeteriaInfo.opens.filter call that assigns weekend) to accept both '토요일'
and '주말' (e.g., check against an allowed set or normalize day_of_week) and apply
the same change to the other similar occurrence around the 91-91 region so both
places handle alternate values consistently.
| <span> | ||
| {dining.price_cash && `₩${dining.price_cash.toLocaleString()} · `} | ||
| <strong>{dining.kcal}kcal</strong> | ||
| </span> |
There was a problem hiding this comment.
price_cash가 0일 때 화면에 0이 렌더링될 수 있습니다.
{dining.price_cash && ...}에서 price_cash가 숫자 0이면 단축평가 결과가 0이 되어 React가 그대로 0을 출력합니다(null/undefined는 안전). 무료 식단 등 0원 가능성이 있다면 명시적 비교가 안전합니다.
🐛 제안 수정
- {dining.price_cash && `₩${dining.price_cash.toLocaleString()} · `}
+ {dining.price_cash != null && dining.price_cash > 0 && `₩${dining.price_cash.toLocaleString()} · `}🤖 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 `@src/components/IndexComponents/IndexMobileCafeteria/index.tsx` around lines
32 - 35, The current render uses a truthy check on dining.price_cash which will
output a raw "0" when price_cash is 0; update the conditional in the span of the
IndexMobileCafeteria render so you explicitly test for null/undefined (e.g.,
dining.price_cash != null) rather than using &&; replace the {dining.price_cash
&& `₩${dining.price_cash.toLocaleString()} · `} usage with a ternary or explicit
null check so 0 is formatted with toLocaleString() (or handled as a free meal
text) and then still render <strong>{dining.kcal}kcal</strong> as before.
| {availableDinings.length > 0 && ( | ||
| <div className={styles['meal-tabs']} aria-label="식당 코너 선택"> | ||
| {availableDinings.map((dining) => ( | ||
| <button | ||
| type="button" | ||
| className={`${styles['meal-tabs__button']} ${ | ||
| dining.place === activePlace ? styles['meal-tabs__button--active'] : '' | ||
| }`} | ||
| key={dining.place} | ||
| onClick={() => handleTabClick(dining.place)} | ||
| > | ||
| {dining.place} | ||
| </button> | ||
| ))} | ||
| </div> |
There was a problem hiding this comment.
탭의 활성 상태가 시각(색상)으로만 전달됩니다 — aria 상태 추가를 권장합니다.
현재 활성 코너는 --active 클래스(보라색)로만 구분되어, 스크린리더 사용자는 어떤 코너가 선택되었는지 알 수 없습니다. 버튼에 aria-pressed(혹은 탭 패턴이면 role="tab"/aria-selected)를 추가해주세요.
♿ 제안 수정
<button
type="button"
+ aria-pressed={dining.place === activePlace}
className={`${styles['meal-tabs__button']} ${
dining.place === activePlace ? styles['meal-tabs__button--active'] : ''
}`}
key={dining.place}
onClick={() => handleTabClick(dining.place)}
>📝 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.
| {availableDinings.length > 0 && ( | |
| <div className={styles['meal-tabs']} aria-label="식당 코너 선택"> | |
| {availableDinings.map((dining) => ( | |
| <button | |
| type="button" | |
| className={`${styles['meal-tabs__button']} ${ | |
| dining.place === activePlace ? styles['meal-tabs__button--active'] : '' | |
| }`} | |
| key={dining.place} | |
| onClick={() => handleTabClick(dining.place)} | |
| > | |
| {dining.place} | |
| </button> | |
| ))} | |
| </div> | |
| {availableDinings.length > 0 && ( | |
| <div className={styles['meal-tabs']} aria-label="식당 코너 선택"> | |
| {availableDinings.map((dining) => ( | |
| <button | |
| type="button" | |
| aria-pressed={dining.place === activePlace} | |
| className={`${styles['meal-tabs__button']} ${ | |
| dining.place === activePlace ? styles['meal-tabs__button--active'] : '' | |
| }`} | |
| key={dining.place} | |
| onClick={() => handleTabClick(dining.place)} | |
| > | |
| {dining.place} | |
| </button> | |
| ))} | |
| </div> |
🤖 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 `@src/components/IndexComponents/IndexMobileCafeteria/index.tsx` around lines
110 - 124, The tab buttons rendered from availableDinings are only visually
marked via the --active class so screen readers can't tell which is selected;
update the button JSX in the map (the element that uses availableDinings,
activePlace and handleTabClick) to expose the state by adding accessibility
attributes—either add aria-pressed={dining.place === activePlace} on each
button, or convert to the tab pattern by adding role="tab" and
aria-selected={dining.place === activePlace} (and ensure the container has
role="tablist" if you choose the tab pattern); keep the existing class toggle
and onClick handler (handleTabClick) intact.
| @@ -0,0 +1,10 @@ | |||
| .layout { | |||
| width: 100%; | |||
| min-height: 100vh; | |||
There was a problem hiding this comment.
100vh만 사용하면 모바일에서 레이아웃 점프가 발생할 수 있습니다.
모바일 브라우저 주소창 변화 시 높이 계산이 흔들릴 수 있어 100dvh를 함께 두는 게 안전합니다.
제안 수정안
.layout {
width: 100%;
- min-height: 100vh;
+ min-height: 100vh;
+ min-height: 100dvh;
box-sizing: border-box;As per coding guidelines src/**: "브라우저/접근성 이슈 등을 검토해주세요."
🤖 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 `@src/components/layout/HomeLayout/HomeLayout.module.scss` at line 3, Update
the min-height declaration in HomeLayout.module.scss so mobile viewport changes
don't cause layout jumps: keep the existing fallback then override with dynamic
viewport units by adding a 100dvh rule after the 100vh one (e.g., leave
min-height: 100vh; then add min-height: 100dvh;), targeting the same selector
where min-height is defined in HomeLayout.module.scss.
| <ul className={styles['navigation__list']}> | ||
| {NAVIGATION_ITEMS.map(({ key, label, href, Icon }) => { | ||
| const resolvedHref = key === 'profile' && !token ? ROUTES.Auth() : href; | ||
| const isActive = pathname === resolvedHref || (key === 'profile' && pathname === ROUTES.AuthModifyInfo()); |
There was a problem hiding this comment.
활성 탭 판별을 하위 경로까지 포함하도록 보완해 주세요.
현재 exact match 중심이라 섹션 하위 페이지에서 활성 표시가 풀릴 수 있습니다. 섹션 탭은 prefix 기반 매칭을 같이 두는 편이 UX가 안정적입니다.
예시 수정
- const isActive = pathname === resolvedHref || (key === 'profile' && pathname === ROUTES.AuthModifyInfo());
+ const isProfilePath = pathname === ROUTES.AuthModifyInfo();
+ const isSectionPath = pathname === resolvedHref || pathname.startsWith(`${resolvedHref}/`);
+ const isActive = key === 'profile' ? isSectionPath || isProfilePath : isSectionPath;📝 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 isActive = pathname === resolvedHref || (key === 'profile' && pathname === ROUTES.AuthModifyInfo()); | |
| const isProfilePath = pathname === ROUTES.AuthModifyInfo(); | |
| const isSectionPath = pathname === resolvedHref || pathname.startsWith(`${resolvedHref}/`); | |
| const isActive = key === 'profile' ? isSectionPath || isProfilePath : isSectionPath; |
🤖 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 `@src/components/layout/MobileBottomNavigation/index.tsx` at line 48, The
current active-tab check in MobileBottomNavigation (the isActive assignment
using pathname, resolvedHref and key === 'profile') only does exact matches;
change it to also treat section tabs as active when the current pathname is a
prefix of the tab's route. Update the isActive logic (in index.tsx where
isActive is computed using pathname, resolvedHref, and key) to return true when
pathname === resolvedHref OR pathname.startsWith(resolvedHref + '/') (and
preserve the special-case profile check using ROUTES.AuthModifyInfo()), ensuring
you normalize trailing slashes if needed so nested routes under a tab remain
active.
What is this PR? 🔍
Changes 📝
ScreenShot 📷
Test CheckList ✅
Precaution
✔️ Please check if the PR fulfills these requirements
developbranch unconditionally?main?yarn lintSummary by CodeRabbit
릴리스 노트
New Features
Refactor
Chores