ProjectR Docs
Screen MapDashboard

Vouchers

Dashboard: every screen, state and flow in Vouchers.

16 screens and overlays, 95 states, 2 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

Issue a voucher by hand (writes to Shopify)

Step 1
Issued Vouchers (Web)
Issued vouchers table with Issue button
Issue voucher
Step 2
Issue voucher, Write banner shown (Web)
Issue sheet warns it writes to Shopify (do not submit)
Submit
Step 3
Issued Vouchers, Load more pagination (Web)
New voucher appears in the Issued list
Open a voucher
Step 4
Voucher detail, Actions by status (Web)
Detail sheet offers Extend, Revoke, Reissue
Revoke
Step 5
Revoke voucher(s)?, Writes to Shopify (Web)
Revoke dialog; Shopify code removed (do not submit)

Branches and edge cases

Errorfrom step 2
Wireframe

Issue voucher

Error

Template not active

Template is not active or Voucher template not found

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Template not active
Errorfrom step 2
Issue voucher, No users specified (Web)
No users specified
Errorfrom step 2
Issue voucher, Over 500 recipients (Web)
Over 500 recipients
Edgefrom step 2
Wireframe

Issue voucher

Edge

Writes off still says issued

With writes off the voucher exists but no Shopify code; toast says Issued

Not reachable on a device: Needs a server error, crash, race or code change

Shopify writes off, still says issued
Edgefrom step 4
Wireframe

Voucher detail

Edge

Extend reactivates expired

Extending an expired voucher re-activates it; Convex only

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Extend reactivates expired
Successfrom step 4
Wireframe

Voucher detail

Success

Reissued

Toast Reissued as <code>

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Reissue
Errorfrom step 4
Wireframe

Voucher detail

Error

Reissue refused

Only active or expired vouchers can be reissued

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Reissue refused
Errorfrom step 5
Wireframe

Revoke voucher(s)?

Error

Revoke refused

Cannot revoke voucher with status: X

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Revoke refused
Edgefrom step 3
Voucher Audit (Web)
Audit trail
Flow diagram

Voucher template lifecycle

Step 1
Voucher Templates (Web)
Template table with row actions
New Template
Step 2
Create Voucher Template, Five tabs with status (Web)
Template form with five tabs
Submit
Step 3
Wireframe

Voucher Templates

Edge

Bulk result messages

2/3 templates activated; N skipped (vouchers already issued)

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Back on the list after save
View a template
Step 4
Voucher template detail (Web)
Template detail
Edit
Step 5
Edit Voucher Template (Web)
Edit form

Branches and edge cases

Errorfrom step 2
Wireframe

Create Voucher Template

Error

Discount value required

Discount value is required for the selected discount type

Not captured yet

Validation fails
Errorfrom step 2
Wireframe

Create Voucher Template

Error

Server discount refusals

discountPercentage must be > 0 and <= 100; discountValue > 0

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Server refuses discount
Gatefrom step 2
Unsaved Changes (Web)
Cancel with dirty form
Errorfrom step 3
Wireframe

Voucher Templates

Error

Delete refused

Cannot delete template: vouchers have already been issued. Deactivate it instead.

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Delete with vouchers issued
Errorfrom step 4
Wireframe

Voucher template detail

Error

No Shopify campaign node yet

Sync refused when the template has no node

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Sync with no Shopify node
Successfrom step 4
Wireframe

Voucher template detail

Success

Shopify sync queued

Toast shows the server message

Needs data: Needs specific backend rows, a role, or a submitted write on a disposable record

Sync queued
Edgefrom step 4
Voucher template detail, Use in Campaign is a stub (Web)
Use in Campaign is a stub
Edgefrom step 5
Edit Voucher Template, Writes to Shopify (Web)
Discount fields changed: node update
Flow diagram

Screens and states

Vouchers Overview

Vouchers Overview (Web)
Screen/dashboard/vouchers

Vouchers Overview

KPIs and Shopify sync health.

src/app/dashboard/vouchers/page.tsx

