11 KiB
11 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-interaction-quality-and-completeness | 03 | execute | 2 |
|
|
true |
|
|
Purpose: Complete the inline edit feedback loop — users see green/red row flashes confirming save success/failure. Tinted skeletons make the loading state feel intentional and branded rather than generic. Output: BillsTracker, VariableExpenses, DebtTracker with flash + skeleton states; DashboardPage with tinted skeletons.
<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>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-interaction-quality-and-completeness/03-CONTEXT.md @.planning/phases/03-interaction-quality-and-completeness/03-RESEARCH.md @.planning/phases/03-interaction-quality-and-completeness/03-01-SUMMARY.md From frontend/src/components/InlineEditCell.tsx (post Plan 01): ```typescript interface InlineEditCellProps { value: number currency: string onSave: (value: number) => Promise onSaveSuccess?: () => void onSaveError?: () => void className?: string } ```From frontend/src/lib/palette.ts:
export const palette = {
bill: { base: '...', light: 'oklch(0.96 0.03 250)', header: '...' },
variable_expense: { base: '...', light: 'oklch(0.97 0.04 85)', header: '...' },
debt: { base: '...', light: 'oklch(0.96 0.04 15)', header: '...' },
saving: { base: '...', light: 'oklch(0.95 0.04 280)', header: '...' },
investment: { base: '...', light: 'oklch(0.96 0.03 320)', header: '...' },
// ...
}
From frontend/src/components/BillsTracker.tsx:
interface Props {
budget: BudgetDetail
onUpdate: (itemId: string, data: { actual_amount?: number; budgeted_amount?: number }) => Promise<void>
}
// Uses: <TableRow key={item.id}> containing <InlineEditCell onSave={...} />
From frontend/src/components/ui/skeleton.tsx:
// Accepts className and style props. Default bg is bg-muted.
// Override with style={{ backgroundColor: '...' }} to tint.
Add flash state and helper to each component:
```typescript
const [flashRowId, setFlashRowId] = useState<string | null>(null)
const [errorRowId, setErrorRowId] = useState<string | null>(null)
const triggerFlash = (id: string, type: 'success' | 'error') => {
if (type === 'success') {
setFlashRowId(id)
setTimeout(() => setFlashRowId(null), 600)
} else {
setErrorRowId(id)
setTimeout(() => setErrorRowId(null), 600)
}
}
```
On each data `<TableRow>` (not the totals row), add inline style for the flash:
```tsx
<TableRow
key={item.id}
className="transition-colors duration-500"
style={
flashRowId === item.id
? { backgroundColor: 'color-mix(in oklch, var(--success) 20%, transparent)' }
: errorRowId === item.id
? { backgroundColor: 'color-mix(in oklch, var(--destructive) 20%, transparent)' }
: undefined
}
>
```
Use `color-mix()` inline style (not Tailwind `bg-success/20`) per research recommendation — avoids potential Tailwind class generation issues.
Pass callbacks to each `<InlineEditCell>`:
```tsx
<InlineEditCell
value={item.actual_amount}
currency={budget.currency}
onSave={(actual) => onUpdate(item.id, { actual_amount: actual })}
onSaveSuccess={() => triggerFlash(item.id, 'success')}
onSaveError={() => triggerFlash(item.id, 'error')}
className={amountColorClass({ type: 'bill', actual: item.actual_amount, budgeted: item.budgeted_amount })}
/>
```
Adjust the `type` argument in `amountColorClass` per component:
- BillsTracker: `type: 'bill'`
- VariableExpenses: `type: 'variable_expense'`
- DebtTracker: `type: 'debt'`
(These should already be correct from Phase 1 — just ensure the new onSaveSuccess/onSaveError props are added.)
**Do NOT modify** the totals row or the CardHeader — only add flash state and wire callbacks.
cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build
All three tracker components have flash state, triggerFlash helper, inline style on data rows, and onSaveSuccess/onSaveError wired to InlineEditCell. Build passes.
Task 2: Add pastel-tinted loading skeletons to DashboardPage and tracker sections
frontend/src/pages/DashboardPage.tsx, frontend/src/components/BillsTracker.tsx, frontend/src/components/VariableExpenses.tsx, frontend/src/components/DebtTracker.tsx
**DashboardPage.tsx** — tint existing loading skeleton block (lines 39-47):
- Import `palette` from `@/lib/palette`
- Replace the existing generic Skeleton elements with tinted versions:
```tsx
if (loading && list.length === 0) {
return (
**BillsTracker.tsx, VariableExpenses.tsx, DebtTracker.tsx** — add skeleton for empty sections:
- Import `Skeleton` from `@/components/ui/skeleton` and ensure `palette` is imported (already imported for `headerGradient`)
- After the filter (e.g., `const bills = budget.items.filter(...)`) add an early return if no items exist:
```tsx
if (bills.length === 0) {
return (
<Card>
<CardHeader style={headerGradient('bill')}>
<CardTitle>{t('dashboard.billsTracker')}</CardTitle>
</CardHeader>
<CardContent className="flex flex-col gap-2 p-4">
{[1, 2, 3].map((i) => (
<Skeleton
key={i}
className="h-10 w-full rounded-md"
style={{ backgroundColor: palette.bill.light }}
/>
))}
</CardContent>
</Card>
)
}
```
Use the matching palette key per component:
- BillsTracker: `palette.bill.light`
- VariableExpenses: `palette.variable_expense.light`
- DebtTracker: `palette.debt.light`
**Note:** These skeletons show when a budget exists but has no items of that type — they serve as visual placeholders indicating the section exists. This is distinct from the DashboardPage loading skeleton (which shows before any data loads).
cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run && bun run build
Dashboard loading skeleton uses palette-tinted backgrounds per section. Each tracker shows tinted skeletons when no items of its type exist. All tests pass, build succeeds.
- `cd frontend && bun vitest run` — full test suite passes
- `cd frontend && bun run build` — production build succeeds
- Row flash uses `color-mix(in oklch, var(--success/destructive) 20%, transparent)` inline style
- Dashboard skeleton uses palette.*.light inline styles
- Tracker skeletons use matching palette key for their section
<success_criteria>
- Inline edit save success produces visible green row flash (~600ms duration)
- Inline edit save failure produces visible red row flash + value revert
- Dashboard loading state shows pastel-tinted skeletons (not grey)
- Empty tracker sections show tinted skeleton placeholders matching their card header color
- No flash or skeleton interferes with existing functionality </success_criteria>