Skip to content

[Feature/#60] 캠페인 목록 테이블 UI 구현 - #69

Merged
YermIm merged 2 commits into
developfrom
feature/#60
Feb 28, 2026
Merged

[Feature/#60] 캠페인 목록 테이블 UI 구현#69
YermIm merged 2 commits into
developfrom
feature/#60

Conversation

@YermIm

@YermIm YermIm commented Feb 28, 2026

Copy link
Copy Markdown
Collaborator

🚨 관련 이슈

close #60

✨ 변경사항

  • 🐞 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.)

✏️ 작업 내용

  • CampaignTable, CampaignRow 컴포넌트 생성해 캠페인 목록 조회 테이블 구현
  • ProgressBar 컴포넌트 제작
  • 창이 줄어들 경우 테이블의 항목이 뭉개지지 않도록 테이블 컨테이너에 min-w-180 적용 -> 가로 스크롤
스크린샷 2026-02-28 오전 10 06 25

😅 미완성 작업

  • 하단 제어 배너 공용 컴포넌트 구현
  • 캠페인 상세 페이지
  • 추후 페이지네이션 추가 예정

📢 논의 사항 및 참고 사항

N/A

💬 리뷰어 가이드 (P-Rules)
P1: 필수 반영 (Critical) - 버그 가능성, 컨벤션 위반. 해결 전 머지 불가.
P2: 적극 권장 (Recommended) - 더 나은 대안 제시. 가급적 반영 권장.
P3: 제안 (Suggestion) - 아이디어 공유. 반영 여부는 드라이버 자율.
P4: 단순 확인/칭찬 (Nit) - 사소한 오타, 칭찬 등 피드백.

Summary by CodeRabbit

새로운 기능

  • 광고 캠프 목록 페이지 추가 - 캠프 테이블 인터페이스로 전체 캠프 한눈에 확인
  • 캠프별 주요 정보 표시 - 플랫폼, 이름, 동기화 상태, 예산 소진률 조회 가능
  • 진행률 표시 기능 추가 - 각 캠프의 예산 사용 현황을 시각적으로 확인

@YermIm YermIm self-assigned this Feb 28, 2026
@YermIm YermIm added the ✨ Feature 기능 개발 label Feb 28, 2026
@YermIm
YermIm requested review from Seojegyeong and jjjsun February 28, 2026 01:20
@coderabbitai

coderabbitai Bot commented Feb 28, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

광고 운영 관리 페이지의 캠페인 목록 UI를 구현합니다. 캠페인 타입 정의, 진행률 표시 컴포넌트(ProgressBar), 캠페인 행(CampaignRow) 및 테이블(CampaignTable) 컴포넌트를 추가하고, AdsListPage에 통합합니다.

Changes

Cohort / File(s) Summary
타입 정의
src/types/ads/campaign.ts
플랫폼(kakao, google, naver), 동기화 상태(inactive, syncing, success), 캠페인 데이터 구조 타입 정의.
공통 컴포넌트
src/components/common/progressbar/ProgressBar.tsx, src/components/common/progressbar/ProgressBar.stories.tsx
예산 소진 현황 표시 ProgressBar 컴포넌트 구현 및 스토리북 추가. 0~100 범위의 진행률을 시각화하며 퍼센티지 레이블 표시.
광고 컴포넌트
src/components/ads/CampaignRow.tsx, src/components/ads/CampaignTable.tsx
캠페인 행(플랫폼 아이콘, 캠페인명, 동기화 상태, 예산 진행률)과 캠페인 테이블(헤더 및 행 목록) 컴포넌트 구현.
페이지 통합
src/pages/ads/list/AdsListPage.tsx
AdsListPage에 CampaignTable 통합. 헤더, 캠페인 목록, 하단 배너 레이아웃 구성.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항인 캠페인 목록 테이블 UI 구현을 명확하게 요약하고 있으며, 관련 이슈 번호 #60도 포함되어 있습니다.
Description check ✅ Passed PR 설명에서 관련 이슈, 변경사항 체크, 작업 내용, 미완성 작업, 논의 사항을 모두 포함하고 있으며 템플릿의 주요 섹션을 충족합니다.
Linked Issues check ✅ Passed CampaignTable, CampaignRow, ProgressBar 컴포넌트를 모두 구현했으며, 이슈 #60의 모든 체크리스트 항목이 완료되었습니다.
Out of Scope Changes check ✅ Passed 모든 코드 변경사항이 이슈 #60의 요구사항인 캠페인 목록 테이블 UI 구현과 직접 관련이 있으며, 범위 내의 변경입니다.

✏️ 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/#60

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.

@github-actions

Copy link
Copy Markdown

📚 Storybook 배포 완료

항목 링크
📖 Storybook https://69a147b60a56365d9e2185ef-bgfixougtt.chromatic.com/
🔍 Chromatic https://www.chromatic.com/build?appId=69a147b60a56365d9e2185ef&number=12

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (5)
src/components/common/progressbar/ProgressBar.stories.tsx (1)

14-19: Storybook 스토리가 잘 구성되어 있습니다.

기본 스토리 설정이 적절합니다. 선택적으로, 다양한 케이스를 테스트하기 위한 추가 스토리를 고려해 볼 수 있습니다:

📚 추가 스토리 예시
export const Empty: TProgressBarStory = {
  args: { value: 0, className: "w-[300px]" },
};

export const Full: TProgressBarStory = {
  args: { value: 100, className: "w-[300px]" },
};

export const Overflow: TProgressBarStory = {
  args: { value: 150, className: "w-[300px]" }, // 클램핑 동작 확인
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/progressbar/ProgressBar.stories.tsx` around lines 14 -
19, Add additional Storybook stories for the ProgressBar to cover edge cases:
create new named exports like Empty, Full, and Overflow of type
TProgressBarStory alongside the existing Default in ProgressBar.stories.tsx;
each should pass different args (e.g., value: 0 for Empty, value: 100 for Full,
and a value >100 for Overflow) and reuse className: "w-[300px]" so you can
verify clamping/overflow behavior in the ProgressBar component and ensure
stories appear in Storybook.
src/components/common/progressbar/ProgressBar.tsx (1)

15-32: 접근성(Accessibility) 개선이 필요합니다.

Progress bar 컴포넌트에 스크린 리더 사용자를 위한 ARIA 속성이 누락되어 있습니다. role="progressbar"와 관련 ARIA 속성을 추가하면 접근성이 향상됩니다.

♿ 접근성 속성 추가 제안
     <div
       className={twMerge("flex items-center gap-3 w-full", className)}
+      role="progressbar"
+      aria-valuenow={progress}
+      aria-valuemin={0}
+      aria-valuemax={100}
+      aria-label="진행률"
       {...rest}
     >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/progressbar/ProgressBar.tsx` around lines 15 - 32, The
ProgressBar component is missing ARIA attributes for screen readers; update the
element that visually represents the bar (the inner div with className "h-full
bg-chart-3..." or the outer container div for the component) to include
role="progressbar" and the attributes aria-valuenow={progress},
aria-valuemin={0}, aria-valuemax={100} and ensure an accessible label via
aria-label or aria-valuetext (e.g., aria-label={`Progress ${progress}%`}); use
the existing progress prop and keep the visual styling and transition unchanged.
src/components/ads/CampaignRow.tsx (2)

37-44: 플랫폼 아이콘에 접근성 라벨 추가를 권장합니다.

스크린 리더 사용자가 어떤 플랫폼인지 인식할 수 있도록 각 로고에 접근성 라벨을 추가하면 좋겠습니다.

♿ 접근성 라벨 추가 예시
         {platforms.map((p, idx) => (
           <div
             key={idx}
             className="flex h-8 w-8 mr-3 items-center justify-center rounded-full shadow-sm overflow-hidden shrink-0"
+            role="img"
+            aria-label={p}
           >
             {LogoMap[p]}
           </div>
         ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ads/CampaignRow.tsx` around lines 37 - 44, Add accessible
labels to the platform icons rendered inside CampaignRow by giving the icon
container an appropriate aria-label (or role="img" with aria-label) derived from
the platform identifier (the platforms array item `p`) or from a lookup in
`LogoMap` (e.g., `LogoMap[p].label` or a new `getPlatformName(p)` helper);
update the mapped element that currently uses `key={idx}` and renders
`{LogoMap[p]}` to include the aria-label/role so screen readers announce the
platform name.

33-64: 클릭 가능한 행에 대한 접근성 고려가 필요합니다.

hover:cursor-pointer와 hover 효과가 적용되어 있어 클릭 가능한 요소로 보이지만, 현재 onClick 핸들러와 키보드 접근성이 없습니다. PR 설명에 캠페인 상세 페이지가 미구현이라고 되어 있으니, 추후 구현 시 아래 사항을 고려해 주세요:

  • onClick 핸들러 추가
  • tabIndex={0}onKeyDown (Enter/Space) 핸들러로 키보드 접근성 지원
  • role="button" 또는 적절한 시맨틱 요소 사용
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ads/CampaignRow.tsx` around lines 33 - 64, The list row
currently looks interactive via hover:cursor-pointer but lacks click and
keyboard handlers; update the root li in the CampaignRow component to be fully
accessible by adding an onClick prop (wired to the navigation or a passed
handler), tabIndex={0}, role="button", and an onKeyDown handler that triggers
the same action for Enter and Space keys (use event.key === 'Enter' || event.key
=== ' ' / 'Spacebar' as appropriate), and include an appropriate aria-label or
aria-describedby using the campaign name to describe the action; ensure the
onClick/onKeyDown handler delegates to the same function so mouse and keyboard
invoke identical behavior (and keep focus styles visible).
src/components/ads/CampaignTable.tsx (1)

5-39: 목업 데이터 구조가 잘 정의되어 있습니다.

현재 UI 구현 단계에서 하드코딩된 데이터로 작업하는 것은 적절합니다. 다만, 추후 API 연동 시 아래 사항을 고려해 주세요:

  1. React Query 사용: 서버 상태 관리를 위해 useQuery 훅으로 데이터 fetching
  2. 로딩/에러 상태 처리: 스켈레톤 UI 또는 에러 메시지 표시
  3. 빈 상태 처리: 캠페인이 없을 때의 empty state UI

코딩 가이드라인에 따라, 서버 상태는 React Query로 관리하고 전역 상태는 Zustand로 분리하는 구조를 권장드립니다.

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

In `@src/components/ads/CampaignTable.tsx` around lines 5 - 39, 현재 CampaignTable
컴포넌트가 하드코딩된 campaigns 배열을 사용하고 있으니, 추후 API 연동을 위해 campaigns 상수 대신 React Query의
useQuery를 사용해 데이터를 패칭하도록 변경하고(함수/키: CampaignTable, campaigns, ICampaign), 로딩 상태는
스켈레톤 UI로, 에러 상태는 적절한 에러 메시지로 처리하고 빈 배열일 경우 빈 상태 UI를 렌더링하도록 구현하세요; 또한 전역으로 관리해야 할
캠페인 상태가 있다면 Zustand(또는 기존 전역 스토어)로 분리해 useQuery의 데이터를 필요한 곳에서만 구독하도록 리팩토링하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/components/ads/CampaignRow.tsx`:
- Around line 37-44: Add accessible labels to the platform icons rendered inside
CampaignRow by giving the icon container an appropriate aria-label (or
role="img" with aria-label) derived from the platform identifier (the platforms
array item `p`) or from a lookup in `LogoMap` (e.g., `LogoMap[p].label` or a new
`getPlatformName(p)` helper); update the mapped element that currently uses
`key={idx}` and renders `{LogoMap[p]}` to include the aria-label/role so screen
readers announce the platform name.
- Around line 33-64: The list row currently looks interactive via
hover:cursor-pointer but lacks click and keyboard handlers; update the root li
in the CampaignRow component to be fully accessible by adding an onClick prop
(wired to the navigation or a passed handler), tabIndex={0}, role="button", and
an onKeyDown handler that triggers the same action for Enter and Space keys (use
event.key === 'Enter' || event.key === ' ' / 'Spacebar' as appropriate), and
include an appropriate aria-label or aria-describedby using the campaign name to
describe the action; ensure the onClick/onKeyDown handler delegates to the same
function so mouse and keyboard invoke identical behavior (and keep focus styles
visible).

In `@src/components/ads/CampaignTable.tsx`:
- Around line 5-39: 현재 CampaignTable 컴포넌트가 하드코딩된 campaigns 배열을 사용하고 있으니, 추후 API
연동을 위해 campaigns 상수 대신 React Query의 useQuery를 사용해 데이터를 패칭하도록 변경하고(함수/키:
CampaignTable, campaigns, ICampaign), 로딩 상태는 스켈레톤 UI로, 에러 상태는 적절한 에러 메시지로 처리하고 빈
배열일 경우 빈 상태 UI를 렌더링하도록 구현하세요; 또한 전역으로 관리해야 할 캠페인 상태가 있다면 Zustand(또는 기존 전역 스토어)로
분리해 useQuery의 데이터를 필요한 곳에서만 구독하도록 리팩토링하세요.

In `@src/components/common/progressbar/ProgressBar.stories.tsx`:
- Around line 14-19: Add additional Storybook stories for the ProgressBar to
cover edge cases: create new named exports like Empty, Full, and Overflow of
type TProgressBarStory alongside the existing Default in
ProgressBar.stories.tsx; each should pass different args (e.g., value: 0 for
Empty, value: 100 for Full, and a value >100 for Overflow) and reuse className:
"w-[300px]" so you can verify clamping/overflow behavior in the ProgressBar
component and ensure stories appear in Storybook.

In `@src/components/common/progressbar/ProgressBar.tsx`:
- Around line 15-32: The ProgressBar component is missing ARIA attributes for
screen readers; update the element that visually represents the bar (the inner
div with className "h-full bg-chart-3..." or the outer container div for the
component) to include role="progressbar" and the attributes
aria-valuenow={progress}, aria-valuemin={0}, aria-valuemax={100} and ensure an
accessible label via aria-label or aria-valuetext (e.g., aria-label={`Progress
${progress}%`}); use the existing progress prop and keep the visual styling and
transition unchanged.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfd37d4 and 9d65327.

⛔ Files ignored due to path filters (3)
  • src/assets/icon/ads/google-logo.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/ads/kakao-logo.svg is excluded by !**/*.svg and included by src/**
  • src/assets/icon/ads/naver-logo.svg is excluded by !**/*.svg and included by src/**
📒 Files selected for processing (6)
  • src/components/ads/CampaignRow.tsx
  • src/components/ads/CampaignTable.tsx
  • src/components/common/progressbar/ProgressBar.stories.tsx
  • src/components/common/progressbar/ProgressBar.tsx
  • src/pages/ads/list/AdsListPage.tsx
  • src/types/ads/campaign.ts

@jjjsun jjjsun left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

P4: 확인했습니다! 고생하셨어요!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ [Feature] 캠페인 목록 리스트(광고 운영 관리) UI 구현

3 participants