Skip to content

삐봇 테스트#1269

Closed
ff1451 wants to merge 5 commits into
developfrom
feat/home-redesign
Closed

삐봇 테스트#1269
ff1451 wants to merge 5 commits into
developfrom
feat/home-redesign

Conversation

@ff1451

@ff1451 ff1451 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor
  • Close #ISSUE_NUMBER

What is this PR? 🔍

  • 기능 :
  • issue : #

Changes 📝

ScreenShot 📷

Test CheckList ✅

  • test 1
  • test 2
  • test 3

Precaution

✔️ Please check if the PR fulfills these requirements

  • It's submitted to the correct branch, not the develop branch unconditionally?
  • If on a hotfix branch, ensure it targets main?
  • There are no warning message when you run yarn lint

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 모바일 홈페이지 리디자인 추가 (날씨, 교통, 매장 정보 통합 표시)
    • 날씨 정보 API 추가
    • 모바일 하단 네비게이션 추가
    • 매장 카운트 및 이벤트 정보 API 추가
  • Refactor

    • 홈페이지 레이아웃 구조 개선
    • Footer 컴포넌트 간소화
  • Chores

    • VS Code TypeScript 설정 업데이트

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ff1451, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e04f2aa7-cabf-4e5c-92ca-e6f54c209f51

📥 Commits

Reviewing files that changed from the base of the PR and between 171ff26 and 2da3db0.

📒 Files selected for processing (4)
  • src/components/IndexComponents/HomePage/MobileHomeRedesign.tsx
  • src/components/IndexComponents/IndexMobileCafeteria/index.tsx
  • src/components/layout/Header/MobileHomeRedesignHeader/index.tsx
  • src/components/layout/MobileBottomNavigation/index.tsx

개요

홈페이지 구조를 데스크톱과 모바일로 완전히 분리하고 모바일 환경을 리디자인합니다. 날씨 및 매장 카운트 API를 추가하고, 새로운 모바일 홈 컴포넌트, 하단 네비게이션, 모바일 카페테리아 UI를 도입하며, Zustand 기반 홈 실험 상태 관리를 추가합니다.

변경사항

홈페이지 모바일 리디자인 및 구조 재구성

