Files
SimpleFinanceDash/.planning/phases/07-quick-add-library/07-02-PLAN.md

14 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
07-quick-add-library 02 execute 2
07-01
frontend/src/lib/api.ts
frontend/src/hooks/useQuickAdd.ts
frontend/src/pages/QuickAddPage.tsx
frontend/src/components/QuickAddPicker.tsx
frontend/src/components/AppLayout.tsx
frontend/src/App.tsx
frontend/src/i18n/en.json
frontend/src/i18n/de.json
false
QADD-01
QADD-02
QADD-03
truths artifacts key_links
User can view, add, edit, and remove saved categories on the quick-add library page
User can browse their quick-add library when adding a one-off item to a budget
Selecting a quick-add item creates a one-off budget item with that name and icon
Quick-add library page is accessible from sidebar navigation
path provides contains
frontend/src/lib/api.ts QuickAddItem type and quickAdd API namespace quickAdd
path provides exports
frontend/src/hooks/useQuickAdd.ts useQuickAdd hook with CRUD operations
useQuickAdd
path provides min_lines
frontend/src/pages/QuickAddPage.tsx Management page for quick-add library 50
path provides min_lines
frontend/src/components/QuickAddPicker.tsx Picker component for selecting quick-add items when adding one-off budget items 30
path provides contains
frontend/src/components/AppLayout.tsx Sidebar nav item for quick-add library quick-add
path provides contains
frontend/src/App.tsx Route for /quick-add QuickAddPage
from to via pattern
frontend/src/hooks/useQuickAdd.ts frontend/src/lib/api.ts quickAdd namespace import import.*quickAdd.*api
from to via pattern
frontend/src/pages/QuickAddPage.tsx frontend/src/hooks/useQuickAdd.ts useQuickAdd hook call useQuickAdd()
from to via pattern
frontend/src/components/QuickAddPicker.tsx frontend/src/lib/api.ts quickAdd.list and budgetItems.create quickAdd|budgetItems
Build the frontend for the quick-add library: a management page for CRUD operations, a picker component for the budget item add flow, and all routing/navigation wiring.

Purpose: Users need a page to manage their saved one-off categories and a way to insert them as budget items with one click when viewing a budget.

Output: QuickAddPage, QuickAddPicker component, useQuickAdd hook, API client additions, routing and i18n

<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/07-quick-add-library/07-01-SUMMARY.md

@frontend/src/lib/api.ts @frontend/src/hooks/useTemplate.ts @frontend/src/pages/TemplatePage.tsx @frontend/src/pages/DashboardPage.tsx @frontend/src/components/AppLayout.tsx @frontend/src/App.tsx @frontend/src/i18n/en.json @frontend/src/i18n/de.json

QuickAddItem JSON shape (GET /api/quick-add returns array of these):

{
  "id": "uuid",
  "user_id": "uuid",
  "name": "string",
  "icon": "string",
  "sort_order": 0,
  "created_at": "timestamp",
  "updated_at": "timestamp"
}

Endpoints:

  • GET /api/quick-add — list all quick-add items
  • POST /api/quick-add — create {name, icon}
  • PUT /api/quick-add/{itemId} — update {name, icon, sort_order}
  • DELETE /api/quick-add/{itemId} — remove

From frontend/src/lib/api.ts:

export const budgetItems = {
  create: (budgetId: string, data: Partial<BudgetItem>) =>
    request<BudgetItem>(`/budgets/${budgetId}/items`, { method: 'POST', body: JSON.stringify(data) }),
}

From frontend/src/hooks/useTemplate.ts (hook pattern to follow):

export function useTemplate() {
  const [template, setTemplate] = useState<TemplateDetail | null>(null)
  const [categories, setCategories] = useState<Category[]>([])
  const [loading, setLoading] = useState(true)
  // ... CRUD functions that call API and refresh state
  return { template, categories, loading, addItem, removeItem, moveItem }
}

From frontend/src/components/AppLayout.tsx (nav items pattern):