Entry

  • Sidebar Vouchers

Exits

  • Refresh → re-query

States · 4

Loading
Sparkcards null · loading.tsx; cards show null while loadingsrc/app/dashboard/vouchers/loading.tsx
Error
Could not load voucher metrics · ErrorEmptyStatesrc/features/vouchers/overview/overview-view.tsx:157
Empty
Sync health empty · Donut empty branch when no chart datasrc/features/vouchers/overview/overview-view.tsx
Edge
Health from a sample · Sample size: last N active voucherssrc/features/vouchers/overview/overview-view.tsx

Voucher Templates

Voucher Templates (Web)
Screen/dashboard/vouchers/templates

Voucher Templates

Create and manage reusable voucher templates.

src/app/dashboard/vouchers/templates/page.tsx

Entry

  • Sidebar Vouchers > Templates
  • Legacy loyalty redirect

Exits

  • New Template (admin) → /templates/new
  • Sync All with Shopify → bumps updatedAt only
  • View, Edit, Duplicate → template routes
  • Issue voucher → Issue sheet
  • Raya campaigns → /raya-campaign?template=
  • Bulk Activate, Duplicate, Export, Delete

States · 9

Loading
Table skeleton · DataTableSkeleton 7x10src/features/loyalty/components/views/voucher-template-management-view.tsx
Error
Could not load templates · ErrorEmptyStatesrc/features/loyalty/components/views/voucher-template-management-view.tsx
Empty
Table default only · No custom empty state foundsrc/features/loyalty/components/voucher-templates/voucher-template-table.tsx
Error
Delete refused · Cannot delete template: vouchers have already been issued. Deactivate it instead.packages/backend/convex/gamificationLoyalty/mutations.ts:1625
Edge
Bulk result messages · 2/3 templates activated; N skipped (vouchers already issued)src/features/loyalty/components/voucher-templates/voucher-template-bulk-actions.tsx
Edge
Bulk delete uses window.confirm · Browser confirm, not a styled dialogsrc/features/loyalty/components/voucher-templates/voucher-template-table.tsx:245
Edge
Sync copies discount id · Row Sync copies shopifyDiscountId; no Shopify writesrc/features/loyalty/components/voucher-templates/voucher-template-table.tsx:118
Edge
No Free Product filter · Type filter omits FREE_PRODUCTsrc/features/loyalty/components/voucher-templates/voucher-template-filters.tsx
Edge
Sync All is not a write · Bumps updatedAt on templates without a node; creates nothingpackages/backend/convex/gamificationLoyalty/mutations.ts:2193

Create Voucher Template

Create Voucher Template (Web)
Screen/dashboard/vouchers/templates/new

Create Voucher Template

Define discount, targeting, eligibility and channels.

src/app/dashboard/vouchers/templates/new/page.tsx

Entry

  • New Template
  • Duplicate with ?duplicate=

Exits

  • Back → unsaved dialog
  • Submit → /vouchers/templates

States · 9

Edge
Five tabs with status · Basics, Discount, Targeting, Channels, Rules with status iconssrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx
Edge
Shopify preview · Side preview with warnings and copy buttonsrc/features/loyalty/components/voucher-templates/shopify-preview.tsx
Error
Discount value required · Discount value is required for the selected discount typesrc/features/loyalty/components/voucher-templates/utils/voucher-template-validation.ts
Error
Server discount refusals · discountPercentage must be > 0 and <= 100; discountValue > 0packages/backend/convex/gamificationLoyalty/mutations.ts:1297
Error
Scope ids required · collections or products scope needs non-empty idspackages/backend/convex/gamificationLoyalty/mutations.ts:1297
Error
Channels invalid · allowedChannels must be omitted or contain a channelpackages/backend/convex/gamificationLoyalty/mutations.ts:1297
Edge
FREE_PRODUCT not offered · Schema supports it but the form shows 3 discount typessrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx
Edge
Hidden fields · codePrefix, maxDiscountAmount, bxgy fields not exposedsrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx
Edge
No write banner · Creating does not touch Shopify; node made on first issuesrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx

