Skip to content

Extract order items summary into reusable component - #537

Merged
mnindrazaka merged 1 commit into
feat/kds-improvementfrom
claude/dazzling-mccarthy-3k7edu
Sep 18, 2026
Merged

mnindrazaka merged 1 commit into
feat/kds-improvementfrom
claude/dazzling-mccarthy-3k7edu

Conversation

@mnindrazaka

Copy link
Copy Markdown
Collaborator

Summary

Extracts the order items and total amount display logic from OrderPreparingView into a new reusable OrderItemsSummary component, then applies it to OrderReadyView to display order details when an order is ready for pickup.

Changes

  • New component: OrderItemsSummary displays a list of order items with quantities, options, notes, and subtotals, plus a total amount row
  • Refactored: OrderPreparingView now uses OrderItemsSummary instead of inline JSX, reducing duplication
  • Enhanced: OrderReadyView now displays the full order summary (items and total) alongside the pickup instructions
  • Updated: OrderStatusScreen passes items and amount props to OrderReadyView
  • Tests: Added assertion in OrderStatusHandler.test.tsx to verify items display in ready state
  • Stories: Updated OrderReadyView.stories.tsx with sample payment items

Implementation details

  • OrderItemsSummary accepts items: PaymentItem[] and amount: number props
  • Item options are displayed as comma-separated values; notes are shown in italics
  • Component uses Tamagui's YStack/XStack for layout and formatRupiah utility for currency formatting
  • Exported from orderStatus/index.ts for barrel discipline

https://claude.ai/code/session_015LLRrnUHRWWJgtAZA4j6ic

Baristas and customers previously saw only "order is ready" with no
item list, so there was no way to verify order contents at pickup or
review them from order history. Extract the item-list rendering
(already used by OrderPreparingView) into a shared OrderItemsSummary
component and reuse it in OrderReadyView; the payment entity already
carries items end-to-end, so no usecase/API changes are needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015LLRrnUHRWWJgtAZA4j6ic
@vercel

vercel Bot commented Sep 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gatherloop-order Ready Ready Preview Sep 18, 2026 5:30am UTC
gatherloop-pos Ready Ready Preview Sep 18, 2026 5:30am UTC
gatherloop-ui-storybook Ready Ready Preview Sep 18, 2026 5:30am UTC

