Skip to content

Conversation

@cl-o-lc
Copy link
Collaborator

@cl-o-lc cl-o-lc commented Sep 19, 2025

실시간 인기 사이트 랭킹을 조회할 수 있는 페이지를 구현했습니다.
사용자는 기간 및 카테고리별로 인기 사이트 목록을 필터링하여 확인할 수 있습니다.

📌 작업 내용

  • 인기 사이트 순위 목록 UI 구현
  • 기간(Period) 및 카테고리(Category)별 필터링 기능 추가
  • 데이터 없음 상태에 대한 UI 처리

🛠️ 변경 사항

  • API 응답 데이터의 식별자 키(id) 불일치로 인한 렌더링 오류 수정 🐞
  • 북마크 페이지에서 전역 헤더 숨김 (ClientHeader 조건부 렌더링)

📸 스크린샷

image image

📝 기타

텅~

Summary by CodeRabbit

  • New Features

    • 실시간 랭킹 페이지 추가: 기간·카테고리 필터, 순위 배지, 검색 횟수 표시, 로딩/에러 처리 및 빈 상태(EmptyState) UI.
    • 인기 사이트 조회용 API 클라이언트 추가.
    • 내비게이션 개선: 랭킹(/ranking), 반응속도 게임, 도움말 등 실제 경로로 연결.
    • 헤더 표시 제어: 북마크 및 하위 경로에서 헤더 숨김.
  • Chores

    • 의존성 업데이트: lucide-react, @types/react, @types/react-dom, typescript 버전 상향.

- 실시간 인기 사이트 랭킹을 표시하는 페이지 UI 구현
- 기간(period) 및 카테고리(category)에 따른 필터링 기능 추가
- 데이터 로딩, 에러, 목록이 없는 경우(Empty State)에 대한 UI 상태 처리를 구현
- API 호출 로직을 popularSites 모듈로 분리
API 응답 데이터의 실제 식별자 키가 `site_id`가 아닌 `id`로 확인되어, FE 데이터 모델과 불일치가 발생했습니다.

이로 인해 RankingPage에서 `site.site_id`가 `undefined`로 평가되어, 목록 렌더링 시 React key 경고가 발생하는 문제를 해결했습니다.

- Site 인터페이스의 `site_id`를 `id`로 변경
- 컴포넌트에서 `key={site.id}`를 사용하도록 수정
@cl-o-lc cl-o-lc self-assigned this Sep 19, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 19, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

실시간 랭킹 페이지와 API 클라이언트, 빈 상태 컴포넌트가 추가되었고, 헤더 내비게이션 링크들이 실경로로 업데이트되었으며 /bookmarks 및 하위 경로에서 헤더를 숨기도록 제어 로직이 도입되었습니다. package.json의 의존성 버전이 상향되었습니다.

Changes

Cohort / File(s) Change Summary
의존성 업데이트
package.json
lucide-react, @types/react, @types/react-dom, typescript 등 버전 상향.
실시간 랭킹 신규 기능
src/app/ranking/page.tsx, src/libs/api/popularSites.ts, src/components/RankingEmptyState.tsx
랭킹 페이지 컴포넌트 추가(필터, 로딩/에러/빈 상태 처리), 인기 사이트 API 클라이언트(Site 인터페이스 및 getPopularSites) 추가, 빈 상태 UI 컴포넌트(EmptyState) 추가.
내비게이션 경로 연결
src/app/bookmarks/page.tsx, src/components/ui/Header.tsx
헤더/페이지 내 네비게이션 링크를 #에서 실제 경로(/ranking, /reaction-test, /help, /bookmarks)로 변경.
헤더 표시 제어
src/components/ClientHeader.tsx
usePathname 기반으로 /bookmarks 및 하위 경로에서 헤더를 숨기도록 조건부 렌더링 추가.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant RP as RankingPage
  participant API as getPopularSites()
  participant BE as Backend API

  User->>RP: 페이지 진입 / 필터 선택
  activate RP
  RP->>API: getPopularSites({period, category})
  activate API
  API->>BE: GET /api/sites/popular/popular-sites?period=...&limit=10[&category=...]
  activate BE
  BE-->>API: 200 + { success, data.sites } / error
  deactivate BE
  API-->>RP: Promise<Site[]> 또는 예외
  deactivate API

  alt 성공 및 데이터 존재
    RP-->>User: 랭킹 리스트 렌더링 (랭크 배지, 사이트, 클릭수)
  else 성공이지만 빈 결과
    RP-->>User: EmptyState 표시
  else 실패
    RP-->>User: 에러 메시지 표시
  end
  deactivate RP
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

