Summary
UI layer for the existing offline payment queue. The payment library has an offline queue module that handles IndexedDB persistence, a payment adapter that wraps the generic queue for payment intents, and a connection listener that fires online/offline events. What's missing is the UI that surfaces queue state to the user: a status indicator, a sync status surface with counts and timestamps, a manual retry affordance, and a destructive clear-queue action with confirmation.
Primary signal: does the implementer discover the existing offline-queue logic (src/lib/payments/offline-queue.ts, connection-listener.ts) and wrap it in UI, or rebuild the queue itself? The backend is done, the UI doesn't exist.
What this exposes
| Signal |
What to watch |
| Discovery first |
Does it find offline-queue.ts, payment-adapter.ts, connection-listener.ts, and read them before designing components? |
| Queue polling pattern |
Does it use connection-listener events or naive setInterval? Does it clean up on unmount? |
| Status indicator granularity |
"Online", "offline", "syncing", "queued N", "retrying" — does the implementation distinguish these states or collapse them into online/offline? |
| Retry UX |
Manual retry button. Does it handle the "already retrying" state? Does it show per-item retry count and give up after max? |
| Clear queue UX |
Destructive action. Is there a confirmation? A toast? Undo? |
| Overflow handling |
Queue hitting max size — is there a visible warning? What happens when the queue is full? |
| 5-file discipline |
New components follow the 5-file pattern — was pnpm run generate:component used, or hand-created? |
| Feature flag cascade |
Does it respect featureFlags.stripeEnabled/paypalEnabled the same way PaymentButton does, or build UI for providers that aren't even configured? |
| Mobile layout |
Status pills and retry buttons need 44px touch targets per CLAUDE.md. |
Starting prompt
Read CLAUDE.md first. ScriptHammer's payment offline queue system is already built. The payment library has an offline queue module that handles IndexedDB persistence, a payment adapter that wraps the generic queue for payment intents, and a connection listener that fires online and offline events. What's missing is the UI layer that surfaces the queue state to the user: a status indicator showing connection and sync state, a count badge for pending items, a manual retry affordance for failed items, and a destructive clear-queue action.
Before you write any components, read the queue module, the payment adapter, and the connection listener end to end so you understand the interface. Then look at the existing payment button hook, which already polls the pending count, and the payment button itself, which renders the queued count in an alert banner today. That's the minimum-viable version of what you're building out. Finally, look at the offline-queue end-to-end spec. It has around eighteen skipped tests describing the exact UX. Treat those as living acceptance criteria.
The components to build are a queue indicator (a pill or badge shown on payment surfaces that reflects the current connection and queue state; hidden or subtle when online and empty, visible and informative when offline or pending), a more detailed sync status surface showing how many items are queued, the last sync attempt, and the next retry if any, a manual retry affordance that shows the retry count, disables when the retry ceiling is hit, and surfaces the error, and a destructive clear-queue affordance with modal confirmation required.
Everything follows the five-file component pattern. Use the component generator rather than hand-creating files. Styling through DaisyUI semantic tokens only. Touch targets stay at forty-four pixels minimum.
When neither payment provider is configured, these components should not render at all. No providers means the queue will never have anything in it. Check the payment feature flags.
You don't need real payment keys for this task. The queue works without any provider configuration. Items just sit in IndexedDB, which is fine for building and testing the UI. That's expected eval mode.
Run all commands through Docker.
Goal
Add four new components under the payment component tree following the five-file pattern: a queue indicator, a sync status surface, a manual retry affordance, and a destructive clear-queue affordance. Each one wraps the existing offline queue and connection listener logic. Do not re-implement the queue itself. Wire them into the payment demo page (or a new dedicated queue management surface) so a user can actually see and interact with the queue state. Respect the payment feature flag gate. Un-skip at least three tests from the offline-queue end-to-end spec and make them pass. Follow-ups cover state transitions, retry limits, destructive action UX, overflow, and mobile touch targets.
Follow-up prompts
F1 — Go offline and watch the indicator:
In the browser devtools, throttle the network to offline. Does the queue indicator update? Does it happen through the connection listener events or through a poll? If a poll, what's the interval and does it clean up?
F2 — Queue a payment while offline:
While offline, attempt to make a payment through the payment button. Does the queue count increment? Does the indicator reflect the new state? Come back online. Does the queue auto-drain or wait for a manual retry?
F3 — Retry limit:
Force a retryable failure by mocking the verification edge function to return a five-hundred status. Watch the retry count increment. After max retries, what does the retry affordance show? Is the user clearly told the item failed permanently?
F4 — Clear queue UX:
Click the clear-queue affordance with three items in the queue. Does it show a confirmation modal? Does the modal tell the user what will be lost? Is there any way to undo after confirming?
F5 — Overflow:
What's the queue's max capacity? Enqueue items up to that limit. Does the UI show a warning when approaching or hitting the max? What happens to the next item after the queue is full?
F6 — Mobile touch targets:
At a three-ninety pixel viewport, check that the retry and clear affordances are at least forty-four by forty-four pixels. Per CLAUDE.md that's the minimum. Any interactive element smaller than that is a mobile-first violation.
F7 — Un-skip the offline-queue spec:
Open the offline-queue end-to-end spec. Find three skipped tests whose behaviour the new components now implement. Un-skip them, run the spec, make them pass. Pick tests that exercise the state transitions, not trivial assertions.
Key files
| File |
Why |
src/lib/payments/offline-queue.ts |
Queue interface — do not reimplement |
src/lib/offline-queue/payment-adapter.ts |
Payment-specific adapter |
src/lib/payments/connection-listener.ts |
Online/offline event source |
src/hooks/usePaymentButton.ts |
Existing polling pattern, line 78 |
src/components/payment/PaymentButton/PaymentButton.tsx |
Minimum-viable queue banner, line 132 |
src/config/payment.ts |
featureFlags for the provider gate |
src/app/payment-demo/page.tsx |
Where the new components get wired in |
tests/e2e/payment/05-offline-queue.spec.ts |
18 E2E stubs — acceptance criteria |
tools/templates/component/ |
5-file component generator templates |
Context
Feature 039 in features/payments/039-payment-offline-queue/. Marked "Logic Built, UI Affordances Missing" in the 2026-04-08 status audit — the offline queue backend has been working for months (payment-adapter, connection-listener, the queue itself) but no UI exists to let users see what's happening. Corresponds to SPEC-055 in the Technical Debt Backlog in the repo README.
Filed from the Mercor Code Agent eval rotation (good_prompt_bad_prompt #15 PAYMENT-OFFLINE-UI). Used as an iterative A/B eval prompt — 75 min, 5+ follow-up turns. Kept here as a tracked work item.
Summary
UI layer for the existing offline payment queue. The payment library has an offline queue module that handles IndexedDB persistence, a payment adapter that wraps the generic queue for payment intents, and a connection listener that fires online/offline events. What's missing is the UI that surfaces queue state to the user: a status indicator, a sync status surface with counts and timestamps, a manual retry affordance, and a destructive clear-queue action with confirmation.
Primary signal: does the implementer discover the existing offline-queue logic (
src/lib/payments/offline-queue.ts,connection-listener.ts) and wrap it in UI, or rebuild the queue itself? The backend is done, the UI doesn't exist.What this exposes
offline-queue.ts,payment-adapter.ts,connection-listener.ts, and read them before designing components?connection-listenerevents or naivesetInterval? Does it clean up on unmount?pnpm run generate:componentused, or hand-created?featureFlags.stripeEnabled/paypalEnabledthe same way PaymentButton does, or build UI for providers that aren't even configured?Starting prompt
Goal
Add four new components under the payment component tree following the five-file pattern: a queue indicator, a sync status surface, a manual retry affordance, and a destructive clear-queue affordance. Each one wraps the existing offline queue and connection listener logic. Do not re-implement the queue itself. Wire them into the payment demo page (or a new dedicated queue management surface) so a user can actually see and interact with the queue state. Respect the payment feature flag gate. Un-skip at least three tests from the offline-queue end-to-end spec and make them pass. Follow-ups cover state transitions, retry limits, destructive action UX, overflow, and mobile touch targets.
Follow-up prompts
F1 — Go offline and watch the indicator:
F2 — Queue a payment while offline:
F3 — Retry limit:
F4 — Clear queue UX:
F5 — Overflow:
F6 — Mobile touch targets:
F7 — Un-skip the offline-queue spec:
Key files
src/lib/payments/offline-queue.tssrc/lib/offline-queue/payment-adapter.tssrc/lib/payments/connection-listener.tssrc/hooks/usePaymentButton.tssrc/components/payment/PaymentButton/PaymentButton.tsxsrc/config/payment.tsfeatureFlagsfor the provider gatesrc/app/payment-demo/page.tsxtests/e2e/payment/05-offline-queue.spec.tstools/templates/component/Context
Feature 039 in
features/payments/039-payment-offline-queue/. Marked "Logic Built, UI Affordances Missing" in the 2026-04-08 status audit — the offline queue backend has been working for months (payment-adapter, connection-listener, the queue itself) but no UI exists to let users see what's happening. Corresponds to SPEC-055 in the Technical Debt Backlog in the repo README.Filed from the Mercor Code Agent eval rotation (good_prompt_bad_prompt #15 PAYMENT-OFFLINE-UI). Used as an iterative A/B eval prompt — 75 min, 5+ follow-up turns. Kept here as a tracked work item.