Skip to content

feat(web): findable registers, exact money and a command palette (2/4) - #10

Merged
daniel-tsx merged 1 commit into
feat/web-ui-shellfrom
feat/web-ui-tables
Oct 24, 2026
Merged

daniel-tsx merged 1 commit into
feat/web-ui-shellfrom
feat/web-ui-tables

Conversation

@daniel-tsx

@daniel-tsx daniel-tsx commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Stacked PR 2 of 4 (#9 → #10 → #11 → #12), on top of #9 (feat/web-ui-shell). After #9 is squash-merged, rebase onto main (git rebase --onto origin/main 0387eb3) so the diff shows only this slice.

What and why

Slice 2: findable registers, exact money and a command palette. Operators had no search, filter, sort or pagination, and IDs were truncated with no full value or copy. formatMoney used Number(value) / 100 with only three zero-decimal currencies, so CLP and ISK displayed 100× too small and BHD and KWD 10× wrong. No API, schema or business-logic change.

  • lib/format.ts: minor units → decimal with string arithmetic and BigInt, using Stripe's zero-, two- and three-decimal exponents. Money reads USD 1,234.56 outside tables; every timestamp reads 2026-10-24 07:15:36 UTC.
  • Every register gets search, facet chips with counts, a currency filter, sortable headers (aria-sort) and a summary saying what the filters cover. State lives in the URL via next/form. Payments page through the API; the ledger currency filter uses the API's currency parameter.
  • IdCell (short ID, full value in the title and for screen readers, copy button, payment links), Amount with raw minor units on hover, and a Ccy column.
  • Command palette (/, Ctrl/⌘+K): open a payment by UUID, search any register, or jump to a page. Native <dialog> and the combobox pattern.
  • The ledger groups lines by journal with debit/credit totals and flags the journal the 500-line API limit may cut short.
  • List pages show the offline state instead of the 500 page when the API is unreachable.

Screenshots: .tmp/web-ui-revamp/screens/slice2 (local, not attached).

Review guide

  • Read carefully:
    • apps/web/lib/format.ts: money must never change value.
    • apps/web/lib/list.ts: money sorts by currency, then exact minor units.
    • apps/web/app/ledger/page.tsx: journal grouping and the API-limit flag.
    • apps/web/components/command-palette.tsx: the only new interactive client component.
  • Skim: the seven list pages, which follow one pattern, and the globals.css additions.
  • Least confident about: filters apply to the rows each API returns (100 payments per page; the latest 200, 300 or 500 elsewhere). Each summary says so; real server-side search is an API follow-up.
  • Tests removed, weakened or skipped: none.

Task size

T1 (apps/web only). Money formatting is display-only; no ledger, rounding or settlement logic changed.

Checks

Result Command Scope / notes
PASS pnpm --filter @fintech-lab/web lint web
PASS pnpm --filter @fintech-lab/web build web; list pages 107 kB first load (was 106 kB)
PASS pnpm --filter @fintech-lab/web typecheck web
PASS pnpm --filter @fintech-lab/web test 12/12: formatting (including values above 2^53), timestamps, URL building, money sort, status
PASS git diff --check whitespace
PASS Browser status chip, search + currency, amount sort, no-match state; palette by keyboard (Ctrl+K → UUID → Enter → trace; arrows; Esc)
NOT RUN pnpm lint/test/build/typecheck (repo-wide) at this head run at the top of the stack (#12), all PASS
NOT RUN Hosted CI pending on this PR

Unverified boundaries

Browser checks were manual. Copy buttons were checked for focus and labels, not clipboard contents. With only 8 local payments, pagination past one page was checked by logic and URL, not with more than 100 rows.

Review

T1 self-review (ponytail-review). Findings and disposition:

  • An out-of-range ?page= said "No payments yet" while payments existed → fixed, with a "Back to the newest" link.
  • A hardcoded currency list slipped into the ledger → removed.
  • BigInt literals aren't allowed at the ES2017 target → replaced with BigInt() calls.

Docs and temporary files

docs/ui-signature.md: new "Money and time" and "Finding records" sections. Temporary files as listed in #9.

🤖 Generated with Claude Code

Slice 2 of the dashboard revamp (T1, apps/web only; no API or business logic change).

- lib/format.ts: exact minor-unit formatting with string arithmetic and
  BigInt (Stripe exponents: zero-, two- and three-decimal currencies),
  "USD 1,234.56" outside tables, and one UTC timestamp format with seconds.
  Replaces Number()/100, which misrendered CLP/BHD-style currencies.
- Every register gets search, facet chips with counts, a currency filter
  where records have one, sortable headers (aria-sort) and a summary that
  says which rows the filters cover. State lives in the URL via next/form.
  Payments page through the API; the ledger currency filter uses the API.
- IdCell: short ID, full value in title and for screen readers, copy button,
  payment links. Tables gain a Ccy column, bare exact amounts and a scroll
  shadow on narrow screens.
- Command palette (/, Ctrl/Cmd+K): open a payment by UUID, search any
  register, or jump to a page; native <dialog> and combobox pattern.
- Ledger groups lines by journal with debit/credit totals and flags the
  journal the 500-line API limit may cut short.
- List pages show the offline state instead of the 500 page when the API is
  unreachable.
- Unit tests for formatting and list helpers; ui-signature.md documents
  money, time and finding-record conventions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant