fix(reports): charts rendered one colour — RSC client/server boundary bug #120

Merged
shad0w merged 1 commit from fix/reports-series-colors into master 2026-06-24 07:05:40 +00:00
Owner

Fixes the real cause of "Reports charts show one colour" (the earlier #118 was the right idea but couldn't take effect because of this bug).

Symptom

Every line / bar series in the comparison charts rendered in recharts' default colour (#3182bd), and the detail-page breakdown swatches had no colour.

Root cause — a React Server Components boundary bug

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] evaluated to SERIES_COLORS[NaN] → undefined, every <Line stroke={undefined}> fell back to the recharts default.

strokeWidth={2} (a literal inside the client chart) still applied — which is why only the colour was wrong. And it passed the jsdom unit tests because those import the array directly, not across the RSC boundary.

Fix

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

Verification

Confirmed in a real browser against seeded data: the line strokes now cycle the 10-colour palette (#2563eb, #16a34a, #9333ea, …) instead of a uniform #3182bd. tsc clean.

🤖 Generated with Claude Code

Fixes the real cause of "Reports charts show one colour" (the earlier #118 was the right idea but couldn't take effect because of this bug). ## Symptom Every line / bar series in the comparison charts rendered in recharts' default colour (`#3182bd`), and the detail-page breakdown swatches had no colour. ## Root cause — a React Server Components boundary bug `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]` evaluated to `SERIES_COLORS[NaN] → undefined`, every `<Line stroke={undefined}>` fell back to the recharts default. `strokeWidth={2}` (a literal inside the client chart) still applied — which is why only the *colour* was wrong. And it passed the jsdom unit tests because those import the array directly, not across the RSC boundary. ## Fix Move the palette into a dependency-free shared module **`lib/report-colors.ts`** (no `"use client"`, no server-only imports) so it resolves to the real array in both the server and client graphs. `charts.tsx` and all four report pages now import it from there. (It can't live in `lib/reports.ts` — that imports Prisma `db`, which must not enter the client bundle.) ## Verification Confirmed in a real browser against seeded data: the line strokes now cycle the 10-colour palette (`#2563eb, #16a34a, #9333ea, …`) instead of a uniform `#3182bd`. `tsc` clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
shad0w added 1 commit 2026-06-24 07:02:04 +00:00
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
34143b5e75
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>
shad0w merged commit 2fcb207add into master 2026-06-24 07:05:40 +00:00
Sign in to join this conversation.
No description provided.