Skip to content
Ritesh FirodiyaGet in touch

Work / Aakalan / Wiki / Surfaces

expense-receipt

Surfacecanonicalverified 2026-09-23

SURFACE.MOBILE.EXPENSE.RECEIPT

Summary

An expense with a bill photographed, including the state where the photo has not uploaded yet.

Raw wireframe

  • .context/designs/mobile/expense/receipt.html

Why it is drawn this way

The pending-upload line is the state that makes the offline promise honest. The expense is already saved and the photo is still on the phone; saying so beats a spinner, and it beats pretending it is done — which is what writing receiptPath up front did, showing every other member a path to an image that was not there. See local-first-ledger.

Tapping opens it full-screen. A bill photographed at a table is unreadable at thumbnail size, which is the whole reason it was taken. The full-screen viewer itself is a Modal in the app and is not drawn — recorded in routes.js under missing.

A wireframe of a receipt is about where the image sits and what it costs, not what is in it. Hence the .shot stand-in rather than a photograph.

Deleting the expense deletes the image for real — the one thing in this product that is not soft-deleted. Keeping the record does not require keeping a picture, and an image nobody can reach from any screen is a bill somebody forgot they uploaded.

On free with no photo attached, this card is absent entirely. This screen is about an expense that already exists, and an upsell in the middle of it would be an advert rather than an offer; the place somebody is actually deciding is add, which carries the Pro mark there.

Related

Sources

  • src/components/expense/receipt-card.tsx
  • src/services/receipts.ts

Every project of mine is written down like this.

Read the résumé