refactor(ssr): Phase 4 — full Selmer migration of POS Sales Summary; remove the wizard; fix add-item + totals
Migrates the POS Sales Summary edit modal off the wizard to a plain Selmer form, building on the parity gate committed earlier. Largest migration so far and the first with no prior test coverage. What changed - Wizard removed: deleted MainStep/EditWizard records, MultiStepFormState, the step-params[...] prefix, the EDN snapshot round-trip, and all mm/* middleware. Replaced with a plain handler + flat wrap-decode/wrap-derive-state. The 51 fc/ cursor refs are de-cursored into explicit data + Selmer templates. - db/id-keyed item merge: wrap-derive-state overlays posted items onto the persisted items by :db/id, so read-only fields the form doesn't post (ledger-side, amount) survive a re-render and the debit/credit split + totals stay correct. New manual rows (temp db/id) ride through as-is. - Inline click-to-edit account cell preserved as three small targeted .account-cell-swap routes (edit/save/cancel-item-account), ported to Selmer with the new field-name scheme. - 100% Selmer modal render path (the remaining Hiccup / hx-swap-oob / "hx-" strings are all grid-page code — grid render lambdas, the filters form, and the submit response-header map — not the modal). - Routes: dropped edit-wizard-navigate + new-summary-item; added form-changed. Fixes (two pre-existing bugs, per request) - "New Summary Item" add button (was throwing `newRowIndex is not defined` and targeting a non-existent `.new-row`) is now a whole-form-swap op=new-item that adds an editable manual row (category + account typeahead + debit/credit money inputs + remove). - The dead totals/balance display (malformed Hiccup that discarded its labels) is replaced by a proper #summary-totals block showing running Total + Balanced/Unbalanced, refreshed via a Rule-4 targeted swap on manual amount edits. Scorecard delta (pos/sales_summaries.clj): LOC 790->732, mm coupling 20->0, wizard records 4->0, fc/ cursor 51->0, step-params 27->0 (2 comments), modal routes 8->6. (hx-swap-oob 1 and mixed-hx live in the grid page, not the modal.) Verification: sales-summary spec 7/7 (incl. the two fixes); full Playwright suite 46/46; cljfmt clean. Skill fed: scorecard row + narrative; gotchas (parity-gate- first, characterize-then-fix, keyup-trigger tests); cookbook (inline click-to-edit cell, db/id-keyed item merge). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -165,6 +165,28 @@ the interop bridge; dynamic HTMX/Alpine attrs go through `sc/attrs->str` →
|
||||
|---------|---------|-------|
|
||||
| `sc/hidden` / `sc/text-input` / `sc/money-input` | `hidden`/`text-input`/`money-input`.html | leaf inputs; class via `inputs/default-input-classes` + `use-size` |
|
||||
| `sc/select` (Phase 3) | `select.html` | generic `<select>`; `options [[value label] …]`, `:value` (string/keyword) marks selected, extra hx-/x- attrs ride through. `location-select.html` generalized — reach for this before `com/select`. Added for the bulk-code status field. |
|
||||
|
||||
## inline click-to-edit cell (Phase 4) — targeted `.account-cell` swap, not a whole-form op
|
||||
|
||||
A "display value + pencil → edit-in-place → check/cancel" cell. Three tiny **stateless** routes,
|
||||
each swapping just the cell (`hx-target="closest .account-cell"`, `outerHTML`): a `display` cell
|
||||
(value + pencil `hx-get edit`), an `edit` cell (typeahead + check `hx-put save` / cancel
|
||||
`hx-get cancel`). State rides in the request (item index + current value via `hx-vals`), so no
|
||||
server-side "which cell is editing" flag is needed. Keep it as its own routes — it is a distinct
|
||||
feature, *not* folded into the whole-form `form-changed` dispatcher (that would lose the targeted
|
||||
swap and re-render the whole modal on every pencil click). The cells are assembled with `sc/*` +
|
||||
`sel/raw` strings (like `edit.clj`'s `footer*`); SVGs ride in as `svg/*` Hiccup via the
|
||||
`sc/a-icon-button` body (no `[:svg]` literal lands in the modal file).
|
||||
|
||||
## db/id-keyed item merge (Phase 4) — for rows the form posts only partially
|
||||
|
||||
When a row renders some fields read-only (so they aren't posted) but the entity holds them
|
||||
(sales-summary auto items post only db/id/category/account — not ledger-side/amount), the flat
|
||||
`wrap-derive-state` must **overlay posted items onto the persisted items by `:db/id`** so the
|
||||
unposted fields survive a re-render: `(merge (by-id (:db/id posted)) posted)`. New rows (temp
|
||||
`:db/id` not in the entity) ride through as-is. This is the row-level analog of edit's
|
||||
"entity-only fields always from the entity"; without it, a re-render drops ledger-side/amount and
|
||||
the debit/credit split + totals break.
|
||||
| `sc/validated-field` | `validated-field.html` | label + body + always-present error `<p>`; pass-through attrs land on the wrapping div (the per-row location cell hangs its swap wiring here) |
|
||||
| `sc/button` / `sc/a-button` / `sc/a-icon-button` | `button`/`a-button`/`a-icon-button`.html | spinner via `{% include "spinner.html" %}`; class via `btn/bg-colors` |
|
||||
| `sc/badge` / `sc/link` | `badge`/`link`.html | |
|
||||
|
||||
Reference in New Issue
Block a user