From 444baa51878b33dbcb89b40e4d1ec126d5347a84 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Thu, 12 Mar 2026 09:20:33 +0100 Subject: [PATCH] docs(04): create phase plan --- .planning/ROADMAP.md | 7 +- .../04-01-PLAN.md | 103 ++++++++ .../04-02-PLAN.md | 219 ++++++++++++++++++ 3 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 .planning/phases/04-chart-polish-and-bug-fixes/04-01-PLAN.md create mode 100644 .planning/phases/04-chart-polish-and-bug-fixes/04-02-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index d557ef0..087a1b8 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -74,7 +74,10 @@ Plans: 1. All chart fills (donut slices, bar segments) use the semantic category colors from `lib/palette.ts` — "Bills" is the same color in the donut chart as it is in the FinancialOverview table 2. Chart tooltips display values formatted with the budget's currency (e.g., "1,234.56" not "1234.56") 3. The `formatCurrency` function uses the user's locale preference from their settings instead of the hardcoded `de-DE` — an English-locale user sees their numbers formatted correctly -**Plans**: TBD +**Plans:** 2 plans +Plans: +- [ ] 04-01-PLAN.md — TDD: formatCurrency locale parameter fix (FIX-01) +- [ ] 04-02-PLAN.md — Chart tooltip wiring and locale threading (IXTN-04) ## Progress @@ -86,4 +89,4 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 | 1. Design Token Foundation | 2/2 | Complete | 2026-03-11 | | 2. Layout and Brand Identity | 0/2 | In progress | - | | 3. Interaction Quality and Completeness | 0/4 | Not started | - | -| 4. Chart Polish and Bug Fixes | 0/TBD | Not started | - | +| 4. Chart Polish and Bug Fixes | 0/2 | Not started | - | diff --git a/.planning/phases/04-chart-polish-and-bug-fixes/04-01-PLAN.md b/.planning/phases/04-chart-polish-and-bug-fixes/04-01-PLAN.md new file mode 100644 index 0000000..7ce5759 --- /dev/null +++ b/.planning/phases/04-chart-polish-and-bug-fixes/04-01-PLAN.md @@ -0,0 +1,103 @@ +--- +phase: 04-chart-polish-and-bug-fixes +plan: 01 +type: tdd +wave: 1 +depends_on: [] +files_modified: + - frontend/src/lib/format.ts + - frontend/src/lib/format.test.ts +autonomous: true +requirements: + - FIX-01 + +must_haves: + truths: + - "formatCurrency no longer hardcodes 'de-DE' — the default locale is 'en'" + - "formatCurrency accepts an optional third locale parameter" + - "Calling formatCurrency(1234.56, 'EUR', 'de') produces German-formatted output" + - "Calling formatCurrency(1234.56, 'USD', 'en') produces English-formatted output" + - "Calling formatCurrency(1234.56, 'EUR') without locale uses 'en' default, not 'de-DE'" + artifacts: + - path: "frontend/src/lib/format.ts" + provides: "Locale-aware formatCurrency function" + contains: "locale" + - path: "frontend/src/lib/format.test.ts" + provides: "Unit tests for formatCurrency locale behavior" + min_lines: 20 + key_links: + - from: "frontend/src/lib/format.ts" + to: "Intl.NumberFormat" + via: "locale parameter passed as first arg" + pattern: "Intl\\.NumberFormat\\(locale" +--- + + +Fix the hardcoded `'de-DE'` locale in `formatCurrency` by adding an optional `locale` parameter with `'en'` as the default. This is the foundation for IXTN-04 (chart tooltips) and ensures all currency formatting respects the user's locale preference. + +Purpose: FIX-01 — English-locale users currently see German number formatting everywhere +Output: Updated `format.ts` with locale parameter, comprehensive unit tests + + + +@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md +@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phases/04-chart-polish-and-bug-fixes/04-RESEARCH.md +@frontend/src/lib/format.ts + + + + Locale-aware formatCurrency + frontend/src/lib/format.ts, frontend/src/lib/format.test.ts + + - formatCurrency(1234.56, 'EUR', 'en') returns a string containing "1,234.56" (English grouping) + - formatCurrency(1234.56, 'EUR', 'de') returns a string containing "1.234,56" (German grouping) + - formatCurrency(1234.56, 'USD', 'en') returns a string containing "$" and "1,234.56" + - formatCurrency(1234.56, 'EUR') with NO locale arg uses 'en' default — does NOT produce German formatting + - formatCurrency(0, 'EUR', 'en') returns a string containing "0.00" + - formatCurrency(-500, 'EUR', 'en') returns a string containing "-" and "500.00" + - formatCurrency(1234.56, 'EUR', '') falls back gracefully (does not throw RangeError) + + + Update `frontend/src/lib/format.ts`: + + ```ts + export function formatCurrency( + amount: number, + currency: string = 'EUR', + locale: string = 'en' + ): string { + return new Intl.NumberFormat(locale || 'en', { + style: 'currency', + currency, + }).format(amount) + } + ``` + + Key points: + - Third parameter `locale` defaults to `'en'` (replacing hardcoded `'de-DE'`) + - Defensive `locale || 'en'` guards against empty string (which throws RangeError) + - All existing call sites pass only 2 args — they will now get English formatting instead of German + - This is intentional and correct per FIX-01 + + + + +cd frontend && bun vitest run src/lib/format.test.ts + + + +- format.test.ts has at least 6 test cases covering locale variations, defaults, and edge cases +- All tests pass green +- formatCurrency signature has 3 parameters: amount, currency, locale +- No hardcoded 'de-DE' remains in format.ts + + + +After completion, create `.planning/phases/04-chart-polish-and-bug-fixes/04-01-SUMMARY.md` + diff --git a/.planning/phases/04-chart-polish-and-bug-fixes/04-02-PLAN.md b/.planning/phases/04-chart-polish-and-bug-fixes/04-02-PLAN.md new file mode 100644 index 0000000..9f7dda7 --- /dev/null +++ b/.planning/phases/04-chart-polish-and-bug-fixes/04-02-PLAN.md @@ -0,0 +1,219 @@ +--- +phase: 04-chart-polish-and-bug-fixes +plan: 02 +type: execute +wave: 2 +depends_on: + - "04-01" +files_modified: + - frontend/src/pages/DashboardPage.tsx + - frontend/src/components/ExpenseBreakdown.tsx + - frontend/src/components/AvailableBalance.tsx +autonomous: true +requirements: + - IXTN-04 + +must_haves: + truths: + - "Hovering over an ExpenseBreakdown pie slice shows a tooltip with the category name and currency-formatted value" + - "Hovering over an AvailableBalance donut slice shows a tooltip with the segment name and currency-formatted value" + - "Chart tooltip values use the budget's currency code (not hardcoded EUR)" + - "Chart tooltip values use the user's preferred_locale for number formatting" + - "AvailableBalance center text also receives the user's locale for formatting" + artifacts: + - path: "frontend/src/components/ExpenseBreakdown.tsx" + provides: "Custom Recharts Tooltip with formatted currency" + contains: "formatCurrency" + - path: "frontend/src/components/AvailableBalance.tsx" + provides: "Custom Recharts Tooltip on donut chart + locale-aware center text" + contains: "Tooltip" + - path: "frontend/src/pages/DashboardPage.tsx" + provides: "Locale threading from useAuth to chart components" + contains: "useAuth" + key_links: + - from: "frontend/src/pages/DashboardPage.tsx" + to: "frontend/src/hooks/useAuth.ts" + via: "useAuth() hook call to get user.preferred_locale" + pattern: "useAuth\\(\\)" + - from: "frontend/src/pages/DashboardPage.tsx" + to: "frontend/src/components/ExpenseBreakdown.tsx" + via: "locale prop passed to ExpenseBreakdown" + pattern: "locale=.*userLocale" + - from: "frontend/src/pages/DashboardPage.tsx" + to: "frontend/src/components/AvailableBalance.tsx" + via: "locale prop passed to AvailableBalance" + pattern: "locale=.*userLocale" + - from: "frontend/src/components/ExpenseBreakdown.tsx" + to: "frontend/src/lib/format.ts" + via: "formatCurrency called inside Tooltip content renderer" + pattern: "formatCurrency.*budget\\.currency.*locale" + - from: "frontend/src/components/AvailableBalance.tsx" + to: "frontend/src/lib/format.ts" + via: "formatCurrency called inside Tooltip content renderer and center text" + pattern: "formatCurrency.*budget\\.currency.*locale" +--- + + +Wire custom currency-formatted tooltips into both chart components and thread the user's locale preference from `useAuth` through `DashboardPage` to the charts. After this plan, hovering over any chart segment shows a properly formatted currency value. + +Purpose: IXTN-04 — chart tooltips currently show raw numbers without currency formatting +Output: Both charts have styled tooltips, locale flows from user settings to chart display + + + +@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md +@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phases/04-chart-polish-and-bug-fixes/04-RESEARCH.md +@.planning/phases/04-chart-polish-and-bug-fixes/04-01-SUMMARY.md + + + + +From frontend/src/lib/format.ts (after Plan 01): +```typescript +export function formatCurrency(amount: number, currency?: string, locale?: string): string +``` + +From frontend/src/lib/api.ts: +```typescript +export interface User { + // ... + preferred_locale: string + // ... +} + +export interface BudgetDetail { + id: string + name: string + currency: string + // ... + totals: BudgetTotals + items: BudgetItem[] +} +``` + +From frontend/src/hooks/useAuth.ts: +```typescript +export function useAuth(): { + user: User | null + loading: boolean + login: (email: string, password: string) => Promise + // ... +} +``` + +From frontend/src/components/ExpenseBreakdown.tsx (current): +```typescript +interface Props { + budget: BudgetDetail +} +// Needs locale prop added +``` + +From frontend/src/components/AvailableBalance.tsx (current): +```typescript +interface Props { + budget: BudgetDetail +} +// Needs locale prop added, also needs Tooltip import added +``` + +From frontend/src/lib/palette.ts: +```typescript +export type CategoryType = 'income' | 'bill' | 'variable_expense' | 'debt' | 'saving' | 'investment' | 'carryover' +export const palette: Record +``` + + + + + + + Task 1: Add locale prop and custom Tooltip to both chart components + frontend/src/components/ExpenseBreakdown.tsx, frontend/src/components/AvailableBalance.tsx + + **ExpenseBreakdown.tsx:** + 1. Add `locale?: string` to the `Props` interface + 2. Import `formatCurrency` from `@/lib/format` + 3. Replace bare `` with a custom `content` renderer: + ```tsx + { + if (!active || !payload?.length) return null + const item = payload[0] + return ( +
+

