feat: bolt card nfc payments and scannable pos, activity and detail screens - #97
Merged
Merged
Conversation
The whole list body suspended on the "any rows?" query, so the search input vanished behind the skeleton until it resolved. Search state now lives above the Suspense boundary and the fallback renders the input, so only the rows show a loading state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
…ment state A free table now starts a bill wherever its tile is tapped, and a table with a single bill opens it the same way — the common cases no longer need aiming at a small button. The "+" stays above the tile for starting a split check. Each bill card also shows how long the bill has been open and flags a payment in flight or a partial settlement, so staff can spot the table waiting on them. openBillsQuery embeds each bill's payments and claims so the floor view stays a single query. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
On a busy floor most tiles are occupied, and solid-filled tiles stopped telling them apart; occupied is now a tint with an accent ring, leaving the solid accent for the payment badges that need attention. Tiles in a row share a height, so a tall tile no longer leaves a gap beside it. The table glyph repeated on every tile carried nothing; a free tile shows a "+" in its place instead of a separate button. A table with several bills shows its running total instead of the seat count, and bill cards read "#3" with an item count rather than repeating "Bill #". The single-bill tile's full-tile link is now aria-hidden and unfocusable, only widening the bill card's own target, so a tap at the tile's centre can no longer land on the "+" instead of the bill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
…ables A line above the grid now sums what is open across the floor, and an "occupied only" toggle, remembered per device, hides free tiles so a large floor shrinks to the tables that need attention. A venue without tables sees a pointer to the tables settings instead of a lone tile with no explanation. The "no table" tile moves to the end: where tables exist it is the exception, and without tables it is the only tile anyway. Bill stats are now derived once per page and shared by the summary and the tiles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
The lone calculator/grid icon gave no hint that it switched views. Both modes now sit in one segmented control, the active one labelled, and the pill slides between them in a single shared motion layout so segments of different widths never make it jump or overstretch. Reduced motion switches instantly. Regenerates the home and tables doc screenshots for the new header and floor view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
The payment method tabs now share the home switch's control: the pill slides between methods and an inactive method shows only its icon. The motion parts move into src/components/sliding-pill.tsx so both controls animate identically, and both get wider side padding so an icon-only segment no longer looks cramped. Regenerates the home, tables and payment doc screenshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
Every payment row was titled just "Payment", with the amount in small print, so staff had to open rows one by one to tell them apart. Rows now lead with the bill label/number (or the payment's serial number), show the table, tip and settling method icons, and put the amount on the right in bold, struck through only when the money never arrived. Day headings read "Today"/"Yesterday" and carry the day's settled total per currency, left off the last group while more pages are pending so it never undercounts. Issues render as warning badges with an inset stripe on the row instead of a dot-joined text line. Both tabs share the row pieces in activity-row.tsx so they stay visually identical; the payment method labels move out of payment-detail.tsx so the list and detail name methods the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
The detail page opened on a raw UUID under a duplicated "Payment detail" title, then a list of rows where half read "—", and each reconciliation spelled out ten fields including hashes nobody reads at the counter. The summary card now names the payment by its daily serial number and shows amount, included tip, payment methods and cancellation up front. Identifiers and bookkeeping timestamps move into collapsed "Technical details" sections with copy buttons. The bill card links to the bill detail and states "No table" instead of a dash. A pending payment gets a primary "Back to payment" button with its expiry time, and the route shows a skeleton instead of an empty page while loading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
Same treatment the payment detail got: the bill detail opened on its raw
UUID, buried "Back to bill" among the rows as an outline button, and
showed "—" for a bill with no table.
The summary card now carries the status badge in its header with the
creation time, shows when the bill was closed or canceled under the total,
and states "No table" explicitly. "Back to bill" is the primary action on
top for an open bill, the bill and device ids move into the collapsed
technical details shared with the payment detail, and the route shows a
skeleton while loading.
The e2e status checks now match "Closed" exactly, since the text also
appears in the new "Closed {date}" line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
The bill detail's payment rows gave only amount, time and status, so telling a cash payment from a card one meant opening each. The activity list already shows method icons; the bill detail now does too. paymentsWithClaimsByBillIdQuery trades its COUNT for an embedded array of the claimed transactions' kinds, the same move payment-history.tsx made. The row takes its claim count from the array's length, which also drops the bigint/string COUNT coercion that existed only for this query. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
Customers with a Bolt Card can now tap it under the Lightning QR instead of scanning. A local Android plugin reads the card's lnurlw:// link in reader mode (so Android does not open a browser for the tag), and the payment's invoice is handed to the card's LNURL-withdraw service (LUD-03/LUD-17). Settlement is still observed by the Spark sync, so the flow writes nothing and a retry cannot charge twice. Android only: iOS reads tags only behind a user-opened system sheet, which cannot wait under a QR. The shared LNURL fetch moved into lnurl-client.ts so the pay and withdraw clients share it; its errors lost the Pay prefix accordingly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bolt Card over NFC (Android)
NfcPluginreads the card'slnurlw://link in reader mode, so Android does not open a browser for the tag.payPaymentWithBoltCardchecks that the payment is still pending and has a Lightning invoice, then hands that invoice to the card's LNURL-withdraw service (LUD-03/LUD-17). It writes nothing: the Spark sync settles the payment the same way it does for a scanned QR. A retry cannot charge twice, because a Lightning invoice can only be paid once.lnurl-client.ts, and its errors dropped thePayprefix.Earlier UX commits on this branch
Test plan
bun run check:ts,bun run check:tests(710 passing).check:lintflags only untracked SVGs outside the repo tree../gradlew :app:compileDebugJavaWithJavac🤖 Generated with Claude Code
https://claude.ai/code/session_01BK6n6yMEXHuB1LsHBmX4Pa