feat🛠️

Poem

달빛 밟고 달리는 토끼예요 🐇
새로 온 랭킹은 번쩍번쩍 ✨
비어도 걱정 마요, 곧 채워질 거예요.
북마크 길에선 살짝 숨고,
링크 따라 클릭하며 춤출래요.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed PR 제목 "[feature] 실시간 순위 페이지 구현"은 변경사항의 핵심(실시간 인기 순위 페이지 추가)을 간결하게 요약하며 src/app/ranking/page.tsx 추가와 관련 컴포넌트·API 변경을 잘 반영합니다; 한 문장으로 명확하고 불필요한 노이즈가 없어 히스토리 스캔 시 주요 변경을 즉시 파악할 수 있습니다.
Description Check ✅ Passed PR 설명은 레포지토리 템플릿의 주요 섹션(## 📌 작업 내용, ## 📸 스크린샷, ## 📝 기타)을 포함하고 있으며 구현한 기능(기간·카테고리 필터, 빈 상태 UI), 버그 수정(id 불일치 수정), 헤더 숨김 변경 등 리뷰에 필요한 핵심 정보를 명확히 전달하므로 전반적으로 완전합니다.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3868b9 and 30c207e.

📒 Files selected for processing (1)
  • src/libs/api/popularSites.ts (1 hunks)

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.

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

🧹 Nitpick comments (7)
src/components/ui/Header.tsx (1)

70-72: 도움말 링크를 실제 경로로 연결

북마크 페이지에서는 /help로 연결하고 있습니다. 헤더도 동일하게 맞추는 게 좋습니다.

다음 변경을 제안합니다:

-          <Link href="#" className="hover:text-black transition-colors">
+          <Link href="/help" className="hover:text-black transition-colors">
             도움말
           </Link>
src/app/bookmarks/page.tsx (1)

192-215: 내비게이션에 대신 next/link 사용

현재 를 사용해 전체 페이지 리로드가 발생합니다. 클라이언트 라우팅을 위해 Link로 교체하세요.

다음 변경을 제안합니다:

-            <a
-              href="/ranking"
-              className="text-gray-600 text-sm font-medium hover:text-black transition-colors no-underline"
-            >
-              실시간 랭킹
-            </a>
+            <Link
+              href="/ranking"
+              className="text-gray-600 text-sm font-medium hover:text-black transition-colors no-underline"
+            >
+              실시간 랭킹
+            </Link>
-            <a
-              href="/reaction-test"
-              className="text-gray-600 text-sm font-medium hover:text-black transition-colors no-underline"
-            >
-              반응속도 게임
-            </a>
+            <Link
+              href="/reaction-test"
+              className="text-gray-600 text-sm font-medium hover:text-black transition-colors no-underline"
+            >
+              반응속도 게임
+            </Link>
-            <a
-              href="/bookmarks"
-              className="text-black text-sm font-semibold no-underline"
-            >
-              북마크
-            </a>
+            <Link
+              href="/bookmarks"
+              className="text-black text-sm font-semibold no-underline"
+            >
+              북마크
+            </Link>
-            <a
-              href="/help"
-              className="text-gray-600 text-sm font-medium hover:text-black transition-colors no-underline"
-            >
-              도움말
-            </a>
+            <Link
+              href="/help"
+              className="text-gray-600 text-sm font-medium hover:text-black transition-colors no-underline"
+            >
+              도움말
+            </Link>
src/components/RankingEmptyState.tsx (1)

6-23: 인라인 스타일 → Tailwind 전환으로 일관성 향상

프로젝트 전반의 Tailwind 사용과 맞추면 유지보수성과 다크모드 대응이 좋아집니다.

다음 변경을 제안합니다:

-    <div
-      style={{
-        textAlign: 'center',
-        padding: '4rem 2rem',
-        backgroundColor: '#fff',
-        borderRadius: '12px',
-        boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
-      }}
-    >
-      <span style={{ fontSize: '4rem' }}>텅~</span>
-      <h2 style={{ marginTop: '1rem', fontWeight: 'bold' }}>
+    <div className="text-center p-16 bg-white rounded-xl shadow-md">
+      <span className="text-6xl">텅~</span>
+      <h2 className="mt-4 font-bold">
         아직 집계된 기록이 없어요
       </h2>
-      <p style={{ color: '#6c757d', fontSize: '1rem' }}>
+      <p className="text-gray-500 text-base">
         사용자들이 사이트를 검색하면 이곳에 실시간 순위가 표시됩니다.
       </p>
     </div>
src/app/ranking/page.tsx (4)

3-6: 타입 import로 명시성 개선

React 네임스페이스 타입 대신 명시적 타입 import를 권장합니다.

+import type { CSSProperties } from 'react';
@@
-const getRankBadgeStyle = (rank: number): React.CSSProperties => {
+const getRankBadgeStyle = (rank: number): CSSProperties => {

Also applies to: 8-13


61-72: 설명 문구가 선택된 카테고리와 불일치

카테고리가 ‘대학교’여도 ‘티켓팅 사이트’로 고정 표기됩니다. 동적으로 표현하세요.

-            지금 가장 많이 검색되는 티켓팅 사이트를 확인하세요.
+            지금 가장 많이 검색되는 {activeCategory === '전체' ? '사이트' : `${activeCategory} 사이트`}를 확인하세요.

85-103: 필터 버튼 a11y 개선

현재 선택 상태를 전달하기 위해 aria-pressed 추가 권장.

-            <button
+            <button
               key={cat}
               onClick={() => setActiveCategory(cat)}
+              aria-pressed={activeCategory === cat}
@@
-            <button
+            <button
               key={p}
               onClick={() => setPeriod(p)}
+              aria-pressed={period === p}

Also applies to: 115-131


206-209: 비정상 값 대비 안전한 표기

click_count가 숫자가 아닐 때 NaN 노출을 방지하세요.

-                      {parseInt(site.click_count, 10).toLocaleString()}
+                      {Number.isFinite(Number(site.click_count))
+                        ? Number(site.click_count).toLocaleString()
+                        : '0'}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac3b4e and d3868b9.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • package.json (2 hunks)
  • src/app/bookmarks/page.tsx (1 hunks)
  • src/app/ranking/page.tsx (1 hunks)
  • src/components/ClientHeader.tsx (2 hunks)
  • src/components/RankingEmptyState.tsx (1 hunks)
  • src/components/ui/Header.tsx (1 hunks)
  • src/libs/api/popularSites.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/ClientHeader.tsx (1)
src/components/ui/Header.tsx (1)
  • Header (23-105)
src/app/ranking/page.tsx (2)
src/libs/api/popularSites.ts (2)
  • Site (1-7)
  • getPopularSites (23-59)
src/components/RankingEmptyState.tsx (1)
  • EmptyState (4-24)
🔇 Additional comments (3)
src/components/ui/Header.tsx (1)

55-57: /ranking 링크 갱신 LGTM

플레이스홀더에서 실제 경로로 전환되어 내비게이션 일관성이 좋아졌습니다.

src/components/ClientHeader.tsx (1)

13-17: 경로 기반 헤더 숨김 로직 LGTM

/bookmarks 및 하위 경로에서 헤더 비노출 처리, 조건부 렌더 모두 적절합니다.

Also applies to: 129-138

package.json (1)

13-29: 의존성 호환성 확인 — CI/환경의 Node.js 버전 확인 필요

Next.js 15.4은 Node.js 18.18+ 및 TypeScript ≥4.5.2를 요구합니다. package.json의 typescript@^5.9.2, @types/react@^19 / @types/react-dom@^19, lucide-react@0.544.0은 React 19과 호환됩니다. 조치: CI/로컬 빌드 이미지 또는 package.json engines에서 Node.js ≥18.18 사용 여부를 확인하세요.

@cl-o-lc cl-o-lc merged commit 770363c into main Sep 19, 2025
1 check was pending
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.

2 participants