Skip to content

Conversation

@yeonjin719
Copy link
Member

🚨 관련 이슈

#91

✨ 변경사항

  • 🐞 BugFix Something isn't working
  • 💻 CrossBrowsing Browser compatibility
  • 🌏 Deploy Deploy
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, etc.)
  • ✨ Feature Feature
  • 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related (storybook, jest, etc.)

✏️ 작업 내용

  • 홈 화면에 있는 API 전부 연결
  • 모달 생성

😅 미완성 작업

  • 배너 움직일 때 리렌더링 문제

📢 논의 사항 및 참고 사항

@yeonjin719 yeonjin719 linked an issue Aug 12, 2025 that may be closed by this pull request
8 tasks
@coderabbitai
Copy link

coderabbitai bot commented Aug 12, 2025

Caution

Review failed

The pull request is closed.

Summary by CodeRabbit

  • New Features
    • 홈 대시보드가 실데이터로 동작: 사용자 등급, 평균/내 데이트 횟수, 월별 장소 그래프, 저장 수 표시
    • 주간 날씨 추천과 강수 확률 차트, 지역 기반 추천/헤더, 지역 변경 모달 추가
    • 이번 주 인기 키워드 워드클라우드 적용
    • 배너 슬라이드별 이미지와 가독성 오버레이 적용
    • 로딩 스피너 표시 및 오류 시 오류 페이지로 이동, 공지 목록 키보드 내비게이션 지원
  • Chores
    • 경로 별칭 도입 및 API/쿼리 훅/타입 정비

Walkthrough

홈 대시보드 관련 API·타입·훅·유틸을 다수 추가하고 정적 컴포넌트들을 실데이터 기반으로 전환했습니다. 지역 변경 모달과 쿼리 키가 도입되었고 차트 옵션·상수·경로 별칭 및 axios import 경로가 정비되었습니다. (요약: 데이터 연동·모달·유틸·타입·쿼리 확장)

Changes

Cohort / File(s) Change Summary
Home API 추가
src/api/home/dateCourse.ts, src/api/home/dateTimes.ts, src/api/home/keyword.ts, src/api/home/level.ts, src/api/home/region.ts, src/api/home/weather.ts
홈 관련 HTTP 래퍼 추가: 데이트 코스 저장수, 월별 장소/데이트 통계, 주간 키워드, 유저 등급, 유저 지역 조회/패치, 주간 날씨/강수 조회 구현.
Notice API 개편
src/api/notice/notice.ts
fetchNotices 파라미터 형태를 TRequestGetNoticeRequest로 변경하여 noticeCategory 필드로 전달하도록 수정.
Axios import 별칭화
src/api/alarm/alarm.ts, src/api/auth/auth.ts, src/api/course/course.ts
axiosInstance import 경로를 상대경로에서 @/api/axiosInstance로 변경(동작 동일).
Home Hooks 추가
src/hooks/home/useDateCourseStates.ts, src/hooks/home/useDatePlaceStates.ts, src/hooks/home/useDateTimes.ts, src/hooks/home/useUserGrade.ts, src/hooks/home/useUserRegion.ts, src/hooks/home/useWeather.ts, src/hooks/home/useKeywordStates.ts
React Query 훅 신설: 각 API에 대응하는 쿼리/뮤테이션 훅(키 및 옵션 포함).
Notice Hooks 추가
src/hooks/notices/useGetNotices.ts
공지용 useInfiniteQuery 훅 추가(페이징/다음 페이지 계산).
Query Key 추가
src/queryKey/queryKey.ts
HomeKeys, NoticeKeys 도입 및 세부 키 정의(파라미터화 포함).
타입 추가 (Home)
src/types/home/dateCourse.ts, src/types/home/datePlace.ts, src/types/home/keyword.ts, src/types/home/level.ts, src/types/home/region.ts, src/types/home/weather.ts
각 API 요청/응답 타입 및 인터페이스 추가.
타입 추가 (Notice)
src/types/notice/notice.ts
TRequestGetNoticeRequest 타입 추가.
상수/차트 옵션 추가
src/constants/weather.ts, src/constants/chartOptions.ts
날씨 관련 enum/라벨과 Chart.js 라인 차트 옵션 추가.
유틸 추가
src/utils/getTodayString.ts, src/utils/getNextSevenDay.ts, src/utils/normalizeEmojiKey.ts, src/utils/weatherMessage.ts
날짜 포맷/주간 날짜 생성, 이모지 정규화, 날씨 문장 생성 유틸 추가.
Modal 시스템 확장
src/components/common/modalProvider.tsx, src/components/modal/regionModal.tsx
MODAL_TYPES/COMPONENTS에 RegionModal 등록 및 RegionModal 컴포넌트 추가(검색 → 선택 → patch).
홈 컴포넌트 데이터 연동
src/components/home/dateCourseStore.tsx, src/components/home/dateLocation.tsx, src/components/home/dateRecommend.tsx, src/components/home/dateTimes.tsx, src/components/home/info.tsx, src/components/home/wordCloud.tsx
정적값을 API 기반 렌더링으로 전환, 로딩/에러 처리 추가, 차트/워드클라우드/날씨 UI 동적화. 일부 컴포넌트의 export/시그니처 변경 포함.
Level 컴포넌트 시그니처 변경
src/components/home/level.tsx, src/pages/home/HomePage.tsx
Level 컴포넌트가 { grade, nextRequiredPoint } props를 받도록 변경 및 HomePage에서 데이터 전달.
Notice 페이지 반영
src/pages/notice/Notice.tsx
fetchNotices 호출에서 요청 파라미터명을 noticeCategory로 사용하도록 변경.
React Query 기본값 확장
src/hooks/customQuery.ts
useCoreQueryoptions?.staleTime을 우선 사용하도록 변경(기본 5분 유지).
경로 별칭 설정
tsconfig.json
baseUrl 및 "@/*": ["src/*"] 경로 매핑 추가(애플리케이션 전반 import에 영향).

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant HomePage
  participant useUserGrade
  participant API_getUserGrade
  User->>HomePage: 홈 접속
  HomePage->>useUserGrade: 쿼리 실행
  useUserGrade->>API_getUserGrade: GET /api/v1/members/grade
  API_getUserGrade-->>useUserGrade: grade 데이터
  useUserGrade-->>HomePage: data / isLoading / error
  HomePage-->>User: 로딩/에러/Level 렌더링
Loading
sequenceDiagram
  actor User
  participant DateRecommend
  participant useGetUserRegion
  participant useWeatherForecast
  participant useRainyInfo
  participant WeatherAPI
  User->>DateRecommend: 화면 진입
  DateRecommend->>useGetUserRegion: 현재 지역 조회
  useGetUserRegion-->>DateRecommend: regionId
  DateRecommend->>useWeatherForecast: startDate, regionId
  DateRecommend->>useRainyInfo: startDate, regionId
  useWeatherForecast->>WeatherAPI: GET /api/v1/weather/{regionId}/weekly
  useRainyInfo->>WeatherAPI: GET /api/v1/weather/{regionId}/precipitation
  WeatherAPI-->>useWeatherForecast: 주간 추천
  WeatherAPI-->>useRainyInfo: 강수 데이터
  useWeatherForecast-->>DateRecommend: forecastData
  useRainyInfo-->>DateRecommend: rainyData
  DateRecommend-->>User: 날씨 추천/차트 표시
Loading
sequenceDiagram
  actor User
  participant RegionModal
  participant useSearchRegion
  participant useUserRegion_patch
  participant RegionAPI
  User->>RegionModal: 검색어 입력/검색
  RegionModal->>useSearchRegion: refetch(keyword)
  useSearchRegion->>RegionAPI: GET /regions/search
  RegionAPI-->>useSearchRegion: 결과
  useSearchRegion-->>RegionModal: region list
  User->>RegionModal: 지역 선택
  RegionModal->>useUserRegion_patch: mutate({ regionId })
  useUserRegion_patch->>RegionAPI: PATCH /api/v1/regions/users
  RegionAPI-->>useUserRegion_patch: 업데이트 응답
  useUserRegion_patch-->>RegionModal: onSuccess
  RegionModal-->>User: 모달 닫힘
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • yujin5959
  • Seojegyeong
  • SEBINorSEBOUT

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f9d4ab and c1b8da1.

⛔ Files ignored due to path filters (4)
  • src/images/banner/bicycle.png is excluded by !**/*.png
  • src/images/banner/bukchon.png is excluded by !**/*.png
  • src/images/banner/itaewon.png is excluded by !**/*.png
  • src/images/banner/sungsu.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • src/components/home/banner.tsx (2 hunks)
  • src/components/home/dateLocation.tsx (1 hunks)
  • src/components/home/dateTimes.tsx (1 hunks)
  • src/components/home/info.tsx (2 hunks)
  • src/components/home/level.tsx (1 hunks)
  • src/components/home/wordCloud.tsx (3 hunks)
  • src/components/modal/regionModal.tsx (1 hunks)
  • src/hooks/home/useDateCourseStates.ts (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 56

🔭 Outside diff range comments (4)
src/components/home/banner.tsx (3)

41-48: 주석과 실제 동작 불일치 (3000ms는 3초)

주석에 “2초”라고 되어 있으나 실제 간격은 3000ms(3초)입니다. 혼선을 줄이기 위해 주석을 정정하거나, 의도대로라면 2000ms로 수정해 주세요.

주석만 정정하는 경우:

-        }, 3000); // 2초
+        }, 3000); // 3초

89-94: 이전/다음 버튼 접근성 보강 (aria-label/title, type="button")

스크린리더 사용자와 폼 내 사용 시를 고려해 버튼에 명확한 라벨과 타입을 지정하는 것을 권장합니다.

-                <button className="ml-5 flex items-center justify-center w-8 h-8 text-white" onClick={goToPrev}>
+                <button
+                    type="button"
+                    aria-label="이전 배너"
+                    title="이전 배너"
+                    className="ml-5 flex items-center justify-center w-8 h-8 text-white"
+                    onClick={goToPrev}
+                >
@@
-                <button className="flex items-center justify-center w-8 h-8 text-white" onClick={goToNext}>
+                <button
+                    type="button"
+                    aria-label="다음 배너"
+                    title="다음 배너"
+                    className="flex items-center justify-center w-8 h-8 text-white"
+                    onClick={goToNext}
+                >

71-79: 리스트 key 안정성 소폭 개선 (index → 값 자체)

정적 리스트이긴 하지만, 가능하면 index 대신 고유한 값(tag)을 key로 쓰는 편이 안전합니다.

-                            key={i}
+                            key={tag}
src/components/home/info.tsx (1)

15-20: button 기본 타입 지정 누락 (폼 내 오동작 예방)

button은 기본적으로 type="submit"입니다. 해당 컴포넌트가 폼 내에서 재사용될 경우 의도치 않은 제출을 유발할 수 있으므로 type="button"을 명시해 주세요.

아래와 같이 수정 제안드립니다:

-                    <button
+                    <button
+                        type="button"
                         className="text-default-gray-800 font-semibold flex justify-center items-center gap-1 whitespace-nowrap hover:cursor-pointer"
                         onClick={() => navigate('/notice')}
                     >
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6fdc4c2 and 9e61971.

⛔ Files ignored due to path filters (1)
  • src/assets/icons/weather/rain.svg is excluded by !**/*.svg
📒 Files selected for processing (40)
  • src/api/home/dateCourse.ts (1 hunks)
  • src/api/home/datePlace.ts (1 hunks)
  • src/api/home/dateTimes.ts (1 hunks)
  • src/api/home/keyword.ts (1 hunks)
  • src/api/home/level.ts (1 hunks)
  • src/api/home/region.ts (1 hunks)
  • src/api/home/weather.ts (1 hunks)
  • src/components/common/modalProvider.tsx (2 hunks)
  • src/components/home/banner.tsx (2 hunks)
  • src/components/home/dateCourseStore.tsx (2 hunks)
  • src/components/home/dateLocation.tsx (1 hunks)
  • src/components/home/dateRecommend.tsx (1 hunks)
  • src/components/home/dateTimes.tsx (1 hunks)
  • src/components/home/info.tsx (2 hunks)
  • src/components/home/level.tsx (1 hunks)
  • src/components/home/wordCloud.tsx (3 hunks)
  • src/components/modal/regionModal.tsx (1 hunks)
  • src/constants/chartOptions.ts (1 hunks)
  • src/constants/weather.ts (1 hunks)
  • src/hooks/customQuery.ts (0 hunks)
  • src/hooks/home/useDateCourseStats.ts (1 hunks)
  • src/hooks/home/useDatePlaceStates.ts (1 hunks)
  • src/hooks/home/useDateTimes.ts (1 hunks)
  • src/hooks/home/useKeywordStats.ts (1 hunks)
  • src/hooks/home/useUserGrade.ts (1 hunks)
  • src/hooks/home/useUserRegion.ts (1 hunks)
  • src/hooks/home/useWeather.ts (1 hunks)
  • src/pages/home/HomePage.tsx (2 hunks)
  • src/queryKey/queryKey.ts (1 hunks)
  • src/types/home/dateCourse.ts (1 hunks)
  • src/types/home/datePlace.ts (1 hunks)
  • src/types/home/dateTimes.ts (1 hunks)
  • src/types/home/keyword.ts (1 hunks)
  • src/types/home/level.ts (1 hunks)
  • src/types/home/region.ts (1 hunks)
  • src/types/home/weather.ts (1 hunks)
  • src/utils/getNextSevenDay.ts (1 hunks)
  • src/utils/getTodayString.ts (1 hunks)
  • src/utils/normalizeEmojiKey.ts (1 hunks)
  • src/utils/weatherMessage.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/hooks/customQuery.ts
🧰 Additional context used
🧬 Code Graph Analysis (26)
src/types/home/dateTimes.ts (1)
src/api/axiosInstance.ts (1)
  • IRefreshResponse (6-10)
src/types/home/dateCourse.ts (1)
src/api/axiosInstance.ts (1)
  • IRefreshResponse (6-10)
src/utils/weatherMessage.ts (1)
src/constants/weather.ts (2)
  • WeatherTypeLabel (10-17)
  • TempCategoryLabel (26-31)
src/utils/getTodayString.ts (2)
src/utils/formatDateInput.tsx (1)
  • formatDateInput (1-11)
src/pages/auth/UserSetting.tsx (1)
  • e (109-112)
src/types/home/keyword.ts (2)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/components/dateCourse/dateKeyword.tsx (1)
  • DateKeyword (5-33)
src/api/home/region.ts (1)
src/types/home/region.ts (2)
  • TPatchUserRegionRequest (3-5)
  • TPatchUserRegionResponse (7-12)
src/hooks/home/useKeywordStats.ts (2)
src/hooks/customQuery.ts (2)
  • useCoreQuery (7-18)
  • useCoreMutation (20-28)
src/hooks/course/useSearchRegion.tsx (2)
  • useSearchRegion (6-11)
  • searchRegion (7-7)
src/types/home/region.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/hooks/home/useDateTimes.ts (2)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/types/home/datePlace.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/hooks/home/useWeather.ts (2)
src/hooks/customQuery.ts (2)
  • useCoreQuery (7-18)
  • useCoreMutation (20-28)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/types/home/level.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/hooks/home/useDateCourseStats.ts (2)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/hooks/home/useUserRegion.ts (4)
src/hooks/auth/useAuth.ts (1)
  • useAuth (5-14)
src/hooks/course/useSearchRegion.tsx (2)
  • useSearchRegion (6-11)
  • searchRegion (7-7)
src/hooks/customQuery.ts (2)
  • useCoreMutation (20-28)
  • useCoreQuery (7-18)
src/pages/auth/UserSetting.tsx (1)
  • User (23-178)
src/api/home/weather.ts (1)
src/types/home/weather.ts (4)
  • TGetWeeklyWeatheerRecommendationRequest (5-8)
  • TGetWeeklyWeatheerRecommendationResponse (25-32)
  • TGetPrecipitationRequest (34-37)
  • TGetPrecipitationResponse (38-45)
src/hooks/home/useUserGrade.ts (1)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/api/home/level.ts (1)
src/types/home/level.ts (1)
  • TUserGradeResponse (4-4)
src/hooks/home/useDatePlaceStates.ts (2)
src/hooks/customQuery.ts (2)
  • useCoreQuery (7-18)
  • useCoreMutation (20-28)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/components/modal/regionModal.tsx (5)
src/components/common/modal.tsx (1)
  • Modal (15-43)
src/hooks/course/useSearchRegion.tsx (2)
  • useSearchRegion (6-11)
  • searchRegion (7-7)
src/components/common/EditableInputBox.tsx (1)
  • EditableInputBox (20-126)
src/components/modal/errorModal.tsx (1)
  • ErrorModal (8-17)
src/pages/TestInputPage.tsx (1)
  • TestInputPage (8-46)
src/components/common/modalProvider.tsx (5)
src/components/common/modal.tsx (1)
  • Modal (15-43)
src/store/useModalStore.ts (5)
  • IModalState (3-9)
  • set (11-37)
  • payload (15-30)
  • payload (16-30)
  • modalType (32-36)
src/components/modal/SettingModal.tsx (1)
  • SettingsModal (16-55)
src/components/modal/errorModal.tsx (1)
  • ErrorModal (8-17)
src/components/modal/dateCourseSearchFilterModal.tsx (1)
  • DateCourseSearchFilterModal (40-127)
src/components/home/info.tsx (1)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/home/dateCourseStore.tsx (3)
src/pages/dateCourse/CoursePage.tsx (2)
  • Course (12-65)
  • navigate (38-38)
src/pages/dateCourse/MakeCourseResult.tsx (1)
  • MakeCourseResult (11-39)
src/pages/dateCourse/MakeCourse.tsx (2)
  • MakeCourse (8-29)
  • navigate (13-13)
src/components/home/level.tsx (5)
src/types/home/level.ts (1)
  • IGradeInfo (7-13)
src/pages/dateTest/DateTestStep.tsx (1)
  • ProgressBar (17-24)
src/components/datetest/ProgressBar.tsx (2)
  • ProgressBar (6-14)
  • IProgressBarProps (1-4)
src/pages/dateCourse/MakeCourseStep.tsx (1)
  • ProgressBar (30-37)
src/pages/dateTest/DatetestResult.tsx (1)
  • item (102-135)
src/pages/home/HomePage.tsx (3)
src/pages/dateCourse/CoursePage.tsx (1)
  • Course (12-65)
src/pages/dateCourse/MakeCourseResult.tsx (1)
  • MakeCourseResult (11-39)
src/components/dateCourse/dateCourseLoading.tsx (1)
  • DateCourseLoading (4-18)
src/components/home/dateRecommend.tsx (4)
src/utils/getTodayString.ts (1)
  • getTodayString (1-7)
src/utils/getNextSevenDay.ts (1)
  • getNextSevenDay (1-21)
src/utils/normalizeEmojiKey.ts (1)
  • normalizeEmojiKey (1-10)
src/utils/weatherMessage.ts (1)
  • getWeatherSentence (4-6)
src/types/home/weather.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
🪛 Biome (2.1.2)
src/components/modal/regionModal.tsx

[error] 59-62: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

src/components/home/dateRecommend.tsx

[error] 103-106: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🔇 Additional comments (20)
src/utils/getTodayString.ts (1)

1-7: API 날짜 포맷 사양 확인 요청 (하이픈 vs 점 구분자)
getTodayString(src/utils/getTodayString.ts)는 YYYY-MM-DD를 반환하지만,
formatDateInput(src/utils/formatDateInput.tsx)은 YYYY.MM.DD를 사용하고 있습니다.
특히 getTodayString의 반환값은 아래 경로에서 API 호출 시 startDate 파라미터로 전달됩니다:

  • src/utils/getTodayString.ts: YYYY-MM-DD 반환
  • src/components/home/dateRecommend.tsx → src/api/home/weather.ts: startDate로 사용

백엔드(API/서버)가 어떤 구분자를 요구하는지 한 번 확인해 주세요.
필요 시 formatDate(date, "YYYY-MM-DD" | "YYYY.MM.DD") 형태의 공용 포맷터를 만들어 포맷을 일원화하는 것을 제안드립니다.

src/components/home/info.tsx (1)

1-1: 메모이제이션 적용 적절

프롭스가 없고 정적 UI 성격이 강한 컴포넌트에 memo 적용은 불필요 렌더링을 줄이는 데 유효합니다.

src/utils/normalizeEmojiKey.ts (1)

1-10: 유니코드 정규화/필터링 로직 적절

이모지 변형 선택자/ZWJ 제거와 NFKD 정규화 후 결합표식 제거 방식은 키 정규화에 적합합니다. 가독성과 목적이 분명합니다.

src/hooks/home/useUserRegion.ts (1)

5-8: 패턴 일관성/LGTM

기존 훅 패턴(useAuth 등)과 동일하게 뮤테이션을 래핑해 반환하고 있어 사용성 측면에서 일관적입니다. 타입 추론도 충분히 동작할 것으로 보입니다.

src/hooks/home/useKeywordStats.ts (1)

10-10: 호환성 확인 완료: gcTime 사용 유지
프로젝트가 @tanstack/react-query v5(“^5.76.1”)를 사용 중이므로 gcTime 옵션이 유효합니다. cacheTime으로 변경할 필요가 없습니다.

src/hooks/home/useDateTimes.ts (1)

1-8: LGTM! React Query 훅 구현이 올바릅니다.

훅 구현이 적절하며, 캐싱 옵션 설정도 합리적입니다. 다른 유사한 훅들과 일관된 패턴을 따르고 있어 좋습니다.

src/components/common/modalProvider.tsx (1)

9-9: LGTM! RegionModal 통합이 올바릅니다.

RegionModal이 기존 모달 시스템에 올바르게 통합되었습니다. import, 타입 정의, 컴포넌트 매핑이 모두 일관된 패턴을 따르고 있어 좋습니다.

Also applies to: 20-20, 28-28

src/types/home/level.ts (2)

1-5: 응답 타입 래핑(TCommonResponse) 적용 적절

공통 응답 타입으로 래핑된 선언이 일관적이며 사용성도 좋습니다.


10-12: level 필드 사용처 숫자 연산/비교 검토 필요

실행한 스크립트에서 .level에 대한 직접적인 숫자 연산(+, -, *, /, %), 비교 연산(<, >, <=, >=), Number(), parseInt() 호출이 검색되지 않았습니다.
그러나 구조 분해 할당이나 다른 변수명으로 사용되는 경우 검색에서 누락될 수 있으므로, 아래를 추가 확인 부탁드립니다:

  • 구조 분해 할당(const { level } = …) 또는 함수 인자로 전달된 level이 숫자 연산/비교에 사용되는지
  • 필요 시 level 타입을 number로 변경하거나, 값이 필요한 로직 직전에 parseInt/Number 변환 로직 추가
src/types/home/keyword.ts (1)

3-12: 키워드 응답/아이템 타입 분리 적절

응답 타입과 아이템 인터페이스가 명확하게 분리되어 이해하기 쉽습니다.

src/hooks/home/useDatePlaceStates.ts (1)

7-11: gcTime 옵션 사용 적합 (React Query v5 확인됨)

  • package.json에서 @tanstack/react-query: ^5.76.1로 v5 버전을 사용 중입니다.
  • React Query v5에서는 cacheTimegcTime으로 변경되었으므로, 해당 코드(gcTime)를 그대로 유지하시면 됩니다.
src/pages/home/HomePage.tsx (1)

24-30: 로딩 UI 처리 적절

전체 화면 로딩 스피너 배치와 배경 처리 모두 자연스럽습니다.

src/queryKey/queryKey.ts (1)

11-20: HomeKeys 네임스페이스가 잘 구성되었습니다.

홈 도메인의 다양한 API를 위한 쿼리 키가 체계적으로 정의되어 있으며, 매개변수가 필요한 weather와 rainyInfo 키도 적절히 처리되었습니다.

src/types/home/region.ts (1)

1-20: 타입 정의가 명확합니다.

지역 관련 API 요청/응답 타입이 적절히 정의되어 있고, TCommonResponse를 활용한 일관된 구조를 따르고 있습니다.

src/components/home/dateTimes.tsx (2)

8-8: 데이터 구조화가 잘 되었습니다.

useDateTimesStats 훅을 통해 API 데이터를 가져오고 로딩/에러 상태를 적절히 처리했습니다.


53-53: memo 적용이 적절합니다.

컴포넌트에 React.memo를 적용하여 불필요한 리렌더링을 방지했습니다.

src/types/home/datePlace.ts (1)

1-21: 타입 정의가 깔끔합니다!

API 응답 타입과 인터페이스 정의가 명확하고 일관성 있게 작성되었습니다. TCommonResponse를 활용한 타입 구성이 적절합니다.

src/api/home/weather.ts (1)

11-21: API 함수 구현이 깔끔합니다!

날씨 관련 API 함수들이 타입 안전하게 잘 구현되었습니다. 적절한 타입 지정과 구조화된 매개변수 처리가 좋습니다.

