fix(frontend): wire up the Scan a receipt capture flow #74
No reviewers
Labels
No labels
area:backend
area:frontend
area:infra
area:ocr
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
phase:M1
phase:M2
phase:M3
phase:M4
phase:M5
phase:M6
phase:M7
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
TJC/bill-splitter!74
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/landing-scan-receipt"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
accept="image/*" capture="environment"), photo preview (Use photo/Retake), and multipart upload.preprocess()(lib/image.ts): downscale to 2000px longest edge, re-encode JPEG 0.85, strip EXIF/HEIC.createSession()+CreateSessionResponseschema; upload runs over XHR for a determinate progress bar.storeIdentityand navigate to/s/:id; 429 shows the rate-limit copy, other errors stay on the preview.Test plan
pnpm test(44 pass, incl. new Landing preview/upload/error cases)pnpm typecheck,pnpm lint,pnpm formatCloses #73
Code review — fixes applied in
b505f89Reviewed the capture flow (8 finder angles + verify). Fixed the following in this PR:
Correctness
blob:URL was only revoked on successful upload or Retake, so navigating away mid-preview/upload leaked it for the page's lifetime. The URL is now derived from the chosen file and revoked on change/unmount.changeevent and left the screen stuck. It now resets after each pick.createImageBitmapran withoutimageOrientation: 'from-image'; re-encoding then stripped the orientation tag, so a portrait photo could arrive rotated. Orientation is now baked into the pixels before re-encode.preprocess()andcreateSession()shared onecatch, so a bad/undecodable image (e.g. HEIC on a browser with no HEIC decoder) told the user to "check your connection." Decode failures now get their own message.xhr.responseparse-failure fallback built anApiErrorwith a 2xx status that could never be reached (a Zod parse failure is always anError). Replaced with a clearinvalid-responseerror.Robustness / cleanup
createSessionhand-rolled the sametype ?? 'unknown'mapping astoApiError; extracted a sharedproblemToApiErrorso the fetch and XHR paths can't drift.pnpm test(45 pass, +1 decode-failure case),typecheck,lint,formatall green.Not fixed here (out of scope for this frontend PR)
POST /api/v1/sessionsreturns429 rate-limitedboth for IP rate-limiting and OCR-queue-full backpressure (SessionsController.cs:82). The client can't tell them apart, so a busy-queue rejection shows "Too many sessions from this network." Distinguishing them needs a separate backend error code (+ docs/04 update).Landing.tsxandJoinByCode.tsx; a sharedis429helper would be nice but touches an unrelated route.