Skip to content

NWP-101: add export options - #166

Open
saumyasingh34335 wants to merge 1 commit into
JJFromTenex:mainfrom
saumyasingh34335:NWP-101-export-options
Open

NWP-101: add export options#166
saumyasingh34335 wants to merge 1 commit into
JJFromTenex:mainfrom
saumyasingh34335:NWP-101-export-options

Conversation

@saumyasingh34335

Copy link
Copy Markdown

Ticket

Closes NWP-101

What changed

Ops can now choose which columns are exported and whether the export covers the current filter or all payments, instead of always getting a fixed 10-column file for the current filter. GET /api/payments/export now reads columns (comma-separated) and scope (current | all) from the query string; both are validated server-side against the existing EXPORT_COLUMNS allowlist (parseExportColumns in src/lib/csv.ts) rather than trusted directly. scope=all reuses the same query builder (filterPayments/sortPayments) with the filtering fields cleared, so there is still one filtering path, not a second one. The filename now reflects scope and status, e.g. payments-disputed-2026-08-13.csv or payments-all-2026-08-13.csv. The Export button on /payments now opens an options dialog (src/app/payments/export-dialog.tsx) with column checkboxes (last4 unchecked by default), a current-filter/all-payments scope choice showing the row count for each (read from the existing GET /api/payments total), and a Download control that's disabled when no columns are selected.

How I verified it

  • npm test passes
  • New behavior is covered by a test
  • Checked it in the browser

npm test:

 Test Files  3 passed (3)
      Tests  36 passed (36)

npx tsc --noEmit and npm run lint both clean.

Against the running dev server, curl:

  • columns=id,amount&scope=all → 200, content-disposition: attachment; filename="payments-all-2026-09-10.csv"
  • status=disputed&columns=id,last4 → 200, content-disposition: attachment; filename="payments-disputed-2026-09-10.csv"
  • columns= (empty selection) → 400 with {"error":"Select at least one column to export."}

I did not personally click through the dialog in a browser — I have no browser-automation tool in this environment, so I'm leaving that box unchecked rather than claiming it. I opened http://localhost:3000/payments for the user to look at, but haven't gotten confirmation back on how the dialog renders or behaves interactively.

Acceptance criteria

  • Ops can choose which columns are included. Card last-four is off by default.
  • Ops can choose scope: current filter or all payments. Current filter is the default, and the row count is visible before download.
  • The filename reflects the scope and the date.
  • Amounts stay in minor units internally and are formatted once on the way out (unchanged from before — toCsv already called formatMoney at the edge), with currency in its own column.
  • Deselecting every column disables Download rather than producing an empty file (both in the dialog and, defensively, server-side with a 400).

Bugs fixed along the way

None found outside the ticket's scope.

Notes for the reviewer

  • I did not add a dedicated row-count endpoint; the dialog fetches GET /api/payments (once for the current filter, once with no filters) and reads the existing total field, per the ticket's instruction to reuse the query builder rather than add a new path.
  • The scope-vs-status filename label is my own design choice, not spelled out in the ticket beyond the one example: scope=allall; scope=current with a specific status → that status; scope=current with status=all (or another filter like merchant/search active) → filtered.
  • The options UI reuses the existing Drawer (Radix Dialog) primitive already in the codebase rather than introducing a new modal component.
  • The "Checked it in the browser" box above is intentionally left unchecked — see "How I verified it."

🤖 Generated with Claude Code

Ops can now choose export columns and scope from the payments Export
button instead of always getting every column for the current filter.

Co-Authored-By: Claude Sonnet 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.

2 participants