src/components/home/dateRecommend.tsx (1)

55-55: 타입 안전성을 위해 명시적인 타입을 사용하세요.

dailyPrecipitations 배열의 요소 타입을 명시적으로 지정하면 타입 안전성이 향상됩니다.

-    const values = rainyData?.result?.dailyPrecipitations?.map((f: { precipitationProbability: number }) => f.precipitationProbability) ?? [];
+    const values = rainyData?.result?.dailyPrecipitations?.map((f) => f.precipitationProbability) ?? [];

Likely an incorrect or invalid review comment.

src/components/home/wordCloud.tsx (1)

37-37: weightFactor 계산식을 검토하세요.

기존 width / 350에서 width / 1500으로 변경되어 폰트 크기가 상당히 작아질 것으로 예상됩니다. 의도한 변경인지 확인이 필요합니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review continued from previous batch...

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 65

🔭 Outside diff range comments (3)
src/components/home/banner.tsx (1)

41-47: 주석과 실제 인터벌(3초) 불일치

현재 interval은 3000ms인데 주석은 "2초"입니다. 주석을 "3초"로 맞추는 편이 혼란이 없습니다.

-        }, 3000); // 2초
+        }, 3000); // 3초
src/components/common/modalProvider.tsx (2)

15-21: MODAL_TYPES에 as const 적용으로 타입 안전성 향상

문자열 literal을 고정하면, modalType을 보다 엄격하게 관리할 수 있어 오타나 잘못된 타입 주입을 컴파일 타임에 방지할 수 있습니다.

-export const MODAL_TYPES = {
+export const MODAL_TYPES = {
     ErrorModal: 'ErrorModal',
     DateCourseSearchFilterModal: 'DateCourseSearchFilterModal',
     SettingsModal: 'SettingsModal', //설정 모달 추가
     AlarmModal: 'AlarmModal',
     RegionModal: 'RegionModal',
-};
+} as const;

추가로, 전역적으로 사용할 수 있도록 타입도 노출하면 좋습니다(파일 바깥 제안 코드):

export type ModalType = typeof MODAL_TYPES[keyof typeof MODAL_TYPES];

34-36: react-hooks/exhaustive-deps: useEffect 의존성에 closeModal 추가 필요

  • 대상: src/components/common/modalProvider.tsx (34–36라인)
  • 설명: ESLint react-hooks/exhaustive-deps 규칙에 따라 closeModal도 의존성 배열에 포함하는 것이 안전합니다. Zustand 액션은 스토어 생성 시 고정된 함수 참조를 반환하므로 동작에는 영향이 없습니다.
   useEffect(() => {
       closeModal();
-  }, [location]);
+  }, [location, closeModal]);

⚠️ 추가 확인: location의 쿼리/해시 변경에도 모달이 닫히는 것이 의도된 동작인지 검토 부탁드립니다.

♻️ Duplicate comments (1)
src/hooks/home/useDateCourseStats.ts (1)

9-11: TanStack Query 옵션 호환성(중복) — gcTime 사용 여부 확인

이 파일도 gcTime을 사용합니다. 앞서 안내한 버전 확인 및 필요 시 cacheTime으로의 교체 제안을 동일하게 적용해 주세요.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6fdc4c2 and 9e61971.

