[Feature/#60] 캠페인 목록 테이블 UI 구현 - #69
Conversation
📝 WalkthroughWalkthrough광고 운영 관리 페이지의 캠페인 목록 UI를 구현합니다. 캠페인 타입 정의, 진행률 표시 컴포넌트(ProgressBar), 캠페인 행(CampaignRow) 및 테이블(CampaignTable) 컴포넌트를 추가하고, AdsListPage에 통합합니다. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
📚 Storybook 배포 완료
|
There was a problem hiding this comment.
🧹 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 연동 시 아래 사항을 고려해 주세요:
- React Query 사용: 서버 상태 관리를 위해
useQuery훅으로 데이터 fetching- 로딩/에러 상태 처리: 스켈레톤 UI 또는 에러 메시지 표시
- 빈 상태 처리: 캠페인이 없을 때의 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
⛔ Files ignored due to path filters (3)
src/assets/icon/ads/google-logo.svgis excluded by!**/*.svgand included bysrc/**src/assets/icon/ads/kakao-logo.svgis excluded by!**/*.svgand included bysrc/**src/assets/icon/ads/naver-logo.svgis excluded by!**/*.svgand included bysrc/**
📒 Files selected for processing (6)
src/components/ads/CampaignRow.tsxsrc/components/ads/CampaignTable.tsxsrc/components/common/progressbar/ProgressBar.stories.tsxsrc/components/common/progressbar/ProgressBar.tsxsrc/pages/ads/list/AdsListPage.tsxsrc/types/ads/campaign.ts
🚨 관련 이슈
close #60
✨ 변경사항
✏️ 작업 내용
min-w-180적용 -> 가로 스크롤😅 미완성 작업
📢 논의 사항 및 참고 사항
N/A
Summary by CodeRabbit
새로운 기능