Files
integreat/docs/superpowers/specs/2026-05-18-inline-account-editing-design.md
2026-05-18 15:38:07 -07:00

6.8 KiB

Inline Account Editing in Sales Summary Wizard

Problem

The current edit wizard for sales summaries renders every item in a flat data-grid with a full typeahead component per row for account assignment. This requires heavy scrolling and makes it hard to see the debit/credit structure at a glance.

Solution

Redesign the wizard's MainStep to mirror the embedded grid's two-column layout (debits / credits), and replace the always-visible typeahead with a click-to-swap inline editing pattern powered by HTMX.

Current Flow

  1. Click pencil icon on a grid row → opens full modal wizard
  2. Wizard renders a data-grid where every row has: category (hidden or text input), account (typeahead), debit, credit
  3. Every row initializes a typeahead component, even if the user only needs to edit one account
  4. Heavy scrolling due to tall rows

New Flow

  1. Click pencil icon on a grid row → opens modal wizard showing two columns (debits / credits) matching the embedded grid layout
  2. Each item's account cell renders in display mode: account name text + hidden input holding the account ID + pencil icon. If no account is assigned, shows a red "Missing acct" pill + pencil icon.
  3. Click pencil on an account cell → hx-get to ::route/edit-item-account → server returns edit mode (typeahead + confirm/cancel buttons), replacing just that cell via hx-swap "innerHTML"
  4. User selects an account in the typeahead → clicks confirm → hx-put to ::route/save-item-account → server returns display mode (updated account name text + updated hidden input + pencil icon)
  5. Click cancel → hx-get to ::route/cancel-item-account → server returns original display mode
  6. When the user submits the entire wizard form, all hidden inputs (including updated account IDs) are collected by the existing multi-form-state decode and saved in a single DB transaction

Key Constraint

HTMX routes only manage interactivity (swapping cells). No DB writes happen until the wizard form is submitted via the existing submit handler.

New Routes

Route Key Method Purpose
::route/edit-item-account GET Returns typeahead + confirm/cancel for one account cell
::route/save-item-account PUT Returns display mode with updated hidden input value
::route/cancel-item-account GET Returns display mode with original hidden input value

Route Parameters

All three routes receive:

  • item-index — the index of the sales-summary/item in the vector (to construct the correct field name prefix)
  • client-id — for the typeahead search URL
  • The form-cursor field name prefix is derived from item-index so the returned hidden input has the correct name attribute (e.g. step-params[sales-summary/items][2][ledger-mapped/account])

Additionally:

  • edit-item-account and cancel-item-account receive the current-account-id as a query param so cancel can restore the original value
  • save-item-account receives the selected account ID from the typeahead's form submission in the request body

Wizard MainStep Changes

Layout

Replace the current flat data-grid with a two-column layout mirroring the embedded grid:

+-------------------------------------------+
| Debits              | Credits             |
|-------------------------------------------|
| Category  Acct  Amt | Category  Acct  Amt |
| ...                 | ...                 |
|-------------------------------------------|
| Total: $X,XXX.XX   | Total: $X,XXX.XX    |
| Delta: $XX.XX       | Delta: $XX.XX       |
+-------------------------------------------+
| [+ New Summary Item]                       |
+-------------------------------------------+

Item Rendering (Display Mode)

For each item (non-manual):

  • Category: text label + hidden input
  • Account: account name text (or "Missing acct" pill) + hidden input with account ID + pencil icon with hx-get
  • Amount: formatted dollar amount (debit or credit column)

Item Rendering (Edit Mode — account cell only)

When the pencil is clicked, only the account cell swaps to:

  • Typeahead component (same account-typeahead* as current)
  • Confirm button (small check icon) with hx-put
  • Cancel button (small X icon) with hx-get

Manual Items

Same as current: category text input, account typeahead, debit/credit money inputs, delete button. The "New Summary Item" button remains. Manual items are always in "edit mode" since they have editable fields beyond just account.

Hidden Inputs

Every item row must include hidden inputs for:

  • db/id
  • sales-summary-item/category (for non-manual items)
  • sales-summary-item/manual? (for manual items)
  • ledger-mapped/account — this is the key one that gets updated by the inline edit flow

When the typeahead swaps in (edit mode), the old hidden input for ledger-mapped/account is replaced by the typeahead's own hidden input. On confirm, the server returns the updated hidden input. On cancel, the server returns the original hidden input.

Total / Unbalanced Rows

Same as current: summary-total-row* and unbalanced-row* with live recalculation via hx-put to ::route/expense-account-total.

Handler Implementation

edit-item-account handler

  1. Parse query params: item index, client-id, current field name prefix
  2. Render the typeahead + confirm/cancel buttons
  3. The typeahead uses the same account-typeahead* pattern
  4. Confirm button: hx-put to ::route/save-item-account, hx-target "closest td", hx-swap "innerHTML"
  5. Cancel button: hx-get to ::route/cancel-item-account, hx-target "closest td", hx-swap "innerHTML"

save-item-account handler

  1. Parse form body: selected account ID, item index, client-id, field name prefix
  2. Resolve account name from DB using d-accounts/clientize
  3. Return display mode HTML: account name text + hidden input (with new account ID) + pencil icon

cancel-item-account handler

  1. Parse query params: item index, client-id, current field name prefix, original account ID
  2. Resolve account name from DB (if account ID exists)
  3. Return display mode HTML: account name text (or "Missing acct" pill) + hidden input (with original account ID) + pencil icon

Route Definitions

Add to routes.cljc:

"/edit/item-account" ::edit-item-account
"/edit/save-item-account" ::save-item-account
"/edit/cancel-item-account" ::cancel-item-account

Files Changed

File Change
src/cljc/auto_ap/routes/pos/sales_summaries.cljc Add 3 new route keys
src/clj/auto_ap/ssr/pos/sales_summaries.clj Rewrite MainStep render-step, add 3 handlers, add helper fns for account display/edit cells

Out of Scope

  • Changes to the embedded grid table (already redesigned)
  • Changes to how the wizard submit handler works
  • Adding the missing ::route/expense-account-total route (pre-existing bug, separate fix)