This commit is contained in:
2026-04-02 14:29:36 +02:00
parent a270deb2db
commit 039fa0bc80
54 changed files with 4944 additions and 170 deletions

View File

@@ -3,11 +3,12 @@
"granularity": "coarse",
"parallelization": true,
"commit_docs": true,
"model_profile": "quality",
"model_profile": "balanced",
"workflow": {
"research": true,
"plan_check": true,
"verifier": true,
"nyquist_validation": true
"nyquist_validation": true,
"_auto_chain_active": true
}
}
}

View File

@@ -0,0 +1,108 @@
---
phase: 02-dashboard-charts-and-layout
plan: 01
subsystem: ui
tags: [react-router, useSearchParams, select, lucide-react, i18n]
# Dependency graph
requires:
- phase: 01-design-foundation-and-primitives
provides: "Design tokens, PageShell, SummaryStrip, ChartEmptyState component"
provides:
- "useMonthParam hook for URL-based month state"
- "MonthNavigator component with prev/next arrows and month dropdown"
- "i18n keys for chart labels and month navigation (EN + DE)"
affects: [02-02, 02-03, dashboard-page-refactor]
# Tech tracking
tech-stack:
added: []
patterns: [URL search param state via useMonthParam, locale-aware month formatting]
key-files:
created:
- src/hooks/useMonthParam.ts
- src/components/dashboard/MonthNavigator.tsx
modified:
- src/i18n/en.json
- src/i18n/de.json
key-decisions:
- "MonthNavigator uses Select dropdown (not popover) for month jump -- consistent with existing form patterns"
- "formatMonthLabel uses Date.toLocaleDateString for locale-aware month display"
- "ChartEmptyState already existed from Phase 1 -- no changes needed"
patterns-established:
- "useMonthParam: URL state hook pattern using useSearchParams callback form to preserve other params"
- "MonthNavigator accepts t() prop for presentational i18n (Phase 1 pattern continued)"
requirements-completed: [UI-DASH-01]
# Metrics
duration: 2min
completed: 2026-03-16
---
# Phase 2 Plan 1: Month Navigation and Chart Infrastructure Summary
**URL-based month navigation hook with MonthNavigator dropdown/arrows and chart i18n keys in EN/DE**
## Performance
- **Duration:** 2 min
- **Started:** 2026-03-16T12:01:18Z
- **Completed:** 2026-03-16T12:03:21Z
- **Tasks:** 2
- **Files modified:** 4
## Accomplishments
- useMonthParam hook reads/writes `?month=YYYY-MM` from URL with current month fallback and year-rollover-safe navigation
- MonthNavigator renders prev/next chevron buttons and a Select dropdown listing available budget months with locale-aware formatting
- Added 10 new i18n keys under `dashboard.*` for chart labels, month navigation, and empty states in both English and German
## Task Commits
Each task was committed atomically:
1. **Task 1: Create useMonthParam hook and MonthNavigator component** - `4481950` (feat)
2. **Task 2: Add chart and month navigation i18n keys** - `42bf1f9` (feat)
## Files Created/Modified
- `src/hooks/useMonthParam.ts` - Custom hook wrapping useSearchParams for month URL state with setMonth and navigateMonth
- `src/components/dashboard/MonthNavigator.tsx` - Prev/next arrow buttons + Select dropdown for month selection
- `src/i18n/en.json` - Added monthNav, noData, expenseDonut, incomeChart, spendChart, budgeted, actual, noBudgetForMonth, createBudget, generateFromTemplate keys
- `src/i18n/de.json` - German translations for all 10 new dashboard keys
## Decisions Made
- MonthNavigator uses the shadcn Select component (not a popover or custom dropdown) for month selection -- consistent with existing form patterns in the project
- formatMonthLabel uses `Date.toLocaleDateString(undefined, { month: "long", year: "numeric" })` for locale-aware month display rather than manual string formatting
- ChartEmptyState component was already created during Phase 1 scaffolding -- verified it matches the plan specification exactly, so no changes were needed
## Deviations from Plan
None - plan executed exactly as written. ChartEmptyState already existed from Phase 1, which is expected since the charts directory was scaffolded earlier.
## Issues Encountered
None
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- useMonthParam hook ready for consumption by DashboardPage refactor (Plan 03)
- MonthNavigator ready to be placed in PageShell action slot (Plan 03)
- ChartEmptyState ready for use in chart components (Plans 02)
- All chart i18n keys available for chart components (Plan 02)
## Self-Check: PASSED
- FOUND: src/hooks/useMonthParam.ts
- FOUND: src/components/dashboard/MonthNavigator.tsx
- FOUND: src/components/dashboard/charts/ChartEmptyState.tsx
- FOUND: .planning/phases/02-dashboard-charts-and-layout/02-01-SUMMARY.md
- FOUND: commit 4481950
- FOUND: commit 42bf1f9
---
*Phase: 02-dashboard-charts-and-layout*
*Completed: 2026-03-16*

View File

@@ -119,6 +119,10 @@ None - no external service configuration required.
- `CollapsibleSections` expects: `groups[]`, `currency`, `openSections: Record<string,boolean>`, `onToggleSection`, `t`
- Plan 02 needs to: group `items` by `CategoryType`, compute per-group totals, manage `openSections` state in `DashboardContent`
## Self-Check: PASSED
All 9 files verified present. Both task commits (21ce6d8, f30b846) and metadata commit (7d08da2) confirmed in git log.
---
*Phase: 03-collapsible-dashboard-sections*
*Completed: 2026-03-17*

View File

@@ -0,0 +1,105 @@
# Phase 3: Collapsible Dashboard Sections - Context
**Gathered:** 2026-03-16
**Status:** Ready for planning
<domain>
## Phase Boundary
Complete the dashboard hybrid view with collapsible per-category sections that show individual line items, group totals, and variance indicators. Add carryover amount display to the balance card. Sections sit below the chart grid and above QuickAdd. This phase does not add editing capabilities or navigation links — the dashboard remains a read-only summary.
</domain>
<decisions>
## Implementation Decisions
### Section header design
- Badge-style chips for totals: two small colored badges showing `[Budget $X]` and `[Actual $X]` right-aligned in the header row
- Left border accent using the category's CSS variable color (thick colored left border on the header row)
- Difference shown in header with color coding: green (`--color-on-budget`) when under/on budget, red (`--color-over-budget`) when over budget
- Chevron-right icon that rotates to chevron-down when expanded (standard Radix Collapsible pattern)
- Group label (from `categoryLabels` in palette.ts) on the left, badges and difference on the right
### Line-item table columns
- Four columns: Item Name, Budgeted, Actual, Difference
- No tier badge — keep it clean for the dashboard summary view
- No notes column — full detail lives on BudgetDetailPage
- Difference column uses red text when over budget (`--color-over-budget`), no full-row tint
- Footer row with bold group totals summing Budget, Actual, and Diff columns
- Read-only — no clickable rows, no navigation links to BudgetDetailPage
### Default expand/collapse behavior
- Smart default: over-budget sections auto-expand on load, on/under-budget sections start collapsed
- Over-budget logic is direction-aware:
- Spending categories (bill, variable_expense, debt): actual > budget = over budget (expand)
- Income category: actual < budget = under-earned (expand)
- Savings/investment categories: actual < budget = under-saved (expand)
- Empty category groups (no items of that type) are hidden entirely — only show sections with at least one budget item
- Expand/collapse state resets on month navigation — smart defaults recalculate per month
### Carryover display
- Subtitle line below balance amount on the balance StatCard: "Includes $X carryover" when non-zero
- Carryover is included in the balance calculation: Balance = Income Actual - Expenses Actual + Carryover
- When carryover is zero, the subtitle line is hidden entirely (clean card for the common case)
- Negative carryover is supported: shown with red styling (e.g., "Includes -$150 carryover"), deducts from balance
### Claude's Discretion
- Smooth collapse/expand CSS animation details (timing, easing)
- Preventing ResizeObserver loop errors when toggling rapidly (success criteria #3)
- Preventing chart resize jank when sections toggle (success criteria #3)
- Exact spacing between section headers and between sections and the chart grid above
- Table cell alignment and typography within line items
- DashboardSkeleton updates for the collapsible sections area
- How to derive and memoize per-group data from budget items
</decisions>
<specifics>
## Specific Ideas
No specific references — open to standard approaches within the established design system.
</specifics>
<code_context>
## Existing Code Insights
### Reusable Assets
- `collapsible.tsx` (ui/): Radix Collapsible primitive already installed — `Collapsible`, `CollapsibleTrigger`, `CollapsibleContent` exports ready to use
- `categoryColors` (palette.ts): CSS variable map for all 6 category types — use for left border accent colors
- `categoryLabels` (palette.ts): English/German labels for all 6 types — use for section header labels
- `Table`/`TableBody`/`TableCell`/`TableFooter`/`TableHead`/`TableHeader`/`TableRow` (ui/table.tsx): Full table primitive set for line items
- `Badge` (ui/badge.tsx): Use for budget/actual chips in section headers
- `StatCard` (components/dashboard/StatCard.tsx): Balance card that needs carryover subtitle
- `SummaryStrip` (components/dashboard/SummaryStrip.tsx): Orchestrates StatCards — may need carryover prop threading
- `formatCurrency` (lib/format.ts): Currency formatting for all monetary values
- `ChevronRight`/`ChevronDown` from `lucide-react`: Expand/collapse icons
### Established Patterns
- Two-tier OKLCH color pattern: text at ~0.55 lightness, chart fills at ~0.65-0.70 (Phase 1) — section border accents should use fill-tier lightness
- Semantic status tokens: `--color-over-budget` (red) and `--color-on-budget` (green) for difference indicators (Phase 1)
- Components accept `t()` as prop to stay presentational (Phase 1) — new section components should follow this
- `useMemo` hooks declared before early returns for Rules of Hooks compliance (Phase 2)
- `EXPENSE_TYPES` / `CATEGORY_TYPES` constants already define category ordering — reuse for section order
- `DashboardContent` pattern: inner component receives budget data, derives per-type totals (Phase 2)
### Integration Points
- `DashboardContent` (DashboardPage.tsx): Currently renders SummaryStrip → chart grid → QuickAdd. Collapsible sections insert between chart grid and QuickAdd.
- `useBudgetDetail(id)`: Returns `{ budget, items }` where items have category joins — items need grouping by `category.type` for sections
- `Budget.carryover_amount`: Field already exists on the Budget type — needs to flow from DashboardContent → SummaryStrip → StatCard
- `useMonthParam`: Month navigation resets expand/collapse state — state should be local React state (useState), not URL params
- i18n: New keys needed for section headers, table column labels, carryover subtitle, and empty states
</code_context>
<deferred>
## Deferred Ideas
None — discussion stayed within phase scope.
</deferred>
---
*Phase: 03-collapsible-dashboard-sections*
*Context gathered: 2026-03-16*