docs(04): create phase plan
This commit is contained in:
@@ -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 | - |
|
||||
|
||||
103
.planning/phases/04-chart-polish-and-bug-fixes/04-01-PLAN.md
Normal file
103
.planning/phases/04-chart-polish-and-bug-fixes/04-01-PLAN.md
Normal file
@@ -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"
|
||||
---
|
||||
|
||||
<objective>
|
||||
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
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/phases/04-chart-polish-and-bug-fixes/04-RESEARCH.md
|
||||
@frontend/src/lib/format.ts
|
||||
</context>
|
||||
|
||||
<feature>
|
||||
<name>Locale-aware formatCurrency</name>
|
||||
<files>frontend/src/lib/format.ts, frontend/src/lib/format.test.ts</files>
|
||||
<behavior>
|
||||
- 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)
|
||||
</behavior>
|
||||
<implementation>
|
||||
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
|
||||
</implementation>
|
||||
</feature>
|
||||
|
||||
<verification>
|
||||
cd frontend && bun vitest run src/lib/format.test.ts
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 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
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/04-chart-polish-and-bug-fixes/04-01-SUMMARY.md`
|
||||
</output>
|
||||
219
.planning/phases/04-chart-polish-and-bug-fixes/04-02-PLAN.md
Normal file
219
.planning/phases/04-chart-polish-and-bug-fixes/04-02-PLAN.md
Normal file
@@ -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"
|
||||
---
|
||||
|
||||
<objective>
|
||||
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
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.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
|
||||
|
||||
<interfaces>
|
||||
<!-- Key types and contracts the executor needs -->
|
||||
|
||||
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<void>
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
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<CategoryType, { light: string; medium: string; base: string }>
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add locale prop and custom Tooltip to both chart components</name>
|
||||
<files>frontend/src/components/ExpenseBreakdown.tsx, frontend/src/components/AvailableBalance.tsx</files>
|
||||
<action>
|
||||
**ExpenseBreakdown.tsx:**
|
||||
1. Add `locale?: string` to the `Props` interface
|
||||
2. Import `formatCurrency` from `@/lib/format`
|
||||
3. Replace bare `<Tooltip />` with a custom `content` renderer:
|
||||
```tsx
|
||||
<Tooltip
|
||||
content={({ active, payload }) => {
|
||||
if (!active || !payload?.length) return null
|
||||
const item = payload[0]
|
||||
return (
|
||||
<div className="rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl">
|
||||
<p className="font-medium text-foreground">{item.name}</p>
|
||||
<p className="font-mono tabular-nums text-muted-foreground">
|
||||
{formatCurrency(Number(item.value), budget.currency, locale)}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
```
|
||||
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 `<Tooltip>` with identical custom `content` renderer pattern inside the `<PieChart>` after the `<Pie>` 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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run</automated>
|
||||
</verify>
|
||||
<done>Both chart components accept an optional locale prop, render custom tooltips with formatCurrency, and AvailableBalance center text passes locale to formatCurrency</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Thread user locale from useAuth through DashboardPage to chart components</name>
|
||||
<files>frontend/src/pages/DashboardPage.tsx</files>
|
||||
<action>
|
||||
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:
|
||||
- `<AvailableBalance budget={current} locale={userLocale} />`
|
||||
- `<ExpenseBreakdown budget={current} locale={userLocale} />`
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run</automated>
|
||||
</verify>
|
||||
<done>DashboardPage calls useAuth(), derives userLocale, and passes it to both ExpenseBreakdown and AvailableBalance as a locale prop</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
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
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 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
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/04-chart-polish-and-bug-fixes/04-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user