Skip to content

[feat] 메인페이지 구현 #70

@mgYang53

Description

@mgYang53

📄 설명

메인페이지(/)를 로그인한 유저의 대시보드로 구현합니다.

현재 HomePage는 인사말만 표시하는 최소한의 상태이며, 피그마 디자인에 맞춰 3개 섹션을 추가합니다:

  • 지금 읽고 있는 책: 가로 캐러셀로 READING 상태 도서 표시, 필터 탭(전체/약속 전/약속 후), 좌우 화살표 네비게이션
  • 내 약속: 약속 중/예정/종료 상태별 카드 리스트, 탭 필터(전체/다가오는 약속/종료된 약속), 펼치기/접기
  • 즐겨찾는 모임: 즐겨찾기 모임 카드 그리드 표시

API 엔드포인트

기능 Method Path 비고
내 약속 리스트 조회 GET `/api/meetings/me` 신규 연동 (커서 기반)
내 약속 탭 카운트 GET `/api/meetings/me/tab-counts` 신규 연동
내 책장 목록 조회 GET `/api/book` 기존 API 재사용
즐겨찾기 모임 목록 GET `/api/gatherings/favorites` 기존 API 재사용
즐겨찾기 토글 POST `/api/gatherings/{id}/favorite` 기존 API 재사용

✅ 해야 할 일

Phase 1: Meeting API 레이어

  • meetings.types.ts에 타입 추가
    • MyMeetingProgressStatus'UPCOMING' | 'ONGOING' | 'DONE' | 'UNKNOWN'
    • MyMeetingRole'LEADER' | 'GATHERING_LEADER' | 'MEMBER' | 'NONE'
    • MyMeetingListItem — 약속 아이템 (meetingId, meetingName, gatheringId, gatheringName, meetingLeaderName, bookName, startDateTime, endDateTime, meetingStatus, myRole, progressStatus)
    • MyMeetingCursor — 커서 (startDateTime, meetingId)
    • MyMeetingListResponse — 리스트 응답 (items, totalCount, pageSize, hasNext, nextCursor)
    • MyMeetingFilter'ALL' | 'UPCOMING' | 'DONE'
    • GetMyMeetingsParams — 조회 파라미터 (filter, startDateTime, meetingId, size)
    • MyMeetingTabCountsResponse — 탭 카운트 (all, upcoming, done)
  • meetings.api.ts에 API 함수 추가
    • getMyMeetings(params)GET /api/meetings/me
    • getMyMeetingTabCounts()GET /api/meetings/me/tab-counts
  • React Query 훅 생성
    • myMeetingQueryKeys.ts — 쿼리 키 팩토리
    • useMyMeetings.tsuseInfiniteQuery (커서 기반, 초기 size=4)
    • useMyMeetingTabCounts.tsuseQuery
  • meetings/index.ts export 추가

Phase 2: 공통 컴포넌트

  • src/shared/ui/BookCarousel.tsx — 가로 스크롤 캐러셀
    • 가로 스크롤 컨테이너 (overflow-x, scroll-behavior: smooth)
    • 좌/우 화살표 버튼 (hover 시에만 표시, 모바일 숨김)
    • 화살표 세로 위치: 썸네일 영역(260px) 기준 중앙
    • 스크롤 양 끝에서 해당 방향 버튼 비활성화
    • 스크롤바 숨김 처리
  • src/shared/ui/index.ts에 BookCarousel export 추가

Phase 3: HomePage 기본 레이아웃

  • HomePage.tsx 리팩터 — 섹션 레이아웃 (gap: 80px)
  • HomeSectionHeader.tsx — 섹션 헤더 공통 컴포넌트
    • 제목 (typo-heading3)
    • 필터 탭 (Tabs 컴포넌트 large 사이즈 재사용)
    • 우측 바로가기 링크 (TextButton + ChevronRight)

