Commit Graph

15 Commits

Author SHA1 Message Date
tyler 1381a7652d fix(acks): make 999 source_batch_id unique per file + surface PCN
Gainwell's MFT ships every 999 with the same ISA interchange
control number (`000000001`) and one 999 ack covers a whole
batch, not a single claim — so the AK2 set_control_number
(patient_control_number) is the same for the ~96 999s in a
batch. With the old synthetic-id formula (`999-{icn}`), all 385
daily acks collapsed onto a single row the operator couldn't
distinguish.

The new formula is `999-{pcn}-{filename_hash8}` (or
`999-{icn}-{filename_hash8}` for envelope-only 999s without an
AK2). The PCN gives the operator a human-readable handle to the
claim batch; the 8-char hash of the inbound filename guarantees
uniqueness within a batch. Fits in the VARCHAR(32) source_batch_id
column (max 22 chars).

Also surface `patient_control_number` in /api/acks list response
(extracted from raw_json's set_responses[0].set_control_number)
and in the Acks UI as the primary label, with the synthetic id
shown dimmed after a middle dot. The detail endpoint already
exposed raw_json for the full 999 parse tree.
2026-06-24 23:55:58 -06:00
Nora f4bafc1c94 feat: History tab on Upload page with one-click Re-export ZIP
Add a second tab to the Upload page that surfaces the persisted batch
archive and lets the user re-download any 837P batch as a ZIP without
re-parsing the original file.

- Backend: /api/batches now carries per-row claimIds (837P only).
  835 batches return an empty list, which the UI uses as the signal
  to hide the Re-export button on those rows. Avoids an extra
  round-trip to /api/batches/{id} per row.
- Frontend: BatchSummary.claimIds added to the list-endpoint type.
- Upload page: page body wrapped in Tabs.Root with a History trigger
  that mirrors ?tab= in the URL for deep-link round-trip. The
  History tab renders UploadHistory → HistoryTable → HistoryRow with
  a one-click Re-export ZIP button per 837P row. The button calls
  POST /api/batches/{id}/export-837 with the row's claim ids and
  downloads the ZIP via downloadBlob. Falls back to the in-memory
  parsedBatches store when the backend returns no rows so the tab
  stays useful in sample-data mode.
- Backend tests: claimIds present on 837P rows, empty on 835 rows.
- Frontend tests: 13 tests covering tab switching, URL deep-link,
  loading/error/empty states, the 837P-vs-835 button visibility
  split, the Re-export happy path, and the failure toast.
2026-06-24 13:57:12 -06:00
Nora fb913f0617 fix(ui): Dashboard greeting uses live operator; api.isConfigured proxies through
Two issues surfaced by going live against the dev backend:

1. Dashboard greeting was hardcoded 'Good morning, Jordan.' in
   src/pages/Dashboard.tsx. The sidebar already pulls from useAuth()
   but the dashboard had been missed. Replace with a time-of-day
   greeting ('morning' / 'afternoon' / 'evening') plus the live
   operator's username from useAuth(). Falls back to 'there' while
   /api/auth/me is in flight so we never flash 'undefined' at the
   operator.

2. api.isConfigured was returning false whenever VITE_API_BASE_URL
   was empty, which is the default in .env.example and the
   recommended setting for the Vite dev proxy / nginx. With the flag
   false, every hook (useClaims, useBatches, useActivity, ...)
   threw notConfiguredError() and silently fell back to the
   in-memory zustand store's hardcoded sample data — so 'files not
   serving' was actually the Dashboard rendering fixtures, not the
   real DB. With the flag now true, joinUrl('') produces relative
   URLs that the proxy intercepts and forwards to FastAPI on :8000.
   Set VITE_API_BASE_URL=disabled to opt out (useful for Storybook
   / offline UI work).

Also installs @radix-ui/react-tabs which was listed in package.json
but missing from node_modules — Vite was failing pre-transform on
tabs.tsx and refusing to compile downstream pages until deps were
re-installed via 'npm install'.
2026-06-22 17:05:27 -06:00
Nora cb87456575 feat(auth): wire AuthProvider + RequireAuth into app shell 2026-06-22 15:37:02 -06:00
Tyler 9bca4b608a feat(release): v0.2.0 — batch 837 export, ClaimCard, theme tokens
Backend:

- New POST /api/batches/{id}/export-837: regenerate X12 837 files
  for a list of claim_ids into a ZIP using HCPF file naming standards,
  with a unique interchange/group control number per export. Wire
  the clearhouse Loop 1000A (NM1*41 + PER) and per-payer receiver
  (NM1*40) blocks so the serializer no longer falls back to
  CYCLONE / RECEIVER placeholders.
- /api/parse-837 and /api/parse-835 now surface the server-side
  batch_id in both JSON and NDJSON response shapes so the frontend
  can hit batch-scoped endpoints without an extra listBatches
  round-trip.
- Filename helpers and the 837 serializer updated to match the new
  HCPF envelope; tests cover batch export, parse batch_id, and the
  serializer's control-number uniqueness guarantee.

Frontend:
- New shared components: ClaimCard, ClaimCard837, DominantKpiCard,
  EditorialNote, ExportBar, TickerTape, and a charts/ set
  (BarChart, HBarChart, SegmentedBar, AgingBars).
- New useBatchExport hook driving ExportBar's download flow against
  the new endpoint.
- ClaimDrawer, Lane, and Layout migrated from raw CSS-variable
  colors to Tailwind theme tokens (bg-card, text-foreground,
  border/60, etc.) for consistency with the rest of the instrument
  chrome; the active tab indicator gains a subtle accent glow.
- Upload, Inbox, Batches, BatchDiff, Reconciliation, and Acks pages
  reworked to compose the new shared components and consume the new
  batch-scoped API surface (notably ExportBar wired into Batches).

Tooling / Docs:
- Add audit-uiux.mjs and a docs/goodclaim.x12 sample fixture.
- Update ClaimDrawer testids and add coverage for the new
  components and the useBatchExport hook.

Rolls up into the v0.2.0 release tag.
2026-06-22 11:01:58 -06:00
Tyler 0678e25de7 feat(drill): ProviderDrawer with Overview tab + DrillDrawerHeader shell 2026-06-21 16:41:15 -06:00
Tyler 50dc0b2fb3 feat(drill): PayerPeekContent + usePayerSummary + api.getPayerSummary 2026-06-21 14:28:49 -06:00
Tyler 1764df0cd5 feat(sp8): Claim drawer Download 837 button
Three pieces:

- src/lib/download.ts: generic downloadTextFile(filename, mime, text)
  helper. Mirrors csv.ts:downloadCsv but takes an explicit MIME type and
  drops the BOM prepend (which would corrupt the ISA segment).

- src/lib/api.ts: serializeClaim837(id) → {text, filename}. Fetches
  GET /api/claims/{id}/serialize-837, pulls the suggested filename from
  Content-Disposition (falls back to claim-{id}.x12 if the header is
  missing). Throws ApiError on non-2xx so callers can branch on .status.

- ClaimDrawerHeader: Download icon button between the amount and the
  close button. Click → api.serializeClaim837 → downloadTextFile.
  Disabled + 'Downloading 837 file' aria-label while the fetch is in
  flight so the click feels responsive. Optional onError prop surfaces
  fetch failures; defaults to a no-op so existing callers stay clean.

Tests: 3 download.test.ts, 3 api.test.ts, 2 header.test.ts (happy
path + error path). Frontend: 350 passing (+8 from 342).
2026-06-20 20:44:39 -06:00
Tyler 7b394fff1a feat(batch-diff): side-by-side claim diff between two batches 2026-06-20 17:17:09 -06:00
Tyler 44e1c4616d feat(frontend): ClaimDetail type + api.getClaimDetail 2026-06-20 10:01:40 -06:00
Tyler fb2a98fc7a feat(parsers+api+ui+db): 999 ACK transaction set end-to-end (SP3 P3) 2026-06-20 08:03:37 -06:00
Tyler 2a853857b1 feat(parsers+api+ui): expose CARC-labeled CAS adjustments (SP3 P2) 2026-06-20 07:44:41 -06:00
Tyler 23ac7f6fda feat(frontend): add listUnmatched, matchRemit, unmatchClaim to api 2026-06-19 23:47:34 -06:00
Tyler 3ddf962da2 feat(frontend): add 6 GET methods (batches, batch, claims, remits, providers, activity) + tests 2026-06-19 19:41:07 -06:00
Tyler 3d3bdfb07c feat(frontend): wire Vite app to FastAPI parser with NDJSON streaming + Upload page 2026-06-19 17:31:59 -06:00