Skip to content

[Feature/#312] 대시보드 예산 소진 UI 스펙 반영 (통합·플랫폼) - #375

Merged
YermIm merged 16 commits into
developfrom
feature/#312
Aug 3, 2026
Merged

[Feature/#312] 대시보드 예산 소진 UI 스펙 반영 (통합·플랫폼)#375
YermIm merged 16 commits into
developfrom
feature/#312

Conversation

@YermIm

@YermIm YermIm commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

🚨 관련 이슈

close #312

✨ 변경사항

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

✏️ 작업 내용

예산 조회·표시 스펙 변경에 맞춰 통합/플랫폼 대시보드의 예산 소진 UI를 개편했습니다.

스크린샷 2026-08-01 오후 10 49 49

스크린샷 2026-08-01 오후 10 50 04

스크린샷 2026-08-01 오후 10 50 19

데이터

  • IBudgetResponse 분리 필드 → budget.ts 어댑터 → useBudget{ gauges[] } 반환
  • 통합: Google·Meta / NAVER · 플랫폼 Google/Meta: 전체+일일 · Naver: 전체만

BudgetGaugeChart

  • 잔여 % 표시, 게이지별 label·Badge, compact / showInsight 분리

통합 대시보드

  • 예산 2게이지 + 구분선, 카드 헤더 Badge 제거
  • 로딩 스켈레톤 2게이지 compact
  • (부가) 트래픽 차트 height 520px, pt-3

플랫폼 대시보드

  • Google/Meta: 2게이지 + 트래픽 fillHeight
  • Naver: 1게이지 + 게이지형 스켈레톤

😅 미완성 작업

  • 캠페인 목록 예산 UI → 별도 이슈

📢 논의 사항 및 참고 사항

통합 실시간 트래픽 height (520px)
예산 게이지가 2개로 늘면서 세로 길이가 길어졌고, 그에 맞춰 왼쪽 실시간 트래픽 차트의 height을 고정(520px)으로 키웠습니다.

예산 게이지 UI
기존: 소진 % · 소진 비율 바 · (사용|전체) · 남은 예산 박스
변경: 남음 % · 남은 비율 바 · (사용|전체, 라벨 2줄) · 남은 예산 박스 유지
주 지표가 소진 → 남음으로 바뀌면서, 남은 금액을 바 하단에 작게 두는 방식을 생각했으나 남은 예산 박스가 이미 있어서 박스는 유지하고 하단은 사용|전체 보조 스케일로 정리했습니다. 금액 위치·박스 역할 변경 등 의견 주시면 반영하겠습니다.

인사이트 UI (1게이지 / 2게이지)
플랫폼 Naver처럼 1게이지일 때는 인사이트를 빼면 세로가 비어 보여서, 당장은 1게이지만 인사이트 영역을 두었습니다. 2게이지(통합·Google/Meta)는 전체가 길어져서 인사이트는 뺐고, compact + showInsight로 분리해 두었습니다.
카드 제목 예산 소진 현황 오른쪽에 한 줄로 넣는 것도 생각했는데, 이미 게이지마다 안정/주의/위험 Badge가 있어서 인사이트가 얼마나 필요한지 잘 모르겠습니다. 어떤 쪽이 나을지 의견 주시면 반영하겠습니다. (현재 SHOW_BUDGET_GAUGE_INSIGHT = false로 off)

API / 백엔드
백엔드 예산 스펙 변경이 아직 반영되지 않은 것 같아 실제 API 규격은 확인하지 못했습니다. IBudgetResponse 분리 필드·어댑터 매핑은 프론트 가정으로 붙여 둔 상태이고, 백 완료 후 스펙에 맞게 수정 예정입니다.

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

Summary by CodeRabbit

  • 새 기능

    • 예산 게이지에 사용액·잔여액·상태 및 초과 예산 인사이트를 표시합니다.
    • 플랫폼별 전체·일일 예산 게이지를 지원합니다.
    • 트래픽 차트가 카드 크기에 맞춰 유연하게 표시됩니다.
  • 개선

    • 대시보드와 플랫폼 화면의 예산·트래픽 레이아웃을 개선했습니다.
    • 로딩 화면이 실제 게이지 구성과 일치하도록 개선되었습니다.
    • 차트 높이, 여백 및 정렬을 조정해 시각적 일관성을 높였습니다.

@YermIm
YermIm requested review from Seojegyeong and jjjsun August 1, 2026 14:00
@YermIm YermIm self-assigned this Aug 1, 2026
@YermIm YermIm added ✨ Feature 기능 개발 🔨 Refactor 코드 리팩토링 labels Aug 1, 2026
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7538ab08-543f-4850-8439-afc83d5cba3e

📥 Commits

Reviewing files that changed from the base of the PR and between 2975cba and b0c0dfa.

📒 Files selected for processing (5)
  • src/components/dashboard/charts/BudgetGaugeChart.tsx
  • src/components/dashboard/charts/TrafficChart.tsx
  • src/components/dashboard/platform/PlatformTrafficChart.tsx
  • src/components/dashboard/platform/SinglePlatformView.tsx
  • src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/dashboard/charts/TrafficChart.tsx
  • src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx
  • src/components/dashboard/charts/BudgetGaugeChart.tsx
  • src/components/dashboard/platform/SinglePlatformView.tsx
  • src/components/dashboard/platform/PlatformTrafficChart.tsx

📝 Walkthrough

Walkthrough

예산 응답을 전체·일일 예산 게이지 모델로 변환합니다. 통합·플랫폼 대시보드는 게이지 배열을 렌더링합니다. 트래픽 차트는 화면별 높이와 fillHeight를 지원합니다. 로딩·오류·빈 상태 레이아웃도 새 높이 규칙을 사용합니다.

Changes

대시보드 예산 및 레이아웃

Layer / File(s) Summary
예산 타입과 데이터 변환
src/types/dashboard/budget.ts, src/types/dashboard/common.ts, src/utils/dashboard/budget.ts, src/hooks/dashboard/useBudget.ts
예산 응답 타입과 게이지 뷰 모델을 추가했습니다. useBudgettoBudgetQueryData를 사용해 통합·플랫폼별 게이지 데이터를 생성합니다.
통합 예산 게이지 렌더링
src/components/dashboard/charts/BudgetGaugeChart.tsx, src/pages/dashboard/overview/OverviewDashboard.tsx, src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx
통합 대시보드는 budget.gauges 배열을 렌더링합니다. BudgetGaugeChart는 잔여율, 상태 배지, 사용·잔여 금액 및 조건부 인사이트를 표시합니다.
플랫폼별 예산 게이지와 로딩 상태
src/components/dashboard/platform/SinglePlatformView.tsx, src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx
Google·Meta는 전체·일일 게이지를 표시하고 Naver는 전체 게이지를 표시합니다. 플랫폼별 게이지 레이아웃과 로딩 스켈레톤을 추가했습니다.
트래픽 차트 높이와 가변 레이아웃
src/constants/dashboard/trafficChartHeights.ts, src/components/dashboard/charts/TrafficChart.tsx, src/components/dashboard/charts/trafficChart.config.ts, src/components/dashboard/platform/PlatformTrafficChart.tsx, src/components/dashboard/overview/skeleton/OverviewSkeleton.tsx, src/pages/dashboard/overview/sections/OverviewKpiSection.tsx
차트 높이 상수를 추가했습니다. TrafficChartheight를 사용하고, PlatformTrafficChartfillHeight에서 컨테이너 높이와 ResizeObserver를 사용합니다. 관련 스켈레톤과 그리드 패딩을 조정했습니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant useBudget
  participant toBudgetQueryData
  participant BudgetGaugeChart
  Dashboard->>useBudget: 예산 데이터 요청
  useBudget->>toBudgetQueryData: 응답과 provider 전달
  toBudgetQueryData-->>useBudget: gauges 배열 반환
  useBudget-->>Dashboard: 변환된 예산 데이터 전달
  Dashboard->>BudgetGaugeChart: 각 gauge 렌더링
Loading

Possibly related PRs

Suggested labels: 🎨 Html&css

Suggested reviewers: seojegyeong, jjjsun

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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 통합·플랫폼 대시보드의 예산 소진 UI 변경이라는 주요 내용을 구체적으로 설명합니다.
Description check ✅ Passed 관련 이슈, 변경사항, 작업 내용, 미완성 작업 및 참고 사항을 템플릿에 맞게 작성했습니다.
Linked Issues check ✅ Passed [#312]의 타입·훅·어댑터 갱신, 통합·플랫폼 게이지 구성, 잔여 비율과 레이아웃 변경을 반영했습니다.
Out of Scope Changes check ✅ Passed 트래픽 차트 높이, 스켈레톤 및 fillHeight 변경은 다중 게이지 레이아웃과 로딩 상태 정리를 지원하며 범위를 벗어나지 않습니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/#312

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.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

📚 Storybook 배포 완료

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

Comment thread src/components/dashboard/charts/BudgetGaugeChart.tsx Outdated
@Seojegyeong

Copy link
Copy Markdown
Collaborator

P4: 저는 아래와 같이 진행하면 좋을 것 같습니다!

  1. 헤더 -1번째 줄(label+Badge) 그대로 유지, 2번째 줄에 전체 예산 ₩30,000,000 신규 추가 (금액은 라벨보다 1~2단계 큰 텍스트)
  2. 하단 박스 - 기존 "남은예산" div 삭제, 인사이트로 통일 (1게이지: 유지 / 2게이지: 신규 추가), 박스는 최대 1개

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/dashboard/charts/BudgetGaugeChart.tsx (1)

70-90: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

totalBudget이 0이면 화면 정보가 서로 모순됩니다.

getSpentPercentagetotalBudget <= 0이면 0을 반환합니다. 따라서 totalBudget = 0, spent > 0인 응답에서 다음이 동시에 나타납니다.

  • remainingPct100 → 게이지는 "100% 남음"으로 가득 참
  • statusgetBudgetStatus(0, ...) → 배지는 "안정"
  • isOverBudgettrue → 인사이트는 "예산을 초과했습니다"
  • 남은 예산 값은 -{spent}

예산 미설정 계정에서 실제로 발생할 수 있는 조합입니다. 사용자는 어느 값을 믿어야 할지 알 수 없습니다.

isOverBudget을 상태 계산에도 반영해 주세요.

🐛 제안 수정
   const slice = { totalBudget, spent };
   const spentPct = getSpentPercentage(slice);
-  const remainingPct = getRemainingPercentage(slice);
   const isOverBudget = spent > totalBudget;
+  const remainingPct = isOverBudget ? 0 : getRemainingPercentage(slice);
   const remainingAmount = isOverBudget
     ? spent - totalBudget
     : totalBudget - spent;
 
-  const status = getBudgetStatus(spentPct, warningThreshold, dangerThreshold);
+  const status = isOverBudget
+    ? "위험"
+    : getBudgetStatus(spentPct, warningThreshold, dangerThreshold);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/charts/BudgetGaugeChart.tsx` around lines 70 - 90,
Update the status calculation in the budget gauge flow to incorporate the
existing isOverBudget result, especially when totalBudget is zero and spent is
positive. Ensure getBudgetStatus and the displayed gauge, badge, and insight
remain consistent with the over-budget state, while preserving normal
calculations for configured budgets.
🧹 Nitpick comments (9)
src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx (1)

64-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

조건부 클래스를 twMerge로 정리해 주세요.

두 분기의 차이는 gap-5 하나입니다. 나머지 클래스는 동일합니다. 또한 gap-5는 게이지가 1개일 때만 적용됩니다. 자식이 1개이면 gap은 효과가 없습니다. 즉 현재 분기는 화면에 아무 차이를 만들지 않습니다.

코딩 가이드라인은 조건부 클래스에 twMerge를 쓰도록 정하고 있습니다.

♻️ 제안 리팩터링
-                <div
-                  className={
-                    budget.gauges.length > 1
-                      ? "flex min-h-0 flex-1 flex-col overflow-y-auto"
-                      : "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto"
-                  }
-                >
+                <div className="flex min-h-0 flex-1 flex-col overflow-y-auto">

코딩 가이드라인의 "Use twMerge for conditional classes" 항목에 따른 제안입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx` around lines
64 - 70, Update the conditional className on the gauge container div to use the
project’s twMerge utility, removing the redundant gap-5 branch while preserving
the shared flex, sizing, and overflow classes.

Source: Coding guidelines

src/utils/dashboard/budget.ts (1)

125-140: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

SHOW_BUDGET_GAUGE_INSIGHT 상수가 사용되지 않습니다.

16행에서 기본값 상수를 선언했습니다. 그러나 133행은 showInsight: true를 직접 넣습니다. 값이 같아도 두 곳을 따로 바꿔야 하는 상태가 됩니다. 상수를 사용해 주세요.

♻️ 제안 리팩터링
   const gauges = viewModel.slices.map((slice) =>
-    toGaugeProps(slice, { compact: isCompact, showInsight: true }),
+    toGaugeProps(slice, {
+      compact: isCompact,
+      showInsight: SHOW_BUDGET_GAUGE_INSIGHT,
+    }),
   );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/dashboard/budget.ts` around lines 125 - 140, Update
toBudgetQueryData to use the existing SHOW_BUDGET_GAUGE_INSIGHT constant for the
toGaugeProps showInsight option instead of the hardcoded true value, keeping the
behavior unchanged while centralizing the default.
src/hooks/dashboard/useBudget.ts (2)

20-27: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

select 결과가 렌더마다 새 객체가 됩니다.

select에 인라인 화살표 함수를 넘깁니다. react-query는 select 함수의 참조가 바뀌면 결과를 다시 계산합니다. toBudgetQueryData는 매번 새 gauges 배열과 새 gauge 객체를 만듭니다. 그 결과 BudgetGaugeChartmemo가 무효화됩니다. SinglePlatformViewresetKeys={[budgetData]}도 매 렌더 변경으로 인식될 수 있습니다.

useCallback으로 select 참조를 고정해 주세요.

♻️ 제안 리팩터링
+import { useCallback } from "react";
+
 export function useBudget(provider?: TProviderType) {
   const orgId = useWorkspaceStore((s) => s.selectedOrgId);
 
   const queryKey = provider
     ? QUERY_KEYS.platform.budget(orgId, provider)
     : QUERY_KEYS.overview.budget(orgId);
 
+  const select = useCallback(
+    (data: IBudgetResponse) => toBudgetQueryData(data, provider),
+    [provider],
+  );
+
   return useCoreQuery<IBudgetResponse, IBudgetQueryData>(
     queryKey,
     () => getBudget(orgId!, provider),
     {
       enabled: !!orgId,
-      select: (data) => toBudgetQueryData(data, provider),
+      select,
     },
   );
 }

경로 지침의 "useCallback, useMemo의 적절한 사용", "불필요한 리렌더링 체크" 항목에 따른 제안입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/dashboard/useBudget.ts` around lines 20 - 27, useBudget의
useCoreQuery 호출에서 인라인 select 콜백을 useCallback으로 메모이제이션해 참조가 렌더마다 바뀌지 않도록 수정하세요.
콜백은 기존처럼 toBudgetQueryData(data, provider)를 호출하고 provider 변경 시 갱신되도록 의존성을 설정하며,
queryKey와 enabled 동작은 유지하세요.

Source: Path instructions


3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

TProviderType을 정의 파일로 직접 가져오세요.

TProviderTypesrc/types/dashboard/provider.ts에 정의되어 있고, overview.ts는 이를 re-export하고 있을 뿐입니다. src/hooks/dashboard/useBudget.ts도 정의 위치와 같은 @/types/dashboard/provider에서 가져와 경로를 일관되게 유지해 주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/dashboard/useBudget.ts` at line 3, Update the TProviderType import
in useBudget.ts to use the defining module "`@/types/dashboard/provider`" instead
of the overview re-export, keeping the imported type and surrounding hook logic
unchanged.
src/components/dashboard/platform/SinglePlatformView.tsx (2)

147-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

이중 게이지 높이 값을 상수로 빼 주세요.

단일 게이지 높이는 PLATFORM_MID_SECTION_HEIGHT_SINGLE 상수를 씁니다. 이중 게이지 높이 min-h-120 h-full은 두 카드에 문자열로 직접 들어 있습니다. 값이 바뀌면 두 곳을 함께 고쳐야 합니다. 단일 게이지와 동일하게 src/constants/dashboard/trafficChartHeights.ts에 상수를 추가해 주세요.

♻️ 제안 리팩터링

src/constants/dashboard/trafficChartHeights.ts에 추가:

export const PLATFORM_MID_SECTION_HEIGHT_DUAL = "min-h-120 h-full" as const;

SinglePlatformView.tsx:

-import { PLATFORM_MID_SECTION_HEIGHT_SINGLE } from "`@/constants/dashboard/trafficChartHeights`";
+import {
+  PLATFORM_MID_SECTION_HEIGHT_DUAL,
+  PLATFORM_MID_SECTION_HEIGHT_SINGLE,
+} from "`@/constants/dashboard/trafficChartHeights`";
             hasDualBudgetGauges
-              ? "min-h-120 h-full overflow-hidden"
+              ? `${PLATFORM_MID_SECTION_HEIGHT_DUAL} overflow-hidden`
               : PLATFORM_MID_SECTION_HEIGHT_SINGLE,
             hasDualBudgetGauges
-              ? "min-h-120 h-full"
+              ? PLATFORM_MID_SECTION_HEIGHT_DUAL
               : PLATFORM_MID_SECTION_HEIGHT_SINGLE,

Also applies to: 187-194

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/platform/SinglePlatformView.tsx` around lines 147 -
155, Extract the duplicated dual-gauge height string into a new
PLATFORM_MID_SECTION_HEIGHT_DUAL constant in trafficChartHeights.ts, then
replace both inline "min-h-120 h-full" usages in SinglePlatformView with that
constant while preserving the existing conditional styling.

232-243: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

게이지 구분선 조건에 항상 참인 검사가 들어 있습니다. 두 파일이 같은 렌더링 패턴을 사용합니다. index > 0이 참이면 배열 길이는 이미 2 이상입니다. 따라서 gauges.length > 1 검사는 결과에 영향을 주지 않습니다. 조건을 읽는 사람이 "1개일 때 예외가 있나"라고 오해합니다.

  • src/components/dashboard/platform/SinglePlatformView.tsx#L232-L243: index > 0 && budgetData.gauges.length > 1 && "mt-5 border-t border-surface-300 pt-5"index > 0 && "mt-5 border-t border-surface-300 pt-5"로 줄여 주세요.
  • src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx#L71-L83: index > 0 && budget.gauges.length > 1 ? "mt-5 border-t border-surface-300 pt-5" : undefinedindex > 0 ? "mt-5 border-t border-surface-300 pt-5" : undefined로 줄여 주세요.

두 곳의 구분선 클래스 문자열이 동일합니다. 공통 상수로 빼 두면 이후 간격을 한 번에 조정할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/platform/SinglePlatformView.tsx` around lines 232 -
243, Remove the redundant gauges.length > 1 check from the gauge separator
condition in src/components/dashboard/platform/SinglePlatformView.tsx lines
232-243, leaving index > 0 as the condition. Apply the same simplification in
src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx lines 71-83.
Extract the identical separator class string into a shared constant and reuse it
at both sites.
src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx (2)

70-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

컴포넌트 props 타입에 I*Props 네이밍을 적용해 주세요.

PlatformBudgetGaugeCompactSkeletonPlatformDualBudgetGaugeSkeleton은 props 타입을 인라인 익명 객체로 선언합니다. 코딩 가이드라인은 컴포넌트 props에 I*Props 형태의 명명된 타입을 쓰도록 정하고 있습니다. 두 컴포넌트가 같은 형태를 쓰므로 하나의 타입으로 정의해 재사용해 주세요.

♻️ 제안 리팩터링
+interface IBudgetGaugeSkeletonProps {
+  /** 라벨 행에 전체 예산 금액을 함께 표시하는 레이아웃 */
+  mergedBudgetHeader?: boolean;
+}
+
 /** compact BudgetGaugeChart 1칸 */
 function PlatformBudgetGaugeCompactSkeleton({
   mergedBudgetHeader = true,
-}: {
-  mergedBudgetHeader?: boolean;
-}) {
+}: IBudgetGaugeSkeletonProps) {
 export function PlatformDualBudgetGaugeSkeleton({
   mergedBudgetHeader = true,
-}: {
-  mergedBudgetHeader?: boolean;
-} = {}) {
+}: IBudgetGaugeSkeletonProps = {}) {

코딩 가이드라인의 "component props use I*Props" 항목에 따른 제안입니다.

Also applies to: 142-146

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx` around lines
70 - 74, PlatformBudgetGaugeCompactSkeleton과 PlatformDualBudgetGaugeSkeleton의
인라인 props 객체 타입을 제거하고, 두 컴포넌트가 공유할 수 있는 I*Props 명명 타입을 정의해 재사용하도록 변경하세요. 해당 타입에는
mergedBudgetHeader의 선택적 boolean 설정과 기본값 동작을 유지하세요.

Source: Coding guidelines


142-159: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

통합 대시보드가 플랫폼 스켈레톤에 의존합니다.

src/components/dashboard/overview/skeleton/OverviewSkeleton.tsx:32-34OverviewBudgetGaugeSkeleton은 이 파일의 PlatformDualBudgetGaugeSkeleton을 감쌉니다. overview 도메인이 platform 도메인을 참조하는 구조입니다. 이후 플랫폼 레이아웃만 바꾸면 통합 대시보드 로딩 화면이 함께 바뀝니다.

두 대시보드가 공유하는 게이지 스켈레톤이므로 components/common/skeleton/ 아래 공통 컴포넌트로 옮기고, 두 도메인이 각각 그것을 사용하도록 정리해 주세요.

코딩 가이드라인의 "Reusable components ... prioritize components/common/" 항목에 따른 제안입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx` around lines
142 - 159, Move the shared PlatformDualBudgetGaugeSkeleton implementation into
components/common/skeleton/ and expose it as a common gauge skeleton component.
Update both PlatformSkeleton and OverviewSkeleton, including
OverviewBudgetGaugeSkeleton, to import and use the common component directly,
removing the overview-to-platform dependency while preserving the
mergedBudgetHeader behavior and layout.

Source: Coding guidelines

src/components/dashboard/platform/PlatformTrafficChart.tsx (1)

175-317: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

chartOptions/series를 useMemo로 감싸는 것을 권장합니다.

ResizeObserverupdateHeight를 통해 chartHeight를 자주 갱신합니다(297-317행). chartOptions(175행)와 series(266행)는 매 렌더마다 새 객체로 생성되므로, 높이가 바뀔 때마다 ReactApexChart가 새 options/series 참조를 받아 불필요하게 다시 그려질 수 있습니다. TrafficChart.tsx는 이미 buildChartOptions 결과를 useMemo로 감싸고 있으니, 같은 패턴을 이 파일에도 적용하면 일관성과 렌더링 성능이 개선됩니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/platform/PlatformTrafficChart.tsx` around lines 175
- 317, Wrap the chartOptions object and series array in useMemo to preserve
their references across chartHeight updates from updateHeight and
ResizeObserver. Include all values used inside each memo’s construction, such as
platformColor, fillHeight, anomalyTimestamp, anomalyY, xMin, xMax, yMax,
seriesData, and the relevant M labels, in the dependency arrays; keep the
existing Apex configuration and data unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/dashboard/charts/BudgetGaugeChart.tsx`:
- Around line 187-198: Update the budget summary block rendering the “남은 예산”
label so it uses an over-budget label when isOverBudget is true, matching the
displayed remainingAmount as an excess amount; preserve the existing label and
value formatting for budgets that are not over.

In `@src/components/dashboard/charts/TrafficChart.tsx`:
- Around line 34-38: Update the height comment in ITrafficChartProps to state
the actual default value of 590 instead of 520, matching
OVERVIEW_TRAFFIC_CHART_HEIGHT.

In `@src/components/dashboard/platform/PlatformTrafficChart.tsx`:
- Around line 412-457: Update both chart container divs in the fillHeight and
non-fillHeight branches around containerRef to include role="group" and the same
aria-label used by TrafficChart.tsx: "실시간 트래픽 변화 차트: 시간대별 클릭수 추이". Keep the
existing classes, refs, and tooltip attributes unchanged.

In `@src/components/dashboard/platform/SinglePlatformView.tsx`:
- Around line 205-209: Update the wrapper div around the budget gauge content in
SinglePlatformView so it always applies the required flex container classes,
while retaining the dual-gauge-specific sizing and column behavior. Ensure the
single-gauge loading, error, and empty child states can use flex-1 and remain
vertically centered.

In `@src/utils/dashboard/budget.ts`:
- Around line 76-86: The mapOverviewBudgetViewModel fallback makes a missing
NAVER value appear as an unused budget. Update the naver handling in
mapOverviewBudgetViewModel so absent NAVER data causes the NAVER gauge/slice to
be omitted rather than substituted with zero, while preserving the existing
Google·Meta legacy fallback behavior.
- Around line 89-105: Update mapPlatformBudgetViewModel so the daily budget
gauge is only created when data.daily exists; do not let toAmountSlice fall back
to the top-level totalBudget/totalSpend for the daily path. Preserve the
lifetime gauge and unsupported-provider behavior, while omitting the daily slice
when its source data is unavailable.

---

Outside diff comments:
In `@src/components/dashboard/charts/BudgetGaugeChart.tsx`:
- Around line 70-90: Update the status calculation in the budget gauge flow to
incorporate the existing isOverBudget result, especially when totalBudget is
zero and spent is positive. Ensure getBudgetStatus and the displayed gauge,
badge, and insight remain consistent with the over-budget state, while
preserving normal calculations for configured budgets.

---

Nitpick comments:
In `@src/components/dashboard/platform/PlatformTrafficChart.tsx`:
- Around line 175-317: Wrap the chartOptions object and series array in useMemo
to preserve their references across chartHeight updates from updateHeight and
ResizeObserver. Include all values used inside each memo’s construction, such as
platformColor, fillHeight, anomalyTimestamp, anomalyY, xMin, xMax, yMax,
seriesData, and the relevant M labels, in the dependency arrays; keep the
existing Apex configuration and data unchanged.

In `@src/components/dashboard/platform/SinglePlatformView.tsx`:
- Around line 147-155: Extract the duplicated dual-gauge height string into a
new PLATFORM_MID_SECTION_HEIGHT_DUAL constant in trafficChartHeights.ts, then
replace both inline "min-h-120 h-full" usages in SinglePlatformView with that
constant while preserving the existing conditional styling.
- Around line 232-243: Remove the redundant gauges.length > 1 check from the
gauge separator condition in
src/components/dashboard/platform/SinglePlatformView.tsx lines 232-243, leaving
index > 0 as the condition. Apply the same simplification in
src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx lines 71-83.
Extract the identical separator class string into a shared constant and reuse it
at both sites.

In `@src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx`:
- Around line 70-74: PlatformBudgetGaugeCompactSkeleton과
PlatformDualBudgetGaugeSkeleton의 인라인 props 객체 타입을 제거하고, 두 컴포넌트가 공유할 수 있는 I*Props
명명 타입을 정의해 재사용하도록 변경하세요. 해당 타입에는 mergedBudgetHeader의 선택적 boolean 설정과 기본값 동작을
유지하세요.
- Around line 142-159: Move the shared PlatformDualBudgetGaugeSkeleton
implementation into components/common/skeleton/ and expose it as a common gauge
skeleton component. Update both PlatformSkeleton and OverviewSkeleton, including
OverviewBudgetGaugeSkeleton, to import and use the common component directly,
removing the overview-to-platform dependency while preserving the
mergedBudgetHeader behavior and layout.

In `@src/hooks/dashboard/useBudget.ts`:
- Around line 20-27: useBudget의 useCoreQuery 호출에서 인라인 select 콜백을 useCallback으로
메모이제이션해 참조가 렌더마다 바뀌지 않도록 수정하세요. 콜백은 기존처럼 toBudgetQueryData(data, provider)를 호출하고
provider 변경 시 갱신되도록 의존성을 설정하며, queryKey와 enabled 동작은 유지하세요.
- Line 3: Update the TProviderType import in useBudget.ts to use the defining
module "`@/types/dashboard/provider`" instead of the overview re-export, keeping
the imported type and surrounding hook logic unchanged.

In `@src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx`:
- Around line 64-70: Update the conditional className on the gauge container div
to use the project’s twMerge utility, removing the redundant gap-5 branch while
preserving the shared flex, sizing, and overflow classes.

In `@src/utils/dashboard/budget.ts`:
- Around line 125-140: Update toBudgetQueryData to use the existing
SHOW_BUDGET_GAUGE_INSIGHT constant for the toGaugeProps showInsight option
instead of the hardcoded true value, keeping the behavior unchanged while
centralizing the default.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 15b52d8e-d2c2-4406-bdf7-ffdde5e2e8e3

📥 Commits

Reviewing files that changed from the base of the PR and between f087cb5 and 2975cba.

📒 Files selected for processing (15)
  • src/components/dashboard/charts/BudgetGaugeChart.tsx
  • src/components/dashboard/charts/TrafficChart.tsx
  • src/components/dashboard/charts/trafficChart.config.ts
  • src/components/dashboard/overview/skeleton/OverviewSkeleton.tsx
  • src/components/dashboard/platform/PlatformTrafficChart.tsx
  • src/components/dashboard/platform/SinglePlatformView.tsx
  • src/components/dashboard/platform/skeleton/PlatformSkeleton.tsx
  • src/constants/dashboard/trafficChartHeights.ts
  • src/hooks/dashboard/useBudget.ts
  • src/pages/dashboard/overview/OverviewDashboard.tsx
  • src/pages/dashboard/overview/sections/OverviewBudgetSection.tsx
  • src/pages/dashboard/overview/sections/OverviewKpiSection.tsx
  • src/types/dashboard/budget.ts
  • src/types/dashboard/common.ts
  • src/utils/dashboard/budget.ts
💤 Files with no reviewable changes (1)
  • src/pages/dashboard/overview/OverviewDashboard.tsx

Comment thread src/components/dashboard/charts/BudgetGaugeChart.tsx
Comment thread src/components/dashboard/charts/TrafficChart.tsx
Comment thread src/components/dashboard/platform/PlatformTrafficChart.tsx
Comment thread src/components/dashboard/platform/SinglePlatformView.tsx Outdated
Comment thread src/utils/dashboard/budget.ts
Comment thread src/utils/dashboard/budget.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: 확인했습니다! 고생하셨어요!

@YermIm
YermIm merged commit 5308f7d into develop Aug 3, 2026
3 checks passed
@YermIm
YermIm deleted the feature/#312 branch August 3, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ [Feature] 대시보드 예산 소진 UI 스펙 반영 (통합·플랫폼)

3 participants