Captured states

Create Voucher Template, Five tabs with status (Web)
Five tabs with status

Voucher template detail

Voucher template detail (Web)
Screen/dashboard/vouchers/templates/[id]

Voucher template detail

Template detail with admin actions.

src/app/dashboard/vouchers/templates/[id]/page.tsx

Entry

  • Row View

Exits

  • Edit, Duplicate
  • Activate or Deactivate
  • Delete → confirm → list
  • Raya campaigns link
  • Sync to Shopify
  • Use in Campaign → loyalty form

States · 8

Loading
Detail skeleton · Loading skeletonsrc/features/loyalty/components/voucher-templates/voucher-template-details.tsx
Error
Template not found · ErrorEmptyState with Back to Templatessrc/features/loyalty/components/voucher-templates/voucher-template-details.tsx
Edge
Writes to Shopify · Sync to Shopify queues a discount node update on the shared campaign nodepackages/backend/convex/gamificationLoyalty/mutations.ts:771
Error
No Shopify campaign node yet · Sync refused when the template has no nodepackages/backend/convex/gamificationLoyalty/mutations.ts:771
Success
Shopify sync queued · Toast shows the server messagesrc/features/loyalty/components/voucher-templates/voucher-template-details.tsx
Edge
Dead Quick Action · Sync with Shopify in Quick Actions has no onClicksrc/features/loyalty/components/voucher-templates/voucher-template-details.tsx:452
Edge
Use in Campaign is a stub · Opens campaign form which pre-fills nothingsrc/features/loyalty/components/voucher-templates/voucher-template-details.tsx
Gate
Write buttons admin only · hasRole admin gates write buttonssrc/features/loyalty/components/voucher-templates/voucher-template-details.tsx

Captured states

Voucher template detail, Use in Campaign is a stub (Web)
Use in Campaign is a stub

Edit Voucher Template

Edit Voucher Template (Web)
Screen/dashboard/vouchers/templates/[id]/edit

Edit Voucher Template

Update template configuration.

src/app/dashboard/vouchers/templates/[id]/edit/page.tsx

Entry

  • Row Edit
  • Detail Edit

Exits

  • Back → unsaved dialog
  • Submit → /vouchers/templates

States · 5

Loading
Form skeleton · Skeleton while loadingsrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx
Edge
Missing template · Yields an empty form, no not-found branchsrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx
Edge
Writes to Shopify · Saving discount fields on a node-backed template pushes updateCampaignDiscountNodepackages/backend/convex/gamificationLoyalty/mutations.ts:1403
Edge
No Shopify banner · ShopifyWriteBanner missing on the edit formsrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx
Edge
Active Status switch · isActive toggle appears only on editsrc/features/loyalty/components/voucher-templates/voucher-template-form.tsx

Captured states

Edit Voucher Template, Writes to Shopify (Web)
Writes to Shopify

Issued Vouchers

Issued Vouchers (Web)
Screen/dashboard/vouchers/issued

Issued Vouchers

All voucher instances with issue, revoke, extend and reissue.

src/app/dashboard/vouchers/issued/page.tsx

Entry

  • Sidebar
  • Dashboard link
  • /vouchers/issue redirect

Exits

  • Issue → Issue sheet
  • Export (admin) → Export dialog
  • Code or View → detail sheet
  • Revoke → confirm
  • Reissue → new code
  • Bulk revoke → confirm

States · 5

Loading
Table skeleton · DataTableSkeleton 11 cols on first page loadsrc/features/vouchers/issued/issued-vouchers-view.tsx
Empty
No vouchers · No vouchers match these filters.src/features/vouchers/issued/issued-vouchers-view.tsx:491
Edge
Scan cap hit · Search stopped at its N-row scan cap; older matches may be missingsrc/features/vouchers/issued/issued-vouchers-view.tsx:443
Edge
Bulk revoke limit 50 · Toast Bulk revoke limited to 50 vouchers per call; button disabledsrc/features/vouchers/issued/issued-vouchers-view.tsx:189
Edge
Load more pagination · Load more button with a disabled twin while loadingsrc/features/vouchers/issued/issued-vouchers-view.tsx

