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

146 lines
6.8 KiB
Markdown

# 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`:
```clojure
"/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)