185 lines
8.4 KiB
Markdown
185 lines
8.4 KiB
Markdown
---
|
|
phase: 03-interaction-quality-and-completeness
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: ["03-00"]
|
|
files_modified:
|
|
- frontend/src/components/InlineEditCell.tsx
|
|
- frontend/src/components/InlineEditCell.test.tsx
|
|
- frontend/src/pages/LoginPage.tsx
|
|
- frontend/src/pages/RegisterPage.tsx
|
|
- frontend/src/components/BudgetSetup.tsx
|
|
autonomous: true
|
|
requirements: [IXTN-01, IXTN-02, IXTN-03]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "Hovering over an inline-editable cell reveals a pencil icon that fades in"
|
|
- "After a successful inline save, the onSaveSuccess callback fires so parents can flash the row"
|
|
- "After a failed inline save, the value reverts and onSaveError callback fires"
|
|
- "Login submit button shows spinner and is disabled while request is in flight"
|
|
- "Register submit button shows spinner and is disabled while request is in flight"
|
|
- "Budget create button shows spinner and is disabled while saving"
|
|
artifacts:
|
|
- path: "frontend/src/components/InlineEditCell.tsx"
|
|
provides: "Pencil icon hover, onSaveSuccess/onSaveError callbacks, try/catch in handleBlur"
|
|
contains: "Pencil"
|
|
- path: "frontend/src/components/InlineEditCell.test.tsx"
|
|
provides: "Tests for pencil icon presence, save callbacks, error revert"
|
|
contains: "onSaveSuccess"
|
|
- path: "frontend/src/pages/LoginPage.tsx"
|
|
provides: "Spinner in submit button during loading"
|
|
contains: "Spinner"
|
|
- path: "frontend/src/pages/RegisterPage.tsx"
|
|
provides: "Spinner in submit button during loading"
|
|
contains: "Spinner"
|
|
- path: "frontend/src/components/BudgetSetup.tsx"
|
|
provides: "Spinner in create button during saving"
|
|
contains: "Spinner"
|
|
key_links:
|
|
- from: "frontend/src/components/InlineEditCell.tsx"
|
|
to: "parent components (BillsTracker, etc.)"
|
|
via: "onSaveSuccess/onSaveError callback props"
|
|
pattern: "onSaveSuccess\\?\\(\\)"
|
|
- from: "frontend/src/pages/LoginPage.tsx"
|
|
to: "ui/spinner.tsx"
|
|
via: "Spinner import"
|
|
pattern: "import.*Spinner"
|
|
---
|
|
|
|
<objective>
|
|
Add pencil icon hover affordance and save/error callbacks to InlineEditCell, plus loading spinners to three form submit buttons (Login, Register, Budget Create).
|
|
|
|
Purpose: Make inline editing discoverable (pencil icon on hover) and prepare the callback interface for row-level flash feedback in downstream plans. Make form submissions feel responsive with spinner indicators.
|
|
Output: Enhanced InlineEditCell with pencil + callbacks, spinner-enabled Login/Register/BudgetSetup forms.
|
|
|
|
Note: CONTEXT.md specifies spinners on "all four forms: Login, Register, Budget Create, Budget Edit." No Budget Edit form component exists in the codebase — only BudgetSetup (create-only). Budget Edit spinner is deferred until that form is built. This plan covers the 3 existing forms.
|
|
</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/STATE.md
|
|
@.planning/phases/03-interaction-quality-and-completeness/03-CONTEXT.md
|
|
@.planning/phases/03-interaction-quality-and-completeness/03-RESEARCH.md
|
|
|
|
<interfaces>
|
|
<!-- InlineEditCell current interface (will be extended) -->
|
|
From frontend/src/components/InlineEditCell.tsx:
|
|
```typescript
|
|
interface InlineEditCellProps {
|
|
value: number
|
|
currency: string
|
|
onSave: (value: number) => Promise<void>
|
|
className?: string
|
|
}
|
|
```
|
|
|
|
From frontend/src/components/ui/spinner.tsx:
|
|
```typescript
|
|
export { Spinner } // SVG spinner component, accepts className
|
|
```
|
|
|
|
From frontend/src/lib/format.ts:
|
|
```typescript
|
|
export function formatCurrency(value: number, currency: string): string
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: Enhance InlineEditCell with pencil icon, save/error callbacks, and try/catch</name>
|
|
<files>frontend/src/components/InlineEditCell.tsx, frontend/src/components/InlineEditCell.test.tsx</files>
|
|
<behavior>
|
|
- Test: Pencil icon element exists in display mode DOM (query by lucide test-id or role)
|
|
- Test: Pencil icon has opacity-0 class (hidden by default, visible on CSS hover — not testable in jsdom but DOM presence is)
|
|
- Test: When onSave resolves successfully, onSaveSuccess callback is called
|
|
- Test: When onSave rejects, value reverts to original and onSaveError callback is called
|
|
- Test: When parsed value equals current value, onSave is NOT called (existing behavior preserved)
|
|
</behavior>
|
|
<action>
|
|
Extend InlineEditCellProps with two optional callbacks:
|
|
```
|
|
onSaveSuccess?: () => void
|
|
onSaveError?: () => void
|
|
```
|
|
|
|
In the display-mode span:
|
|
- Add `group` class to the outer span
|
|
- Change span to `flex items-center justify-end gap-1`
|
|
- After the formatted value text, add: `<Pencil className="size-3 opacity-0 transition-opacity duration-150 group-hover:opacity-100 text-muted-foreground" />`
|
|
- Import `Pencil` from `lucide-react`
|
|
|
|
In handleBlur:
|
|
- Wrap the `await onSave(num)` in try/catch
|
|
- On success: call `onSaveSuccess?.()`
|
|
- On catch: revert inputValue to `String(value)`, call `onSaveError?.()`
|
|
- `setEditing(false)` remains in finally or after try/catch
|
|
|
|
Extend existing test file (InlineEditCell.test.tsx) with new test cases for the behaviors above. Use `vi.fn()` for the callback mocks. For error test, make onSave return `Promise.reject()`.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/components/InlineEditCell.test.tsx</automated>
|
|
</verify>
|
|
<done>InlineEditCell renders pencil icon in display mode, fires onSaveSuccess on successful save, fires onSaveError and reverts value on failed save. All tests pass.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Add loading spinners to Login, Register, and BudgetSetup submit buttons</name>
|
|
<files>frontend/src/pages/LoginPage.tsx, frontend/src/pages/RegisterPage.tsx, frontend/src/components/BudgetSetup.tsx</files>
|
|
<action>
|
|
In each file, import Spinner: `import { Spinner } from '@/components/ui/spinner'`
|
|
|
|
**LoginPage.tsx** (line ~81):
|
|
- The submit Button already has `disabled={loading}`.
|
|
- Add `className="w-full min-w-[120px]"` (keep existing w-full, add min-w).
|
|
- Replace the button text content with: `{loading ? <Spinner /> : t('auth.login')}`
|
|
|
|
**RegisterPage.tsx** (line ~89):
|
|
- Same pattern as LoginPage. Button already has `disabled={loading}`.
|
|
- Add `min-w-[120px]` to className.
|
|
- Replace text with: `{loading ? <Spinner /> : t('auth.register')}`
|
|
|
|
**BudgetSetup.tsx** (line ~92):
|
|
- Button already has `disabled={saving || !name || !startDate || !endDate}`.
|
|
- Add `className="min-w-[120px]"` to Button.
|
|
- Replace button text with: `{saving ? <Spinner /> : t('budget.create')}`
|
|
|
|
Note: CONTEXT.md mentions "Budget Edit" as a fourth form, but no Budget Edit component exists in the codebase (BudgetSetup is create-only). Spinner for Budget Edit is deferred until that form is created.
|
|
|
|
Do NOT modify any other logic in these files — only the Button content and className.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/LoginPage.test.tsx src/pages/RegisterPage.test.tsx src/components/BudgetSetup.test.tsx && bun run build</automated>
|
|
</verify>
|
|
<done>All three form submit buttons show Spinner component when loading/saving state is true, buttons are disabled during loading, min-width prevents layout shift. Build passes with zero errors.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `cd frontend && bun vitest run` — full test suite passes
|
|
- `cd frontend && bun run build` — production build succeeds with zero TypeScript errors
|
|
- InlineEditCell tests cover pencil icon, save success callback, save error + revert
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Pencil icon renders in InlineEditCell display mode (opacity-0, visible on hover via CSS)
|
|
- onSaveSuccess fires after successful save; onSaveError fires and reverts value on failure
|
|
- Login, Register, BudgetSetup buttons show Spinner when loading, disabled to prevent double-submit
|
|
- Budget Edit spinner is explicitly deferred (no form component exists yet)
|
|
- All existing tests continue to pass; new tests cover the added behaviors
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/03-interaction-quality-and-completeness/03-01-SUMMARY.md`
|
|
</output>
|