Captured states

Issued Vouchers, Load more pagination (Web)
Load more pagination

Issue voucher

Issue voucher (Web)
SheetIssueVoucherSheet

Issue voucher

Issue a voucher to one user or in bulk.

src/features/vouchers/issue/issue-voucher-sheet.tsx

Entry

  • Issued page header Issue
  • Templates row Issue voucher

Exits

  • Submit → closes, toast Issued voucher code
  • Close → cancels

States · 9

Edge
Writes to Shopify · Issuing creates a customer code on the template's shared Shopify discount nodepackages/backend/convex/dashboard/mutations.ts:150
Edge
Writes off still says issued · With writes off the voucher exists but no Shopify code; toast says Issuedpackages/backend/convex/dashboard/mutations.ts:162
Edge
Write banner shown · ShopifyWriteBanner warns when writes are offsrc/features/vouchers/issue/issue-voucher-sheet.tsx
Error
Template not active · Template is not active or Voucher template not foundpackages/backend/convex/dashboard/mutations.ts
Error
No users specified · No users specifiedpackages/backend/convex/dashboard/mutations.ts
Error
Over 500 recipients · Max 500 per batch badge disables Submit; server rejectssrc/features/vouchers/issue/issue-vouchers-view.tsx
Edge
Unknown users skipped · N unknown user id(s) skippedpackages/backend/convex/dashboard/mutations.ts
Edge
Context line · Issuing from template: X when launched from a template rowsrc/features/vouchers/issue/issue-voucher-sheet.tsx
Edge
Single path toasts raw error · The catch toasts err.message directlysrc/features/vouchers/issue/issue-vouchers-view.tsx

Captured states

Issue voucher, Write banner shown (Web)
Write banner shown
Issue voucher, No users specified (Web)
No users specified
Issue voucher, Over 500 recipients (Web)
Over 500 recipients

Voucher detail

Voucher detail (Web)
SheetVoucherDetailSheet

Voucher detail

Voucher fields with extend, revoke and reissue.

src/features/vouchers/issued/issued-vouchers-view.tsx

Entry

  • Row code click or View

Exits

  • Extend expiry → date picker
  • Revoke → confirm dialog
  • Reissue with new code

States · 7

Edge
Actions by status · Active: extend, revoke, reissue. Expired: reissue. Used, cancelled: nonesrc/features/vouchers/issued/issued-vouchers-view.tsx:514
Edge
Extend reactivates expired · Extending an expired voucher re-activates it; Convex onlypackages/backend/convex/dashboard/mutations.ts:420
Edge
Writes to Shopify · Reissue mints a new voucher with a new Shopify code; the old code stays on Shopifypackages/backend/convex/dashboard/mutations.ts:461
Error
Reissue refused · Only active or expired vouchers can be reissuedpackages/backend/convex/dashboard/mutations.ts:461
Success
Reissued · Toast Reissued as <code>src/features/vouchers/issued/issued-vouchers-view.tsx
Error
Past expiry refused · newExpiresAt must be in the futurepackages/backend/convex/dashboard/mutations.ts
Edge
Shopify discount pending · Detail shows synced or pending for the Shopify discountsrc/features/vouchers/issued/issued-vouchers-view.tsx

Captured states

Voucher detail, Actions by status (Web)
Actions by status

Revoke voucher(s)?

Revoke voucher(s)? (Web)
DialogVoucherRevokeDialogs

Revoke voucher(s)?

Confirm revoking one or many vouchers.

src/features/vouchers/issued/issued-vouchers-view.tsx

Entry

  • Row Revoke
  • Bulk bar Revoke selected

Exits

  • Revoke → toast
  • Cancel → closes

States · 5