⛔ Files ignored due to path filters (1)
  • src/assets/icons/weather/rain.svg is excluded by !**/*.svg
📒 Files selected for processing (40)
  • src/api/home/dateCourse.ts (1 hunks)
  • src/api/home/datePlace.ts (1 hunks)
  • src/api/home/dateTimes.ts (1 hunks)
  • src/api/home/keyword.ts (1 hunks)
  • src/api/home/level.ts (1 hunks)
  • src/api/home/region.ts (1 hunks)
  • src/api/home/weather.ts (1 hunks)
  • src/components/common/modalProvider.tsx (2 hunks)
  • src/components/home/banner.tsx (2 hunks)
  • src/components/home/dateCourseStore.tsx (2 hunks)
  • src/components/home/dateLocation.tsx (1 hunks)
  • src/components/home/dateRecommend.tsx (1 hunks)
  • src/components/home/dateTimes.tsx (1 hunks)
  • src/components/home/info.tsx (2 hunks)
  • src/components/home/level.tsx (1 hunks)
  • src/components/home/wordCloud.tsx (3 hunks)
  • src/components/modal/regionModal.tsx (1 hunks)
  • src/constants/chartOptions.ts (1 hunks)
  • src/constants/weather.ts (1 hunks)
  • src/hooks/customQuery.ts (0 hunks)
  • src/hooks/home/useDateCourseStats.ts (1 hunks)
  • src/hooks/home/useDatePlaceStates.ts (1 hunks)
  • src/hooks/home/useDateTimes.ts (1 hunks)
  • src/hooks/home/useKeywordStats.ts (1 hunks)
  • src/hooks/home/useUserGrade.ts (1 hunks)
  • src/hooks/home/useUserRegion.ts (1 hunks)
  • src/hooks/home/useWeather.ts (1 hunks)
  • src/pages/home/HomePage.tsx (2 hunks)
  • src/queryKey/queryKey.ts (1 hunks)
  • src/types/home/dateCourse.ts (1 hunks)
  • src/types/home/datePlace.ts (1 hunks)
  • src/types/home/dateTimes.ts (1 hunks)
  • src/types/home/keyword.ts (1 hunks)
  • src/types/home/level.ts (1 hunks)
  • src/types/home/region.ts (1 hunks)
  • src/types/home/weather.ts (1 hunks)
  • src/utils/getNextSevenDay.ts (1 hunks)
  • src/utils/getTodayString.ts (1 hunks)
  • src/utils/normalizeEmojiKey.ts (1 hunks)
  • src/utils/weatherMessage.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/hooks/customQuery.ts
🧰 Additional context used
🧬 Code Graph Analysis (32)
src/utils/weatherMessage.ts (1)
src/constants/weather.ts (2)
  • WeatherTypeLabel (10-17)
  • TempCategoryLabel (26-31)
src/api/home/level.ts (2)
src/types/home/level.ts (1)
  • TUserGradeResponse (4-4)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/hooks/home/useDateCourseStats.ts (3)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-17)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-20)
src/api/home/dateCourse.ts (1)
  • getDateCourseSavedCount (5-12)
src/hooks/home/useUserGrade.ts (3)
src/hooks/customQuery.ts (2)
  • useCoreQuery (7-17)
  • useCoreMutation (20-28)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-20)
src/api/home/level.ts (1)
  • getUserGrade (5-8)
src/api/home/keyword.ts (2)
src/types/home/keyword.ts (1)
  • TWeeklyKeywordResponse (4-6)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/api/home/region.ts (2)
src/types/home/region.ts (2)
  • TPatchUserRegionRequest (3-5)
  • TPatchUserRegionResponse (7-12)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/hooks/home/useKeywordStats.ts (3)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-17)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-20)
src/api/home/keyword.ts (1)
  • getWeeklyKeywords (5-8)
src/types/home/dateTimes.ts (1)
src/api/axiosInstance.ts (1)
  • IRefreshResponse (6-10)
src/api/home/dateTimes.ts (2)
src/types/home/datePlace.ts (2)
  • TMonthlyDatePlaceResponse (4-4)
  • TGetDateTimeStats (6-9)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/hooks/home/useUserRegion.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreMutation (19-27)
src/api/home/region.ts (1)
  • patchUserRegion (5-8)
src/hooks/auth/useAuth.ts (1)
  • useAuth (5-14)
src/pages/auth/JoinPage.tsx (1)
  • Join (19-190)
src/types/home/level.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/hooks/home/useDateTimes.ts (3)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-17)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-20)
src/api/home/dateTimes.ts (1)
  • getDateTimeStats (14-17)
src/api/home/dateCourse.ts (2)
src/types/home/dateCourse.ts (1)
  • IDateCourseSavedCountResponse (2-9)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/utils/getTodayString.ts (2)
src/utils/formatDateInput.tsx (1)
  • formatDateInput (1-11)
src/pages/auth/UserSetting.tsx (1)
  • e (109-112)
src/types/home/keyword.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/hooks/home/useWeather.ts (4)
src/hooks/customQuery.ts (2)
  • useCoreQuery (7-17)
  • useCoreMutation (20-28)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-20)
src/api/home/weather.ts (2)
  • getWeeklyWeatherRecommendation (11-17)
  • getPrecipitation (18-21)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/types/home/region.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/components/home/banner.tsx (1)
src/pages/dateTest/dateTest.tsx (1)
  • src (87-94)
src/components/home/dateTimes.tsx (2)
src/hooks/home/useDateTimes.ts (1)
  • useDateTimesStats (6-8)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/home/dateCourseStore.tsx (1)
src/hooks/home/useDateCourseStats.ts (1)
  • useDateCourseSavedCount (7-13)
src/components/home/dateRecommend.tsx (9)
src/utils/getTodayString.ts (1)
  • getTodayString (1-7)
src/hooks/home/useWeather.ts (2)
  • useWeatherForecast (7-12)
  • useRainyInfo (14-19)
src/utils/getNextSevenDay.ts (1)
  • getNextSevenDay (1-21)
src/utils/normalizeEmojiKey.ts (1)
  • normalizeEmojiKey (1-10)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/common/modalProvider.tsx (1)
  • MODAL_TYPES (15-21)
src/components/common/Button.tsx (1)
  • Button (14-42)
src/utils/weatherMessage.ts (1)
  • getWeatherSentence (4-6)
src/constants/chartOptions.ts (1)
  • chartOptions (1-24)
src/types/home/datePlace.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/components/common/modalProvider.tsx (2)
src/components/common/modal.tsx (1)
  • Modal (15-43)
src/store/useModalStore.ts (5)
  • IModalState (3-9)
  • set (11-37)
  • payload (15-30)
  • payload (16-30)
  • modalType (32-36)
src/api/home/datePlace.ts (2)
src/types/home/datePlace.ts (1)
  • TMonthlyDatePlaceResponse (4-4)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/api/home/weather.ts (2)
src/types/home/weather.ts (4)
  • TGetWeeklyWeatheerRecommendationRequest (5-8)
  • TGetWeeklyWeatheerRecommendationResponse (25-32)
  • TGetPrecipitationRequest (34-37)
  • TGetPrecipitationResponse (38-45)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/types/home/weather.ts (2)
src/types/dateCourse/dateCourse.ts (1)
  • TRegion (78-93)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/components/modal/regionModal.tsx (5)
src/hooks/home/useUserRegion.ts (1)
  • useUserRegion (5-8)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/components/common/modal.tsx (1)
  • Modal (15-43)
src/components/common/EditableInputBox.tsx (1)
  • EditableInputBox (20-126)
src/pages/TestInputPage.tsx (1)
  • TestInputPage (8-46)
src/components/home/dateLocation.tsx (2)
src/hooks/home/useDatePlaceStates.ts (1)
  • useMontlyPlaceStates (6-12)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/hooks/home/useDatePlaceStates.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-17)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-20)
src/api/home/datePlace.ts (1)
  • getMonthlyDatePlaceStates (4-7)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/components/home/wordCloud.tsx (1)
src/hooks/home/useKeywordStats.ts (1)
  • useWeeklyKeywords (7-13)
src/components/home/level.tsx (4)
src/types/home/level.ts (1)
  • IGradeInfo (7-13)
src/components/datetest/ProgressBar.tsx (2)
  • ProgressBar (6-14)
  • IProgressBarProps (1-4)
src/pages/dateTest/DateTestStep.tsx (1)
  • ProgressBar (17-24)
src/pages/dateCourse/MakeCourseStep.tsx (1)
  • ProgressBar (30-37)
src/pages/home/HomePage.tsx (2)
src/hooks/home/useUserGrade.ts (1)
  • useUserGrade (7-13)
src/pages/RedirectPage.tsx (1)
  • data (30-38)
🪛 Biome (2.1.2)
src/components/home/dateRecommend.tsx

[error] 103-106: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

src/components/modal/regionModal.tsx

[error] 59-62: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🔇 Additional comments (22)
src/utils/getTodayString.ts (1)

1-7: 반환 타입 명시 및 KST 기준 여부 확인 요청

  • src/utils/getTodayString.ts 함수 시그니처에 반환 타입 string 명시 권장
  • src/components/home/dateRecommend.tsx: const startDate = getTodayString()로 사용 중
  • src/api/home/weather.ts: startDate 파라미터 전달부에서 KST 기준 날짜 요구 여부 확인 필요
-export function getTodayString() {
+export function getTodayString(): string {
     const today = new Date();
     const yyyy = today.getFullYear();
     const mm = String(today.getMonth() + 1).padStart(2, '0');
     const dd = String(today.getDate()).padStart(2, '0');
     return `${yyyy}-${mm}-${dd}`;
 }

백엔드 문서를 참고해 API가 KST(Asia/Seoul) 기준 날짜를 요구하는지 검토해 주세요.

src/utils/normalizeEmojiKey.ts (1)

1-10: 유니코드 프로퍼티 이스케이프(\p{...}) 지원 여부 확인 요청
현재 tsconfig.app.json에는 target: ES2020, tsconfig.node.json에는 ES2022로 설정되어 있으나, 실제 브라우저·런타임 지원 범위는 별도의 browserslist 또는 빌드 도구 설정에 따라 달라집니다. 아래 사항을 확인해 주세요.

  • .browserslistrc 또는 package.jsonbrowserslist에 ES2018 유니코드 프로퍼티 이스케이프(\p{Mn}|\p{Me}|\p{Mc})를 지원하는 최소 브라우저 버전이 포함되어 있는지
  • Babel을 사용 중이라면 @babel/plugin-proposal-unicode-property-regex 같은 플러그인이 활성화되어 있는지
  • 필요 시 해당 정규식을 대체할 폴리필이나 로직(예: NPM 패키지)을 적용할 것
src/components/common/modalProvider.tsx (1)

38-39: LGTM: 신규 모달 등록 및 전달 프로프 정상

RegionModal이 등록되었고 onClosemodalProps가 적절히 전달됩니다. 모달 시스템과의 결합부는 일관적입니다.

src/utils/getNextSevenDay.ts (1)

14-18: SSR 환경에서 Intl.DateTimeFormat ‘ko-KR’ 지원 여부 검증 필요

아래 변경안은 브라우저에서는 정상 동작하지만, 서버(Node) 번들 환경에서 ICU 데이터 포함 여부에 따라 한국어 포맷이 정상 적용되지 않을 수 있습니다.
Node.js 빌드 시 기본 Small-ICU만 포함된 경우엔 ‘en’ 등으로 폴백되므로, SSR 환경에서 full-ICU 사용 여부 또는 Node 버전을 명시하고 ICU 설정을 검토해 주세요.

• 검토 위치

  • 파일: src/utils/getNextSevenDay.ts
  • 라인: 14–18

• 제안된 수정안

-        // 한국어 표기 (예: 8월 12일)
-        const label = `${date.getMonth() + 1}월 ${date.getDate()}일`;
+        // 한국어 포맷터 사용
+        const label = new Intl.DateTimeFormat('ko-KR', {
+          month: 'numeric',
+          day: 'numeric',
+        }).format(date);
         result.push(label);

• 확인 사항

  1. package.json의 engines.node 필드에 최소 Node.js 버전(예: v14 이상)을 명시
  2. 서버 번들에 full-ICU가 포함되어 있는지, 필요 시 full-icu 패키지 추가 또는 --icu-data-dir 설정 검토
  3. SSR 환경에서 의도한 로케일 포맷이 정상 출력되는지 테스트
src/hooks/home/useUserGrade.ts (1)

9-11: TanStack Query 버전 v5 확인 – gcTime 옵션 유지 가능

프로젝트에서 @tanstack/react-query v5.76.1을 사용 중이므로 gcTime 옵션을 그대로 유지하시면 됩니다.

src/types/home/dateCourse.ts (1)

4-5: code 필드 타입 검증 요청

백엔드에서 code가 문자열인지 숫자인지 스펙을 재확인해 주세요. 일치하지 않으면 파싱/비교 로직에서 미묘한 버그가 발생할 수 있습니다.

필요 시 인터페이스의 code 타입을 백엔드 스펙에 맞춰 조정해 주세요.

src/api/home/region.ts (1)

5-8: 백엔드 응답 형태(200 vs 204) 확인 필요

현재 src/api/home/region.tspatchUserRegion 함수는 응답 본문(data)을 항상 반환한다고 가정하고 있습니다.
그러나 일부 PATCH API는 204 No Content를 반환할 수 있어, 이 경우 dataundefined가 되어 런타임 오류가 발생할 수 있습니다.

  • 검증 스크립트로 호출처(patchUserRegion())를 검색했으나 결과가 없었습니다.
    • 호출처가 아직 구현되지 않았거나 자동화 검증으로는 찾을 수 없는 상태입니다.
  • API 명세 혹은 백엔드 팀에 실제 응답 스펙(200 with body vs 204 No Content)을 확인해주세요.
  • 204를 반환할 경우에도 타입 정의와 처리 로직이 안전하도록 수정이 필요합니다.
src/utils/weatherMessage.ts (1)

4-6: LGTM — 단순하고 명확한 문장 생성

라벨 매핑을 그대로 활용해 문장을 만드는 방식이 간결하고 충분합니다.

src/types/home/level.ts (1)

7-13: API 응답 스키마와 타입 일치 여부 확인 필요
IGradeInfogradelevelstring으로 정의되어 있는데,
실제 API가 숫자 레벨(예: 1, 2, 3)이나 제한된 등급 집합(예: 'BRONZE' | 'SILVER' | …)을 반환한다면
더 구체적인 타입(숫자 또는 문자열 리터럴 유니온)으로 좁히는 것이 안전합니다.
또한 username 필수 여부도 백엔드 스펙 또는 예시 응답으로 확인해 주세요.

확인 지점:

  • src/types/home/level.ts: IGradeInfo 정의부
  • API 호출부 (TUserGradeResponse 사용 위치)
  • src/components/home/level.tsx: Level 컴포넌트에서 props로 소비되는 방식
src/types/home/keyword.ts (1)

3-12: LGTM — 응답 스키마 타입 정의가 명확합니다

placeCategoryLogList 구조가 간결하게 표현되어 있고, UI에서 사용하기에 충분합니다.

src/api/home/keyword.ts (1)

4-8: API 함수 구현이 깔끔합니다!

간단하고 명확한 구조로 잘 구현되어 있습니다. 타입 안전성도 잘 확보되어 있고 주석도 적절합니다.

src/pages/home/HomePage.tsx (2)

21-23: 에러 처리 로직이 적절합니다.

에러 발생 시 '/error' 페이지로 리다이렉트하는 로직이 잘 구현되어 있습니다.


24-30: 로딩 상태 처리가 잘 되어 있습니다.

ClipLoader를 사용한 로딩 화면이 적절하게 구현되어 있습니다.

src/queryKey/queryKey.ts (1)

11-20: 쿼리 키 구조가 체계적으로 잘 정의되어 있습니다.

HomeKeys의 모든 쿼리 키가 명확하고 일관된 네이밍 패턴을 따르고 있습니다. 매개변수가 있는 키들(weather, rainyInfo)도 적절하게 구현되어 있습니다.

src/components/home/dateTimes.tsx (5)

1-1: 메모이제이션 패턴이 일관성 있게 적용되어 있습니다.

React.memo를 사용한 최적화가 다른 홈 컴포넌트들과 일치하는 패턴으로 잘 구현되어 있습니다.


8-13: API 연동과 상태 처리가 잘 구현되어 있습니다.

useDateTimesStats 훅을 사용한 데이터 페칭과 에러/로딩 상태 처리가 적절하게 구현되어 있습니다.


26-30: 로딩 상태 표시가 사용자 친화적입니다.

"로딩..." 텍스트로 로딩 상태를 명확하게 표시하고 있어 사용자 경험이 좋습니다.


39-43: 일관된 로딩 처리가 잘 되어 있습니다.

두 번째 카드에서도 첫 번째 카드와 동일한 패턴으로 로딩 상태를 처리하고 있어 일관성이 있습니다.


47-48: 에러 상태 표시가 적절합니다.

에러 발생 시 명확한 메시지를 표시하여 사용자가 상황을 이해할 수 있도록 잘 구현되어 있습니다.

src/hooks/home/useWeather.ts (1)

9-11: 캐싱 전략(선택): staleTime 조정으로 네트워크 호출 최적화

아래 위치(src/hooks/home/useWeather.ts 9-11)의 설정을 보시면

staleTime: 0,
enabled: !!startDate || !!regionId,

staleTime: 0 설정은 포커스 변경이나 컴포넌트 리마운트 시마다 과도한 refetch를 유발할 수 있습니다.
주간 날씨 데이터 특성상 515분(300_000900_000 ms) 정도로 늘려 불필요한 네트워크 호출을 줄이는 것을 고려해 보세요.

예시:

- staleTime: 0,
+ staleTime: 5 * 60 * 1000, // 5분
src/types/home/datePlace.ts (1)

11-15: 타입 정의 적절합니다

월별 로그 타입 구조가 명확하고, 응답 래퍼 타입(TCommonResponse) 일관성도 좋습니다.

src/types/home/weather.ts (1)

19-24: TRegion 타입은 중복이 아닌 별도 정의입니다

src/types/home/weather.ts의 TRegion과
src/types/dateCourse/dateCourse.ts의 TRegion은 필드 이름(name vs regionName), 중첩 구조(regionCode vs flat), 추가 속성(latitude, longitude, gridX, gridY, regionCodeId) 등이 서로 달라 실제로 중복되지 않습니다.
따라서 기존 타입을 그대로 재사용하기보다는, 각 도메인에 맞게 별도로 유지하는 것이 더 명확합니다.

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review continued from previous batch...

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
src/queryKey/queryKey.ts (2)

19-19: 오타 수정이 필요합니다.

montlyPlaceStates에서 'h'가 누락되었습니다.

-    montlyPlaceStates: () => ['home', 'montlyPlaceStates'],
+    monthlyPlaceStates: () => ['home', 'monthlyPlaceStates'],

15-16: 매개변수 타입을 명시해 주세요.

weatherrainyInfo 함수의 매개변수에 타입이 명시되지 않았습니다. 타입 안전성을 위해 타입을 추가하는 것이 좋겠습니다.

다음과 같이 수정하는 것을 제안합니다:

-    weather: (startDate, regionId) => ['home', 'weather', 'forecast', startDate, regionId],
-    rainyInfo: (startDate, regionId) => ['home', 'rainy', 'forecast', startDate, regionId],
+    weather: (startDate: string, regionId: number) => ['home', 'weather', 'forecast', startDate, regionId],
+    rainyInfo: (startDate: string, regionId: number) => ['home', 'rainy', 'forecast', startDate, regionId],
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e61971 and a7dc908.

📒 Files selected for processing (5)
  • src/api/notice/notice.ts (1 hunks)
  • src/components/home/info.tsx (2 hunks)
  • src/hooks/notices/useGetNotices.ts (1 hunks)
  • src/queryKey/queryKey.ts (1 hunks)
  • src/types/notice/notice.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/hooks/notices/useGetNotices.ts (4)
src/types/notice/notice.ts (1)
  • TRequestGetNoticeRequest (11-15)
src/queryKey/queryKey.ts (1)
  • NoticeKeys (22-25)
src/api/notice/notice.ts (1)
  • fetchNotices (6-11)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/types/notice/notice.ts (1)
src/pages/notice/Notice.tsx (6)
  • getNotices (29-55)
  • Notice (13-119)
  • setLoading (30-52)
  • notice (97-104)
  • notice (58-58)
  • category (76-89)
src/api/notice/notice.ts (3)
src/types/notice/notice.ts (2)
  • TRequestGetNoticeRequest (11-15)
  • TFetchNoticesResponse (17-23)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/pages/notice/Notice.tsx (6)
  • getNotices (29-55)
  • Notice (13-119)
  • setLoading (30-52)
  • notice (97-104)
  • category (76-89)
  • notice (58-58)
src/components/home/info.tsx (3)
src/hooks/notices/useGetNotices.ts (1)
  • useGetNotices (8-15)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/pages/home/HomePage.tsx (1)
  • Home (10-43)
🪛 Biome (2.1.2)
src/components/home/info.tsx

[error] 34-38: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

🔇 Additional comments (2)
src/types/notice/notice.ts (1)

11-15: 타입 정의가 잘 추가되었습니다.

API 요청 파라미터를 위한 타입이 명확하게 정의되어 있습니다.

src/api/notice/notice.ts (1)

6-11: API 함수 구현이 적절합니다.

타입을 활용하여 파라미터가 명확하게 정의되었고, 기본값 설정도 적절합니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 20

🔭 Outside diff range comments (3)
src/hooks/customQuery.ts (1)

23-25: AxiosError 메시지 처리 보강(응답 스키마 미정/네트워크 오류 대비)

error.response?.data.message는 서버 스키마가 다르거나 data가 문자열일 경우 안전하지 않습니다. error.message를 보조로 활용하고, 한국어 기본 문구로 정리하는 것을 권장합니다.

-        onError: (error) => {
-            toast.error(error.response?.data.message || 'An error occurred.');
-        },
+        onError: (error) => {
+            const respData = (error as AxiosError<any>).response?.data;
+            const msg =
+                (typeof respData === 'object' && respData?.message) ||
+                (error as AxiosError).message ||
+                '알 수 없는 오류가 발생했습니다.';
+            toast.error(msg);
+        },
src/pages/notice/Notice.tsx (1)

40-41: 디버그 로그 제거 또는 환경별 분기 처리

프로덕션에서 콘솔 노이즈를 줄이기 위해 로그를 제거하거나 개발 환경에서만 출력하도록 분기하는 것을 권장합니다.

다음과 같이 조정 가능합니다:

-                console.log('API 응답:', response);
+                // TODO: 필요 시 개발 환경에서만 로깅
+                // if (process.env.NODE_ENV === 'development') console.debug('API 응답:', response);
src/components/home/dateRecommend.tsx (1)

164-164: 차트 타입 정의 개선

Line 컴포넌트에 전달되는 dataoptions의 타입을 명시적으로 정의하면 타입 안전성이 향상됩니다.

Chart.js의 타입을 import하여 사용하세요:

import type { ChartData, ChartOptions } from 'chart.js';

// rainData 변수 선언 시
const rainData: ChartData<'line'> = useMemo(() => {
    // ...
}, [dateList, rainyData]);
♻️ Duplicate comments (31)
src/utils/getTodayString.ts (1)

1-7: 타임존 의존성 최소화(UTC getter 사용)로 SSR/클라이언트 일관성 확보
로컬 타임존 기반(getFullYear/getMonth/getDate)은 SSR 수화 불일치 위험이 있습니다. UTC getter 사용으로 안정성을 높이세요.

 export function getTodayString(date: Date = new Date()): string {
     const today = date;
-    const yyyy = today.getFullYear();
-    const mm = String(today.getMonth() + 1).padStart(2, '0');
-    const dd = String(today.getDate()).padStart(2, '0');
+    const yyyy = today.getUTCFullYear();
+    const mm = String(today.getUTCMonth() + 1).padStart(2, '0');
+    const dd = String(today.getUTCDate()).padStart(2, '0');
     return `${yyyy}-${mm}-${dd}`;
 }
src/utils/getNextSevenDay.ts (1)

3-11: 입력 유효성 가드 및 setDate 기준 일관화

  • 잘못된 날짜 문자열 입력 시 조기 가드가 필요합니다.
  • date.setDate(start.getDate() + i) 대신 복제된 date 기준으로 누적 변경이 더 명확합니다.
 export function getNextSevenDay(startDate: string): string[] {
     const result: string[] = [];
     const start = new Date(startDate);
 
+    if (Number.isNaN(start.getTime())) {
+        // TODO: 필요 시 throw로 전환하거나 오늘 기준으로 대체
+        return [];
+    }
+
     for (let i = 0; i < 7; i++) {
         const date = new Date(start);
-        date.setDate(start.getDate() + i);
+        date.setDate(date.getDate() + i);
         const label = date.toLocaleDateString('ko-KR', { month: 'long', day: 'numeric' });
 
         result.push(label);
     }
 
     return result;
 }
src/components/home/level.tsx (3)

11-15: 불필요한 스텁 함수 제거 및 직접 참조로 단순화

현재 getCharacterImage는 항상 동일한 이미지를 반환합니다. 함수 없이 ramji를 직접 사용하는 편이 명확합니다.

다음 diff 적용을 고려해 주세요:

-    // 등급별 캐릭터 이미지 (필요시)
-    const getCharacterImage = () => {
-        // 등급에 따른 캐릭터 이미지 변경 로직
-        return ramji; // 기본 이미지
-    };
...
-                        src={getCharacterImage()}
+                        src={ramji}

Also applies to: 25-25


40-46: 중복 ProgressBar 구현 재사용 고려

레포 내 유사 ProgressBar가 존재합니다(src/components/datetest/ProgressBar.tsx). 재사용하면 스타일/전환 일관성과 유지보수성이 좋아집니다. 현재 퍼센트만 있으면 step=percentage, total=100으로 매핑 가능합니다.

적용 예시:

-                        <div className="w-full h-6 bg-default-gray-400 rounded-full mt-[32px] relative">
-                            <div
-                                className="absolute top-1 ml-1 h-4 bg-primary-500 rounded-full transition-all duration-500"
-                                style={{ width: `${Math.max(0, Math.min(100, percentage))}%` }}
-                            />
-                        </div>
+                        <div className="w-full h-6 bg-default-gray-400 rounded-full mt-[32px] relative">
+                            <ProgressBar step={Math.max(0, Math.min(100, percentage))} total={100} />
+                        </div>

컴포넌트 import 추가(파일 상단):

import ProgressBar from '@/components/datetest/ProgressBar';

16-18: % 진행률 계산 로직 및 타입 확장 필요

현재 nextRequiredPoint(다음 레벨까지 남은 점수)만을 퍼센트로 사용하고 있어, 진행률 계산이 부정확할 수 있습니다. currentPoint(현재 포인트)와 합산하여 전체 필요 포인트 대비 진행률을 계산하도록 로직과 타입을 확장해야 합니다.

수정 제안:

  • 타입 정의에 currentPoint: number 추가 (파일: src/types/home/level.ts)
  • Level 컴포넌트에서 currentPoint, nextRequiredPoint를 받아 전체 점수 대비 진행률 계산

Diff 예시:

--- a/src/components/home/level.tsx
+++ b/src/components/home/level.tsx
@@ -9,7 +9,7 @@ function Level({ grade, nextRequiredPoint }: IGradeInfo) {
     const [percentage, setPercentage] = useState<number>(0);
     useEffect(() => {
-        setPercentage(nextRequiredPoint);
+        const total = currentPoint + nextRequiredPoint;
+        setPercentage(total > 0 ? Math.round((currentPoint / total) * 100) : 0);
     }, [currentPoint, nextRequiredPoint]);
 
     return (
--- a/src/types/home/level.ts
+++ b/src/types/home/level.ts
@@ -10,7 +10,8 @@ export interface IGradeInfo {
     level: string;
     description: string;
     nextRequiredPoint: number;
+    currentPoint: number; // 현재 레벨 진행 점수
 }

• 위 변경에 맞춰 API 응답 스펙 또는 데이터 매핑 로직도 함께 검토해 주세요.
Level 컴포넌트 호출부에서 currentPoint 값을 함께 전달하도록 수정이 필요합니다.

src/types/home/region.ts (1)

7-12: result 내부 message 중복 정의 제거 권장

TCommonResponse에 상위 message가 있으므로 result.message는 중복입니다. 혼란을 줄이기 위해 제거를 권장합니다.

아래 diff를 고려해 주세요:

 export type TPatchUserRegionResponse = TCommonResponse<{
     regionId: number;
     name: string;
     regionCode: TRegionCode;
-    message: string;
 }>;

중첩 result.message 사용 여부를 점검해 주세요:

#!/bin/bash
# 타입 사용/응답 핸들링에서 result.message 접근 여부 확인
rg -n "TPatchUserRegionResponse|patchUserRegion" -A 5 -B 5 src
rg -n "result\.message" src | rg -v "types"
src/types/home/dateCourse.ts (1)

3-3: 주석 정정: 파일 목적과 타입 불일치

현재 주석이 “사용자 등급 응답 타입”으로 표기되어 있으나, 실제로는 “데이트 코스 저장 횟수” 응답 타입입니다. 혼선을 줄이기 위해 주석을 정정해 주세요.

-// 사용자 등급 응답 타입 (실제 API 응답 구조)
+// 데이트 코스 저장 횟수 응답 타입 (실제 API 응답 구조)
src/api/home/level.ts (1)

6-8: Axios 응답 제네릭 명시 + 오류 전파 의도 주석 추가 제안

타입 안정성 확보와 에러 처리 정책 명시로 일관성을 높일 수 있습니다. (이전 리뷰의 제안과 동일합니다)

 // 사용자 등급 조회 API
 export const getUserGrade = async (): Promise<TUserGradeResponse> => {
-    const { data } = await axiosInstance.get('/api/v1/members/grade');
+    // NOTE: 에러는 상위(react-query)에서 처리하도록 전파합니다.
+    const { data } = await axiosInstance.get<TUserGradeResponse>('/api/v1/members/grade');
     return data;
 };
src/api/home/dateCourse.ts (1)

5-8: Axios 제네릭으로 응답 타입 안전성 강화

응답 타입을 제네릭으로 명시하면 다운스트림 코드의 타입 안정성이 올라갑니다. (이전 리뷰 제안과 동일)

 export const getDateCourseSavedCount = async (): Promise<TDateCourseSavedCountResponse> => {
-    const { data } = await axiosInstance.get('/api/v1/logs/datecourses/saved-count');
+    const { data } = await axiosInstance.get<TDateCourseSavedCountResponse>('/api/v1/logs/datecourses/saved-count');
     return data;
 };
src/hooks/home/useUserGrade.ts (1)

8-11: 불필요한 람다 제거로 가독성 개선

무인자 fetcher는 그대로 전달해도 됩니다. (과거 동일 제안)

 export const useUserGrade = () => {
-    return useCoreQuery(HomeKeys.getUserGrade().queryKey, () => getUserGrade(), {
+    return useCoreQuery(HomeKeys.getUserGrade().queryKey, getUserGrade, {
         gcTime: 15 * 60 * 1000, // 15분
         retry: 3,
     });
 };
src/hooks/home/useKeywordStates.ts (1)

8-11: gcTime 사용 버전 확인 (앞선 코멘트와 동일)

해당 옵션은 TanStack Query v5 전용입니다. v4라면 cacheTime으로 교체가 필요합니다. 위 useUserGrade.ts 코멘트의 검증 스크립트를 참고해 주세요.

src/api/home/keyword.ts (1)

6-8: Axios 제네릭으로 응답 타입 안전성 강화

응답 타입을 제네릭으로 명시해 타입 안정성을 확보해 주세요. (기존 리뷰 제안과 동일)

 // 이번 주 인기 키워드 조회 API
 export const getWeeklyKeywords = async (): Promise<TWeeklyKeywordResponse> => {
-    const { data } = await axiosInstance.get('/api/v1/logs/keyword/weekly');
+    const { data } = await axiosInstance.get<TWeeklyKeywordResponse>('/api/v1/logs/keyword/weekly');
     return data;
 };
src/hooks/home/useDatePlaceStates.ts (1)

7-10: staleTime 중복 설정 제거 권장

useCoreQuery에서 이미 기본 staleTime(5분)을 제공하고 있으므로 여기서 명시적으로 설정할 필요가 없습니다.

-    return useCoreQuery(HomeKeys.monthlyPlaceStates().queryKey, () => getMonthlyDatePlaceStates(), {
+    return useCoreQuery(HomeKeys.monthlyPlaceStates().queryKey, getMonthlyDatePlaceStates, {
         gcTime: 15 * 60 * 1000,
         retry: 3,
     });
src/components/home/dateCourseStore.tsx (1)

25-25: 데이터 안전성을 위한 기본값 추가 제안

데이터 로딩 완료 후에도 data?.result.count가 undefined일 수 있으므로 기본값 설정을 권장합니다.

-                        <div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">{data?.result.count}명</div>
+                        <div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">
+                            {(data?.result.count ?? 0).toLocaleString()}명
+                        </div>
src/hooks/home/useDateTimes.ts (1)

7-7: 옵션 객체를 여러 줄로 정리

가독성 향상을 위해 옵션 객체를 여러 줄로 나누어 주세요.

-    return useCoreQuery(HomeKeys.dateTimes().queryKey, () => getDateTimeStates(), { staleTime: 5 * 60 * 1000, gcTime: 15 * 60 * 1000, retry: 3 });
+    return useCoreQuery(HomeKeys.dateTimes().queryKey, () => getDateTimeStates(), {
+        staleTime: 5 * 60 * 1000,
+        gcTime: 15 * 60 * 1000,
+        retry: 3,
+    });
src/hooks/home/useUserRegion.ts (1)

6-8: 지역 변경 시 관련 쿼리 무효화 필요

사용자 지역이 변경되면 지역에 의존하는 홈 데이터(날씨, 강수 정보 등)를 무효화해야 합니다.

+import { useQueryClient } from '@tanstack/react-query';
+
 export function useUserRegion() {
-    return useCoreMutation(patchUserRegion);
+    const queryClient = useQueryClient();
+    return useCoreMutation(patchUserRegion, {
+        onSuccess: () => {
+            // 지역 변경에 영향받는 홈 데이터 무효화
+            queryClient.invalidateQueries({ queryKey: HomeKeys.all().queryKey });
+        },
+    });
 }
src/utils/weatherMessage.ts (1)

4-8: 기존 리뷰 의견이 반영되었습니다

이전 리뷰에서 제안된 안전 가드가 적절히 구현되었습니다. WeatherTypeLabelTempCategoryLabel에서 undefined 값이 반환될 경우를 대비해 filter(Boolean)join(' ')을 사용하여 안전하게 처리하고 있습니다.

src/pages/home/HomePage.tsx (3)

19-27: 에러 처리와 로딩 상태 개선이 완료되었습니다

이전 리뷰에서 제안된 Navigate 컴포넌트를 사용한 에러 처리가 적절히 구현되었습니다. useEffect를 사용한 명령형 네비게이션 대신 선언적 방식을 사용하여 더 깔끔한 코드가 되었습니다.


34-34: 옵셔널 체이닝 일관성 문제가 여전히 남아있습니다

이전 리뷰에서 지적된 문제가 여전히 해결되지 않았습니다. gradeData?.result.username에서 result에 대한 옵셔널 체이닝이 누락되어 있어 런타임 에러가 발생할 수 있습니다.

-                        <span className="font-heading2">{gradeData?.result.username}</span>
+                        <span className="font-heading2">{gradeData?.result?.username ?? '회원'}</span>

39-39: 스프레드 연산자 안전성 문제가 해결되었습니다

이전 리뷰에서 제안된 조건부 렌더링이 적절히 구현되었습니다. gradeData?.result && <Level {...gradeData.result} />로 변경하여 undefined 스프레드 문제를 해결했습니다.

src/hooks/notices/useGetNotices.ts (1)

13-13: getNextPageParam 로직이 올바르게 수정되었습니다

이전 리뷰에서 지적된 문제가 해결되었습니다. lastPage.result.hasNextPage를 확인하여 다음 페이지가 있을 때만 currentPage + 1을 반환하도록 수정되어 무한 스크롤이 올바르게 동작할 것입니다.

src/components/home/dateLocation.tsx (3)

29-41: 옵셔널 체이닝과 키 안정성이 개선되었습니다

이전 리뷰에서 제안된 안전한 옵셔널 체이닝(data?.result?.datePlaceLogList ?? [])이 적절히 적용되었습니다. 다만 key={idx} 사용은 여전히 불안정할 수 있습니다.

더 안정적인 키 사용을 위해 다음과 같이 수정하는 것을 권장합니다:

-                            <div className="flex flex-col items-center" key={idx}>
+                            <div className="flex flex-col items-center" key={`${graph.year}-${graph.month}`}>

30-30: 최소 높이 설정이 적용되었습니다

이전 리뷰에서 제안된 Math.max를 사용한 최소 높이 설정이 올바르게 구현되어 count가 0일 때도 시각적으로 막대가 완전히 사라지지 않습니다.


5-5: 함수명 오타가 여전히 남아있습니다

이전 리뷰에서 지적된 useMonthlyPlaceStates의 오타(useMontlyPlaceStates)가 여전히 해결되지 않았습니다. 일관성을 위해 전체 코드베이스에서 일괄 수정이 필요합니다.

src/api/home/dateTimes.ts (1)

5-9: 에러 처리 일관성을 확보해 주세요.

동일한 파일 내에서 getDateTimeStates 함수만 에러 처리가 누락되어 있습니다. 일관된 에러 처리를 위해 try-catch 블록을 추가하시기 바랍니다.

export const getDateTimeStates = async (): Promise<TGetDateTimeStates> => {
-    const { data } = await axiosInstance.get('/api/v1/logs/datecourses/average');
-    return data;
+    try {
+        const { data } = await axiosInstance.get('/api/v1/logs/datecourses/average');
+        return data;
+    } catch {
+        throw new Error('데이트 시간 통계를 가져오는데 실패했습니다.');
+    }
};
src/api/home/region.ts (1)

5-8: 타입 안전성 강화를 권장합니다.

Axios 제네릭을 사용하여 응답 타입을 명시하면 컴파일 타임에 타입 안전성을 확보할 수 있습니다.

export const patchUserRegion = async ({ regionId }: TPatchUserRegionRequest): Promise<TPatchUserRegionResponse> => {
-    const { data } = await axiosInstance.patch('/api/v1/regions/users', { regionId });
+    const { data } = await axiosInstance.patch<TPatchUserRegionResponse>('/api/v1/regions/users', { regionId });
    return data;
};
src/types/home/datePlace.ts (1)

6-9: 타입 명명 일관성 개선 제안

TGetDateTimeStates는 다른 응답 타입들과 달리 Response 접미사가 없습니다. 일관성을 위해 TDateTimeStatesResponse로 변경하는 것을 고려해보세요.

-export type TGetDateTimeStates = TCommonResponse<{
+export type TDateTimeStatesResponse = TCommonResponse<{
     averageDateCount: number;
     myDateCount: number;
 }>;
src/queryKey/queryKey.ts (1)

15-16: weather와 rainyInfo 함수의 매개변수 타입 추가 필요

타입 안전성을 위해 매개변수에 명시적인 타입을 추가하는 것이 좋습니다.

-    weather: (startDate, regionId) => ['home', 'weather', 'forecast', startDate, regionId],
-    rainyInfo: (startDate, regionId) => ['home', 'rainy', 'forecast', startDate, regionId],
+    weather: (startDate: string, regionId: number) => ['home', 'weather', 'forecast', startDate, regionId],
+    rainyInfo: (startDate: string, regionId: number) => ['home', 'rainy', 'forecast', startDate, regionId],
src/components/home/wordCloud.tsx (1)

84-84: WordCloud.stop() 호출 위치 재검토 필요

ResizeObserver effect 내부에서 WordCloud.stop()을 호출하는 것은 리사이즈 시마다 워드클라우드를 중지시킵니다. cleanup 함수에서 호출하는 것이 더 적절할 수 있습니다.

 useEffect(() => {
     if (!containerRef.current || !throttledDrawRef.current) return;
-    WordCloud.stop();
     const resizeObserver = new ResizeObserver((entries) => {
         for (const entry of entries) {
             const { width, height } = entry.contentRect;
+            WordCloud.stop();
             throttledDrawRef.current?.(width, height);
         }
     });
src/components/home/dateRecommend.tsx (2)

103-109: 버튼 타입 속성 추가 완료

이전 리뷰에서 지적된 버튼 타입 속성이 올바르게 추가되었습니다.


137-138: non-null assertion 연산자 사용 주의

currentRec.weatherType!currentRec.tempCategory!에서 non-null assertion을 사용하고 있습니다. 안전한 처리를 위해 기본값을 제공하는 것이 좋습니다.

-    weather: currentRec.weatherType!,
-    temp: currentRec.tempCategory!,
+    weather: currentRec.weatherType ?? 'SUNNY',
+    temp: currentRec.tempCategory ?? 'WARM',
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7dc908 and 9df3483.

📒 Files selected for processing (41)
  • src/api/alarm/alarm.ts (1 hunks)
  • src/api/auth/auth.ts (1 hunks)
  • src/api/course/course.ts (1 hunks)
  • src/api/home/dateCourse.ts (1 hunks)
  • src/api/home/dateTimes.ts (1 hunks)
  • src/api/home/keyword.ts (1 hunks)
  • src/api/home/level.ts (1 hunks)
  • src/api/home/region.ts (1 hunks)
  • src/api/home/weather.ts (1 hunks)
  • src/api/notice/notice.ts (1 hunks)
  • src/components/home/dateCourseStore.tsx (2 hunks)
  • src/components/home/dateLocation.tsx (1 hunks)
  • src/components/home/dateRecommend.tsx (1 hunks)
  • src/components/home/dateTimes.tsx (1 hunks)
  • src/components/home/info.tsx (2 hunks)
  • src/components/home/level.tsx (1 hunks)
  • src/components/home/wordCloud.tsx (3 hunks)
  • src/components/modal/regionModal.tsx (1 hunks)
  • src/constants/chartOptions.ts (1 hunks)
  • src/constants/weather.ts (1 hunks)
  • src/hooks/customQuery.ts (1 hunks)
  • src/hooks/home/useDateCourseStates.ts (1 hunks)
  • src/hooks/home/useDatePlaceStates.ts (1 hunks)
  • src/hooks/home/useDateTimes.ts (1 hunks)
  • src/hooks/home/useKeywordStates.ts (1 hunks)
  • src/hooks/home/useUserGrade.ts (1 hunks)
  • src/hooks/home/useUserRegion.ts (1 hunks)
  • src/hooks/home/useWeather.ts (1 hunks)
  • src/hooks/notices/useGetNotices.ts (1 hunks)
  • src/pages/home/HomePage.tsx (2 hunks)
  • src/pages/notice/Notice.tsx (1 hunks)
  • src/queryKey/queryKey.ts (1 hunks)
  • src/types/home/dateCourse.ts (1 hunks)
  • src/types/home/datePlace.ts (1 hunks)
  • src/types/home/region.ts (1 hunks)
  • src/types/home/weather.ts (1 hunks)
  • src/utils/getNextSevenDay.ts (1 hunks)
  • src/utils/getTodayString.ts (1 hunks)
  • src/utils/normalizeEmojiKey.ts (1 hunks)
  • src/utils/weatherMessage.ts (1 hunks)
  • tsconfig.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (32)
src/api/course/course.ts (1)
src/hooks/course/useSearchRegion.tsx (2)
  • searchRegion (7-7)
  • useSearchRegion (6-11)
src/hooks/home/useKeywordStates.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/keyword.ts (1)
  • getWeeklyKeywords (6-9)
src/hooks/course/useSearchRegion.tsx (2)
  • useSearchRegion (6-11)
  • searchRegion (7-7)
src/api/home/region.ts (3)
src/types/home/region.ts (3)
  • TPatchUserRegionRequest (3-5)
  • TPatchUserRegionResponse (7-12)
  • TGetUserRegionResponse (21-29)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/api/home/level.ts (2)
src/types/home/level.ts (1)
  • TUserGradeResponse (4-4)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/hooks/home/useDatePlaceStates.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/dateTimes.ts (1)
  • getMonthlyDatePlaceStates (6-9)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/api/home/dateCourse.ts (2)
src/types/home/dateCourse.ts (1)
  • TDateCourseSavedCountResponse (4-6)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/hooks/home/useDateCourseStates.ts (3)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/dateCourse.ts (1)
  • getDateCourseSavedCount (5-8)
src/api/home/keyword.ts (2)
src/types/home/keyword.ts (1)
  • TWeeklyKeywordResponse (4-6)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/api/home/weather.ts (2)
src/types/home/weather.ts (4)
  • TGetWeeklyWeatherRecommendationRequest (5-8)
  • TGetWeeklyWeatherRecommendationResponse (25-32)
  • TGetPrecipitationRequest (34-37)
  • TGetPrecipitationResponse (38-45)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/api/auth/auth.ts (1)
src/api/axiosInstance.ts (1)
  • error (20-68)
src/types/home/dateCourse.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/hooks/home/useDateTimes.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/dateTimes.ts (1)
  • getDateTimeStates (11-14)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/utils/weatherMessage.ts (1)
src/constants/weather.ts (2)
  • WeatherTypeLabel (10-17)
  • TempCategoryLabel (26-31)
src/hooks/notices/useGetNotices.ts (3)
src/types/notice/notice.ts (1)
  • TRequestGetNoticeRequest (11-15)
src/queryKey/queryKey.ts (1)
  • NoticeKeys (23-26)
src/api/notice/notice.ts (1)
  • fetchNotices (6-11)
src/components/home/info.tsx (3)
src/hooks/notices/useGetNotices.ts (1)
  • useGetNotices (8-15)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/pages/notice/NoticeDetail.tsx (2)
  • NoticeDetail (8-69)
  • noticeId (17-42)
src/utils/getTodayString.ts (2)
src/utils/formatDateInput.tsx (1)
  • formatDateInput (1-11)
src/pages/auth/UserSetting.tsx (1)
  • e (109-112)
src/components/home/dateCourseStore.tsx (2)
src/hooks/home/useDateCourseStates.ts (1)
  • useDateCourseSavedCount (7-12)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/modal/regionModal.tsx (7)
src/hooks/home/useUserRegion.ts (1)
  • useUserRegion (6-8)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/components/common/modal.tsx (1)
  • Modal (15-43)
src/components/common/EditableInputBox.tsx (1)
  • EditableInputBox (20-126)
src/components/common/modalProvider.tsx (1)
  • ModalProvider (24-33)
src/components/modal/errorModal.tsx (1)
  • ErrorModal (8-17)
src/pages/TestInputPage.tsx (1)
  • TestInputPage (8-46)
src/hooks/home/useWeather.ts (5)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/weather.ts (2)
  • getWeeklyWeatherRecommendation (11-17)
  • getPrecipitation (19-22)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/hooks/auth/useAuth.ts (1)
  • useAuth (5-14)
src/api/home/dateTimes.ts (2)
src/types/home/datePlace.ts (2)
  • TMonthlyDatePlaceResponse (4-4)
  • TGetDateTimeStates (6-9)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/components/home/dateRecommend.tsx (9)
src/hooks/home/useUserRegion.ts (1)
  • useGetUserRegion (10-12)
src/utils/getTodayString.ts (1)
  • getTodayString (1-7)
src/hooks/home/useWeather.ts (2)
  • useWeatherForecast (7-12)
  • useRainyInfo (14-19)
src/utils/getNextSevenDay.ts (1)
  • getNextSevenDay (1-14)
src/utils/normalizeEmojiKey.ts (1)
  • normalizeEmojiKey (1-9)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/common/modalProvider.tsx (1)
  • MODAL_TYPES (15-21)
src/components/common/Button.tsx (1)
  • Button (14-42)
src/utils/weatherMessage.ts (1)
  • getWeatherSentence (4-8)
src/types/home/region.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/types/home/weather.ts (2)
src/types/dateCourse/dateCourse.ts (1)
  • TRegion (78-93)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/components/home/dateTimes.tsx (2)
src/hooks/home/useDateTimes.ts (1)
  • useDateTimesstates (6-8)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/home/level.tsx (6)
src/types/home/level.ts (1)
  • IGradeInfo (7-13)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/datetest/ProgressBar.tsx (2)
  • ProgressBar (6-14)
  • IProgressBarProps (1-4)
src/pages/dateCourse/MakeCourseStep.tsx (2)
  • ProgressBar (30-37)
  • MakeCourseStep (39-160)
src/pages/dateTest/DateTestStep.tsx (1)
  • ProgressBar (17-24)
src/pages/dateTest/DatetestResult.tsx (1)
  • item (102-135)
src/pages/home/HomePage.tsx (2)
src/hooks/home/useUserGrade.ts (1)
  • useUserGrade (7-12)
src/pages/RedirectPage.tsx (1)
  • data (30-38)
src/hooks/home/useUserGrade.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/level.ts (1)
  • getUserGrade (6-9)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/types/home/datePlace.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/api/notice/notice.ts (2)
src/types/notice/notice.ts (2)
  • TRequestGetNoticeRequest (11-15)
  • TFetchNoticesResponse (17-23)
src/api/axiosInstance.ts (1)
  • axiosInstance (11-14)
src/components/home/wordCloud.tsx (1)
src/hooks/home/useKeywordStates.ts (1)
  • useWeeklyKeywords (7-12)
src/hooks/home/useUserRegion.ts (4)
src/hooks/customQuery.ts (2)
  • useCoreMutation (20-28)
  • useCoreQuery (7-18)
src/api/home/region.ts (2)
  • patchUserRegion (5-8)
  • getUserRegion (10-13)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/hooks/course/useSearchRegion.tsx (2)
  • useSearchRegion (6-11)
  • searchRegion (7-7)
src/components/home/dateLocation.tsx (2)
src/hooks/home/useDatePlaceStates.ts (1)
  • useMonthlyPlaceStates (6-11)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
🪛 Biome (2.1.2)
src/components/home/info.tsx

[error] 50-50: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 50-50: The HTML element li is non-interactive and should not have an interactive role.

Replace li with a div or a span.
Unsafe fix: Remove the role attribute.

(lint/a11y/noNoninteractiveElementToInteractiveRole)

🔇 Additional comments (21)
src/api/course/course.ts (1)

3-3: 경로 별칭(@/api/axiosInstance)로의 전환, 적절합니다

모듈 경로 정리가 일관되고 가독성도 좋아졌습니다. 함수 시그니처/동작에 영향 없습니다.

src/api/alarm/alarm.ts (1)

3-3: 경로 별칭(@/api/axiosInstance) 적용 LGTM

API 로직 변경 없이 import 정리만 이뤄졌고, 타입/파라미터도 그대로입니다.

src/utils/normalizeEmojiKey.ts (1)

1-9: 이모지 키 정규화 유틸 구현 좋습니다

  • 반환 타입 명시, VS-15/16/ZWJ 제거, \p{M} 사용 등 모두 적절합니다. 홈 화면 아이콘 매핑 용도로 충분히 견고해 보입니다.
src/hooks/customQuery.ts (1)

7-18: 쿼리 키에 동적 파라미터 포함 확인 완료

홈 화면에서 변경되는 지역(startDate, regionId) 및 검색 키워드(keyword)를 사용하는 훅은 모두 queryKey에 해당 변수를 포함하고 있으며, 나머지 훅은 동적 파라미터가 불필요한 고정 쿼리입니다.

검증된 훅 목록:

  • useSearchRegion (keyword 포함)
  • useWeatherForecast, useRainyInfo (startDate, regionId 포함)

따라서 캐시 충돌 우려가 없습니다.

src/constants/chartOptions.ts (1)

3-24: 차트 옵션 타입 명시 및 v4 옵션 배치 적합 — 좋습니다

ChartOptions<'line'> 타입 지정과 scales.x.grid.drawOnChartArea/scales.x.border.display 배치가 Chart.js v4와 호환됩니다. 소비자 측 as any 회피에도 도움이 됩니다.

src/components/home/level.tsx (1)

42-45: 진행바 width 클램핑 적용 좋습니다

0~100% 클램핑으로 레이아웃 안전성이 확보되었습니다.

src/pages/notice/Notice.tsx (1)

35-38: API 파라미터명 변경 반영(LGTM)

noticeCategory로의 변경이 타입/백엔드 계약과 일치합니다. 다른 영향 범위도 적절해 보입니다.

src/hooks/home/useUserGrade.ts (1)

9-10: gcTime 옵션 사용 확인 완료: 변경 불필요

프로젝트가 TanStack Query v5.76.1을 사용 중이므로 gcTime 옵션이 정상 지원됩니다.
따라서 기존 설정을 그대로 유지하시면 됩니다.

src/hooks/home/useDatePlaceStates.ts (1)

6-11: 함수명과 쿼리 키가 올바르게 수정되었습니다

이전 리뷰에서 지적된 montlymonthly 오탈자가 올바르게 수정되어 useMonthlyPlaceStates 함수명과 HomeKeys.monthlyPlaceStates() 쿼리 키가 일치합니다. 알리아스 경로도 올바르게 적용되었습니다.

src/components/home/dateCourseStore.tsx (1)

11-13: 에러 처리가 적절하게 개선되었습니다

이전 리뷰에서 지적된 렌더 단계에서의 navigate 호출 문제가 <Navigate> 컴포넌트 사용으로 올바르게 해결되었습니다.

src/hooks/home/useDateCourseStates.ts (1)

7-12: 훅 구현이 적절합니다

쿼리 옵션과 코멘트가 잘 작성되어 있고, 캐시 시간과 재시도 설정이 적절합니다.

src/components/home/dateTimes.tsx (3)

11-17: 로딩 상태 UI가 개선되었습니다

기존의 텍스트 기반 로딩 상태 대신 ClipLoader를 사용하여 일관된 로딩 경험을 제공합니다. 전체 컨테이너를 차지하는 중앙 정렬 레이아웃도 적절합니다.


30-30: 데이터 기반 렌더링으로 성공적으로 전환되었습니다

하드코딩된 값들이 displaystates?.averageDateCountdisplaystates?.myDateCount로 대체되어 실제 API 데이터를 표시합니다. 옵셔널 체이닝을 사용하여 안전하게 처리하고 있습니다.

Also applies to: 40-40


45-45: 에러 상태 표시가 추가되었습니다

API 호출 실패 시 사용자에게 명확한 피드백을 제공하는 에러 메시지가 추가되었습니다. 빨간색으로 표시하여 시각적으로도 구분됩니다.

src/api/home/dateTimes.ts (1)

11-14: 코드 품질이 좋습니다.

API 함수 구조와 타입 정의가 명확하고, 네이밍도 적절합니다.

src/api/home/weather.ts (2)

11-17: API 함수 구현이 적절합니다.

함수 구조와 타입 정의가 명확하며, 파라미터 전달 방식도 적절합니다.


19-22: 깔끔한 구현입니다.

객체 단축 속성을 잘 활용하고 있으며, API 엔드포인트와 파라미터 처리가 적절합니다.

src/hooks/home/useWeather.ts (2)

7-12: 쿼리 조건과 캐시 설정이 적절합니다.

이전 리뷰에서 지적된 enabled 조건과 staleTime 설정이 올바르게 수정되어 날씨 데이터의 특성에 맞게 구현되었습니다.


14-19: 일관된 구현으로 잘 작성되었습니다.

두 훅 모두 동일한 패턴으로 구현되어 일관성이 좋습니다. 필수 파라미터 검증과 적절한 캐시 시간 설정이 잘 되어 있습니다.

src/components/modal/regionModal.tsx (1)

16-16: useUserRegion 훅 사용 방식 정상 확인
useUserRegion이 내부적으로 useCoreMutation(patchUserRegion)을 반환하여 React Query의 mutation 훅과 동일한 형태로 동작합니다.
따라서

const { mutate: patchUserRegionMutate } = useUserRegion();

구문은 올바르며, 추가 수정이 필요 없습니다.

src/api/notice/notice.ts (1)

1-11: API 함수 변경사항이 적절합니다

noticeCategory 파라미터 사용 및 기본값 설정이 올바르게 구현되었습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🔭 Outside diff range comments (1)
src/components/home/info.tsx (1)

29-34: button 기본 type 명시 (폼 내에서의 의도치 않은 submit 방지)

Biome 경고가 지적하듯 두 버튼 모두 type="button"을 명시하세요.

                     <button
+                        type="button"
                         className="text-default-gray-800 font-semibold flex justify-center items-center gap-1 whitespace-nowrap hover:cursor-pointer"
                         onClick={() => navigate('/notice')}
                     >

또한 목록 내 버튼에도 type을 명시합니다(위 다른 코멘트의 diff에 포함되어 있습니다).

-                                <button
+                                <button
+                                    type="button"
                                     className="whitespace-nowrap text-ellipsis overflow-hidden w-full text-left"

Also applies to: 41-53

♻️ Duplicate comments (14)
src/components/home/info.tsx (1)

1-1: 불필요한 리렌더 최소화를 위해 React.memo 적용 제안

현재 props가 없는 정적 컴포넌트여서 memo로 감싸면 상위 리렌더 전파를 줄일 수 있습니다. 이전 코멘트와 동일 제안입니다.

+import { memo } from 'react';
 
-export default MainInfo;
+export default memo(MainInfo);

Also applies to: 63-63

src/components/home/dateLocation.tsx (5)

1-6: useMonthlyPlaceStates 네이밍/경로 정리 확인 — LGTM

이전 오탈자(montly → monthly) 지적 사항이 반영되었습니다. 임포트/경로 일관성 좋습니다.


17-23: 로딩 상태 처리 및 클래스 오타 수정 확인 — LGTM

로딩 상태가 카드 내부에서 일관되게 처리되고, self-center 오타도 반영되었습니다.


11-13: useMemo 의존성 범위 축소 제안(선택)

불필요한 재계산을 줄이기 위해 deps를 리스트에 한정하는 것을 권장합니다.

-    }, [data]);
+    }, [data?.result?.datePlaceLogList]);

29-41: 빈 데이터(0개)일 때 플레이스홀더 UI 추가 권장

데이터가 비어 있을 경우 차트 영역이 공백으로 남습니다. 간단한 “데이터가 없습니다” 플레이스홀더를 표시하면 UX가 좋아집니다.

-                    {(data?.result?.datePlaceLogList ?? []).map((graph, idx) => {
+                    {(data?.result?.datePlaceLogList?.length ?? 0) === 0 ? (
+                        <div className="text-default-gray-400 text-sm">데이터가 없습니다</div>
+                    ) : (
+                        (data?.result?.datePlaceLogList ?? []).map((graph, idx) => {
                         const height = maxCount ? Math.max((graph.count / maxCount) * 200, 4) : 4;
                         return (
                             <div className="flex flex-col items-center" key={idx}>
                                 <span className="text-xs text-default-gray-500 mb-1">{graph.count}</span>
                                 <div
                                     className="w-10 bg-default-gray-400 mb-2 flex items-start justify-center transition-all duration-300"
                                     style={{ height: `${height}px` }}
                                 />
                                 <div className="text-default-gray-500 mt-1">{graph.month}월</div>
                             </div>
                         );
-                    })}
+                        })
+                    )}

32-32: key={idx} 대신 안정적인 키 사용 권장

재정렬/삽입 시 리렌더링 부작용을 줄이려면 월/연도 기반의 고유 키를 사용해 주세요.

-                            <div className="flex flex-col items-center" key={idx}>
+                            <div className="flex flex-col items-center" key={`${graph.year}-${graph.month}`}>
src/hooks/home/useDateTimes.ts (1)

6-8: 옵션 객체 다중 라인 + 불필요한 래핑 함수 제거

가독성을 위해 옵션을 다중 라인으로, 쿼리 함수는 직접 전달로 정리하면 좋습니다. (이전 코멘트와 동일 제안)

 export const useDateTimeStates = () => {
-    return useCoreQuery(HomeKeys.dateTimes().queryKey, () => getDateTimeStates(), { staleTime: 5 * 60 * 1000, gcTime: 15 * 60 * 1000, retry: 3 });
+    return useCoreQuery(HomeKeys.dateTimes().queryKey, getDateTimeStates, {
+        staleTime: 5 * 60 * 1000,
+        gcTime: 15 * 60 * 1000,
+        retry: 3,
+        // 선택: 컴포넌트에서 result 접근 제거
+        // select: (d) => d.result,
+    });
 };
src/components/home/wordCloud.tsx (3)

16-22: 이전 리뷰 피드백이 반영되었습니다.

null 체크와 빈 배열 fallback이 추가되어 런타임 에러를 방지할 수 있습니다.


41-46: weightFactor 최적화가 적용되었습니다.

이전 리뷰 피드백이 반영되어 최소/최대 크기 제한이 추가되었습니다.


78-81: WordCloud cleanup이 올바르게 구현되었습니다.

이전 리뷰 피드백이 반영되어 cleanup 함수에서 WordCloud.stop()을 호출하도록 개선되었습니다.

src/utils/getNextSevenDay.ts (1)

3-4: 날짜 유효성 검사 추가 필요

잘못된 startDate 입력 시 Invalid Date가 발생하여 "NaN월 NaN일" 같은 결과가 생성될 수 있습니다.

 export function getNextSevenDay(startDate: string): string[] {
     const result: string[] = [];
     const start = new Date(startDate);
+    
+    if (isNaN(start.getTime())) {
+        console.error('Invalid date provided:', startDate);
+        return [];
+    }
src/types/home/weather.ts (1)

31-31: 중복된 message 필드 제거 필요

TCommonResponse에 이미 message 필드가 있는데, result 내부에도 중복 선언되어 있습니다.

 export type TGetWeeklyWeatherRecommendationResponse = TCommonResponse<{
     region: TWeatherRegion;
     startDate: string;
     endDate: string;
     dailyRecommendations: TDailyRecommendations[];
     totalDays: number;
-    message: string;
 }>;

 export type TGetPrecipitationResponse = TCommonResponse<{
     region: TWeatherRegion;
     startDate: string;
     endDate: string;
     dailyPrecipitations: TDailyPrecipitations[];
     totalDays: number;
-    message: string;
 }>;

Also applies to: 44-44

src/components/home/dateRecommend.tsx (2)

137-138: non-null assertion 대신 안전한 접근 사용

! 연산자는 런타임 에러 위험이 있습니다.

-    weather: currentRec.weatherType!,
-    temp: currentRec.tempCategory!,
+    weather: currentRec.weatherType ?? 'SUNNY',
+    temp: currentRec.tempCategory ?? 'WARM',

90-96: 로딩 상태 UX 개선

사용자가 무엇을 기다리고 있는지 명확하게 표시하면 좋습니다.

 if (rainyLoading || forecastLoading) {
     return (
         <MainCard>
-            <ClipLoader />
+            <div className="flex flex-col items-center justify-center gap-2">
+                <ClipLoader />
+                <span className="text-sm text-gray-600">날씨 정보를 불러오는 중...</span>
+            </div>
         </MainCard>
     );
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9df3483 and 3b98c27.

📒 Files selected for processing (12)
  • src/components/home/dateLocation.tsx (1 hunks)
  • src/components/home/dateRecommend.tsx (1 hunks)
  • src/components/home/dateTimes.tsx (1 hunks)
  • src/components/home/info.tsx (2 hunks)
  • src/components/home/wordCloud.tsx (3 hunks)
  • src/components/modal/regionModal.tsx (1 hunks)
  • src/hooks/customQuery.ts (1 hunks)
  • src/hooks/home/useDateCourseStates.ts (1 hunks)
  • src/hooks/home/useDateTimes.ts (1 hunks)
  • src/hooks/home/useKeywordStates.ts (1 hunks)
  • src/types/home/weather.ts (1 hunks)
  • src/utils/getNextSevenDay.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
src/components/modal/regionModal.tsx (6)
src/hooks/home/useUserRegion.ts (1)
  • useUserRegion (6-8)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/components/common/modal.tsx (1)
  • Modal (15-43)
src/components/common/EditableInputBox.tsx (1)
  • EditableInputBox (20-126)
src/components/modal/errorModal.tsx (1)
  • ErrorModal (8-17)
src/store/useModalStore.ts (1)
  • IModalState (3-9)
src/hooks/home/useDateTimes.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/dateTimes.ts (1)
  • getDateTimeStates (11-14)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/components/home/info.tsx (4)
src/hooks/notices/useGetNotices.ts (1)
  • useGetNotices (8-15)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/pages/notice/Notice.tsx (4)
  • Notice (13-119)
  • getNotices (29-55)
  • notice (97-104)
  • category (76-89)
src/pages/notice/NoticeDetail.tsx (2)
  • NoticeDetail (8-69)
  • noticeId (17-42)
src/hooks/home/useKeywordStates.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/keyword.ts (1)
  • getWeeklyKeywords (6-9)
src/hooks/course/useSearchRegion.tsx (2)
  • useSearchRegion (6-11)
  • searchRegion (7-7)
src/components/home/dateTimes.tsx (2)
src/hooks/home/useDateTimes.ts (1)
  • useDateTimeStates (6-8)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/hooks/home/useDateCourseStates.ts (4)
src/hooks/customQuery.ts (1)
  • useCoreQuery (7-18)
src/queryKey/queryKey.ts (1)
  • HomeKeys (11-21)
src/api/home/dateCourse.ts (1)
  • getDateCourseSavedCount (5-8)
src/hooks/course/useSearchRegion.tsx (1)
  • useSearchRegion (6-11)
src/types/home/weather.ts (1)
src/types/common/common.ts (1)
  • TCommonResponse (4-9)
src/components/home/dateLocation.tsx (2)
src/hooks/home/useDatePlaceStates.ts (1)
  • useMonthlyPlaceStates (6-11)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/home/dateRecommend.tsx (9)
src/hooks/home/useUserRegion.ts (1)
  • useGetUserRegion (10-12)
src/utils/getTodayString.ts (1)
  • getTodayString (1-7)
src/hooks/home/useWeather.ts (2)
  • useWeatherForecast (7-12)
  • useRainyInfo (14-19)
src/utils/getNextSevenDay.ts (1)
  • getNextSevenDay (1-14)
src/utils/normalizeEmojiKey.ts (1)
  • normalizeEmojiKey (1-9)
src/components/home/mainCard.tsx (1)
  • MainCard (6-8)
src/components/common/modalProvider.tsx (1)
  • MODAL_TYPES (15-21)
src/components/common/Button.tsx (1)
  • Button (14-42)
src/utils/weatherMessage.ts (1)
  • getWeatherSentence (4-8)
src/components/home/wordCloud.tsx (1)
src/hooks/home/useKeywordStates.ts (1)
  • useWeeklyKeywords (7-12)
🪛 Biome (2.1.2)
src/components/modal/regionModal.tsx

[error] 62-62: The elements with this role can be changed to the following elements:
For examples and more information, see WAI-ARIA Roles (lint/a11y/useSemanticElements) [error] 66-66: The HTML element with the interactive role "option" is not focusable. A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "option". Add a tabIndex attribute to make this element focusable. (lint/a11y/useFocusableInteractive) [error] 66-66: The elements with this role can be changed to the following elements: For examples and more information, see WAI-ARIA Roles (lint/a11y/useSemanticElements) src/components/home/info.tsx [error] 42-52: Provide an explicit type prop for the button element. The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application. Allowed button types are: submit, button or reset (lint/a11y/useButtonType) 🔇 Additional comments (12) src/components/home/info.tsx (2) 14-16: 에러 시 반환 패턴은 현재 컨텍스트에서 안전합니다 에러 분기에서 를 반환하도록 수정되어 리디렉션 루프 위험이 낮고, React Router v6에서 일반적으로 사용하는 패턴입니다. 이 부분은 LGTM입니다. 17-23: 로딩 분기에서 명시적으로 반환하도록 변경된 점 좋습니다 이제 로딩 상태에서 명확히 UI를 반환하여 깜빡임/미표시 이슈가 없습니다. LGTM. src/hooks/customQuery.ts (1) 13-17: staleTime 기본값 보장 순서 수정 — LGTM ...options 뒤에 staleTime을 계산해 넣어 undefined로 인한 기본값 덮어쓰기 이슈가 제거되었습니다. 호출부에서 staleTime을 명시하면 그대로 반영되고, 미지정 시 5분 기본값이 유지됩니다. src/components/home/wordCloud.tsx (7) 1-2: import 구문이 정리되었습니다. 타입 전용 import에서 값 import로 변경하고 React hooks를 추가한 것이 적절합니다. 7-7: API 연결이 올바르게 구현되었습니다. 정적 데이터에서 동적 API 데이터로 전환한 것이 PR 목표와 일치합니다. 9-11: 컴포넌트 구조 개선이 잘 되었습니다. 함수명을 명시적으로 선언하고 state 관리를 추가한 것이 좋습니다. 49-53: 색상 그라디언트 개선이 좋습니다. 더 세밀한 색상 단계로 변경하여 시각적 표현이 향상되었습니다. 105-106: 레이아웃 개선이 적절합니다. 컨테이너 높이를 85%에서 90%로 증가시키고 canvas에 left offset을 추가한 것이 좋습니다. 111-111: export 패턴이 명확해졌습니다. 함수명을 명시적으로 선언하고 별도로 export하는 패턴이 더 명확합니다. 31-31: canvas 스타일링: width - 10px 계산 로직 확인 요청 현재 코드베이스 내에서 width - 10 계산을 사용하는 부분은 아래 한 곳뿐입니다. 아래 항목들을 중심으로 브라우저 환경에서 레이아웃이 의도대로 동작하는지 확인해 주세요. 파일: src/components/home/wordCloud.tsx 위치: canvas.style.width = \${width - 10}px`;` 실제 화면에서 캔버스가 부모 컨테이너 너비보다 10px 작게 렌더링되는지 반응형(창 크기 변경) 시 캔버스 크기가 의도대로 조정되는지 다른 요소와 겹치거나 수평 스크롤이 생기지 않는지 확인 src/components/home/dateRecommend.tsx (2) 50-51: 날짜 처리 로직 개선 가능 safeStartDate가 API 응답에 의존하는데, 응답이 없을 때를 대비한 폴백이 잘 되어 있습니다. 현재 rainyData?.result?.startDate ?? startDate 로직이 적절하게 구현되어 있어 API 응답이 없어도 안전하게 처리됩니다. 54-79: 차트 데이터 구성 우수 차트 데이터 구성이 깔끔하고, useMemo를 통한 최적화도 적절합니다. 강수확률 데이터 매핑이 안전하게 처리됨 차트 스타일링이 일관성 있게 적용됨 datalabels 설정이 적절함

@yeonjin719 yeonjin719 merged commit c6fd58b into develop Aug 13, 2025
2 of 3 checks passed
@yeonjin719 yeonjin719 deleted the feature/#91 branch August 13, 2025 04:40
@yeonjin719 yeonjin719 changed the title [Feature/#91] 메인 화면 API 연결 [Feature] 메인 화면 API 연결 Aug 18, 2025
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.

✨ [Feature] 메인 API 연결

3 participants