Phase 4: 지금 읽고 있는 책 섹션

  • ReadingBooksSection.tsx
    • useBooks({ status: 'READING' }) 재사용
    • 탭: 전체(활성) / 약속 전, 약속 후 (UI만 배치, API 미지원으로 추후 활성화)
    • "내 책장 바로가기" → /books
  • HomeBookCard.tsx — 홈 전용 도서 카드
    • 너비 180px, 썸네일 180×260px, rounded-small, shadow
    • 제목: typo-subtitle2, 2줄 line-clamp-2
    • 저자: typo-caption1 text-grey-600, 1줄 line-clamp-1
    • 카드 간 24px gap
    • 클릭 시 /books/{bookId}로 이동
  • 빈 상태: "내 책장이 비어있어요." + "책 추가하기" 버튼 (→ /books/search)

Phase 5: 내 약속 섹션

  • MyMeetingsSection.tsx
    • useMyMeetings(filter) + useMyMeetingTabCounts() 사용
    • 탭: 전체/다가오는 약속/종료된 약속 (카운트 배지)
    • 약속 중(ONGOING) → 최상단 별도 카드 스타일 (bg-accent-100, border-accent-200)
    • 초기 4개 노출, "펼치기" → fetchNextPage, "접기" → 첫 페이지만 표시
    • 최대 높이 392px, overflow-y scroll
  • HomeMeetingCard.tsx — 홈 전용 약속 카드
    • 상태 태그: 약속 중(red) / 예정(yellow) / 종료(grey) — Badge 재사용
    • 모임 이름 | 약속 이름 (말줄임 처리)
    • 약속장 배지 (myRole === 'LEADER' → purple badge)
    • D-Day 표시 (예정 약속, 프론트에서 계산)
    • 날짜/시간 포맷: YY.MM.DD(요일) HH:mm ~ YY.MM.DD(요일) HH:mm
    • 액션 버튼: 예정 → "사전 의견 작성하기" (primary/disabled), 종료 → "개인 회고 작성하기"
  • 빈 상태: "참여 중인 약속이 없어요" (높이 98px)

Phase 6: 즐겨찾는 모임 섹션

  • FavoriteGatheringsSection.tsx
    • useFavoriteGatherings() 재사용
    • GatheringCard 컴포넌트 재사용
    • 카드 그리드: 3열, gap-small
    • 즐겨찾기 토글: useToggleFavorite() 재사용
    • 클릭: navigate(ROUTES.GATHERING_DETAIL(gatheringId))
    • "모임 홈 바로가기" → /gatherings
  • 빈 상태: "즐겨찾기한 모임이 없어요." + 설명 텍스트 (높이 140px)

Phase 7: 검증

  • Lint 통과 (pnpm lint)
  • Build 통과 (pnpm build)
  • 기능 테스트
    • 3개 섹션 렌더링 확인
    • 각 섹션 빈 상태 UI 확인
    • 캐러셀 좌우 스크롤 및 화살표 동작
    • 내 약속 탭 전환 및 펼치기/접기
    • 즐겨찾기 모임 토글
    • 바로가기 링크 이동

📝 메모

도서 카드 '약속 전/약속 후' 태그

  • 현재 Book API(PersonalBookListResponse)에 meetingTag 필드가 없음
  • 탭 UI만 배치하고, 전체 탭만 활성화 상태로 구현
  • 백엔드 API에 필드 추가 시 바로 연동 가능하도록 준비

재사용하는 기존 코드

  • useUserProfile()src/features/user/hooks/useUserProfile.ts
  • useBooks()src/features/book/hooks/useBooks.ts
  • useFavoriteGatherings()src/features/gatherings/hooks/useFavoriteGatherings.ts
  • useToggleFavorite()src/features/gatherings/hooks/useToggleFavorite.ts
  • GatheringCardsrc/features/gatherings/components/GatheringCard.tsx
  • Badge, Button, TextButton, Tabssrc/shared/ui/
  • ROUTESsrc/shared/constants/routes.ts

Metadata

Metadata

Assignees

Labels

feat새로운 기능 추가

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions