Skip to content

[Feature/#76] 캠페인 상세 정보 레이아웃 및 카드 컴포넌트 구현 - #81

Merged
YermIm merged 7 commits into
developfrom
feature/#76
Mar 4, 2026
Merged

YermIm merged 7 commits into
developfrom
feature/#76

Conversation

@YermIm

@YermIm YermIm commented Mar 3, 2026

Copy link
Copy Markdown
Collaborator

🚨 관련 이슈

close #76

✨ 변경사항

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

✏️ 작업 내용

  • InfoCard를 공통 레이아웃으로 활용하여 CampaignInfoCard, PlatformCard 컴포넌트 구현
  • 반응형 레이아웃 적용
  • 사이드바 라우팅 및 활성화 로직 개선
스크린샷 2026-03-04 오전 1 13 18

😅 미완성 작업

  • 사이드바 하위 메뉴 활성화 로직 개선

📢 논의 사항 및 참고 사항

  • 전체 화면에서 카드의 너비가 너무 길게 늘어나는 것이 UI상 어색한 거 같아 최대 크기를 고정하였습니다.
  • 상세 페이지 이동 시 사이드바의 하위 메뉴 활성화가 풀리는 현상은 추후 해결 예정입니다.

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

Summary by CodeRabbit

  • 새로운 기능
    • 캠페인 목록에서 행 클릭으로 상세 페이지로 이동 가능
    • 캠페인 상세 페이지 추가: 예산 현황, 등록 날짜, 연동 플랫폼 정보 표시
    • 캠페인 정보 카드 및 플랫폼 카드 컴포넌트 추가
  • 버그 수정 / 개선
    • 사이드바 경로 매칭 로직 개선으로 활성 상태 판단 정확도 향상
  • 접근성/사용성
    • 캠페인 행에 키보드 액세스(Enter/Space) 지원 추가
  • 문서
    • InfoCard용 스토리북 스토리 추가

@YermIm YermIm self-assigned this Mar 3, 2026
@YermIm YermIm added the ✨ Feature 기능 개발 label Mar 3, 2026
@YermIm
YermIm requested review from Seojegyeong and jjjsun March 3, 2026 16:23
@coderabbitai

coderabbitai Bot commented Mar 3, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

캠페인 상세 페이지 레이아웃과 정보 섹션을 추가하고, InfoCard 계열 컴포넌트들을 도입했으며, 캠페인 테이블의 행 클릭으로 상세 페이지로 네비게이션되도록 연결했습니다. Sidebar의 경로 매칭 로직도 강화되었습니다.

Changes

Cohort / File(s) Summary
Sidebar 경로 매칭 로직 개선
src/components/Sidebar/Sidebar.tsx
isChildActive/isParentActive 로직을 강화: 경로 누락 방지, 루트 경로("/") 처리 보강, location.pathname.startsWith로 자식 경로 매칭 변경.
기본 정보 카드 컴포넌트
src/components/common/card/InfoCard.tsx, src/components/common/card/InfoCard.stories.tsx, src/components/ads/CampaignInfoCard.tsx, src/components/ads/PlatformCard.tsx
InfoCard 컴포넌트와 Storybook 스토리 추가. CampaignInfoCard(예산·등록일) 및 PlatformCard(연동 플랫폼 로고 그리드) 컴포넌트 추가.
캠페인 테이블 상호작용
src/components/ads/CampaignRow.tsx, src/components/ads/CampaignTable.tsx
CampaignRow에 선택적 onClick 및 키보드 접근성(Enter/Space) 추가. CampaignTable에 onRowClick?: (id: number) => void 도입, MOCK_CAMPAIGNS 사용 및 행 클릭 시 콜백 호출로 네비게이션 연동 준비.
페이지·라우팅·목업 데이터
src/pages/ads/list/AdsListPage.tsx, src/pages/ads/list/CampaignDetail.tsx, src/pages/ads/list/campaign.mock.ts, src/routes/MainRoutes.tsx
AdsListPage에서 onRowClick 핸들러로 navigate(/ads/${id}) 연결. CampaignDetail 페이지 추가(모의 데이터 사용). MainRoutes에 /ads/:id 라우트 및 lazy 로딩 등록.

Sequence Diagram(s)

sequenceDiagram
    actor 사용자
    participant CampaignTable
    participant CampaignRow
    participant Router as Navigation
    participant CampaignDetail

    사용자->>CampaignRow: 캠페인 행 클릭 (마우스/Enter/Space)
    CampaignRow->>CampaignTable: onClick 트리거
    CampaignTable->>Router: onRowClick(id) -> navigate(`/ads/${id}`)
    Router->>CampaignDetail: 라우팅 /ads/:id 로드
    CampaignDetail->>CampaignDetail: CampaignInfoCard, PlatformCard 렌더링
    CampaignDetail-->>사용자: 상세 화면 표시
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Seojegyeong
  • jjjsun
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Out of Scope Changes check ❓ Inconclusive 사이드바 라우팅 로직 개선(Sidebar.tsx 변경)이 #76 이슈의 명시적 요구사항 범위를 벗어날 수 있으며, PR 설명에서 '미완성 작업'으로 표시되어 있습니다. 사이드바 변경사항이 #76 구현에 필수적인지, 아니면 별도 이슈로 분리해야 하는지 명확히 하시기 바랍니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 요약하고 있습니다. 캠페인 상세 정보 레이아웃 및 카드 컴포넌트 구현이라는 핵심 작업을 잘 표현하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 잘 따르고 있으며, 관련 이슈, 변경사항, 작업 내용, 미완성 작업, 참고 사항 등이 적절하게 작성되어 있습니다.
Linked Issues check ✅ Passed PR의 코드 변경사항이 #76 이슈의 모든 주요 요구사항을 충족합니다: CampaignDetail 페이지 라우팅 설정, 헤더 섹션 구현, 캠페인 정보 카드 및 플랫폼 카드 컴포넌트 구현, 반응형 레이아웃 적용이 완료되었습니다.

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

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

github-actions Bot commented Mar 3, 2026

Copy link
Copy Markdown

📚 Storybook 배포 완료

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

@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.

Actionable comments posted: 4

🧹 Nitpick comments (6)
src/components/ads/CampaignTable.tsx (1)

10-43: 하드코딩된 캠페인 데이터를 props로 분리하는 것이 좋습니다.

현재 campaigns 데이터가 컴포넌트 내부에 하드코딩되어 있습니다. 개발 단계에서는 괜찮지만, 실제 사용 시에는 props로 전달받거나 React Query를 통해 서버에서 가져오도록 분리하면 컴포넌트 재사용성이 높아집니다.

♻️ Props로 분리 제안
+import type { ICampaign } from "@/types/ads/campaign";
+
 interface ICampaignTableProps {
+  campaigns: ICampaign[];
   onRowClick?: (id: number) => void;
 }

-export default function CampaignTable({ onRowClick }: ICampaignTableProps) {
-  const campaigns: ICampaign[] = [
-    // ... hardcoded data
-  ];
+export default function CampaignTable({ campaigns, onRowClick }: ICampaignTableProps) {
🤖 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 10 - 43, The campaigns
array is hardcoded inside the CampaignTable component; refactor by moving the
campaigns data into a prop (e.g., add a campaigns: ICampaign[] prop to the
CampaignTable component) and update all internal references from the local
campaigns variable to the prop (or alternatively fetch via React Query outside
the component and pass results in). Ensure the component signature
(CampaignTable) accepts the new prop, provide a sensible default or mark it
optional if needed, and update any callers to pass the campaign list so the
component no longer declares the const campaigns = [...] internally.
src/components/Sidebar/Sidebar.tsx (1)

115-122: 주석 처리된 레거시 코드를 제거하는 것이 좋습니다.

새로운 로직이 정상 동작하는 것이 확인되면, 주석 처리된 이전 코드는 제거해주세요. Git 히스토리에서 언제든 복구할 수 있으니 코드베이스를 깔끔하게 유지하는 것이 좋습니다.

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

In `@src/components/Sidebar/Sidebar.tsx` around lines 115 - 122, Remove the
commented legacy code block in Sidebar.tsx that defines isChildActive,
isParentActive, and showChevron (the three commented const lines and their
related ternary logic), since the new logic is in place; simply delete those
commented lines to clean up the file—these identifiers (isChildActive,
isParentActive, showChevron) are the unique symbols to look for when locating
the obsolete comments.
src/components/ads/PlatformCard.tsx (1)

16-20: LogoMapCampaignRow.tsx와 중복됩니다.

동일한 LogoMap 상수가 CampaignRow.tsx에도 정의되어 있습니다. 공통 상수 파일로 추출하면 유지보수가 편해지고, 새로운 플랫폼 추가 시 한 곳만 수정하면 됩니다.

♻️ 공통 상수로 추출 제안
// src/constants/platformLogos.tsx
import type { ReactNode } from "react";
import type { TPlatform } from "@/types/ads/campaign";

import GoogleLogo from "@/assets/icon/ads/google-logo.svg?react";
import KakaoLogo from "@/assets/icon/ads/kakao-logo.svg?react";
import NaverLogo from "@/assets/icon/ads/naver-logo.svg?react";

export const PlatformLogoMap: Record<TPlatform, ReactNode> = {
  kakao: <KakaoLogo className="w-full h-full" />,
  google: <GoogleLogo className="w-full h-full" />,
  naver: <NaverLogo className="w-full h-full" />,
};

그 후 CampaignRow.tsxPlatformCard.tsx에서 import하여 사용:

-const LogoMap: Record<TPlatform, ReactNode> = {
-  kakao: <KakaoLogo className="w-full h-full" />,
-  google: <GoogleLogo className="w-full h-full" />,
-  naver: <NaverLogo className="w-full h-full" />,
-};
+import { PlatformLogoMap } from "@/constants/platformLogos";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ads/PlatformCard.tsx` around lines 16 - 20, Extract the
duplicated LogoMap constant into a single shared constant (e.g.,
PlatformLogoMap) and import it from both files: remove the LogoMap definition in
PlatformCard.tsx and CampaignRow.tsx and add an import of PlatformLogoMap from a
new module (suggested name: src/constants/platformLogos.tsx) that exports
PlatformLogoMap:Record<TPlatform,ReactNode> with the same mappings (KakaoLogo,
GoogleLogo, NaverLogo). Update references in PlatformCard (and CampaignRow) to
use PlatformLogoMap instead of the local LogoMap and ensure imports for
TPlatform and SVG components are moved into the new constants file.
src/components/ads/CampaignInfoCard.tsx (1)

22-24: Badge variant를 커스텀 스타일로 완전히 덮어쓰고 있습니다.

variant="running"을 지정했지만 badgeStyle이 모든 스타일을 덮어씁니다. 이런 경우 Badge에 새로운 variant(예: neutral 또는 label)를 추가하거나, 별도의 Label 컴포넌트를 만드는 것이 더 명확할 수 있습니다.

Also applies to: 32-34

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

In `@src/components/ads/CampaignInfoCard.tsx` around lines 22 - 24, The Badge in
CampaignInfoCard is being fully overridden by badgeStyle which negates the
variant="running" intent; update the component so we either add a new Badge
variant (e.g., "neutral" or "label") and use that variant instead of overriding,
or create a small Label component and replace Badge usage; locate the Badge
usages in CampaignInfoCard (the Badge elements with prop variant="running" and
className={badgeStyle}) and change them to use the new variant or the new Label
component, and adjust the badgeStyle CSS to only extend (compose) the existing
badge styles rather than replace them so the Badge's built-in styling remains
intact.
src/pages/ads/list/AdsListPage.tsx (1)

8-10: handleCampaignClick 함수의 useCallback 래핑 고려

현재 구현에서는 컴포넌트가 리렌더링될 때마다 handleCampaignClick 함수가 새로 생성됩니다. CampaignTable이 React.memo로 최적화되어 있다면 불필요한 리렌더링을 유발할 수 있습니다.

다만 현재 페이지가 단순하고 상태 변경이 적어 실질적인 성능 영향은 미미할 것으로 보여, 선택적으로 적용하시면 됩니다.

♻️ useCallback 적용 예시
+import { useCallback } from "react";
 import { useNavigate } from "react-router-dom";

 import CampaignTable from "@/components/ads/CampaignTable";
 import ControlBox from "@/components/common/controlbox/ControlBox";

 export default function AdsListPage() {
   const navigate = useNavigate();
-  const handleCampaignClick = (id: string | number) => {
-    navigate(`/ads/${id}`);
-  };
+  const handleCampaignClick = useCallback(
+    (id: string | number) => {
+      navigate(`/ads/${id}`);
+    },
+    [navigate]
+  );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ads/list/AdsListPage.tsx` around lines 8 - 10, Wrap the
handleCampaignClick function with React's useCallback to avoid recreating it on
every render (which can cause unnecessary re-renders of memoized children like
CampaignTable); change the declaration of handleCampaignClick to useCallback(()
=> { navigate(`/ads/${id}`); }, [navigate]) (ensure you import useCallback from
React) so the callback is stable unless the navigate reference changes.
src/pages/ads/list/CampaignDetail.tsx (1)

43-44: 빈 placeholder div에 대한 주석 보완

현재 {/* ads list */} 주석 아래 빈 div가 있습니다. 향후 구현 예정인 내용이라면 TODO 주석으로 명시해두면 추적하기 좋습니다.

✏️ 주석 보완 예시
-          {/* ads list */}
-          <div className="min-w-180" />
-          {/* control box */}
+          {/* TODO: ads list - 광고 소재 목록 테이블 구현 예정 */}
+          <div className="min-w-180" />
+          {/* TODO: control box - 캠페인 제어 박스 구현 예정 */}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ads/list/CampaignDetail.tsx` around lines 43 - 44, The placeholder
empty div under the JSX comment "{/* ads list */}" (the <div
className="min-w-180" /> element) needs a clearer TODO-style comment so future
work is discoverable; replace or augment the current comment with a TODO that
states the intended purpose (e.g., "TODO: render ads list here / placeholder for
ads list layout") and optionally include an owner or ticket reference; update
the comment near the div with that TODO text so tools and reviewers can track
the pending implementation.
🤖 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/ads/CampaignRow.tsx`:
- Around line 36-39: The list item in CampaignRow (the <li> that currently only
uses onClick) lacks keyboard accessibility; update the element in the
CampaignRow component to behave like a clickable button by adding role="button",
tabIndex={0}, and an onKeyDown handler that triggers the same onClick logic when
Enter or Space is pressed (handle Space with preventDefault to avoid page
scroll), ensuring the existing onClick handler is reused so mouse and keyboard
activate identical behavior.

In `@src/components/common/card/InfoCard.tsx`:
- Around line 4-15: The IInfoCardProps interface declares isActive but InfoCard
does not destructure or use it; either remove isActive from IInfoCardProps (and
any external usages) to eliminate the unused prop, or update the InfoCard
function signature to accept isActive (export default function InfoCard({ title,
children, className, isActive }: IInfoCardProps)) and apply it (e.g.,
conditionally append an active class to className or pass it to the root
element) or at minimum add a TODO comment in InfoCard noting planned use of
isActive; reference IInfoCardProps and InfoCard when making the change.

In `@src/pages/ads/list/AdsListPage.tsx`:
- Line 25: The onRowClick handler is hardcoded to pass id 1 which causes every
click to navigate to /ads/1; change the JSX to pass the existing
handleCampaignClick callback directly so CampaignTable can supply the clicked
row's campaign.id (i.e., replace onRowClick={() => handleCampaignClick(1)} with
onRowClick={handleCampaignClick}) ensuring the types match between
CampaignTable's onRowClick and the handleCampaignClick function.

In `@src/pages/ads/list/CampaignDetail.tsx`:
- Around line 5-6: CampaignDetail 컴포넌트가 URL에서 캠페인 ID를 읽지 않아 항상 정적 데이터를 렌더링합니다;
수정하려면 React Router의 useParams를 사용해 ads/:id 라우트의 id를 추출하고(예: const { id } =
useParams()), 해당 id로 데이터를 조회하거나 props/상태를 초기화하도록 CampaignDetail 내부 로직을 연결하세요; 만약
아직 데이터 로딩을 구현하지 않은 초기 레이아웃 단계라면 useParams를 남겨두고 TODO 주석을 추가해 향후 fetch 함수(또는
useEffect로 fetchCampaignById)를 호출하도록 명확히 표시하세요.

---

Nitpick comments:
In `@src/components/ads/CampaignInfoCard.tsx`:
- Around line 22-24: The Badge in CampaignInfoCard is being fully overridden by
badgeStyle which negates the variant="running" intent; update the component so
we either add a new Badge variant (e.g., "neutral" or "label") and use that
variant instead of overriding, or create a small Label component and replace
Badge usage; locate the Badge usages in CampaignInfoCard (the Badge elements
with prop variant="running" and className={badgeStyle}) and change them to use
the new variant or the new Label component, and adjust the badgeStyle CSS to
only extend (compose) the existing badge styles rather than replace them so the
Badge's built-in styling remains intact.

In `@src/components/ads/CampaignTable.tsx`:
- Around line 10-43: The campaigns array is hardcoded inside the CampaignTable
component; refactor by moving the campaigns data into a prop (e.g., add a
campaigns: ICampaign[] prop to the CampaignTable component) and update all
internal references from the local campaigns variable to the prop (or
alternatively fetch via React Query outside the component and pass results in).
Ensure the component signature (CampaignTable) accepts the new prop, provide a
sensible default or mark it optional if needed, and update any callers to pass
the campaign list so the component no longer declares the const campaigns =
[...] internally.

In `@src/components/ads/PlatformCard.tsx`:
- Around line 16-20: Extract the duplicated LogoMap constant into a single
shared constant (e.g., PlatformLogoMap) and import it from both files: remove
the LogoMap definition in PlatformCard.tsx and CampaignRow.tsx and add an import
of PlatformLogoMap from a new module (suggested name:
src/constants/platformLogos.tsx) that exports
PlatformLogoMap:Record<TPlatform,ReactNode> with the same mappings (KakaoLogo,
GoogleLogo, NaverLogo). Update references in PlatformCard (and CampaignRow) to
use PlatformLogoMap instead of the local LogoMap and ensure imports for
TPlatform and SVG components are moved into the new constants file.

In `@src/components/Sidebar/Sidebar.tsx`:
- Around line 115-122: Remove the commented legacy code block in Sidebar.tsx
that defines isChildActive, isParentActive, and showChevron (the three commented
const lines and their related ternary logic), since the new logic is in place;
simply delete those commented lines to clean up the file—these identifiers
(isChildActive, isParentActive, showChevron) are the unique symbols to look for
when locating the obsolete comments.

In `@src/pages/ads/list/AdsListPage.tsx`:
- Around line 8-10: Wrap the handleCampaignClick function with React's
useCallback to avoid recreating it on every render (which can cause unnecessary
re-renders of memoized children like CampaignTable); change the declaration of
handleCampaignClick to useCallback(() => { navigate(`/ads/${id}`); },
[navigate]) (ensure you import useCallback from React) so the callback is stable
unless the navigate reference changes.

In `@src/pages/ads/list/CampaignDetail.tsx`:
- Around line 43-44: The placeholder empty div under the JSX comment "{/* ads
list */}" (the <div className="min-w-180" /> element) needs a clearer TODO-style
comment so future work is discoverable; replace or augment the current comment
with a TODO that states the intended purpose (e.g., "TODO: render ads list here
/ placeholder for ads list layout") and optionally include an owner or ticket
reference; update the comment near the div with that TODO text so tools and
reviewers can track the pending implementation.

ℹ️ 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 0fcae03 and 6c9f8f3.

📒 Files selected for processing (10)
  • src/components/Sidebar/Sidebar.tsx
  • src/components/ads/CampaignInfoCard.tsx
  • src/components/ads/CampaignRow.tsx
  • src/components/ads/CampaignTable.tsx
  • src/components/ads/PlatformCard.tsx
  • src/components/common/card/InfoCard.stories.tsx
  • src/components/common/card/InfoCard.tsx
  • src/pages/ads/list/AdsListPage.tsx
  • src/pages/ads/list/CampaignDetail.tsx
  • src/routes/MainRoutes.tsx

Comment thread src/components/ads/CampaignRow.tsx
Comment thread src/components/common/card/InfoCard.tsx
Comment thread src/pages/ads/list/AdsListPage.tsx Outdated
Comment thread src/pages/ads/list/CampaignDetail.tsx
@github-actions

github-actions Bot commented Mar 3, 2026

Copy link
Copy Markdown

📚 Storybook 배포 완료

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

@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 (2)
src/components/ads/CampaignTable.tsx (1)

25-30: 스프레드 연산자 사용 시 불필요한 props 전달에 주의해 주세요.

{...campaign}으로 전달하면 CampaignRow에서 사용하지 않는 id, budget, startDate, description 등의 props도 함께 전달됩니다. 현재는 동작에 문제가 없지만, 명시적으로 필요한 props만 전달하는 방식이 더 명확합니다.

♻️ 명시적 props 전달 예시
 {MOCK_CAMPAIGNS.map((campaign) => (
   <CampaignRow
     key={campaign.id}
-    {...campaign}
+    platforms={campaign.platforms}
+    name={campaign.name}
+    status={campaign.status}
+    statusText={campaign.statusText}
+    progress={campaign.progress}
     onClick={() => onRowClick?.(campaign.id)}
   />
 ))}
🤖 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 25 - 30, The component is
passing entire campaign objects via the spread operator into CampaignRow (see
MOCK_CAMPAIGNS and CampaignRow usage), which sends unnecessary props (id,
budget, startDate, description) to the child; fix by replacing {...campaign}
with only the explicit props CampaignRow needs (e.g., title, status, clicks,
impressions — whatever props CampaignRow declares) and keep the existing key and
onClick handler (onRowClick?.(campaign.id)) so only required data flows into
CampaignRow.
src/pages/ads/list/campaign.mock.ts (1)

15-27: 목 데이터의 상태값 일관성을 확인해 주세요.

id: 1 캠페인의 경우 status: "success", statusText: "완료"인데 progress: 65로 설정되어 있습니다. 완료 상태라면 progress가 100이어야 하지 않을까요? 현재 목 데이터 단계이므로 큰 문제는 아니지만, 추후 실제 API 연동 시 상태와 진행률 간의 정합성을 맞춰주시면 좋겠습니다.

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

In `@src/pages/ads/list/campaign.mock.ts` around lines 15 - 27, The MOCK_CAMPAIGNS
entry with id: 1 has inconsistent state fields (status: "success", statusText:
"완료" but progress: 65); update the mock so the fields are consistent—either set
progress to 100 when status === "success"/statusText === "완료" or change
status/statusText to match a 65% in-progress state; locate the MOCK_CAMPAIGNS
array (ICampaign entries) and make the fix for the object with id 1.
🤖 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/CampaignTable.tsx`:
- Around line 25-30: The component is passing entire campaign objects via the
spread operator into CampaignRow (see MOCK_CAMPAIGNS and CampaignRow usage),
which sends unnecessary props (id, budget, startDate, description) to the child;
fix by replacing {...campaign} with only the explicit props CampaignRow needs
(e.g., title, status, clicks, impressions — whatever props CampaignRow declares)
and keep the existing key and onClick handler (onRowClick?.(campaign.id)) so
only required data flows into CampaignRow.

In `@src/pages/ads/list/campaign.mock.ts`:
- Around line 15-27: The MOCK_CAMPAIGNS entry with id: 1 has inconsistent state
fields (status: "success", statusText: "완료" but progress: 65); update the mock
so the fields are consistent—either set progress to 100 when status ===
"success"/statusText === "완료" or change status/statusText to match a 65%
in-progress state; locate the MOCK_CAMPAIGNS array (ICampaign entries) and make
the fix for the object with id 1.

ℹ️ 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 6c9f8f3 and 46bfe00.

📒 Files selected for processing (6)
  • src/components/ads/CampaignRow.tsx
  • src/components/ads/CampaignTable.tsx
  • src/components/common/card/InfoCard.tsx
  • src/pages/ads/list/AdsListPage.tsx
  • src/pages/ads/list/CampaignDetail.tsx
  • src/pages/ads/list/campaign.mock.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/pages/ads/list/CampaignDetail.tsx
  • src/components/ads/CampaignRow.tsx
  • src/components/common/card/InfoCard.tsx
  • src/pages/ads/list/AdsListPage.tsx

@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] 캠페인 상세 정보 레이아웃 및 정보 섹션 구현

3 participants