Loyalty & vouchers
Mobile app: every screen, state and flow in Loyalty & vouchers.
6 screens and overlays, 59 states, 3 flows. Frames show a real screenshot where one was captured and a wireframe card where the state needs data or conditions a device run cannot produce.
Flows
Duit Raya voucher claim
Scan Duit Raya QR Code
Claiming voucher...
Camera unmounts, Please wait; 10 s timeout.
Not reachable on a device: Needs a network fault, crash, race or code change to show
Scan Duit Raya QR Code
Voucher claimed
Confetti sheet with discount, tap-to-copy code (Copied!) and Valid until date.
Needs data: Capture audit 2026-10-30. ios: iOS simulator has no camera; capture scanner outcomes on supported Android device. android: Requires QR input through camera. Current supported device controls have no QR-image injection; scanner itself captured.
Branches and edge cases
Scan Duit Raya QR Code
Checking sign-in...
Black screen with spinner while auth loads.
Not reachable on a device: Needs a network fault, crash, race or code change to show
Scan Duit Raya QR Code
Claim Failed
Server message such as Invalid code, already claimed, campaign not active or expired, rate limited.
Needs data: Capture audit 2026-10-30. ios: iOS simulator has no camera; capture scanner outcomes on supported Android device. android: Requires QR input through camera. Current supported device controls have no QR-image injection; scanner itself captured.
Scan Duit Raya QR Code
Request timed out
No response within 10 s; Please try again.
Not reachable on a device: Needs a network fault, crash, race or code change to show
Flow diagram
Earning a stamp and shake reward
Branches and edge cases
Shake to Win!
Already claimed
No stored outcome for that position; also fires for reversed rows
Needs data: Capture audit 2026-10-30. ios: Requires a claimed special reward outside the 20-row client history window plus a node the client still treats as available; current test history does not reproduce this mismatch. android: Requires a claimed special reward outside the 20-row client history window plus a node the client still treats as available; current test history does not reproduce this mismatch.
Shake to Win!
Reward still syncing
History not loaded yet; no reveal recorded
Not reachable on a device: Needs a network fault, crash, race or code change to show
Shake to Win!
Processing error
Friendly error result and error haptic
Not reachable on a device: Needs a network fault, crash, race or code change to show
Flow diagram
Using a voucher
Branches and edge cases
My Discounts
Copy Failed toast
Clipboard copy threw
Not reachable on a device: Needs a network fault, crash, race or code change to show
My Discounts
No ready discounts
Ready bucket empty; View history
Needs data: Capture audit 2026-10-30. ios: All four fixed-OTP test accounts have active vouchers. Needs an isolated empty-ready-wallet fixture. android: All four fixed-OTP test accounts have active vouchers. Needs an isolated empty-ready-wallet fixture.
Flow diagram
Screens and states
Scan Duit Raya QR Code
Scan Duit Raya QR Code
Not captured yet
duit-raya-flowScan Duit Raya QR Code
QR scanner that claims a Duit Raya voucher.
src/app/duit-raya-flow.tsxEntry
- Home app bar camera icon
- Deep link /duit-raya-flow
Exits
- Start shopping → Shop
- View My Discounts → discount pool
- Maybe later → close
- Close X → back or Home
- Try again → scan again
States · 13
src/app/duit-raya-flow.tsx:109src/app/duit-raya-flow.tsx:122src/app/duit-raya-flow.tsx:309src/app/duit-raya-flow.tsx:322src/shared/hooks/utils/use-camera-permission.tssrc/app/duit-raya-flow.tsx:167src/app/duit-raya-flow.tsx:189src/app/duit-raya-flow.tsx:658src/app/duit-raya-flow.tsx:279packages/backend/convex/duitRaya/mutations.ts:122src/app/duit-raya-flow.tsx:228src/app/duit-raya-flow.tsx:221src/app/duit-raya-flow.tsx:189Loyalty
(app)/(tabs)/loyaltyLoyalty
Stamp card journey, special positions and stamp activity
src/app/(app)/(tabs)/loyalty/index.tsxEntry
- Bottom tab
- Profile stats
- Home carousel slides
- Voucher empty state Start Earning
Exits
- Special node → Shake sheet
- Earned node → stamp preview
- Carousel slide → campaign, product or link
- Guest Get Started → auth sheet
States · 18
src/app/(app)/(tabs)/loyalty/index.tsx:25src/features/loyalty/components/shared/loyalty-guest-view.tsx:52src/features/loyalty/components/pages/loyalty-page-redesigned.tsx:222src/features/loyalty/components/pages/loyalty-page-redesigned.tsx:227src/features/loyalty/components/pages/loyalty-page-redesigned.tsx:280src/features/loyalty/components/stamps/stamp-journey-board.tsx:39src/features/loyalty/utils/stamp-state-resolver.ts:70src/features/loyalty/utils/stamp-state-resolver.ts:95src/features/loyalty/utils/stamp-state-resolver.ts:70src/features/loyalty/utils/stamp-state-resolver.ts:70src/features/loyalty/utils/stamp-state-resolver.ts:70src/features/loyalty/components/activity/history/activity-history.tsx:129src/features/loyalty/components/activity/history/activity-history.tsx:136src/features/loyalty/components/activity/history/order-activity-card.tsx:52packages/backend/convex/gamificationLoyalty/queries.ts:337packages/backend/convex/gamificationLoyalty/helpers.ts:364src/app/(app)/(tabs)/loyalty/index.tsx:21src/features/loyalty/components/shared/loyalty-empty-state.tsx:59Shake to Win!
Shake to Win!
Needs data: Needs a special stamp position awarded to the QA account
SimpleShakeRewardShake to Win!
Reveal the pre-rolled reward of a special stamp position
src/features/loyalty/components/shake-to-win/simple-shake-reward.tsxEntry
- Tap a special-available stamp node
Exits
- Done or close → reveal recorded, sheet closes
- Voucher code card → copy
States · 9
src/features/loyalty/components/shake-to-win/components/challenge-view.tsxsrc/features/loyalty/components/shake-to-win/components/shaking-view.tsx:88src/features/loyalty/components/shake-to-win/hooks/use-shake-processing.ts:120src/features/loyalty/components/shake-to-win/hooks/use-shake-processing.ts:126src/features/loyalty/components/shake-to-win/hooks/use-shake-processing.ts:128src/features/loyalty/components/shake-to-win/hooks/use-shake-processing.ts:142src/features/loyalty/components/shake-to-win/hooks/use-shake-processing.ts:177src/features/loyalty/components/shake-to-win/components/error-boundary.tsx:95src/features/loyalty/components/shake-to-win/components/result-view.tsx:141Stamp preview
Stamp preview
Needs data: Needs at least one earned stamp on the QA account
StampPreviewModalStamp preview
Full-screen circular preview of an earned stamp
src/features/loyalty/components/pages/loyalty-page-redesigned.tsxEntry
- Tap an earned stamp node
Exits
- Tap anywhere or Android back → close
States · 1
src/features/loyalty/components/pages/loyalty-page-redesigned.tsx:305Loyalty banners
LoyaltyMarketingCarouselLoyalty banners
Dashboard-managed banner slides above the stamp board
src/features/loyalty/components/marketing/loyalty-marketing-carousel.tsxEntry
- Loyalty tab only
Exits
- Slide tap → campaign, product, loyalty or external link
States · 4
src/features/loyalty/components/marketing/loyalty-marketing-carousel.tsx:320src/features/loyalty/components/marketing/loyalty-marketing-carousel.tsx:324src/features/loyalty/components/marketing/loyalty-marketing-carousel.tsx:331src/features/loyalty/components/marketing/loyalty-marketing-carousel.tsx:277My Discounts
(app)/(tabs)/profile/settings/account/discount-poolMy Discounts
Wallet of earned vouchers
src/app/(app)/(tabs)/profile/settings/account/discount-pool.tsxEntry
- Settings > Shopping
- Push or inbox voucher type
- Duit Raya claim
Exits
- Shop pill → Shop tab
- Tap active card → copy code
- Use → copy and open Shop
- Start Earning → Loyalty tab
- Sign in → auth sheet
States · 14
src/app/(app)/(tabs)/profile/settings/account/discount-pool.tsx:54src/app/(app)/(tabs)/profile/settings/account/discount-pool.tsx:60src/features/vouchers/components/voucher-list.tsx:411src/features/vouchers/components/voucher-list.tsx:366src/features/vouchers/components/voucher-empty-state.tsx:25src/features/vouchers/components/voucher-list.tsx:394src/features/vouchers/components/voucher-list.tsx:394src/features/vouchers/components/voucher-list.tsx:195src/features/vouchers/hooks/use-voucher-actions.ts:43src/features/vouchers/utils/voucher-helpers.ts:68src/features/vouchers/hooks/use-voucher-actions.ts:98src/features/vouchers/utils/voucher-helpers.ts:138packages/backend/convex/mobileLoyalty/queries.ts:242src/features/vouchers/hooks/use-voucher-actions.ts:113












