const navItems = [
  { path: '/', label: t('nav.dashboard'), icon: LayoutDashboard },
  { path: '/categories', label: t('nav.categories'), icon: Tags },
  { path: '/template', label: t('nav.template'), icon: FileText },
  { path: '/settings', label: t('nav.settings'), icon: Settings },
]
Task 1: API client, hook, management page, routing, and i18n frontend/src/lib/api.ts, frontend/src/hooks/useQuickAdd.ts, frontend/src/pages/QuickAddPage.tsx, frontend/src/components/AppLayout.tsx, frontend/src/App.tsx, frontend/src/i18n/en.json, frontend/src/i18n/de.json 1. **API client** (`frontend/src/lib/api.ts`): Add QuickAddItem interface after the TemplateDetail interface: ```typescript export interface QuickAddItem { id: string user_id: string name: string icon: string sort_order: number created_at: string updated_at: string } ``` Add quickAdd namespace after the template namespace: ```typescript export const quickAdd = { list: () => request('/quick-add'), create: (data: { name: string; icon: string }) => request('/quick-add', { method: 'POST', body: JSON.stringify(data) }), update: (id: string, data: { name: string; icon: string; sort_order: number }) => request(`/quick-add/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string) => request(`/quick-add/${id}`, { method: 'DELETE' }), } ```
  1. Hook (frontend/src/hooks/useQuickAdd.ts): Create useQuickAdd() hook following the useTemplate pattern:

    • State: items: QuickAddItem[], loading: boolean
    • On mount: fetch via quickAdd.list(), set items (default to empty array)
    • addItem(name, icon): calls quickAdd.create(), refreshes list
    • updateItem(id, name, icon, sortOrder): calls quickAdd.update(), refreshes list
    • removeItem(id): calls quickAdd.delete(), refreshes list
    • Return: { items, loading, addItem, updateItem, removeItem }
  2. Management page (frontend/src/pages/QuickAddPage.tsx): Follow the TemplatePage pattern (pastel gradient header, table layout):

    • Header with gradient: bg-gradient-to-r from-amber-50 to-orange-50 (warm tone for one-offs, distinct from template's violet)
    • Title from i18n: t('quickAdd.title')
    • Add form row at top: text input for name, text input for icon (emoji or short string), Add button
    • Table with columns: Name, Icon, Actions (Edit pencil button, Delete trash button)
    • Edit mode: clicking edit turns row into inline inputs, Save/Cancel buttons
    • Delete: immediate delete (no confirmation needed for library items — they are presets, not budget data)
    • Empty state: use EmptyState component with Zap icon, heading "No saved items", subtext "Save your frequently-used one-off categories here for quick access."
  3. Sidebar nav (frontend/src/components/AppLayout.tsx): Add nav item after template: { path: '/quick-add', label: t('nav.quickAdd'), icon: Zap } Import Zap from lucide-react.

  4. Route (frontend/src/App.tsx): Add route: <Route path="/quick-add" element={<QuickAddPage />} /> Import QuickAddPage.

  5. i18n — add keys to both en.json and de.json: English (en.json):

    "nav": { ... "quickAdd": "Quick Add" },
    "quickAdd": {
      "title": "Quick-Add Library",
      "name": "Name",
      "icon": "Icon",
      "addItem": "Add Item",
      "noItems": "No saved items",
      "noItemsHint": "Save your frequently-used one-off categories here for quick access.",
      "editItem": "Edit",
      "deleteItem": "Remove",
      "save": "Save",
      "cancel": "Cancel"
    }
    

    German (de.json): translate equivalently:

    "nav": { ... "quickAdd": "Schnellzugriff" },
    "quickAdd": {
      "title": "Schnellzugriff-Bibliothek",
      "name": "Name",
      "icon": "Symbol",
      "addItem": "Hinzufuegen",
      "noItems": "Keine gespeicherten Eintraege",
      "noItemsHint": "Speichere hier haeufig genutzte Einmal-Kategorien fuer schnellen Zugriff.",
      "editItem": "Bearbeiten",
      "deleteItem": "Entfernen",
      "save": "Speichern",
      "cancel": "Abbrechen"
    }
    
cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build QuickAddPage renders with add form, table, and empty state. Sidebar shows "Quick Add" nav item. Route /quick-add works. All i18n keys present in both languages. Build succeeds. Task 2: Quick-add picker in dashboard for one-off budget items frontend/src/components/QuickAddPicker.tsx, frontend/src/pages/DashboardPage.tsx 1. **QuickAddPicker component** (`frontend/src/components/QuickAddPicker.tsx`): A dropdown/popover that lets users add a one-off item to the current budget from their quick-add library.

Props:

interface Props {
  budgetId: string
  onItemAdded: () => void  // callback to refresh budget after adding
}

Implementation:

  • On mount, fetch quick-add items via quickAdd.list() (direct API call, not hook — this is a lightweight picker, not a full CRUD page)
  • Render a Popover (from shadcn/ui) with trigger button: icon Zap + text "Quick Add" (from i18n quickAdd.addOneOff)
  • Inside popover: list of quick-add items, each as a clickable row showing icon + name
  • On click: create a budget item via budgetItems.create(budgetId, { category_id: null, item_tier: 'one_off', notes: item.name }) — Since quick-add items are independent presets (not linked to categories), the picker creates a one-off budget item. The backend CreateBudgetItem handler must accept this. However, looking at the existing BudgetItem model, category_id is required (UUID NOT NULL in DB). So instead:
    • The picker should first check if a category with the same name exists for the user. If not, create one via categories.create({ name: item.name, type: 'variable_expense', icon: item.icon }), then create the budget item with that category_id and item_tier: 'one_off'.
    • Alternatively (simpler): show the quick-add library items, and on click, find or create a matching category, then call budgetItems.create(budgetId, { category_id, item_tier: 'one_off' }).
  • After creation: call onItemAdded() to refresh, close popover
  • If quick-add library is empty: show a small message "No saved items" with a link to /quick-add
  • Add loading spinner on the clicked item while creating

Add i18n keys:

  • en.json: "quickAdd": { ... "addOneOff": "Quick Add", "emptyPicker": "No saved items", "goToLibrary": "Manage library" }
  • de.json: equivalent translations
  1. Wire into DashboardPage (frontend/src/pages/DashboardPage.tsx):
    • Import QuickAddPicker
    • Import categories as categoriesApi from api.ts
    • Add QuickAddPicker next to the budget selector (after the "Create Budget" button), only visible when a budget is selected:
      {current && (
        <QuickAddPicker
          budgetId={current.id}
          onItemAdded={() => selectBudget(current.id)}
        />
      )}
      
    • The onItemAdded callback re-fetches the current budget to show the new item cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build QuickAddPicker renders in dashboard toolbar. Clicking a quick-add item creates a one-off budget item (finding or creating the category first). Popover closes after add. Empty library shows link to management page. Build succeeds.
Task 3: Verify complete quick-add library feature Human verifies the complete quick-add library feature: 1. Management page at /quick-add with add/edit/remove for saved one-off categories 2. Quick-add picker button in dashboard toolbar that creates one-off budget items from saved library 3. Sidebar navigation includes Quick Add link Steps to verify: 1. Start the app: `docker compose up --build` 2. Navigate to /quick-add from sidebar — verify empty state shows 3. Add 2-3 items (e.g., "Pharmacy" with pill emoji, "Haircut" with scissors emoji) 4. Verify items appear in the table with edit/delete actions 5. Edit one item name — verify it updates 6. Delete one item — verify it disappears 7. Go to Dashboard, select a budget 8. Click "Quick Add" button in toolbar — verify popover shows your saved items 9. Click one item — verify a new one-off budget item appears in the budget 10. Verify the new item shows with item_tier badge "one-off" All quick-add library features work end-to-end: management page CRUD, picker creates one-off budget items, sidebar nav accessible - `bun run build` succeeds with no TypeScript errors - QuickAddPage renders management UI with CRUD operations - QuickAddPicker creates one-off budget items from library - Sidebar shows Quick Add navigation item - Route /quick-add loads the management page - All i18n keys present in en.json and de.json

<success_criteria>

  • User can add, edit, and remove items from the quick-add library page (QADD-03)
  • User can save a one-off category with icon to their library (QADD-01)
  • User can browse and select from library when adding one-off items to a budget (QADD-02)
  • Selected quick-add item creates a one-off budget item in the current budget </success_criteria>
After completion, create `.planning/phases/07-quick-add-library/07-02-SUMMARY.md`