fix(reports): chart series all rendered one colour (RSC boundary bug)
Some checks failed
PR checks / checks (pull_request) Failing after 15s
PR checks / integration (pull_request) Successful in 41s

The comparison charts (and detail-page breakdown swatches) rendered every
series in recharts' default colour instead of the per-item palette.

Root cause: `SERIES_COLORS` was defined in `components/reports/charts.tsx`,
which is a "use client" module. The report **pages are server components** and
imported the palette from it. A plain value imported from a client module into
a server component is a client-reference proxy, not the real array — so
`SERIES_COLORS[i % SERIES_COLORS.length]` was `SERIES_COLORS[NaN]` → undefined,
every line got `stroke={undefined}`, and recharts fell back to #3182bd. (The
literal `strokeWidth={2}` still applied, which is why only the colour was wrong.
It passed jsdom tests because those import the array directly, not across the
RSC boundary.)

Fix: move the palette to a dependency-free shared module `lib/report-colors.ts`
(no "use client", no server-only imports) that resolves to the real array in
both server and client graphs. `charts.tsx` and all four report pages import it
from there. It can't live in `lib/reports.ts` (that imports Prisma `db`, which
must not enter the client bundle).

Verified in a real browser: line strokes now cycle the 10-colour palette
(#2563eb, #16a34a, …) instead of a uniform #3182bd.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hardik 2026-06-24 12:31:40 +05:30
parent cf69292be3
commit 34143b5e75
6 changed files with 33 additions and 5 deletions

View file

@ -19,7 +19,8 @@ import {
WEEK_LABELS,
} from "@/lib/reports";
import { ReportsToolbar } from "@/components/reports/reports-toolbar";
import { TrendChart, BreakdownChart, SERIES_COLORS } from "@/components/reports/charts";
import { TrendChart, BreakdownChart } from "@/components/reports/charts";
import { SERIES_COLORS } from "@/lib/report-colors";
import { Kpi, KpiStrip } from "@/components/reports/kpi";
import { ReportBreadcrumb, ReportTitle, SegLink } from "@/components/reports/report-header";

View file

@ -25,7 +25,8 @@ import {
type NodeSpend,
} from "@/lib/reports";
import { ReportsToolbar } from "@/components/reports/reports-toolbar";
import { ComparisonChart, Sparkline, SERIES_COLORS, type Series } from "@/components/reports/charts";
import { ComparisonChart, Sparkline, type Series } from "@/components/reports/charts";
import { SERIES_COLORS } from "@/lib/report-colors";
import { Kpi, KpiStrip } from "@/components/reports/kpi";
import { ReportBreadcrumb, ReportTitle, SelectCheckbox, CompareBar } from "@/components/reports/report-header";

View file

@ -19,7 +19,8 @@ import {
type Tier,
} from "@/lib/reports";
import { ReportsToolbar } from "@/components/reports/reports-toolbar";
import { TrendChart, BreakdownChart, SERIES_COLORS } from "@/components/reports/charts";
import { TrendChart, BreakdownChart } from "@/components/reports/charts";
import { SERIES_COLORS } from "@/lib/report-colors";
import { Kpi, KpiStrip } from "@/components/reports/kpi";
import { ReportBreadcrumb, ReportTitle, SegLink } from "@/components/reports/report-header";

View file

@ -23,7 +23,8 @@ import {
type CostCentreSpend,
} from "@/lib/reports";
import { ReportsToolbar } from "@/components/reports/reports-toolbar";
import { ComparisonChart, Sparkline, SERIES_COLORS, type Series } from "@/components/reports/charts";
import { ComparisonChart, Sparkline, type Series } from "@/components/reports/charts";
import { SERIES_COLORS } from "@/lib/report-colors";
import { Kpi, KpiStrip } from "@/components/reports/kpi";
import { ReportBreadcrumb, ReportTitle, SelectCheckbox, CompareBar } from "@/components/reports/report-header";

View file

@ -13,8 +13,11 @@ import {
CartesianGrid,
Cell,
} from "recharts";
import { SERIES_COLORS } from "@/lib/report-colors";
export const SERIES_COLORS = ["#2563eb", "#16a34a", "#9333ea", "#ea580c", "#0891b2", "#dc2626", "#ca8a04", "#4f46e5", "#0d9488", "#db2777"];
// Re-exported for back-compat; new server-component code should import the
// palette from "@/lib/report-colors" directly (see that file for why).
export { SERIES_COLORS };
/** Compact Indian-currency formatter for axis ticks / tooltips (₹..K / ₹..L / ₹..Cr). */
export function formatINRShort(n: number): string {

21
App/lib/report-colors.ts Normal file
View file

@ -0,0 +1,21 @@
// Shared categorical palette for the Reports charts + table swatches.
//
// This is a plain, dependency-free module (NO "use client", no server-only
// imports) so it can be imported by BOTH the server-component report pages and
// the client chart components and resolve to the real array in each. It must NOT
// live in a "use client" module: a plain value imported from a client module
// into a server component becomes a client-reference proxy (not the array), so
// `SERIES_COLORS[i]` would silently be `undefined` and every series would fall
// back to recharts' default colour.
export const SERIES_COLORS = [
"#2563eb",
"#16a34a",
"#9333ea",
"#ea580c",
"#0891b2",
"#dc2626",
"#ca8a04",
"#4f46e5",
"#0d9488",
"#db2777",
];