Skip to content

feat: #191 홈 대시보드 리스트럭처링#275

Merged
FLYLIKEB merged 6 commits intomainfrom
feature/issue-191-home-restructure
Mar 16, 2026
Merged

feat: #191 홈 대시보드 리스트럭처링#275
FLYLIKEB merged 6 commits intomainfrom
feature/issue-191-home-restructure

Conversation

@FLYLIKEB
Copy link
Copy Markdown
Owner

@FLYLIKEB FLYLIKEB commented Mar 16, 2026

Summary

Test plan

  • npm run build
  • 새 컴포넌트 테스트 통과 (10/10)
  • Home 테스트 업데이트 및 통과 (3/3)
  • 홈 대시보드 UI 수동 확인
  • Search 피드 탭 수동 확인

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • 홈에 프로모션 배너(24시간 해제 유지), 빠른 접근, 주간 캘린더, 추천 콘텐츠 카드, 모드 캐러셀, 날짜별 노트 드로어 및 템플릿/태그/위시리스트 페이지 추가
    • 템플릿(평가 스키마) 편집 지원 및 템플릿 목록/핀 관리 UI 추가
    • FAB에 그룹화된 빠른 액션 및 새/주요 표시 추가
    • 검색 탭을 URL로 사전선택 가능
  • Refactor

    • 홈·캘린더·달력 UI 재구성 및 컴포넌트 기반으로 단순화
  • Bug Fixes

    • 연도/판매자 정보 부재 시 자리표시자(*) 항상 표시
  • Tests

    • 배너, 빠른접근, 추천콘텐츠, 주간캘린더 및 홈 관련 테스트 추가/갱신

- 홈을 대시보드 스타일로 재구성: 배너 + 퀵액세스 + 주간캘린더 + 추천차록
- HomeBanner: 컨텍스트 배너 + CTA (24시간 dismiss)
- QuickAccess: 내 차록/탐색/캘린더 퀵 버튼
- WeeklyCalendar: 7일 미니 캘린더 + 연속기록 뱃지
- RecommendedContent: 인기 차록 수평 스크롤
- 기존 ForYou/Following/Tags 피드를 Search 페이지 "피드" 탭으로 이동
- TDD: 4개 컴포넌트 테스트 + Home 테스트 업데이트

Closes #191

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cha-log Ready Ready Preview, Comment Mar 16, 2026 0:15am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 16, 2026

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

홈 화면을 대시보드형으로 재구성하고 상단 배너·퀵 액세스·모드 캐러셀·주간 캘린더·추천 콘텐츠 등 신규 컴포넌트를 추가했으며, 캘린더·템플릿 관련 API/서비스·타입 정의와 다수의 페이지·모달 및 테스트를 도입·조정했습니다. (50단어 이내)

Changes

Cohort / File(s) Summary
홈 UI 컴포넌트
src/components/home/HomeBanner.tsx, src/components/home/QuickAccess.tsx, src/components/home/RecommendedContent.tsx, src/components/home/WeeklyCalendar.tsx, src/components/home/ModeCarousel.tsx
홈 대시보드용 신규 컴포넌트 추가: 배너(24시간 dismiss, localStorage), 퀵액세스 버튼(라우팅), 추천 콘텐츠(노트 카드 수평 스크롤), 주간 캘린더(사용자 캘린더 데이터 페치·streak·CTA), 모드 토글 캐러셀.
홈/캘린더 보조 컴포넌트
src/components/calendar/DateNotesDrawer.tsx, src/components/calendar/StreakCards.tsx, src/components/home/CalendarWidget.tsx
달력 관련 재구성: DateNotesDrawer/ StreakCards 추가, CalendarWidget을 새 컴포지션으로 전환(달력 렌더링·모달/드로어 분리, dateUtils 사용).
페이지 추가/수정
src/pages/Home.tsx, src/pages/TagManager.tsx, src/pages/TastingTemplates.tsx, src/pages/WishlistedTeas.tsx, src/pages/TeaCalendar.tsx, src/pages/Cellar.tsx, src/pages/Search.tsx
Home 페이지 구조 대대적 변경(새 섹션 배치·피드 단순화), TagManager/TastingTemplates/WishlistedTeas/TeaCalendar 새 페이지 및 로직 추가, Cellar에서 일부 액션 카드 제거, Search 탭 초기값을 URL 기반으로 변경.
모달·FAB·템플릿 편집
src/components/AddTemplateModal.tsx, src/components/SpeedDialFAB.tsx
AddTemplateModal에 편집 모드 추가(스키마 편집 로직, notesApi.updateSchema 호출), SpeedDialFAB 항목 및 그룹 재구성(새 아이템·isPrimary/isNew 플래그).
API 클라이언트·타입·백엔드 변경
src/lib/api/notes.api.ts, packages/types/index.ts, packages/types/package.json, backend/src/notes/notes.controller.ts, backend/src/notes/notes.service.ts
notesApi.updateSchema 엔드포인트 추가, 공용 타입 패키지(@chalog/types) 추가(Tea/RatingSchema/RatingAxis/Axes/Note 등), 백엔드에 PATCH /notes/schemas/:schemaId 및 서비스 updateSchema 구현(검증·축 삭제·재생성).
달력 유틸·유틸리티
src/utils/dateUtils.ts
날짜 유틸 추가: DAY_NAMES, formatDateKey, formatDateLabel, getWeekDays.
테스트 변경/추가
src/components/home/__tests__/*, src/pages/__tests__/Home.test.tsx
Home 관련 유닛 테스트 추가 및 기존 Home 테스트 리팩터링: 컴포넌트 렌더/상호작용 검증, API/Auth 모킹, localStorage 검증 등.
경미한 UI 변경
src/components/NoteCard.tsx, src/components/profile/UserNoteList.tsx
teaYear/teaSeller 렌더링 변경: 존재 여부와 관계없이 값 또는 '*' 플레이스홀더를 항상 렌더링하도록 수정.

Sequence Diagram(s)

sequenceDiagram
participant User
participant Home as Home Component
participant Auth as AuthContext
participant API as notesApi
participant Router as react-router

User->>Home: 방문
Home->>Auth: useAuth (user?)
Auth-->>Home: user|null
alt user exists
Home->>API: getCalendar(year, month)
API-->>Home: calendarData (dates, streak)
Home->>Home: compute week days & modifiers
Home->>Home: render WeeklyCalendar (streak, days)
User->>Home: 클릭(오늘 차록 쓰기)
Home->>Router: navigate("/note/new")
else no user
Home->>Home: render unauthenticated variant
end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
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.
Out of Scope Changes check ❓ Inconclusive PR은 주로 홈 대시보드 리스트럭처링과 관련된 변경사항들로 구성되어 있습니다. 다만 TastingTemplates, TagManager, ModeCarousel 등 일부 컴포넌트는 #191 이슈의 직접적인 요구사항에 명시되지 않은 추가 기능입니다. TastingTemplates, TagManager, ModeCarousel 등 추가 컴포넌트들이 #191 이슈 범위에 포함되는지 확인이 필요합니다. 이들이 의도된 추가 기능인지 명확히 하세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 이슈 번호(#191)와 변경의 핵심인 '홈 대시보드 리스트럭처링'을 명확하게 담고 있어, 주요 변경사항을 잘 요약하고 있습니다.
Linked Issues check ✅ Passed PR의 코드 변경사항이 #191 이슈의 모든 주요 요구사항을 충족합니다: 배너(HomeBanner), 퀵액세스(QuickAccess), 주간캘린더(WeeklyCalendar), 추천콘텐츠(RecommendedContent) 컴포넌트 추가 및 홈 재구성, 소프트한 카드 스타일, 기존 요소들의 Search 페이지로의 이동 등이 모두 구현되었습니다.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/issue-191-home-restructure
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

CodeRabbit can use oxc to improve the quality of JavaScript and TypeScript code reviews.

Add a configuration file to your project to customize how CodeRabbit runs oxc.

Copy link
Copy Markdown
Contributor

@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: 3

🧹 Nitpick comments (8)
src/components/home/__tests__/QuickAccess.test.tsx (1)

30-34: 클릭 가능성 테스트가 실제 동작을 검증하지 못합니다.

현재는 버튼 개수만 확인해서 onClick 네비게이션이 깨져도 통과할 수 있습니다. 각 버튼 클릭 후 기대 경로(또는 navigate 호출)를 검증하도록 보강해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/home/__tests__/QuickAccess.test.tsx` around lines 30 - 34, The
test in QuickAccess.test.tsx only checks button count and must be strengthened
to verify onClick navigation: render QuickAccess with a router (use the existing
renderWithRouter or MemoryRouter), locate each QuickAccess button via
screen.getAllByRole('button') or getByText, simulate clicks using
userEvent.click, and assert navigation occurred by checking the history/location
pathname or by mocking/react-spying on useNavigate and verifying it was called
with the expected route; update the test to click each specific button and
assert the expected path or navigate call for QuickAccess.
src/components/home/__tests__/HomeBanner.test.tsx (1)

40-44: 24시간 만료 규칙을 검증하는 케이스를 추가해 주세요.

현재는 저장 여부만 확인하고 있어, “24시간 내 숨김 / 24시간 경과 후 재노출” 규칙 회귀를 잡기 어렵습니다. 타임스탬프를 사전 주입한 케이스 2개를 추가하는 것이 좋습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/home/__tests__/HomeBanner.test.tsx` around lines 40 - 44, Add
two tests around the HomeBanner localStorage timestamp rule: set the
'chalog-banner-dismissed' value to a JSON/timestamp payload representing a
recent dismissal (Date.now() minus less than 24*60*60*1000) and assert the
banner does not render after calling renderWithRouter(<HomeBanner />), then set
it to an old timestamp (Date.now() minus greater than 24*60*60*1000) and assert
the banner does render; use the same helpers (renderWithRouter, screen,
fireEvent) and the exact key 'chalog-banner-dismissed' to pre-inject the
timestamp values so the tests verify both "24시간 내 숨김" and "24시간 경과 후 재노출"
behaviors.
src/components/home/__tests__/RecommendedContent.test.tsx (1)

29-37: 핵심 비동기 렌더링 경로 검증이 빠져 있습니다.

현재 테스트는 정적 텍스트만 확인해서, 실제 추천 카드 렌더링/API 연동 문제가 있어도 놓칠 수 있습니다. findByText('철관음') 같은 비동기 assertion과 notesApi.getAll 호출 검증을 추가하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/home/__tests__/RecommendedContent.test.tsx` around lines 29 -
37, The tests only assert static headings — add an async assertion to verify the
actual recommended card renders and that the API is invoked: in the
RecommendedContent tests, after renderWithRouter(<RecommendedContent />) use an
async query such as await screen.findByText('철관음') (or another known card title)
to wait for the async render, and add a mock/spy assertion that notesApi.getAll
was called (e.g., expect(notesApi.getAll).toHaveBeenCalled()) to ensure the
component fetched data.
src/components/home/__tests__/WeeklyCalendar.test.tsx (1)

35-41: 요일 버튼 검증이 너무 느슨합니다.

현재는 전체 버튼 수(>= 7)만 확인해서, 요일 셀 구조가 깨져도 다른 버튼 수로 우연히 통과할 수 있습니다. 요일 영역을 명시적으로 타겟팅하는 쿼리(텍스트/테스트아이디 기반)로 바꾸는 편이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/home/__tests__/WeeklyCalendar.test.tsx` around lines 35 - 41,
The test "7개의 요일 버튼이 표시된다" in WeeklyCalendar.test.tsx is too loose because it
counts all buttons; update it to target the weekday buttons specifically (e.g.,
use screen.getAllByTestId('weekday-button') or assert each weekday label via
screen.getByText('월'), screen.getByText('화'), ...), and if the component lacks
identifiers add a stable attribute (data-testid="weekday-button" on the weekday
button elements or a data-testid for the weekday region in WeeklyCalendar) so
the test explicitly verifies the seven weekday controls rather than any buttons
on the page.
src/pages/Search.tsx (2)

86-86: isFeedLoading 상태가 설정되지만 사용되지 않습니다.

isFeedLoading 상태 변수가 Line 86에서 선언되고 Lines 230, 234에서 설정되지만, ForYouFeed 컴포넌트는 isLoading prop을 받지 않습니다 (context snippet에 따르면 notes: Note[]만 필요). 이 상태를 제거하거나, ForYouFeed에 로딩 표시기가 필요하다면 해당 prop을 추가하는 것을 고려해 주세요.

♻️ 제안: 사용하지 않는 상태 제거 또는 ForYouFeed에 isLoading 전달

옵션 1: 사용하지 않는 상태 제거

- const [isFeedLoading, setIsFeedLoading] = useState(false);

옵션 2: ForYouFeed 컴포넌트가 isLoading을 지원하도록 업데이트 후 전달

- <ForYouFeed notes={feedNotes} />
+ <ForYouFeed notes={feedNotes} isLoading={isFeedLoading} />

Also applies to: 229-234

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/Search.tsx` at line 86, The isFeedLoading state (isFeedLoading and
setIsFeedLoading) is declared in Search.tsx but never consumed by ForYouFeed;
either remove the unused state and any setIsFeedLoading calls (cleanup the state
and its setters) or update the ForYouFeed component to accept an isLoading prop
and pass isFeedLoading into it from Search.tsx, then implement loading UI inside
ForYouFeed; locate references to isFeedLoading/setIsFeedLoading in Search.tsx
and the ForYouFeed component to apply the chosen fix.

459-461: authLoadingfalse로 하드코딩되어 있습니다.

FollowingFeedTagsFeedauthLoading={false}가 하드코딩되어 있습니다. useAuth 훅에서 실제 로딩 상태를 가져와 전달하면 인증 상태 확인 중 더 정확한 UI를 표시할 수 있습니다.

♻️ 제안: AuthContext에서 실제 로딩 상태 사용
- const { user } = useAuth();
+ const { user, isLoading: authLoading } = useAuth();
  <FollowingFeed
    notes={followingNotes}
    isLoading={isFollowingLoading}
    isLoggedIn={!!user}
-   authLoading={false}
+   authLoading={authLoading}
  />
  <TagsFeed
    notes={tagFeedNotes}
    followedTags={followedTags}
    isLoading={isTagsLoading}
    isLoggedIn={!!user}
-   authLoading={false}
+   authLoading={authLoading}
  />

Also applies to: 468-470

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/Search.tsx` around lines 459 - 461, The authLoading prop is
hardcoded to false when rendering FollowingFeed and TagsFeed; instead obtain the
real loading state from the useAuth hook and pass it through. Update the Search
component to call useAuth (or reuse its result if already called) and replace
authLoading={false} with authLoading={authLoading} (or the exact variable name
returned by useAuth), ensuring both FollowingFeed and TagsFeed receive the true
loading state so their UI can reflect authentication loading properly.
src/pages/Home.tsx (1)

34-34: recentContributors가 항상 빈 배열로 전달됩니다.

HomeFooter에 빈 배열이 하드코딩되어 있어 최근 기여자 섹션이 렌더링되지 않습니다. 이것이 의도된 동작이라면, 향후 구현 계획이 있는지 TODO 주석을 추가하거나, 사용하지 않는다면 HomeFooter 컴포넌트 사용을 제거하는 것을 고려해 주세요.

💡 제안: 의도를 명확히 하는 주석 추가
+ {/* TODO: 최근 기여자 데이터 연동 필요 */}
  <HomeFooter recentContributors={[]} />

또는 사용하지 않는다면:

- <HomeFooter recentContributors={[]} />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/Home.tsx` at line 34, The HomeFooter is always receiving an empty
array via the recentContributors prop (HomeFooter recentContributors=[]), so
either wire it to real data or make the intent explicit: replace the hardcoded
[] with the actual contributors source (e.g., pass a state/prop or result of
fetchContributors in Home.tsx) so recent contributors render, or if it's
intentionally unused add a TODO comment above the HomeFooter explaining planned
implementation, or remove the HomeFooter invocation entirely; update the symbol
HomeFooter and the prop recentContributors accordingly.
src/pages/__tests__/Home.test.tsx (1)

52-54: 테스트 타임아웃 값이 다소 높습니다.

waitFor 타임아웃이 5000ms~10000ms로 설정되어 있습니다. CI 환경을 고려한 것으로 보이지만, 이렇게 높은 값은 테스트가 불안정하거나 컴포넌트 렌더링이 느린 것을 나타낼 수 있습니다. 가능하다면 기본 타임아웃(1000ms)으로 충분한지 확인해 보세요.

Also applies to: 60-62, 68-70

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/__tests__/Home.test.tsx` around lines 52 - 54, The three waitFor
calls in Home.test.tsx using explicit long timeouts should be shortened: replace
the { timeout: 10000 } (and the other instances at the same file) with either
the default waitFor timeout (remove the options object) or a smaller explicit
timeout (e.g., 1000–5000ms) and re-run tests; locate the waitFor(...) blocks
that assert screen.getByText('캘린더') and the two other similar waitFor assertions
and update their timeout values (or remove the timeout) so tests rely on the
default/react-testing-library timing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/home/RecommendedContent.tsx`:
- Around line 15-19: 현재 RecommendedContent에서 notesApi.getAll(undefined, true)로
전체 공개 노트를 받아온 뒤 클라이언트에서 slice(0, 10)으로 잘라 사용해 불필요한 트래픽과 지연을 유발합니다; 변경할 때는
notesApi.getAll 호출에 정렬/페이지/limit 파라미터를 전달하여 서버에서 필요한 항목(예: limit=10, 적절한 sort)을
반환하도록 하고 이후 setNotes에는 이미 제한된 결과만 전달하도록 수정하세요 (참조: notesApi.getAll, setNotes, 현재
사용된 slice 제거).

In `@src/components/home/WeeklyCalendar.tsx`:
- Around line 36-41: fetchCalendar only requests notes for the single month of
today, so weeks that span month boundaries miss hasNote markers; update
fetchCalendar to compute the displayed week's start and end dates (e.g.,
startOfWeek/endOfWeek based on today or the displayed week) and request data for
all months that intersect that range — either call notesApi.getCalendar for each
month in the range (merge results into calendarData) or add a date-range API
call and use that; adjust the logic that sets calendarData/hasNote accordingly
(refer to fetchCalendar, notesApi.getCalendar, today, and calendarData in
WeeklyCalendar and apply the same fix to the other fetch/merge logic between
lines 55-90).

In `@src/pages/Home.tsx`:
- Around line 19-21: The handleRefresh function currently calls
window.location.reload(), which causes a full page reload and loses React state;
instead implement an in-app refresh by converting handleRefresh into a
state-based trigger (e.g., increment a refreshCounter or toggle a refreshKey in
the Home component) and pass that trigger or dedicated onRefresh callbacks to
child components so they re-fetch their own data (or use your data-fetching
library’s invalidate/refetch API inside children); update the handleRefresh
implementation to update this refresh state and update child components to
accept an onRefresh prop or subscribe to the refreshKey to perform their local
fetches instead of relying on a full reload.

---

Nitpick comments:
In `@src/components/home/__tests__/HomeBanner.test.tsx`:
- Around line 40-44: Add two tests around the HomeBanner localStorage timestamp
rule: set the 'chalog-banner-dismissed' value to a JSON/timestamp payload
representing a recent dismissal (Date.now() minus less than 24*60*60*1000) and
assert the banner does not render after calling renderWithRouter(<HomeBanner
/>), then set it to an old timestamp (Date.now() minus greater than
24*60*60*1000) and assert the banner does render; use the same helpers
(renderWithRouter, screen, fireEvent) and the exact key
'chalog-banner-dismissed' to pre-inject the timestamp values so the tests verify
both "24시간 내 숨김" and "24시간 경과 후 재노출" behaviors.

In `@src/components/home/__tests__/QuickAccess.test.tsx`:
- Around line 30-34: The test in QuickAccess.test.tsx only checks button count
and must be strengthened to verify onClick navigation: render QuickAccess with a
router (use the existing renderWithRouter or MemoryRouter), locate each
QuickAccess button via screen.getAllByRole('button') or getByText, simulate
clicks using userEvent.click, and assert navigation occurred by checking the
history/location pathname or by mocking/react-spying on useNavigate and
verifying it was called with the expected route; update the test to click each
specific button and assert the expected path or navigate call for QuickAccess.

In `@src/components/home/__tests__/RecommendedContent.test.tsx`:
- Around line 29-37: The tests only assert static headings — add an async
assertion to verify the actual recommended card renders and that the API is
invoked: in the RecommendedContent tests, after
renderWithRouter(<RecommendedContent />) use an async query such as await
screen.findByText('철관음') (or another known card title) to wait for the async
render, and add a mock/spy assertion that notesApi.getAll was called (e.g.,
expect(notesApi.getAll).toHaveBeenCalled()) to ensure the component fetched
data.

In `@src/components/home/__tests__/WeeklyCalendar.test.tsx`:
- Around line 35-41: The test "7개의 요일 버튼이 표시된다" in WeeklyCalendar.test.tsx is
too loose because it counts all buttons; update it to target the weekday buttons
specifically (e.g., use screen.getAllByTestId('weekday-button') or assert each
weekday label via screen.getByText('월'), screen.getByText('화'), ...), and if the
component lacks identifiers add a stable attribute (data-testid="weekday-button"
on the weekday button elements or a data-testid for the weekday region in
WeeklyCalendar) so the test explicitly verifies the seven weekday controls
rather than any buttons on the page.

In `@src/pages/__tests__/Home.test.tsx`:
- Around line 52-54: The three waitFor calls in Home.test.tsx using explicit
long timeouts should be shortened: replace the { timeout: 10000 } (and the other
instances at the same file) with either the default waitFor timeout (remove the
options object) or a smaller explicit timeout (e.g., 1000–5000ms) and re-run
tests; locate the waitFor(...) blocks that assert screen.getByText('캘린더') and
the two other similar waitFor assertions and update their timeout values (or
remove the timeout) so tests rely on the default/react-testing-library timing.

In `@src/pages/Home.tsx`:
- Line 34: The HomeFooter is always receiving an empty array via the
recentContributors prop (HomeFooter recentContributors=[]), so either wire it to
real data or make the intent explicit: replace the hardcoded [] with the actual
contributors source (e.g., pass a state/prop or result of fetchContributors in
Home.tsx) so recent contributors render, or if it's intentionally unused add a
TODO comment above the HomeFooter explaining planned implementation, or remove
the HomeFooter invocation entirely; update the symbol HomeFooter and the prop
recentContributors accordingly.

In `@src/pages/Search.tsx`:
- Line 86: The isFeedLoading state (isFeedLoading and setIsFeedLoading) is
declared in Search.tsx but never consumed by ForYouFeed; either remove the
unused state and any setIsFeedLoading calls (cleanup the state and its setters)
or update the ForYouFeed component to accept an isLoading prop and pass
isFeedLoading into it from Search.tsx, then implement loading UI inside
ForYouFeed; locate references to isFeedLoading/setIsFeedLoading in Search.tsx
and the ForYouFeed component to apply the chosen fix.
- Around line 459-461: The authLoading prop is hardcoded to false when rendering
FollowingFeed and TagsFeed; instead obtain the real loading state from the
useAuth hook and pass it through. Update the Search component to call useAuth
(or reuse its result if already called) and replace authLoading={false} with
authLoading={authLoading} (or the exact variable name returned by useAuth),
ensuring both FollowingFeed and TagsFeed receive the true loading state so their
UI can reflect authentication loading properly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cde91237-dcca-452b-a7ae-91fe94144fea

📥 Commits

Reviewing files that changed from the base of the PR and between 3d314f4 and 6af46a2.

📒 Files selected for processing (11)
  • src/components/home/HomeBanner.tsx
  • src/components/home/QuickAccess.tsx
  • src/components/home/RecommendedContent.tsx
  • src/components/home/WeeklyCalendar.tsx
  • src/components/home/__tests__/HomeBanner.test.tsx
  • src/components/home/__tests__/QuickAccess.test.tsx
  • src/components/home/__tests__/RecommendedContent.test.tsx
  • src/components/home/__tests__/WeeklyCalendar.test.tsx
  • src/pages/Home.tsx
  • src/pages/Search.tsx
  • src/pages/__tests__/Home.test.tsx

Comment thread src/components/home/RecommendedContent.tsx Outdated
Comment on lines +36 to +41
const fetchCalendar = useCallback(async () => {
if (!user) return;
setIsLoading(true);
try {
const data = await notesApi.getCalendar(user.id, today.getFullYear(), today.getMonth() + 1);
setCalendarData(data);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

월 경계 주간에서 기록 점 표시가 누락될 수 있습니다.

주간은 7일 범위를 렌더링하지만, 데이터는 today 기준 단일 월만 조회합니다. 주 시작/끝이 다른 월에 걸리는 주에는 해당 월의 기록 점(hasNote)이 표시되지 않습니다.

제안 수정안
-      const data = await notesApi.getCalendar(user.id, today.getFullYear(), today.getMonth() + 1);
-      setCalendarData(data);
+      const monthKeys = Array.from(
+        new Set(weekDays.map((d) => `${d.getFullYear()}-${d.getMonth() + 1}`))
+      );
+
+      const monthly = await Promise.all(
+        monthKeys.map((key) => {
+          const [year, month] = key.split('-').map(Number);
+          return notesApi.getCalendar(user.id, year, month);
+        })
+      );
+
+      const mergedDates = monthly.flatMap((m) => m.dates);
+      const currentKey = `${today.getFullYear()}-${today.getMonth() + 1}`;
+      const currentMonth = monthly[monthKeys.indexOf(currentKey)];
+
+      setCalendarData({
+        dates: mergedDates,
+        streak: currentMonth?.streak ?? { current: 0, longest: 0 },
+      });

Also applies to: 55-90

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/home/WeeklyCalendar.tsx` around lines 36 - 41, fetchCalendar
only requests notes for the single month of today, so weeks that span month
boundaries miss hasNote markers; update fetchCalendar to compute the displayed
week's start and end dates (e.g., startOfWeek/endOfWeek based on today or the
displayed week) and request data for all months that intersect that range —
either call notesApi.getCalendar for each month in the range (merge results into
calendarData) or add a date-range API call and use that; adjust the logic that
sets calendarData/hasNote accordingly (refer to fetchCalendar,
notesApi.getCalendar, today, and calendarData in WeeklyCalendar and apply the
same fix to the other fetch/merge logic between lines 55-90).

Comment thread src/pages/Home.tsx
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@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.

♻️ Duplicate comments (1)
src/pages/Home.tsx (1)

19-23: ⚠️ Potential issue | 🟠 Major

Pull-to-refresh가 현재 실질적으로 동작하지 않습니다.

지금 구현은 제스처는 연결되어 있지만 실제 갱신 트리거가 없어 사용자 입장에서 새로고침 효과가 없습니다. 이전 코멘트의 연장선 이슈로, no-op 대신 refresh 상태를 올려 데이터 컴포넌트 재조회가 일어나게 연결해 주세요.

🔧 제안 수정안
-import { useCallback } from 'react';
+import { useCallback, useState } from 'react';

 export function Home() {
   useScrollRestoration();

   const { user: currentUser } = useAuth();
+  const [refreshNonce, setRefreshNonce] = useState(0);

   const handleRefresh = useCallback(async () => {
-    // 컴포넌트들이 자체 데이터를 관리하므로 no-op (각 컴포넌트가 mount 시 fetch)
+    setRefreshNonce((prev) => prev + 1);
   }, []);

   usePullToRefreshForPage(handleRefresh, '/');

   return (
     <div className="min-h-screen pb-20">
       <Header showProfile showLogo />
       <div className="px-4 py-5 pb-20 sm:px-6 space-y-5 md:space-y-6">
         <HeroSection />
         <HomeBanner />
         <QuickAccess />
-        {currentUser && <WeeklyCalendar />}
-        <RecommendedContent />
+        {currentUser && <WeeklyCalendar key={`weekly-${refreshNonce}`} />}
+        <RecommendedContent key={`recommended-${refreshNonce}`} />
         <HomeFooter recentContributors={[]} />
       </div>
       <BottomNav />
     </div>
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/Home.tsx` around lines 19 - 23, handleRefresh is a no-op so
pull-to-refresh doesn't trigger data reload; change it to bump a local state
(e.g., refreshKey via useState) inside handleRefresh (setRefreshKey(k => k + 1)
or similar) and apply that state as a key prop to the container that renders the
child data components (so they remount and re-fetch on change); keep
usePullToRefreshForPage(handleRefresh, '/') as-is but ensure handleRefresh
triggers the remount by updating refreshKey in Home.
🧹 Nitpick comments (1)
src/pages/Home.tsx (1)

34-34: HomeFooter에 빈 배열 고정 전달은 의미 없는 렌더 경로입니다.

src/components/HomeFooter.tsx 구현상 recentContributors.length > 0일 때만 섹션이 렌더링되어, 현재 호출은 화면/기능 관점에서 효과가 없습니다. 실제 데이터 연결 전까지는 렌더를 제거하거나 주석으로 의도를 남기는 편이 더 명확합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/Home.tsx` at line 34, Home.tsx currently always renders <HomeFooter
recentContributors={[]} /> which is a no-op because HomeFooter only renders when
recentContributors.length > 0; remove this meaningless render (or replace it
with a clear TODO/comment) until real contributor data is wired up, or change it
to conditional rendering (e.g., only include the HomeFooter component when
recentContributors has items) so the code path matches HomeFooter's behavior;
update references to the recentContributors prop accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/pages/Home.tsx`:
- Around line 19-23: handleRefresh is a no-op so pull-to-refresh doesn't trigger
data reload; change it to bump a local state (e.g., refreshKey via useState)
inside handleRefresh (setRefreshKey(k => k + 1) or similar) and apply that state
as a key prop to the container that renders the child data components (so they
remount and re-fetch on change); keep usePullToRefreshForPage(handleRefresh,
'/') as-is but ensure handleRefresh triggers the remount by updating refreshKey
in Home.

---

Nitpick comments:
In `@src/pages/Home.tsx`:
- Line 34: Home.tsx currently always renders <HomeFooter recentContributors={[]}
/> which is a no-op because HomeFooter only renders when
recentContributors.length > 0; remove this meaningless render (or replace it
with a clear TODO/comment) until real contributor data is wired up, or change it
to conditional rendering (e.g., only include the HomeFooter component when
recentContributors has items) so the code path matches HomeFooter's behavior;
update references to the recentContributors prop accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 488ae27c-4211-435b-b463-dcce6e37eb9c

📥 Commits

Reviewing files that changed from the base of the PR and between 6af46a2 and 6f63847.

📒 Files selected for processing (1)
  • src/pages/Home.tsx

- NoteCard: 조건부 → 항상 표시 (teaYear || '*', teaSeller || '*')
- RecommendedContent: 연도/구입처 추가
- UserNoteList 그리드: 통일된 포맷으로 변경

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@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.

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

15-19: ⚠️ Potential issue | 🟠 Major

추천 목록 조회를 서버 제한으로 변경해 주세요.

Line 15-19은 전체 공개 차록을 받은 뒤 클라이언트에서 slice(0, 10) 하는 구조라 홈 초기 로드 비용이 커집니다. API 호출에서 sort/page/limit를 직접 지정해 서버에서 10개만 내려받는 방식이 안전합니다.

제안 수정안
-    notesApi.getAll(undefined, true)
+    notesApi.getAll(
+      undefined,
+      true,
+      undefined,
+      undefined,
+      undefined,
+      'rating',
+      1,
+      10
+    )
       .then((data) => {
         const arr = Array.isArray(data) ? data as Note[] : [];
-        setNotes(arr.slice(0, 10));
+        setNotes(arr);
       })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/home/RecommendedContent.tsx` around lines 15 - 19, The current
logic in RecommendedContent (where notesApi.getAll(undefined, true) is called
and then sliced with setNotes(arr.slice(0, 10))) fetches all public notes and
trims on the client; change the API call to request only 10 items server-side by
supplying the appropriate query params (e.g., sort/page/limit or whatever the
notesApi.getAll signature accepts) so the server returns max 10 results, then
keep the same Array.isArray check and setNotes call (remove the client-side
slice). Update the call site in RecommendedContent and ensure any type
assertions (Note[]) remain correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/components/home/RecommendedContent.tsx`:
- Around line 15-19: The current logic in RecommendedContent (where
notesApi.getAll(undefined, true) is called and then sliced with
setNotes(arr.slice(0, 10))) fetches all public notes and trims on the client;
change the API call to request only 10 items server-side by supplying the
appropriate query params (e.g., sort/page/limit or whatever the notesApi.getAll
signature accepts) so the server returns max 10 results, then keep the same
Array.isArray check and setNotes call (remove the client-side slice). Update the
call site in RecommendedContent and ensure any type assertions (Note[]) remain
correct.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 29a4b4e8-eec4-403c-94b4-32fdcd073421

📥 Commits

Reviewing files that changed from the base of the PR and between 6f63847 and d52244d.

📒 Files selected for processing (3)
  • src/components/NoteCard.tsx
  • src/components/home/RecommendedContent.tsx
  • src/components/profile/UserNoteList.tsx

- 홈: 추천 차록 아래에 맞춤/구독/향미 피드 탭 추가
- 탐색: 피드 탭 제거, 검색+탐색만 유지
- 퀵액세스: 캘린더 → 내 찻장으로 변경
- 추천 차록 더보기: 탐색 탭으로 이동 (/sasaek?tab=explore)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- RecommendedContent를 props 기반으로 변경 (자체 fetch 제거, API 호출 1회로 감소)
- 홈에서 수평 하이라이트 카드 + 피드 탭을 하나의 "차록 흐름" 섹션으로 통합
- 테스트 mock에 usersApi.getOnboardingPreference 추가
- 비동기 테스트 안정화 (timeout 이슈 해결)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@FLYLIKEB FLYLIKEB merged commit 5ef40f1 into main Mar 16, 2026
2 of 3 checks passed
@FLYLIKEB FLYLIKEB deleted the feature/issue-191-home-restructure branch March 16, 2026 12:16
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.

레퍼런스 UI 분석: 해피문데이 - 홈화면 및 캘린더 방식

1 participant