@mnindrazaka
mnindrazaka changed the base branch from main to feat/kds-improvement September 18, 2026 05:35
@mnindrazaka
mnindrazaka merged commit 0f01f1a into feat/kds-improvement Sep 18, 2026
7 checks passed
@mnindrazaka
mnindrazaka deleted the claude/dazzling-mccarthy-3k7edu branch September 18, 2026 05:36
mnindrazaka added a commit that referenced this pull request Sep 18, 2026
* fix(order): show ordered items on the ready-for-pickup screen (#537)

Baristas and customers previously saw only "order is ready" with no
item list, so there was no way to verify order contents at pickup or
review them from order history. Extract the item-list rendering
(already used by OrderPreparingView) into a shared OrderItemsSummary
component and reuse it in OrderReadyView; the payment entity already
carries items end-to-end, so no usecase/API changes are needed.


Claude-Session: https://claude.ai/code/session_015LLRrnUHRWWJgtAZA4j6ic

Co-authored-by: Claude <noreply@anthropic.com>

* fix(pos): reset item amount and re-validate stock before adding to cart (#535)

Selecting a product while the grid was mid-revalidate or mid-param-change
silently dropped the click, leaving the picker on the previous product's
amount. SELECT_PRODUCT now also resets amount to 1 from those states, not
just 'loaded'.

Also add a soft stock check: the amount picked before pressing Submit can
be stale by the time the fresh variant comes back (another cashier may
have sold the last ones in the meantime). FETCH_VARIANT_SUCCESS now caps
the amount to the freshly fetched sellableQuantity, or bounces back to the
picker if the variant just went sold out, instead of blindly adding the
stale amount to the cart.


Claude-Session: https://claude.ai/code/session_016oePpwRYKhb8cuhcu6V8pc

Co-authored-by: Claude <noreply@anthropic.com>

* fix(api): send KDS pushes at high priority so a locked phone is woken (#536)

The Expo push payload omitted `priority`, so Expo defaulted to
`priority: 'default'` — FCM `normal` on Android, `apns-priority: 5` on
iOS. Both platforms treat that as deliverable whenever convenient:
Android holds normal-priority messages for the duration of Doze and iOS
batches priority-5 pushes to conserve power. A barista locking the phone
therefore got nothing, and every held order arrived at once the moment
the screen came back on.

Expo delivers to FCM as a data message that `expo-notifications`' own
service turns into the visible notification, so waking the app is a
precondition for the notification existing at all — and a
normal-priority data message in Doze wakes nothing.

`KdsPushPriorityHigh` is set in the domain next to `Sound` and
`ChannelId`, and used by both construction sites: the dispatched order
and the setup screen's test notification, which would otherwise behave
differently from the real thing.


Claude-Session: https://claude.ai/code/session_01AhcJGVXhTqVvjHnJhqgHQ8

Co-authored-by: Claude <noreply@anthropic.com>

* docs: PRD for guest web push notifications in order-web (#538)

* docs: add PRD for guest web push notifications in order-web

The order app tells a guest their order is ready only by short polling
from an open tab (OrderStatusUsecase's 10s interval), so a guest who
locks their phone or switches apps learns nothing. The staff side of the
same gap was closed by docs/prd-kds-order-notifications.md; this is the
guest-facing half.

Specifies Web Push with VAPID signed by apps/api, a hand-written service
worker in apps/order-web, subscriptions keyed to the existing
gl_session_id guest identity, and a guest_notifications outbox enqueued
inside CompleteTransaction. Covers the new tables, API contract, backend
and libs/ui file layout, and the iOS Home-Screen constraint that decides
most of the UX. Broken into nine phases, one PR each.

No code changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ErZwY6wGvnRSiAUYbDKWY

* docs: add phase dependency graph to web push PRD

The numbered phase list read as a strict sequence when three of the nine
phases depend on nothing. Adds a Phase dependencies section: a per-phase
table separating hard dependencies (does not compile or test without the
other) from soft ones (merge order and acceptance only), plus the six
parallel waves the graph collapses into and the six-phase critical path.

Splits the transport types into domain/web_push_gateway_repository.go so
phases 1 and 2 share no symbol and can be built at the same time (D17),
recorded as a deliberate departure from the convention both existing
gateway interfaces follow, with the cost of reverting it stated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ErZwY6wGvnRSiAUYbDKWY

---------

Co-authored-by: Claude <noreply@anthropic.com>

* feat(api): add web push subscription table, contract and endpoints (#540)

Phase 1 of docs/prd-order-web-push-notifications.md: the guest-facing
subscription slice for order-ready web push. Adds the
web_push_subscriptions table, WebPushSubscriptionRepository with its
MySQL implementation and mock, WebPushSubscriptionUsecase (subscribe
upserting on endpoint, unsubscribe soft-deleting, list by session,
config), the three contract schemas/operations, the
web-push-subscription handler/route wrapped in RequireSessionId, the
public VAPID config route, and the WEB_PUSH_VAPID_PUBLIC_KEY /
WEB_PUSH_VAPID_PRIVATE_KEY / WEB_PUSH_SUBJECT env vars. Nothing sends
a push yet — that lands in later phases.


Claude-Session: https://claude.ai/code/session_017QR4LhgGxxLcyq7GYUUumC

Co-authored-by: Claude <noreply@anthropic.com>

* feat(order-web): add service worker, manifest and icons for web push (#539)

Phase 6 of docs/prd-order-web-push-notifications.md. Ships the inert
static prerequisites for guest web push: sw.js handles push and
notificationclick, manifest.webmanifest enables standalone install
(required for iOS Web Push per D12), icons derived from the venue
logo, and next.config.js serves sw.js/the manifest with
Cache-Control: no-cache so an updated worker isn't stuck behind
Vercel's default caching. No registration code yet — phase 7 wires
the browser repository that calls navigator.serviceWorker.register.


Claude-Session: https://claude.ai/code/session_01J7xY2DeP62zXsQB7XJjLAu

Co-authored-by: Claude <noreply@anthropic.com>

* feat(api): add the Web Push gateway repository (#541)

Implements phase 2 of docs/prd-order-web-push-notifications.md:
WebPushGatewayRepository, sending VAPID-signed, RFC 8291-encrypted
notifications via github.com/SherClockHolmes/webpush-go, mirroring
data/expopush's shape. A 404/410 from the push service maps to
WebPushErrorCodeGone so the dispatcher (phase 5) can prune the dead
subscription; every other failure is transient and left for a retry.

Adds the three WEB_PUSH_* VAPID env vars, since phase 1 (which would
otherwise declare the public key) hasn't landed yet.


Claude-Session: https://claude.ai/code/session_01RuApWSajokdXCzxhje9RtX

Co-authored-by: Claude <noreply@anthropic.com>

* feat(api): add guest notification outbox table and message rule (#542)

Phase 3 of docs/prd-order-web-push-notifications.md: the guest_notifications
table, GuestNotification/GuestNotificationStatus, the pure
BuildGuestPushMessage message rule (FR-5), the GuestNotificationRepository
with its MySQL implementation and generated mock, and
PaymentRepository.GetPaymentByTransactionId, which FR-2's session resolution
needs and did not exist yet. Nothing calls any of it yet — wiring lands in
phase 4.


Claude-Session: https://claude.ai/code/session_018uc2bsM4Qf2h2pidvQCpCE

Co-authored-by: Claude <noreply@anthropic.com>

* feat(ui): add order notification subscribe frontend domain slice (#543)

Phase 7 of docs/prd-order-web-push-notifications.md: the WebPushSubscription/
WebPushConfig entities, the browser-side (WebPushRepository) and API-side
(WebPushSubscriptionRepository) interfaces, their API and browser
implementations, mock repositories, and the OrderNotificationSubscribeUsecase
FSM per FR-6. No UI wiring yet — that's phase 8.


Claude-Session: https://claude.ai/code/session_01RnkFJUWC9TZdgwzLCWn65g

Co-authored-by: Claude <noreply@anthropic.com>

* feat(api): enqueue guest notification on completion, delete on uncompletion (#544)

Phase 4 of docs/prd-order-web-push-notifications.md. CompleteTransaction
resolves the guest's session from the payment row and enqueues a
guest_notifications row after the completion write succeeds, tolerating a
missing payment as a skipped row rather than failing the completion (FR-2).
UncompleteTransaction deletes the outbox row so a correction doesn't
suppress the next real completion (D7). Nothing dispatches these rows yet.


Claude-Session: https://claude.ai/code/session_015WHemhoFz8dJ5KPodVa6G2

Co-authored-by: Claude <noreply@anthropic.com>

* feat(api): dispatch guest web push notifications on completion (phase 5) (#545)

GuestNotificationUsecase.DispatchPending claims pending outbox rows and
delivers each to every live subscription for its session, pruning
subscriptions the push service reports gone (410/404) and retrying
everything else up to the existing attempt ceiling. CompleteTransaction
kicks a dispatch after its commit, and the sweeper (renamed
runNotificationSweeper) now drives both the KDS and guest outboxes from
one ticker per docs/prd-order-web-push-notifications.md D5.


Claude-Session: https://claude.ai/code/session_01DFUNkiPqmE1cdMm9YfbDBs

Co-authored-by: Claude <noreply@anthropic.com>

* feat(ui): add the guest notification opt-in card (phase 8) (#546)

Adds OrderNotificationOptIn, rendered by OrderPreparingView and driven by
OrderStatusHandler's second use case (OrderNotificationSubscribeUsecase).
The composition root in app/order/OrderStatus.tsx now wires up
ServiceWorkerWebPushRepository and ApiWebPushSubscriptionRepository, so a
guest can tap "Beri tahu saya" and actually receive a push once phase 5's
dispatcher fires — the first phase where the feature is guest-visible.


Claude-Session: https://claude.ai/code/session_01JV1mYWtZpUB58Y28SLU3dy

Co-authored-by: Claude <noreply@anthropic.com>

* feat: improve ux of order app

* feat(kds-mobile): bundle a custom order-alert.wav notification sound (#548)

Adds the placeholder chime as the KDS push sound per D23: wires it through
the expo-notifications config plugin's sounds array, bumps the Android
channel id to orders-v2 (a channel's sound is immutable after creation),
and points KDS_PUSH_SOUND at the same filename so the API-built payload
and the bundled asset agree.


Claude-Session: https://claude.ai/code/session_016CkPhzZeN5QCniQDuCUfmt

Co-authored-by: Claude <noreply@anthropic.com>

* docs: documentation and e2e coverage for guest web push notifications (phase 9) (#547)

Closes out docs/prd-order-web-push-notifications.md: a docs-site page
explaining the feature to an operator (including the iOS Home Screen
requirement and what to check when a guest reports nothing arrived), the
three VAPID env vars documented in .env.example and README.md with a
runnable key-generation command (apps/api/cmd/generatevapidkeys, mirroring
the existing cmd/dokucheck and cmd/dokustub tools), and an order-web-e2e
spec that drives a real browser subscription from the preparing screen and
confirms a web_push_subscriptions row exists for the guest's session.

Note: .github/workflows/e2e-main.yml also needs a throwaway VAPID keypair
generated for the API step (the same way it already does for the DOKU
signing key) so this spec has a real key to subscribe against post-merge —
not included here because this token lacks the `workflow` OAuth scope to
push workflow file changes. See the PR description for the exact diff to
apply by hand.


Claude-Session: https://claude.ai/code/session_011j7au7oUXbhNzcxh5ijis2

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* feat: update kds notification sound

* Add web push configuration to deploy workflow

* Generate a throwaway VAPID keypair on e2e setup

* fix(ui): mock CheckCircle2 icon used by OrderReadyView

The jest mock for @tamagui/lucide-icons was missing CheckCircle2,
so OrderReadyView rendered undefined and failed OrderStatusHandler's
"already ready" test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YLHEzYqXJTqXbpRQZDMQUL

---------

Co-authored-by: Claude <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