레이어 / 파일 요약
API 레이어 확장
src/api/weather/*, src/api/store/APIDetail.ts, src/api/store/entity.ts, src/api/store/index.ts, src/api/store/queries.ts, src/api/index.ts
날씨 정보 조회 API (WeatherInfo, WeatherResponse, weatherQueries)와 매장 카운트 API (StoreCounts, StoreEventCount, StoreCountsResponse, StoreEventCountResponse)를 추가하고 React Query 쿼리 구성을 정의합니다.
홈 레이아웃 기반 페이지 구조
src/utils/zustand/homeExperiment.ts, src/components/layout/HomeLayout/*, src/pages/index.tsx
Zustand 스토어로 모바일 리디자인 A/B 테스트 variant를 관리하고, HomeLayout 컴포넌트에서 미디어 쿼리와 variant에 따라 헤더, 네비게이션, 레이아웃을 조건부 렌더링하며, 페이지 레벨에서 HomePage로 통합합니다.
모바일 홈 리디자인 UI
src/components/IndexComponents/HomePage/MobileHomeRedesign.tsx, src/components/IndexComponents/HomePage/MobileHomeRedesign.module.scss
새로운 모바일 홈 화면을 구현하여 날씨, 사용자 인사말, 식단, 교통(콜밴, 버스), 주변 상점 섹션을 각각 쿼리 데이터로 표시합니다.
모바일 카페테리아 UI
src/components/IndexComponents/IndexMobileCafeteria/index.tsx, src/components/IndexComponents/IndexMobileCafeteria/IndexMobileCafeteria.module.scss
식단 데이터를 캐러셀로 표시하고 코너별 탭으로 필터링하며, 스크롤 동기화와 부드러운 스크롤 네비게이션을 구현합니다.
모바일 네비게이션 및 헤더
src/components/layout/MobileBottomNavigation/*, src/components/layout/Header/MobileHomeRedesignHeader/*
하단 고정 네비게이션 (홈/카테고리/게시판/프로필)을 구현하고, 프로필 링크는 토큰 상태에 따라 동적으로 결정하며, 리디자인 전용 헤더에 로고와 알림 아이콘을 배치합니다.
홈페이지 분기 및 레거시 지원
src/components/IndexComponents/HomePage/index.tsx, src/components/IndexComponents/HomePage/DesktopHome.tsx, src/components/IndexComponents/HomePage/MobileHome.tsx, src/components/IndexComponents/HomePage/MobileHomeLegacy.tsx
미디어 쿼리로 데스크톱/모바일을 분기하고, 모바일 환경에서 실험 variant에 따라 리디자인 또는 레거시 버전을 선택 렌더링합니다.
홈페이지 타입 정의 및 스타일
src/components/IndexComponents/HomePage/types.ts, src/components/IndexComponents/HomePage/HomePage.module.scss
홈페이지 컴포넌트가 필요로 하는 배너, 카테고리, 핫클럽 데이터 타입을 정의하고, 모바일 레이아웃의 최소 폭과 간격을 조정합니다.
마이너 조정 및 정리
.vscode/settings.json, src/api/dinings/entity.ts, src/components/cafeteria/components/CafeteriaInfo/index.tsx, src/components/layout/Footer/index.tsx
VS Code TypeScript SDK 설정 추가, OriginalDining.kcal을 non-nullable로 변경, 카페테리아 정보에서 "주말" 표기를 "토요일"로 변경, Footer를 모바일 환경에서 조기 종료하도록 리팩토링합니다.

시퀀스 다이어그램

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
Loading

예상 코드 리뷰 난이도

🎯 4 (복잡함) | ⏱️ ~50분

관련 PR

  • BCSDLab/KOIN_WEB_RECODE#1264: 홈화면 컴포넌트 분리 및 모바일 리디자인 구현에서 동일 파일 및 기능 변경이 겹침

추천 레이블

✨ Feature

추천 리뷰어

  • hyejun0228
  • dooohun
  • ParkSungju01
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning PR 제목 '삐봇 테스트'는 변경 사항과 무관하며, 실제 내용인 홈 화면 리디자인과 API 통합을 반영하지 않습니다. PR 제목을 '홈 화면 리디자인: 모바일/데스크톱 레이아웃 분리 및 날씨/상점 API 통합' 또는 유사한 실질적 내용을 설명하는 제목으로 변경하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/home-redesign

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 916db03 and 171ff26.

⛔ Files ignored due to path filters (30)
  • .yarn/cache/@esbuild-darwin-arm64-npm-0.27.2-d675c4a521-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@esbuild-linux-x64-npm-0.27.2-11f1a3d9db-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@img-sharp-darwin-arm64-npm-0.34.3-8944698b4c-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@img-sharp-libvips-darwin-arm64-npm-1.2.0-2d65006be7-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@img-sharp-libvips-linux-x64-npm-1.2.0-91cf635ac8-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@img-sharp-linux-x64-npm-0.34.3-aa297ca1ca-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@next-swc-darwin-arm64-npm-15.5.18-ac1ed6c8cc-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@rollup-rollup-darwin-arm64-npm-4.59.0-db3495ba42-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@rollup-rollup-linux-x64-gnu-npm-4.59.0-da6c703f69-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@sentry-cli-darwin-npm-2.45.0-76059cfa9f-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@sentry-cli-darwin-npm-2.58.5-1f667e3b9d-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@sentry-cli-linux-x64-npm-2.45.0-6e5f26280b-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@sentry-cli-linux-x64-npm-2.58.5-7cea7778bc-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@unrs-resolver-binding-darwin-arm64-npm-1.11.1-c78d4bd2cb-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • .yarn/cache/@unrs-resolver-binding-linux-x64-gnu-npm-1.11.1-93a00570de-10.zip is excluded by !**/.yarn/**, !**/*.zip, !.yarn/** and included by **
  • src/assets/svg/common/arrow-right-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/bbico-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/bus-time-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/category-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/clipboard-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/fork-knife-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/home-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/koin-title-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/notification-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/notification-on-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/qr-code-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/route-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/sun-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/user-icon.svg is excluded by !**/*.svg and included by **
  • src/assets/svg/common/van-icon.svg is excluded by !**/*.svg and included by **
📒 Files selected for processing (31)
  • .vscode/settings.json
  • src/api/dinings/entity.ts
  • src/api/index.ts
  • src/api/store/APIDetail.ts
  • src/api/store/entity.ts
  • src/api/store/index.ts
  • src/api/store/queries.ts
  • src/api/weather/APIDetail.ts
  • src/api/weather/entity.ts
  • src/api/weather/index.ts
  • src/api/weather/queries.ts
  • src/components/IndexComponents/HomePage/DesktopHome.tsx
  • src/components/IndexComponents/HomePage/HomePage.module.scss
  • src/components/IndexComponents/HomePage/MobileHome.tsx
  • src/components/IndexComponents/HomePage/MobileHomeLegacy.tsx
  • src/components/IndexComponents/HomePage/MobileHomeRedesign.module.scss
  • src/components/IndexComponents/HomePage/MobileHomeRedesign.tsx
  • src/components/IndexComponents/HomePage/index.tsx
  • src/components/IndexComponents/HomePage/types.ts
  • src/components/IndexComponents/IndexMobileCafeteria/IndexMobileCafeteria.module.scss
  • src/components/IndexComponents/IndexMobileCafeteria/index.tsx
  • src/components/cafeteria/components/CafeteriaInfo/index.tsx
  • src/components/layout/Footer/index.tsx
  • src/components/layout/Header/MobileHomeRedesignHeader/MobileHomeRedesignHeader.module.scss
  • src/components/layout/Header/MobileHomeRedesignHeader/index.tsx
  • src/components/layout/HomeLayout/HomeLayout.module.scss
  • src/components/layout/HomeLayout/index.tsx
  • src/components/layout/MobileBottomNavigation/MobileBottomNavigation.module.scss
  • src/components/layout/MobileBottomNavigation/index.tsx
  • src/pages/index.tsx
  • src/utils/zustand/homeExperiment.ts
💤 Files with no reviewable changes (1)
  • src/components/IndexComponents/HomePage/HomePage.module.scss

Comment thread .vscode/settings.json
Comment on lines +11 to +12
"js/ts.tsdk.path": ".yarn/sdks/typescript/lib",
"js/ts.tsdk.promptToUseWorkspaceVersion": true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 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:


VS Code TypeScript SDK 설정 키 불일치 수정 필요

  • .vscode/settings.json 11-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.

Comment thread src/api/dinings/entity.ts
price_card: number | null;
price_cash: number | null;
kcal: number | null;
kcal: number;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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 === '토요일');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

요일 값 전환기 호환 처리가 있으면 더 안전합니다.

현재는 토요일만 필터링해서, 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.

Comment on lines +32 to +35
<span>
{dining.price_cash && `₩${dining.price_cash.toLocaleString()} · `}
<strong>{dining.kcal}kcal</strong>
</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

price_cash0일 때 화면에 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.

Comment on lines +110 to +124
{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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

탭의 활성 상태가 시각(색상)으로만 전달됩니다 — 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.

Suggested change
{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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

활성 탭 판별을 하위 경로까지 포함하도록 보완해 주세요.

현재 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.

Suggested change
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.

@ff1451 ff1451 closed this Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant