Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (21)
Walkthrough홈 페이지를 모듈화하여 CouncilNoticeSection, HomeClubSection, ScheduleSection 등 섹션 컴포넌트를 추가했고, 각 섹션을 SectionAsyncBoundary로 래핑해 Suspense 및 Sentry ErrorBoundary 처리를 통합했습니다. BottomNav를 데이터 드리븐으로 리팩터링해 NavLink 기반 렌더링과 BottomNavItem 구성으로 대체했고, 여러 홈 관련 훅(useGetHomeMyClubs, useGetHomeRecruitingClubs, useInfiniteClubCarousel 등)과 카루셀/미니 스케줄 컴포넌트를 추가했습니다. SimpleClubCard·SimpleAppliedClubCard와 useGetAppliedClubs·useGetJoinedClubs 파일은 삭제되었고, SCHEDULE_DAYS와 clubQueryKeys가 새로 추가되어 여러 파일의 import 경로가 변경되었습니다. Possibly related PRs
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
홈 화면 리디자인을 위해 기존 Home 페이지의 섹션 렌더링/로딩/에러 처리 방식을 컴포넌트 단위로 재구성하고, 주간(미니) 일정 미리보기·공의회 공지·동아리 캐러셀 UI를 추가/개선합니다. 동시에 레이아웃(스크롤바 숨김), 헤더/하단 네비게이션 스타일도 함께 업데이트합니다.
Changes:
- Home을 섹션 단위 컴포넌트(AsyncBoundary + Skeleton/ErrorFallback)로 분리하고 새 UI 구성 적용
- 동아리 무한 캐러셀 훅/컴포넌트 추가 및 모집중/내 동아리 섹션 구성 변경
- 미니 일정 프리뷰/공지 카드/레이아웃 스크롤바/헤더·하단 네비게이션 스타일 업데이트, 요일 상수 공통화
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/pages/Schedule/index.tsx | 요일 라벨을 공통 상수로 교체 |
| src/pages/Home/types.ts | 홈 캐러셀 카드용 타입 추가 |
| src/pages/Home/index.tsx | Home 섹션을 SectionAsyncBoundary 기반 구성으로 재작성 |
| src/pages/Home/hooks/useInfiniteClubCarousel.ts | 무한 캐러셀 스크롤/인디케이터/루프 보정 로직 추가 |
| src/pages/Home/hooks/useGetJoinedClubs.ts | 기존 단일 joined 훅 제거 |
| src/pages/Home/hooks/useGetHomeClubs.ts | 홈 전용(내 동아리 + 모집중) 쿼리 훅 추가 |
| src/pages/Home/hooks/useGetAppliedClubs.ts | 기존 단일 applied 훅 제거 |
| src/pages/Home/components/SimpleClubCard.tsx | 기존 단순 카드 컴포넌트 제거 |
| src/pages/Home/components/SimpleAppliedClubCard.tsx | 기존 단순 카드 컴포넌트 제거 |
| src/pages/Home/components/SectionTitle.tsx | 섹션 헤더(제목/더보기) 컴포넌트 추가 |
| src/pages/Home/components/SectionErrorFallback.tsx | 홈 섹션 공용 에러 폴백 UI 추가 |
| src/pages/Home/components/SectionAsyncBoundary.tsx | 섹션 단위 Suspense + Sentry ErrorBoundary 래퍼 추가 |
| src/pages/Home/components/ScheduleSection.tsx | 일정 섹션(타이틀 + 미니 프리뷰) 컴포넌트화 |
| src/pages/Home/components/RecommendedClubCard.tsx | 캐러셀 카드 UI 추가 |
| src/pages/Home/components/MiniSchedulePreview.tsx | 홈 미니 일정 프리뷰 추가 |
| src/pages/Home/components/InfiniteClubCarousel.tsx | 캐러셀 렌더/인디케이터 UI 추가 |
| src/pages/Home/components/HomeClubSection.tsx | 내 동아리/모집중 동아리 섹션 구성 변경 |
| src/pages/Home/components/CouncilNoticeSection.tsx | 공의회 공지 섹션 추가(스켈레톤/폴백 포함) |
| src/pages/Home/components/CouncilNoticeCard.tsx | 공지 카드 스타일/타입 적용 변경 |
| src/constants/schedule.ts | 요일 상수(SCHEDULE_DAYS) 추가 |
| src/components/layout/index.tsx | main 스크롤바 숨김 클래스 추가 |
| src/components/layout/Header/components/NotificationBell.tsx | 알림 아이콘 교체 |
| src/components/layout/Header/components/InfoHeader.tsx | 헤더 스타일(패딩/그림자/라운드) 변경 |
| src/components/layout/BottomNav/index.tsx | BottomNav를 NavLink 기반으로 리팩터링 및 스타일 변경 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| useEffect(() => { | ||
| const scrollNode = scrollRef.current; | ||
| if (!scrollNode) return; | ||
|
|
||
| const handleScrollEnd = () => { | ||
| if (isAdjustingLoopRef.current) return; | ||
| syncCarouselPosition(); | ||
| }; | ||
|
|
||
| scrollNode.addEventListener('scrollend', handleScrollEnd); | ||
| return () => { | ||
| scrollNode.removeEventListener('scrollend', handleScrollEnd); | ||
| clearRestoreSnapFrame(); |
There was a problem hiding this comment.
scrollend 이벤트에만 의존해 루프 위치 보정(syncCarouselPosition)을 실행하고 있는데, scrollend는 브라우저 지원이 제한적이라(특히 iOS Safari) 보정 로직이 아예 동작하지 않을 수 있습니다. 이 경우 3세그먼트 복제 리스트의 끝에 도달하면 무한 캐러셀처럼 동작하지 않습니다. scroll 이벤트에 debounce/timeout(예: 마지막 스크롤 후 N ms)으로 sync를 호출하거나, pointerup/touchend 등 보조 트리거를 추가해 호환성 있는 종료 감지를 구현해 주세요.
| const dateList = getMonthDateList(); | ||
| const weeks: Date[][] = []; | ||
|
|
||
| for (let index = 0; index < dateList.length; index += 7) { | ||
| weeks.push(dateList.slice(index, index + 7)); | ||
| } | ||
|
|
||
| const handleDateClick = (date: Date) => { | ||
| navigate(`/schedule?year=${date.getFullYear()}&month=${date.getMonth() + 1}&day=${date.getDate()}`); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="h-[193px] overflow-hidden rounded-[20px] bg-white px-3 pt-3 shadow-[0_0_3px_rgba(0,0,0,0.2)]"> | ||
| <ul className="grid grid-cols-7 justify-items-center text-center text-[13px] leading-5 font-bold text-indigo-600"> | ||
| {SCHEDULE_DAYS.map((dayLabel) => ( | ||
| <li key={dayLabel}>{dayLabel}</li> | ||
| ))} | ||
| </ul> | ||
|
|
||
| <div className="mt-1"> | ||
| {weeks.map((weekDates) => ( | ||
| <CalendarWeekRow | ||
| key={weekDates[0].toISOString()} | ||
| dates={weekDates} | ||
| schedules={data.schedules} | ||
| isCurrentMonth={isCurrentMonth} | ||
| isSelectedDay={isSelectedDay} | ||
| isSunday={isSunday} | ||
| onDateClick={handleDateClick} | ||
| /> | ||
| ))} | ||
| </div> |
There was a problem hiding this comment.
현재 getMonthDateList()로 월 전체(최대 6주)를 만든 뒤 모든 weeks를 렌더링하지만, 컨테이너가 h-[193px] overflow-hidden이라 대부분의 주가 잘려서(특히 오늘이 월 후반인 경우) 사용자가 ‘이번 주/오늘’이 보이지 않는 미리보기를 보게 됩니다. 주간 미리보기 의도라면 ‘오늘이 포함된 주(또는 ±1주)’만 slice해서 렌더링하거나, 월 전체를 보여줄 거라면 높이/overflow 정책을 조정(세로 스크롤 허용 등)해 주세요.
| <Link | ||
| to={`/council/notice/${id}`} | ||
| key={id} | ||
| className="bg-indigo-0 border-indigo-5 block rounded-lg border-b px-3 py-3" | ||
| className="block rounded-lg border border-[#f4f6f9] bg-white px-3 py-3 shadow-[0_0_3px_rgba(0,0,0,0.2)]" |
There was a problem hiding this comment.
key는 리스트 렌더링 시 부모가 부여하는 용도라, 단일 컴포넌트 내부의 <Link>에 key={id}를 둘 필요가 없습니다(오해만 유발). 맵핑하는 쪽에서 이미 key를 주고 있으니 여기서는 제거해 주세요.
| const { data, hasNextPage, isFetchingNextPage, fetchNextPage } = useGetHomeRecruitingClubs({ | ||
| limit: CLUB_CAROUSEL_LIMIT, | ||
| }); | ||
|
|
||
| useEffect(() => { | ||
| if (hasNextPage && !isFetchingNextPage) { | ||
| void fetchNextPage(); | ||
| } | ||
| }, [fetchNextPage, hasNextPage, isFetchingNextPage]); |
There was a problem hiding this comment.
useEffect에서 hasNextPage인 동안 자동으로 fetchNextPage()를 반복 호출하고 있어, 홈 진입 시 전체 모집중 동아리 페이지를 끝까지 모두 프리페치하게 됩니다(페이지 수가 많으면 초기 로딩/트래픽 증가). 홈 캐러셀 목적이 ‘일부 추천 노출’이라면 1페이지만 사용하거나, 사용자 인터랙션(캐러셀 끝 접근) 시에만 다음 페이지를 가져오도록 제한해 주세요.
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (10)
src/components/layout/Header/components/InfoHeader.tsx (1)
11-13:text-caption1대신 프로젝트 타이포 토큰을 써주세요.가이드에 있는 캡션 토큰은
text-cap1/text-cap2라서, 지금 클래스는 타이포 스케일에서 벗어날 가능성이 있습니다.As per coding guidelines,
**/*.{ts,tsx}: Use typography tokens (text-h1throughtext-h5,text-sub1throughtext-sub4,text-body1throughtext-body3,text-cap1throughtext-cap2) fromsrc/styles/theme.css.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/layout/Header/components/InfoHeader.tsx` around lines 11 - 13, The JSX in InfoHeader (component InfoHeader.tsx) uses a non-standard class "text-caption1"; replace it with the project's typography token (either "text-cap1" or "text-cap2" as appropriate for the visual weight) in the div that renders {myInfo.name} {myInfo.studentNumber}, i.e., update the className on that element to use the theme's typography token from src/styles/theme.css so it conforms to the typography scale.src/pages/Home/components/SectionTitle.tsx (1)
11-12: 타이포그래피 토큰으로 맞춰주세요.
text-[16px],text-[14px]대신 공용text-sub*/text-body*/text-cap*토큰을 쓰는 편이 홈 섹션 간 스케일이 덜 흔들립니다.As per coding guidelines,
**/*.{ts,tsx}: Use typography tokens (text-h1throughtext-h5,text-sub1throughtext-sub4,text-body1throughtext-body3,text-cap1throughtext-cap2) fromsrc/styles/theme.css.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/components/SectionTitle.tsx` around lines 11 - 12, Replace the hard-coded pixel typography classes in SectionTitle (the h2 rendering {title} and the Link to={to}) with the project typography tokens from src/styles/theme.css; specifically swap text-[16px] on the h2 for the appropriate text-sub*/text-body* token (e.g., text-sub2 or text-body1 as per design) and replace text-[14px] on the Link with the matching smaller token (e.g., text-sub4 or text-body2), ensuring you only use the permitted tokens (text-h1..h5, text-sub1..sub4, text-body1..body3, text-cap1..cap2) in the SectionTitle component.src/components/layout/index.tsx (1)
26-31:twMerge대신cn()으로 통일해주세요.이 파일도 조건부 Tailwind 조합을 하고 있어서 공용
cn()유틸로 맞춰두는 편이 클래스 병합 방식이 일관됩니다.♻️ 제안 수정
-import { twMerge } from 'tailwind-merge'; +import { cn } from '@/utils/ts/cn'; ... - className={twMerge( + className={cn(As per coding guidelines,
**/*.{ts,tsx}: Usecn()utility fromsrc/utils/ts/cn.tsto merge Tailwind CSS classes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/layout/index.tsx` around lines 26 - 31, Replace the twMerge call with the shared cn() utility to make Tailwind class merging consistent: import cn from the cn utility, then swap twMerge(...) for cn(...) where the className is built (the expression that currently references twMerge and the variables isInfoHeader, showBottomNav, contentClassName); keep the same conditional class strings ('pt-15' vs 'pt-11', 'pb-19', base classes) and ensure the final className uses cn(content strings, contentClassName) so contentClassName still merges correctly.src/pages/Home/hooks/useGetHomeClubs.ts (1)
2-4: 공용 query key는 페이지 훅 밖으로 빼고 infinite 전용 key를 분리해 주세요.
clubQueryKeys를@/pages/Club/ClubList/hooks/useGetClubs에서 가져오면 Home 훅이 다른 페이지 내부 구현에 묶입니다. 같은listkey가 일반 query에도 쓰이면useInfiniteQuery와 캐시 shape가 충돌할 수 있으니 분리 여부를 확인해 주세요. As per coding guidelines, "Use React Query withuseSuspenseQueryand query key factory pattern for server state management" and "Separate page-specific logic into page-dedicatedhooks/directories instead of keeping it in the page component".Also applies to: 29-31
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/hooks/useGetHomeClubs.ts` around lines 2 - 4, The Home hook is importing clubQueryKeys from another page hook which couples Home to ClubList and risks query key collisions between normal and infinite queries; update useGetHomeClubs to stop importing clubQueryKeys from '@/pages/Club/ClubList/hooks/useGetClubs' and instead create or import a shared query key factory (e.g., clubQueryKeysFactory) outside page-specific hooks, and define a distinct key for infinite lists (e.g., clubQueryKeys.infinite.list or clubInfiniteQueryKeys.list) so useGetHomeClubs and useGetClubs each consume the appropriate key shape and avoid mixing useInfiniteQuery keys with standard list keys; ensure the new key factory is colocated in a shared queries module and update references in useGetHomeClubs and useGetClubs accordingly.src/pages/Home/components/RecommendedClubCard.tsx (1)
18-20: 색상/타이포를 raw 값보다 theme token으로 맞춰 주세요.
border-[#f4f6f9],text-[#5a6b7f],text-[16px]같은 값이 많아서 이 카드만 디자인 시스템에서 벗어납니다. theme color/typography token으로 맞추면 이후 유지보수가 쉬워집니다. As per coding guidelines, "Prioritize color tokens fromsrc/styles/theme.css" and "Use typography tokens (text-h1throughtext-cap2) fromsrc/styles/theme.css".Also applies to: 30-41
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/components/RecommendedClubCard.tsx` around lines 18 - 20, The RecommendedClubCard component is using raw color and typography utilities (e.g., border-[`#f4f6f9`], text-[`#5a6b7f`], text-[16px])—replace those with the design system theme tokens instead: swap border-[`#f4f6f9`] for the appropriate border color token, replace raw hex text colors with the theme color tokens, and change text-[16px]/other raw size classes to the corresponding typography tokens (text-h1…text-cap2) used across the project; update the className on the root (className={cn(...)} in RecommendedClubCard) and any inner element classes referenced around the same block (lines ~30–41) to use the theme tokens so the card conforms to the design system.src/pages/Home/components/InfiniteClubCarousel.tsx (1)
4-4: 상대 경로 대신 alias import로 맞춰 주세요.이 파일만
./RecommendedClubCard를 써서 현재 import 규칙에서 벗어납니다. As per coding guidelines, "Use@/*alias for import paths instead of relative paths".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/components/InfiniteClubCarousel.tsx` at line 4, The import in InfiniteClubCarousel.tsx uses a relative path for RecommendedClubCard; replace the relative import ("./RecommendedClubCard") with the project alias form (use the "@/..." alias) so it follows the coding guideline to use `@/`* aliases for imports, ensuring the import statement references RecommendedClubCard via the alias instead of a relative path.src/pages/Home/components/MiniSchedulePreview.tsx (1)
55-55: 커스텀 폰트 사이즈 대신 typography 토큰 사용 권장
text-[13px]는 커스텀 값입니다. 가능하다면text-cap1또는text-cap2같은 typography 토큰 사용을 고려해주세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/components/MiniSchedulePreview.tsx` at line 55, The className on the ul in MiniSchedulePreview uses a custom font size token "text-[13px]"; replace it with the project's typography token (e.g., text-cap1 or text-cap2) to align with design tokens. Update the class string in the MiniSchedulePreview component (the ul with className "... text-[13px] ...") to use the appropriate token (text-cap1 or text-cap2) and ensure visual parity with the previous 13px size before committing.src/pages/Home/components/HomeClubSection.tsx (1)
61-67: normalizeAppliedClub에서 subLabel 누락
normalizeJoinedClub과normalizeRecruitingClub은subLabel을 설정하지만,normalizeAppliedClub은categoryName이 있음에도subLabel을 설정하지 않습니다. 의도된 것인지 확인해주세요.♻️ 제안
function normalizeAppliedClub(club: AppliedClub): HomeClubCardItem { return { id: club.id, name: club.name, imageUrl: club.imageUrl, + subLabel: club.categoryName, badgeLabel: '승인 대기', }; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/components/HomeClubSection.tsx` around lines 61 - 67, The normalizeAppliedClub function is missing the subLabel property while normalizeJoinedClub and normalizeRecruitingClub set subLabel from categoryName; update normalizeAppliedClub (returning HomeClubCardItem for AppliedClub) to include subLabel: club.categoryName (or formatted equivalent) alongside id, name, imageUrl, and badgeLabel so the applied-club cards display the category like the others.src/pages/Home/hooks/useInfiniteClubCarousel.ts (2)
171-185: useEffect 의존성 배열 검토빈 의존성 배열
[]로 설정되어 있으나,syncCarouselPosition을 내부에서 호출합니다.useEffectEvent로 감싸져 있어 의존성에 포함하지 않아도 되지만, ESLint 규칙에 따라 경고가 발생할 수 있습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/hooks/useInfiniteClubCarousel.ts` around lines 171 - 185, The effect adds a 'scrollend' listener but uses syncCarouselPosition, which triggers ESLint dependency warnings; wrap the handler in a stable reference using useEffectEvent (e.g., create handleScrollEnd via useEffectEvent that calls syncCarouselPosition and checks isAdjustingLoopRef.current) and then register/remove that stable handler in the useEffect so the dependency array can remain empty; ensure clearRestoreSnapFrame is still called in the cleanup and reference scrollRef, isAdjustingLoopRef, syncCarouselPosition, and clearRestoreSnapFrame when locating the code to modify.
91-108: jumpToLoopPosition의 double rAF 패턴두 번의
requestAnimationFrame을 중첩하여 snap 복원을 지연시키는 패턴입니다. 브라우저에 따라 동작이 다를 수 있으므로, 필요시 테스트를 권장합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Home/hooks/useInfiniteClubCarousel.ts` around lines 91 - 108, The double requestAnimationFrame in jumpToLoopPosition (which sets restoreSnapFrameRef.current) can be unreliable across browsers; replace the nested rAF pattern with a single requestAnimationFrame followed by setTimeout(..., 0) to defer restoring scrollSnapType to the next macrotask, and update clearRestoreSnapFrame and restoreSnapFrameRef handling to cancel both the RAF (via cancelAnimationFrame) and the timeout (via clearTimeout) — or store separate refs (e.g., restoreSnapRafRef and restoreSnapTimeoutRef) — so isAdjustingLoopRef, scrollRef, and scrollNode.style.scrollSnapType are restored reliably and cancellations work correctly.
🤖 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/layout/Header/components/NotificationBell.tsx`:
- Around line 9-10: The NotificationBell's Link currently renders only an icon
so screen readers can't convey its purpose; update the Link (the element
rendering Link to {'chats'}) to include an accessible name by adding an
aria-label (e.g., aria-label="Open chats" or aria-label="Notifications") or
adding visually hidden text inside the Link next to <ChatCatIcon />; ensure the
label accurately describes the action and that keyboard focus/role remains on
the Link (no extra interactive elements), so screen readers can announce the
link purpose.
In `@src/pages/Home/components/CouncilNoticeCard.tsx`:
- Around line 11-13: 'truncate' on the title div (the element rendering {title}
in CouncilNoticeCard.tsx) can fail inside a flex row; update the element with
either min-w-0 or flex-1 (e.g., add the Tailwind class "min-w-0" or "flex-1") so
the truncation/ellipsis works and the unread dot isn't pushed out of view.
In `@src/pages/Home/components/InfiniteClubCarousel.tsx`:
- Around line 24-25: The root div in the InfiniteClubCarousel component
currently uses className="gap-1" which has no effect because the div is not a
flex/grid container; update the root div (the returned top-level element in
InfiniteClubCarousel) to use either a container utility like "flex flex-col
gap-1" or the spacing utility "space-y-1" (e.g., replace "gap-1" with "flex
flex-col" plus gap or with "space-y-1") so the intended vertical spacing between
the indicator and the list is applied.
In `@src/pages/Home/components/RecommendedClubCard.tsx`:
- Around line 23-26: The card image in RecommendedClubCard currently uses
alt={club.name}, causing screen readers to read the link label twice; change the
img to a decorative image by setting alt="" (empty string) and add
aria-hidden="true" (or role="presentation") on the same <img> element (which
uses club.imageUrl and className with cn(...)) so the adjacent club.name text
remains the accessible label.
In `@src/pages/Home/components/SectionErrorFallback.tsx`:
- Around line 3-4: The error message in SectionErrorFallback is currently only a
visual span and should be exposed to assistive tech; modify the component
(SectionErrorFallback) so the error container or the message element includes
role="alert" (and optionally aria-live="assertive") on the same element that
renders the span with text "불러오는 중 오류가 발생했어요", keeping the existing className
composition and layout intact; ensure you add the attribute to the outer div or
the span within the component so screen readers receive the update immediately
without changing visual styling.
In `@src/pages/Home/components/SectionTitle.tsx`:
- Around line 12-14: The "더보기" Link in SectionTitle is missing an accessible
label; update the Link element in the SectionTitle component to add an
aria-label that includes the section title (e.g., aria-label={`${title} 더보기`}),
ensuring you reference the component prop name title and keep the existing
className and to prop unchanged; verify the SectionTitle props type includes
title as a string so the label is type-safe and consistent across usages.
---
Nitpick comments:
In `@src/components/layout/Header/components/InfoHeader.tsx`:
- Around line 11-13: The JSX in InfoHeader (component InfoHeader.tsx) uses a
non-standard class "text-caption1"; replace it with the project's typography
token (either "text-cap1" or "text-cap2" as appropriate for the visual weight)
in the div that renders {myInfo.name} {myInfo.studentNumber}, i.e., update the
className on that element to use the theme's typography token from
src/styles/theme.css so it conforms to the typography scale.
In `@src/components/layout/index.tsx`:
- Around line 26-31: Replace the twMerge call with the shared cn() utility to
make Tailwind class merging consistent: import cn from the cn utility, then swap
twMerge(...) for cn(...) where the className is built (the expression that
currently references twMerge and the variables isInfoHeader, showBottomNav,
contentClassName); keep the same conditional class strings ('pt-15' vs 'pt-11',
'pb-19', base classes) and ensure the final className uses cn(content strings,
contentClassName) so contentClassName still merges correctly.
In `@src/pages/Home/components/HomeClubSection.tsx`:
- Around line 61-67: The normalizeAppliedClub function is missing the subLabel
property while normalizeJoinedClub and normalizeRecruitingClub set subLabel from
categoryName; update normalizeAppliedClub (returning HomeClubCardItem for
AppliedClub) to include subLabel: club.categoryName (or formatted equivalent)
alongside id, name, imageUrl, and badgeLabel so the applied-club cards display
the category like the others.
In `@src/pages/Home/components/InfiniteClubCarousel.tsx`:
- Line 4: The import in InfiniteClubCarousel.tsx uses a relative path for
RecommendedClubCard; replace the relative import ("./RecommendedClubCard") with
the project alias form (use the "@/..." alias) so it follows the coding
guideline to use `@/`* aliases for imports, ensuring the import statement
references RecommendedClubCard via the alias instead of a relative path.
In `@src/pages/Home/components/MiniSchedulePreview.tsx`:
- Line 55: The className on the ul in MiniSchedulePreview uses a custom font
size token "text-[13px]"; replace it with the project's typography token (e.g.,
text-cap1 or text-cap2) to align with design tokens. Update the class string in
the MiniSchedulePreview component (the ul with className "... text-[13px] ...")
to use the appropriate token (text-cap1 or text-cap2) and ensure visual parity
with the previous 13px size before committing.
In `@src/pages/Home/components/RecommendedClubCard.tsx`:
- Around line 18-20: The RecommendedClubCard component is using raw color and
typography utilities (e.g., border-[`#f4f6f9`], text-[`#5a6b7f`],
text-[16px])—replace those with the design system theme tokens instead: swap
border-[`#f4f6f9`] for the appropriate border color token, replace raw hex text
colors with the theme color tokens, and change text-[16px]/other raw size
classes to the corresponding typography tokens (text-h1…text-cap2) used across
the project; update the className on the root (className={cn(...)} in
RecommendedClubCard) and any inner element classes referenced around the same
block (lines ~30–41) to use the theme tokens so the card conforms to the design
system.
In `@src/pages/Home/components/SectionTitle.tsx`:
- Around line 11-12: Replace the hard-coded pixel typography classes in
SectionTitle (the h2 rendering {title} and the Link to={to}) with the project
typography tokens from src/styles/theme.css; specifically swap text-[16px] on
the h2 for the appropriate text-sub*/text-body* token (e.g., text-sub2 or
text-body1 as per design) and replace text-[14px] on the Link with the matching
smaller token (e.g., text-sub4 or text-body2), ensuring you only use the
permitted tokens (text-h1..h5, text-sub1..sub4, text-body1..body3,
text-cap1..cap2) in the SectionTitle component.
In `@src/pages/Home/hooks/useGetHomeClubs.ts`:
- Around line 2-4: The Home hook is importing clubQueryKeys from another page
hook which couples Home to ClubList and risks query key collisions between
normal and infinite queries; update useGetHomeClubs to stop importing
clubQueryKeys from '@/pages/Club/ClubList/hooks/useGetClubs' and instead create
or import a shared query key factory (e.g., clubQueryKeysFactory) outside
page-specific hooks, and define a distinct key for infinite lists (e.g.,
clubQueryKeys.infinite.list or clubInfiniteQueryKeys.list) so useGetHomeClubs
and useGetClubs each consume the appropriate key shape and avoid mixing
useInfiniteQuery keys with standard list keys; ensure the new key factory is
colocated in a shared queries module and update references in useGetHomeClubs
and useGetClubs accordingly.
In `@src/pages/Home/hooks/useInfiniteClubCarousel.ts`:
- Around line 171-185: The effect adds a 'scrollend' listener but uses
syncCarouselPosition, which triggers ESLint dependency warnings; wrap the
handler in a stable reference using useEffectEvent (e.g., create handleScrollEnd
via useEffectEvent that calls syncCarouselPosition and checks
isAdjustingLoopRef.current) and then register/remove that stable handler in the
useEffect so the dependency array can remain empty; ensure clearRestoreSnapFrame
is still called in the cleanup and reference scrollRef, isAdjustingLoopRef,
syncCarouselPosition, and clearRestoreSnapFrame when locating the code to
modify.
- Around line 91-108: The double requestAnimationFrame in jumpToLoopPosition
(which sets restoreSnapFrameRef.current) can be unreliable across browsers;
replace the nested rAF pattern with a single requestAnimationFrame followed by
setTimeout(..., 0) to defer restoring scrollSnapType to the next macrotask, and
update clearRestoreSnapFrame and restoreSnapFrameRef handling to cancel both the
RAF (via cancelAnimationFrame) and the timeout (via clearTimeout) — or store
separate refs (e.g., restoreSnapRafRef and restoreSnapTimeoutRef) — so
isAdjustingLoopRef, scrollRef, and scrollNode.style.scrollSnapType are restored
reliably and cancellations work correctly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 99537938-fe7e-43ae-8994-c9d6af7444f1
⛔ Files ignored due to path filters (1)
src/assets/svg/chat-cat.svgis excluded by!**/*.svg,!src/assets/**and included by**
📒 Files selected for processing (24)
src/components/layout/BottomNav/index.tsxsrc/components/layout/Header/components/InfoHeader.tsxsrc/components/layout/Header/components/NotificationBell.tsxsrc/components/layout/index.tsxsrc/constants/schedule.tssrc/pages/Home/components/CouncilNoticeCard.tsxsrc/pages/Home/components/CouncilNoticeSection.tsxsrc/pages/Home/components/HomeClubSection.tsxsrc/pages/Home/components/InfiniteClubCarousel.tsxsrc/pages/Home/components/MiniSchedulePreview.tsxsrc/pages/Home/components/RecommendedClubCard.tsxsrc/pages/Home/components/ScheduleSection.tsxsrc/pages/Home/components/SectionAsyncBoundary.tsxsrc/pages/Home/components/SectionErrorFallback.tsxsrc/pages/Home/components/SectionTitle.tsxsrc/pages/Home/components/SimpleAppliedClubCard.tsxsrc/pages/Home/components/SimpleClubCard.tsxsrc/pages/Home/hooks/useGetAppliedClubs.tssrc/pages/Home/hooks/useGetHomeClubs.tssrc/pages/Home/hooks/useGetJoinedClubs.tssrc/pages/Home/hooks/useInfiniteClubCarousel.tssrc/pages/Home/index.tsxsrc/pages/Home/types.tssrc/pages/Schedule/index.tsx
💤 Files with no reviewable changes (4)
- src/pages/Home/components/SimpleClubCard.tsx
- src/pages/Home/components/SimpleAppliedClubCard.tsx
- src/pages/Home/hooks/useGetAppliedClubs.ts
- src/pages/Home/hooks/useGetJoinedClubs.ts
| return ( | ||
| <div className="gap-1"> |
There was a problem hiding this comment.
gap-1이 현재는 적용되지 않습니다.
루트 div가 flex/grid 컨테이너가 아니라 indicator와 리스트 사이 간격이 생기지 않습니다. flex flex-col 또는 space-y-1로 바꿔 주세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/Home/components/InfiniteClubCarousel.tsx` around lines 24 - 25, The
root div in the InfiniteClubCarousel component currently uses className="gap-1"
which has no effect because the div is not a flex/grid container; update the
root div (the returned top-level element in InfiniteClubCarousel) to use either
a container utility like "flex flex-col gap-1" or the spacing utility
"space-y-1" (e.g., replace "gap-1" with "flex flex-col" plus gap or with
"space-y-1") so the intended vertical spacing between the indicator and the list
is applied.
- src/apis/club/queries.ts에 clubQueryKeys 팩토리 이동 - infinite.list 키 네임스페이스 추가로 일반 쿼리와 무한 쿼리 키 충돌 방지 - useGetClubs, useGetHomeClubs 포함 전체 참조를 공유 모듈로 일원화
normalizeAppliedClub에 subLabel: club.categoryName 추가
- NotificationBell Link에 aria-label="채팅 열기" 추가 - CouncilNoticeCard 제목에 min-w-0 추가로 flex 컨테이너 내 truncate 정상화 - RecommendedClubCard 이미지를 장식용(alt="", aria-hidden)으로 변경해 중복 읽기 방지 - SectionErrorFallback 컨테이너에 role="alert" 추가 - SectionTitle 더보기 Link에 aria-label 추가
scrollend를 지원하지 않는 iOS Safari < 26에서 루프 보정이 동작하지 않는 문제를 scroll 이벤트 + 150ms debounce로 해결
월 전체 weeks를 렌더링하면 overflow-hidden으로 오늘이 잘려 보이지 않는 문제를 오늘이 포함된 주부터 2주 slice로 수정
- layout/index.tsx: twMerge 직접 호출을 cn 유틸로 통일 - InfoHeader.tsx: text-caption1을 text-cap1으로 수정
0eeb4ef to
da4c330
Compare
Summary by CodeRabbit
릴리스 노트
새로운 기능
스타일
버그 수정 / 안정성
정리