Skip to content

Customer feature requests: admin presence, invoice filters, lots edit, paddle tally#9

Open
curiousdaniel wants to merge 2 commits into
mainfrom
feat/customer-feature-requests
Open

Customer feature requests: admin presence, invoice filters, lots edit, paddle tally#9
curiousdaniel wants to merge 2 commits into
mainfrom
feat/customer-feature-requests

Conversation

@curiousdaniel
Copy link
Copy Markdown
Collaborator

Follow-up to #8. With the bug fixes deployed, this PR ships the feature requests from the customer feedback.

Stacking note: This branch is based on fix/clerking-and-invoice-glitches (#8) so its diff also includes those bug-fix commits until #8 merges. Recommended to merge #8 first; this branch will rebase cleanly afterwards.

Summary

  • Lots tab — full sale visibility, edit & void from any historical lot. Search by lot, paddle, buyer, consignor, description, or notes; sort by lot/qty/status/paddle/hammer/consignor; expandable rows show every detail and host Edit / Void buttons that reuse SaleCorrectionModal and a new shared voidSale helper extracted from RecentSales.
  • Invoices — sortable + filterable table. Click any column header to sort (invoice #, name, paddle, hammer/BP/tax/total, status). New search box filters by invoice #, buyer name, paddle, and total. Status select and result count moved into the same filter bar.
  • PaddleTally — live winning-bids panel. A new component shows running totals (hammer + projected buyer's premium + tax) for a paddle plus the list of every won lot, before invoices are generated. Surfaced in the Clerking sidebar and as a collapsible widget on the Invoices page so cashiers can confirm what's on a paddle pre-invoice. Backed by pure buildPaddleTally with unit tests.
  • New-invoice-after-paid surfacing. upsertInvoiceForBidder now reports supplementalAfterPaid when it opens a new invoice for a bidder whose prior invoices are all paid. SaleForm shows a follow-up toast so the clerk knows a fresh invoice was opened.
  • Admin dashboard — live presence + 24h activity + extended metrics. New heartbeat tables (user_activity_pings + user_activity_summary), a heartbeat API (/api/admin/heartbeat), a HeartbeatProvider that pings every 60 s while the tab is visible, summary cards (Online now, Active in last 24h, totals), green-dot per-row presence, and new columns for consignors, invoices, and rolled-up invoice totals ($). All migration-aware: reads and writes degrade gracefully if the new tables aren't yet present.
  • Tests: +15 unit tests, 177/177 passing. next build, tsc --noEmit, and next lint all clean (only the two pre-existing exhaustive-deps warnings in InvoiceDetail remain).

Required deploy step

Run the new migration once before this ships to production:

```
psql "$DATABASE_URL" -f db/migrate_user_activity.sql
```

Until the migration runs, the heartbeat endpoint and admin reads silently no-op, so you can safely deploy in either order.

Test plan

  • npm run test (vitest) — should report 26 files / 177 tests passing.
  • npm run build (next build) — should succeed.
  • In dev:
    • Lots tab: search by paddle / buyer name returns the expected lot; expand a sold lot and Void → lot becomes unsold and disappears from invoices.
    • Invoices tab: clicking each column header toggles asc/desc; search by paddle, buyer, total all narrow correctly; PaddleTally widget shows projected total for an unallocated paddle.
    • Clerking: PaddleTally sidebar updates live as you record sales; recording a sale for a paddle whose prior invoice is paid shows the new "New invoice opened" toast.
    • Admin: a second tab signed in as another user shows up with a green dot; let it sit > 90 s and the dot turns grey.

Made with Cursor

Daniel West and others added 2 commits May 20, 2026 21:46
Submit-lock guards prevent double-submits across bidder add, sale form,
and payment modal. Bidder adds immediately flush a single-event cloud
snapshot so background pulls can't wipe local-only bidders.

Sticky consignor: stop clearing consignor between lots in clerking;
add an opt-out preference (default on). Lot autofill still overrides
when a different consignor is loaded.

Invoices stop scroll-jumping: list sorts by invoice number instead of
generatedAt; recalc skips the row update and generatedAt bump when
nothing actually changed; allocate + recalc now run in one Dexie
transaction so totals update once instead of flickering.

Paid invoices stop reverting to unpaid: PaymentModal bumps generatedAt
and uses enqueueInvoicePatch instead of full invoice.put. applyRemoteOp
and snapshotMerge preserve local paid status when an incoming row says
unpaid.

Auto-allocate sale to the bidder's open invoice on every successful
clerk write, so items can no longer go missing from invoices. Inside-tx
duplicate-sale guard catches multi-device races. One-shot repair pass
detaches legacy duplicate sale rows attached to the same lot on one
invoice (gated by a localStorage flag). InvoiceDetail does display-side
dedupe by lotId as a belt-and-suspenders.

Tests cover paid-status protection, no-op recalc, sticky consignor
pref, and the duplicate-line repair pass. All 162 tests pass; tsc and
next lint clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bug fixes for the recent auction shipped in #8; this round adds the
features customers asked for after using ClerkPad live:

Lots tab — full sale visibility from any historical lot
- Search by lot #, description, paddle, buyer name, consignor, or notes.
- Sortable columns and a status filter.
- Expandable rows show buyer, hammer, paddle, clerk, qty, consignor,
  recorded-at, and invoice allocation state.
- Edit and Void actions on every row (not just the most recent 20)
  via the existing SaleCorrectionModal and a new shared `voidSale`
  helper extracted from RecentSales.

Invoices — sortable, searchable table
- Click any column header to sort (invoice #, name, paddle, hammer,
  buyer's premium, tax, total, status).
- Inline search across invoice #, buyer name, paddle, and total so
  cashiers can find an invoice without scrolling.
- Status filter and result count moved into the same filter bar.

PaddleTally — live winning-bids panel
- New PaddleTally component shows running totals (hammer + projected BP
  + tax) and a list of every won lot for a paddle, before the invoice
  is generated.
- Added to the Clerking sidebar and as a collapsible widget on the
  Invoices page so the cashier can confirm what's on a paddle pre-
  invoice. Backed by `buildPaddleTally` in `lib/services/paddleTally.ts`
  with unit tests covering allocated/unallocated/mixed cases.

New invoice after paid bidder bids again — UX surface
- `upsertInvoiceForBidder` now reports `supplementalAfterPaid` when it
  opens a fresh invoice for a bidder whose prior invoices are all paid.
- SaleForm shows a follow-up toast so the clerk knows a new invoice was
  opened (the auto-allocate logic already created the invoice; this
  just makes it visible).

Admin dashboard — live presence + 24h activity + extended metrics
- Heartbeat-based activity tracking via two new tables
  (`user_activity_pings` ledger + `user_activity_summary` rolling
  counter) added in `db/migrate_user_activity.sql` and reflected in
  `db/schema.sql`. Both reads and writes degrade gracefully if the
  migration hasn't been run yet.
- New `HeartbeatProvider` pings `/api/admin/heartbeat` every 60s while
  the tab is visible; admin SQL joins the summary so each row shows a
  green dot when seen within 90s and the rolling 24h ping count.
- Summary cards above the user table: Online now, Active in last 24h,
  total synced events, total sales, total invoice $.
- Per-row columns now include consignor count, invoice count, and a
  rolled-up invoice total ($) computed from cloud snapshot payloads.
- `isOnlineNow` extracted as a pure helper with unit tests.

Tests
- 5 new tests for invoice column comparator.
- 4 new tests for `buildPaddleTally`.
- 6 new tests for `isOnlineNow` boundary behavior.
- 26 test files, 177 tests passing. `next build`, `tsc --noEmit`, and
  `next lint` all pass (only the two pre-existing exhaustive-deps
  warnings in InvoiceDetail remain).

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerkpad Ready Ready Preview, Comment May 21, 2026 5:07am

Request Review

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