- 03-02-SUMMARY.md: documents CollapsibleSections wired into dashboard - STATE.md: records key-prop reset decision, phase 3 completion, updated session - ROADMAP.md: phase 3 plans (2/2) marked complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
119 lines
6.8 KiB
Markdown
119 lines
6.8 KiB
Markdown
---
|
|
phase: 03-collapsible-dashboard-sections
|
|
plan: "02"
|
|
subsystem: ui
|
|
tags: [react, typescript, tailwind, radix-ui, collapsible, dashboard, state]
|
|
|
|
# Dependency graph
|
|
requires:
|
|
- phase: 03-collapsible-dashboard-sections/03-01
|
|
provides: CollapsibleSections component, CategorySection component, carryover display
|
|
- phase: 02-dashboard-charts-and-layout
|
|
provides: DashboardContent structure, useBudgetDetail hook, chart layout
|
|
provides:
|
|
- groupedSections useMemo deriving non-empty category groups from budget items
|
|
- openSections state with direction-aware smart defaults (over-budget expanded)
|
|
- Month-navigation state reset via key={budgetId} on DashboardContent
|
|
- CollapsibleSections integrated between chart grid and QuickAdd button
|
|
- DashboardSkeleton updated with section header placeholders
|
|
affects:
|
|
- Phase 04 (any further dashboard enhancements will build on this layout)
|
|
|
|
# Tech tracking
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- "key prop state reset: DashboardContent keyed by budgetId to reset all local state on month navigation"
|
|
- "direction-aware budget logic: income/saving/investment over-budget when actual < budgeted; bill/variable_expense/debt over when actual > budgeted"
|
|
- "lazy useState initializer: groupedSections-derived open state initialized once via () => callback"
|
|
|
|
key-files:
|
|
created: []
|
|
modified:
|
|
- src/pages/DashboardPage.tsx
|
|
- src/components/dashboard/DashboardSkeleton.tsx
|
|
|
|
key-decisions:
|
|
- "key prop state reset over useEffect: keying DashboardContent by budgetId causes full remount on month change, cleanly resetting openSections without violating react-hooks/set-state-in-effect or react-hooks/refs lint rules"
|
|
- "isOverBudget placed at module level as pure helper for reuse in useState initializer and documentation clarity"
|
|
- "CATEGORY_TYPES_ALL includes income first (income -> bill -> variable_expense -> debt -> saving -> investment) to match logical reading order in the dashboard sections area"
|
|
|
|
patterns-established:
|
|
- "key prop state reset: use key={derivedId} on inner content components to reset all local state on ID change — avoids useEffect+setState pattern flagged by strict linters"
|
|
|
|
requirements-completed: [UI-DASH-01, UI-COLLAPSE-01]
|
|
|
|
# Metrics
|
|
duration: 2min
|
|
completed: 2026-03-17
|
|
---
|
|
|
|
# Phase 3 Plan 02: Dashboard Collapsible Sections Integration Summary
|
|
|
|
**Collapsible per-category sections wired into DashboardContent with direction-aware smart expand defaults, month-navigation state reset via key prop, and updated DashboardSkeleton.**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** 2 min
|
|
- **Started:** 2026-03-17T14:11:14Z
|
|
- **Completed:** 2026-03-17T14:13:56Z
|
|
- **Tasks:** 1 auto (1 checkpoint auto-approved)
|
|
- **Files modified:** 2
|
|
|
|
## Accomplishments
|
|
- Integrated CollapsibleSections between chart grid and QuickAdd in DashboardContent
|
|
- groupedSections useMemo filters empty category groups and computes budgeted/actual totals per group
|
|
- Direction-aware isOverBudget helper correctly expands overspent expense sections and under-earned income/saving/investment sections on load
|
|
- State resets cleanly on month navigation using key={budgetId} on DashboardContent (avoids useEffect+setState lint violations)
|
|
- DashboardSkeleton updated with 3 section header placeholders matching real CategorySection header structure
|
|
|
|
## Task Commits
|
|
|
|
Each task was committed atomically:
|
|
|
|
1. **Task 1: Wire collapsible sections into DashboardContent with smart defaults** - `9a8d13f` (feat)
|
|
2. **Task 2: Verify collapsible sections and carryover display** - checkpoint:human-verify (auto-approved, no commit)
|
|
|
|
**Plan metadata:** (docs commit — see final commit)
|
|
|
|
## Files Created/Modified
|
|
- `/home/jlmak/Projects/jlmak/SimpleFinanceDash/src/pages/DashboardPage.tsx` - Added CATEGORY_TYPES_ALL, isOverBudget helper, groupedSections useMemo, openSections useState, handleToggleSection callback, CollapsibleSections JSX insertion, key={budgetId} on DashboardContent
|
|
- `/home/jlmak/Projects/jlmak/SimpleFinanceDash/src/components/dashboard/DashboardSkeleton.tsx` - Added 3 skeleton section header rows after chart grid skeleton
|
|
|
|
## Decisions Made
|
|
- **key prop state reset over useEffect:** The plan specified `useEffect(() => { setOpenSections(...) }, [budgetId])` for month navigation reset. This triggered `react-hooks/set-state-in-effect` and `react-hooks/refs` errors with the strict linter. Used `key={currentBudget.id}` on `DashboardContent` instead — causes full remount on month change, cleanly resetting all local state without effect side effects.
|
|
- **isOverBudget at module level:** Placed as pure function alongside constants for clarity and to enable reuse in the `useState` lazy initializer.
|
|
- **CATEGORY_TYPES_ALL order:** income first, then expense types, matching the logical top-to-bottom financial reading order (income earned → bills → variable → debt → savings → investments).
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 1 - Bug] Replaced useEffect+setState with key prop state reset**
|
|
- **Found during:** Task 1 (lint verification step)
|
|
- **Issue:** Plan-specified `useEffect(() => setOpenSections(...), [budgetId])` triggered `react-hooks/set-state-in-effect` error. Attempted `useRef` comparison during render — triggered `react-hooks/refs` error. Both patterns rejected by the project's strict linter.
|
|
- **Fix:** Removed useEffect entirely. Added `key={currentBudget.id}` to `<DashboardContent>` in DashboardPage. When `budgetId` changes, React unmounts and remounts DashboardContent, resetting all local state including `openSections` (which re-initializes from `groupedSections` via the lazy `useState` initializer).
|
|
- **Files modified:** `src/pages/DashboardPage.tsx`
|
|
- **Verification:** `npx eslint src/pages/DashboardPage.tsx` — no errors. `bun run build` passes.
|
|
- **Committed in:** `9a8d13f` (Task 1 commit)
|
|
|
|
---
|
|
|
|
**Total deviations:** 1 auto-fixed (1 bug — lint-incompatible pattern replaced with idiomatic React)
|
|
**Impact on plan:** Fix improves code quality. key-prop reset is the canonical React pattern for this use case. Functional behavior is identical: openSections resets to smart defaults on month navigation.
|
|
|
|
## Issues Encountered
|
|
- Strict linter (`react-hooks/set-state-in-effect`, `react-hooks/refs`) rejected two approaches before key-prop solution was used. All pre-existing lint errors (MonthNavigator, badge.tsx, button.tsx, sidebar.tsx, useBudgets.ts) remain as documented in STATE.md — not caused by this plan.
|
|
|
|
## User Setup Required
|
|
None - no external service configuration required.
|
|
|
|
## Next Phase Readiness
|
|
- Phase 3 is now complete: CollapsibleSections fully integrated into the live dashboard with all state management
|
|
- Dashboard hybrid view delivers the full financial picture: SummaryStrip -> charts -> collapsible category sections -> QuickAdd
|
|
- Phase 4 can build additional features on this complete dashboard foundation
|
|
|
|
---
|
|
*Phase: 03-collapsible-dashboard-sections*
|
|
*Completed: 2026-03-17*
|