--- 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" --- 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. @/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md @/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md @.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 From frontend/src/components/InlineEditCell.tsx: ```typescript interface InlineEditCellProps { value: number currency: string onSave: (value: number) => Promise 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 ``` Task 1: Enhance InlineEditCell with pencil icon, save/error callbacks, and try/catch frontend/src/components/InlineEditCell.tsx, frontend/src/components/InlineEditCell.test.tsx - 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) 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: `` - 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()`. cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/components/InlineEditCell.test.tsx InlineEditCell renders pencil icon in display mode, fires onSaveSuccess on successful save, fires onSaveError and reverts value on failed save. All tests pass. Task 2: Add loading spinners to Login, Register, and BudgetSetup submit buttons frontend/src/pages/LoginPage.tsx, frontend/src/pages/RegisterPage.tsx, frontend/src/components/BudgetSetup.tsx 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 ? : 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 ? : 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 ? : 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. 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 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. - `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 - 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 After completion, create `.planning/phases/03-interaction-quality-and-completeness/03-01-SUMMARY.md`