Edge
Writes to Shopify · Revoke deletes the discount code from the shared Shopify node, not the nodepackages/backend/convex/dashboard/mutations.ts
Error
Revoke refused · Cannot revoke voucher with status: Xpackages/backend/convex/dashboard/mutations.ts
Edge
Bulk failures hidden · Per-voucher failures are returned but UI reports revokedCount onlysrc/features/vouchers/issued/issued-vouchers-view.tsx
Edge
Fixed reason strings · Reasons are Revoked from issued list or Bulk revoke from dashboardsrc/features/vouchers/issued/issued-vouchers-view.tsx
Edge
No Shopify banner · ShopifyWriteBanner missing on revokesrc/features/vouchers/issued/issued-vouchers-view.tsx

Captured states

Revoke voucher(s)?, Writes to Shopify (Web)
Writes to Shopify

Voucher Audit

Voucher Audit (Web)
Screen/dashboard/vouchers/audit

Voucher Audit

Voucher-related admin actions.

src/app/dashboard/vouchers/audit/page.tsx

Entry

  • Sidebar Vouchers > Audit

Exits

  • Copy ids → clipboard toast
  • Load more → next batch

States · 5

Gate
audit:view admin · Gated on audit:view, not vouchers:viewsrc/features/vouchers/audit/voucher-audit-view.tsx
Loading
Skeleton on zero rows · DataTableSkeleton 6x6 only with no rowssrc/features/vouchers/audit/voucher-audit-view.tsx
Empty
No voucher audit entries · No voucher-related audit entries match these filters.src/features/vouchers/audit/voucher-audit-view.tsx
Edge
Empty page with Load more · Client filter on 50 raw rows can show empty while Load more remainssrc/features/vouchers/audit/voucher-audit-view.tsx:28
Edge
Load more replaces batch · Cursor is set rather than appendedsrc/features/vouchers/audit/voucher-audit-view.tsx:150

Issue voucher redirect

Issue voucher redirect (Web)
Redirect/dashboard/vouchers/issue

Issue voucher redirect

Redirect kept for one release cycle.

src/app/dashboard/vouchers/issue/page.tsx

Entry

  • Old bookmarks

Exits

  • Redirect → /vouchers/issued

States · 1

Edge
Does not open the sheet · Lands on Issued without opening the Issue sheetsrc/app/dashboard/vouchers/issue/page.tsx

Code Pools

Code Pools (Web)
Screen/dashboard/vouchers/pools

Code Pools

Pre-generated claim-code batches.

src/app/dashboard/vouchers/pools/page.tsx

Entry

  • Sidebar
  • Loyalty dashboard link
  • Raya list View as Pools

Exits

  • New Pool → /pools/new
  • Code Campaigns (Raya) → /raya-campaign
  • Open detail → /pools/[id]
  • Copy slug

States · 3

Loading
KPI cards null · Table is client side after the query returnssrc/features/vouchers/pools/pools-list-view.tsx
Empty
No pools yet · Create one to start distributing claim codes.src/features/vouchers/pools/pools-list-view.tsx
Edge
Default status active · URL status filter defaults to active; Clear Filters appears otherwisesrc/features/vouchers/pools/pools-list-view.tsx

Create Pool

Create Pool (Web)
Screen/dashboard/vouchers/pools/new

Create Pool

Generate a batch of claim codes against a template.

src/app/dashboard/vouchers/pools/new/page.tsx

Entry

  • New Pool

Exits

  • Back or Cancel → list
  • Create pool & generate codes → /pools/[id]

States · 8

Gate
Generation paused · Submit disabled: Paused until pool-at-generation landssrc/features/vouchers/pools/pool-create-form.tsx:164
Edge
Writes to Shopify · Would create the campaign then generate live Shopify discount codes (paused)packages/backend/convex/duitRaya/mutations.ts:469
Edge
Write banner shown · Inline ShopifyWriteBanner is presentsrc/features/vouchers/pools/pool-create-form.tsx
Edge
Template link hint · Option marked Shopify-linked or not; hint says link before generatingsrc/features/vouchers/pools/pool-create-form.tsx
Error
End before start · End date must be after start datesrc/features/vouchers/pools/pool-create-form.tsx
Error
Quantity too high · Generate up to 10,000 codes per poolsrc/features/vouchers/pools/pool-create-form.tsx
Error
Server refusals · Slug exists, template not linked to Shopify, ceiling exceededpackages/backend/convex/duitRaya/mutations.ts
Edge
Dead end · Create would also create the campaign firstsrc/features/vouchers/pools/pool-create-form.tsx:329