{item.name}

+

+ {formatCurrency(Number(item.value), budget.currency, locale)} +

+
+ ) + }} + /> + ``` + 4. Destructure `locale = 'en'` from props with default + + **AvailableBalance.tsx:** + 1. Add `locale?: string` to the `Props` interface + 2. Import `Tooltip` from `recharts` (add to existing import) + 3. Add `` with identical custom `content` renderer pattern inside the `` after the `` element + 4. Update the center text `formatCurrency(available, budget.currency)` call to include locale: `formatCurrency(available, budget.currency, locale)` + 5. Destructure `locale = 'en'` from props with default + + **Do NOT** use `ChartContainer` or `ChartTooltipContent` from shadcn — these charts use raw Recharts primitives and the project rule forbids editing shadcn ui source files. + + **Tooltip styling** must match shadcn design system: `rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl` — this replicates the ChartTooltipContent styling without importing it. +
+ + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run + + Both chart components accept an optional locale prop, render custom tooltips with formatCurrency, and AvailableBalance center text passes locale to formatCurrency +
+ + + Task 2: Thread user locale from useAuth through DashboardPage to chart components + frontend/src/pages/DashboardPage.tsx + + 1. Add `useAuth` import: `import { useAuth } from '@/hooks/useAuth'` + 2. Inside `DashboardPage` function body, call: `const { user } = useAuth()` + 3. Derive locale with defensive fallback: `const userLocale = user?.preferred_locale || 'en'` + 4. Pass `locale={userLocale}` prop to both chart component instances: + - `` + - `` + 5. Do NOT pass locale to other components (BillsTracker, VariableExpenses, DebtTracker, FinancialOverview) — those components use formatCurrency with the new 'en' default which is correct. A full locale-threading pass across all table components is out of scope for this phase. + + The `useAuth()` hook is idempotent — it reads from the same React state already initialized by `App.tsx`, so there is no double-fetch concern. + + + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run + + DashboardPage calls useAuth(), derives userLocale, and passes it to both ExpenseBreakdown and AvailableBalance as a locale prop + + +
+ + +1. `cd frontend && bun vitest run` — full test suite passes +2. `cd frontend && bun run build` — production build succeeds with no TypeScript errors +3. Manual: hover over ExpenseBreakdown pie slices — tooltip shows category name + formatted currency +4. Manual: hover over AvailableBalance donut slices — tooltip shows segment name + formatted currency +5. Manual: AvailableBalance center text formats using user's locale preference + + + +- ExpenseBreakdown shows formatted currency tooltip on hover (not raw numbers) +- AvailableBalance shows formatted currency tooltip on hover (previously had no tooltip) +- AvailableBalance center text uses the user's locale for formatting +- DashboardPage reads user.preferred_locale via useAuth and threads it to both chart components +- Full test suite and build pass with no errors + + + +After completion, create `.planning/phases/04-chart-polish-and-bug-fixes/04-02-SUMMARY.md` +