Captured states

Create Pool, Generation paused (Web)
Generation paused

Pool Detail

Pool Detail (Web)
Screen/dashboard/vouchers/pools/[id]

Pool Detail

Pool detail, codes and provisioning.

src/app/dashboard/vouchers/pools/[id]/page.tsx

Entry

  • Pools list
  • Create redirect
  • Raya pool links

Exits

  • Back to Pools
  • Export CSV
  • More menu → edit, analytics, delete
  • Generate remaining (paused)
  • Code menu → copy, reset

States · 11

Loading
Skeleton forever on bad id · 600px skeleton when campaign missing; no not-foundsrc/features/vouchers/pools/pool-detail-view.tsx:264
Edge
Provisioning running · Title Provisioning codes while a run is in progresssrc/features/vouchers/pools/pool-detail-view.tsx
Error
Provisioning stopped · Destructive alert with provisioningErrorsrc/features/vouchers/pools/pool-detail-view.tsx
Success
Provisioning complete · X of Y requested codes generatedsrc/features/vouchers/pools/pool-detail-view.tsx
Gate
Generate remaining paused · Disabled by GENERATION_PAUSEDsrc/features/vouchers/pools/pool-detail-view.tsx:465
Edge
Writes to Shopify · Generate remaining would add live Shopify codes via workflow (paused in UI)packages/backend/convex/duitRaya/mutations.ts:546
Empty
No codes generated yet · Also No <status> codes. when filteredsrc/features/vouchers/pools/pool-detail-view.tsx
Edge
First 50 codes only · Showing first 50 of N codes; use Export for the full listsrc/features/vouchers/pools/pool-detail-view.tsx
Edge
Export truncated · Alert with Dismiss when export is cutsrc/features/vouchers/pools/pool-detail-view.tsx
Edge
Reset has no confirm · Unlike Raya, Reset to available runs immediatelysrc/features/vouchers/pools/pool-detail-view.tsx
Error
Reset refused when redeemed · Voucher already redeemed; Shopify code cannot be reversedpackages/backend/convex/duitRaya/mutations.ts

Edit pool

Edit pool (Web)
SheetPoolEditSheet

Edit pool

Update pool name, description, dates and active flag.

src/features/vouchers/pools/pool-detail-view.tsx

Entry

  • More menu Edit pool

Exits

  • Save → toast Pool updated
  • Close

States · 3

Error
Name required · Name is requiredsrc/features/vouchers/pools/pool-detail-view.tsx:560
Error
Dates invalid · Start and end dates required; end must be after startsrc/features/vouchers/pools/pool-detail-view.tsx:560
Edge
Slug and count fixed · Slug and code count cannot change after creationsrc/features/vouchers/pools/pool-detail-view.tsx:560

Delete pool?

Delete pool? (Web)
DialogPoolDeleteAlert

Delete pool?

Deactivate or hard delete a pool.

src/features/vouchers/pools/pool-detail-view.tsx

Entry

  • More menu Delete pool

Exits

  • Delete → /vouchers/pools
  • Cancel → closes

States · 3

Gate
Hard delete super admin · Switch visible to all admins; server refuses non-super-adminpackages/backend/convex/duitRaya/mutations.ts:1440
Success
Deactivated or deleted · Pool deactivated or Pool deleted (N codes removed)src/features/vouchers/pools/pool-detail-view.tsx:645
Edge
Background delete · Large deletes continue in the background with a progress messagepackages/backend/convex/duitRaya/mutations.ts

On this page