ProjectR Docs
Screen MapMobile app

Notifications

Mobile app: every screen, state and flow in Notifications.

6 screens and overlays, 58 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

Notification permission on Home

Step 1
Home, Notification ask (Android)
Home stays in front for about 1.5 s after sign-in
Wait 1.5 s
Step 2
Know when your order ships, Offer rule (iOS)Know when your order ships, Offer rule (Android)
Modal asks: Stay in the loop
Tap Turn on notifications
Step 3
Wireframe

Know when your order ships

Loading

Requesting permission

Primary button loading and disabled

Not reachable on a device: OS dialog over the app; screenshot via adb only

OS permission dialog is up over the modal
Allow
Step 4
Know when your order ships, Granted (iOS)Know when your order ships, Granted (Android)
Modal closes once permission is granted

Branches and edge cases

Edgefrom step 1
Account gate, Home notification offer mounted (iOS)Account gate, Home notification offer mounted (Android)
Rules say skip the ask
Edgefrom step 2
Know when your order ships, Dismissal is remembered (iOS)Know when your order ships, Dismissal is remembered (Android)
Not now, swipe or back
Errorfrom step 3
Know when your order ships, Notifications Disabled (Android)
OS dialog denied, can ask later
Edgefrom step 3
Know when your order ships, Second denial swaps to Open Settings (iOS)Know when your order ships, Second denial swaps to Open Settings (Android)
OS denied for good
Errorfrom step 3
Wireframe

Know when your order ships

Error

Unable to request permission

Danger toast titled Error when the request throws; modal closes

Not reachable on a device: Capture audit 2026-10-30. ios: Prior source investigation: no distinct reachable UI for this state. android: Prior source investigation: no distinct reachable UI for this state.

OS request errors
Edgefrom step 2
Know when your order ships, Blocked by the OS (iOS)Know when your order ships, Blocked by the OS (Android)
Already blocked at open
Successfrom step 4
Know when your order ships, Open Settings (iOS)Know when your order ships, Open Settings (Android)
Open Settings tapped
Flow diagram

Notification permission

Step 1
Home, Notification ask (Android)
Home settles after sign-in (an order confirmation asks the same way after 1.2 s)
Wait 1.5 s
Step 2
Know when your order ships, Offer rule (iOS)Know when your order ships, Offer rule (Android)
Permission modal appears when the rules allow
Turn on notifications
Step 3
Wireframe

Know when your order ships

Loading

Requesting permission

Primary button loading and disabled

Not reachable on a device: OS dialog over the app; screenshot via adb only

OS dialog asks for notifications
Allow
Step 4
Notification Preferences, Push enabled or disabled toast (Android)
Later, Preferences shows the push master toggle

Branches and edge cases

Edgefrom step 1
Wireframe

Order Confirmed!

Edge

Notification prompt

Once per visit if eligible, pushes notification-permission modal

Needs data: Capture audit 2026-10-30. ios: Real checkout/payment required; do not bypass route allowlist. android: Real checkout/payment required; do not bypass route allowlist.

Already granted or decided: nothing
Edgefrom step 2
Know when your order ships, Dismissal is remembered (iOS)Know when your order ships, Dismissal is remembered (Android)
Not now: marker set, close
Errorfrom step 3
Know when your order ships, Notifications Disabled (Android)
OS dialog denied, can ask later
Edgefrom step 3
Know when your order ships, Second denial swaps to Open Settings (iOS)Know when your order ships, Second denial swaps to Open Settings (Android)
OS denied for good
Errorfrom step 3
Wireframe

Know when your order ships

Error

Unable to request permission

Danger toast titled Error when the request throws; modal closes

Not reachable on a device: Capture audit 2026-10-30. ios: Prior source investigation: no distinct reachable UI for this state. android: Prior source investigation: no distinct reachable UI for this state.

OS request errors
Errorfrom step 4
Notification Preferences, OS permission refused (Android)
Master toggle on, OS refused
Edgefrom step 4
Notification Preferences, Toggle opens Settings (iOS)Notification Preferences, Toggle opens Settings (Android)
OS will not ask again
Edgefrom step 4
Notification Preferences, Push blocked by the OS (iOS)Notification Preferences, Push blocked by the OS (Android)
Push blocked banner
Edgefrom step 4
Wireframe

Notification Preferences

Loading

Loading your preferences

Centered spinner (progressbar role) until the backend answers; no default toggles are shown

Not captured yet

Preferences still loading
Errorfrom step 4
Wireframe

Notification Preferences

Error

Could not save preferences

Save failed

Not reachable on a device: Needs a network fault, crash, race or code change to show

Preferences save fails
Flow diagram

Notification inbox and taps

Step 1
Notifications, Populated inbox (iOS)Notifications, Populated inbox (Android)
Inbox lists notifications with unread dots
Tap a row with content
Step 2
Notification, Loaded with hero image (iOS)Notification, Loaded with hero image (Android)
Detail page shows hero image, body and CTA

Branches and edge cases

Gatefrom step 1
Notifications, Sign in to view notifications (iOS)Notifications, Sign in to view notifications (Android)
Guest opens the inbox
Edgefrom step 1
Wireframe

Notifications

Loading

Notification skeleton

First page loading, 6 rows

Not reachable on a device: Needs a network fault, crash, race or code change to show

Loading
Errorfrom step 1
Wireframe

Notifications

Error

Couldn't load notifications

Timeout; Try again redrives session

Not reachable on a device: Needs a network fault, crash, race or code change to show

Load times out
Emptyfrom step 1
Notifications, All caught up (iOS)Notifications, All caught up (Android)
No rows
Edgefrom step 1
Notifications, Row without destination (iOS)Notifications, Row without destination (Android)
General row has no destination
Successfrom step 1
Orders (iOS)Orders (Android)
Typed route to Orders
Edgefrom step 1
Notification deleted, Notification deleted, tap to undo (iOS)Notification deleted, Notification deleted, tap to undo (Android)
Swipe left to delete
Errorfrom step 2
Notification, Invalid CTA path (iOS)Notification, Invalid CTA path (Android)
Invalid CTA path
Errorfrom step 2
Notification, Unable to load notification (iOS)Notification, Unable to load notification (Android)
Detail fails to load
Edgefrom step 1
Notifications, Looking for more in this category (Android)
Category chip with few matches
Emptyfrom step 1
Notifications, No notifications in this category (iOS)Notifications, No notifications in this category (Android)
Chip still empty after auto-load
Successfrom step 2
Wireframe

Push notification tap

Success

Opens detail page for rich content

A push whose notification has detail content opens /notifications/detail/[id], like an inbox tap. A valid deepLink still wins

Needs data: Capture audit 2026-10-30. ios: Physical device required; simulator push listener disabled. android: Physical device required; simulator push listener disabled.

Push tap with rich content
Edgefrom step 2
Notification, Plain notification fallback (iOS)Notification, Plain notification fallback (Android)
Plain notification, no rich content
Flow diagram

Screens and states

Know when your order ships

Know when your order ships (iOS)Know when your order ships (Android)
Modal(modals)/notification-permission

Know when your order ships

Soft ask before the OS notification dialog. Offered once on Home after sign-in and again after an order. After a final OS denial it offers Open Settings instead.

src/app/(modals)/notification-permission.tsx

Entry

  • Home after sign-in, 1.5 s settled (useOfferNotificationsOnHome)
  • Order confirmation after 1.2 s
  • Developer settings row

Exits

  • Turn on notifications → OS dialog, then close
  • Open Settings (OS blocked) → system settings, then close
  • Not now → close to previous or Home
  • Swipe or back → same as Not now

States · 17

Edge
Offer rule · Not dismissed, OS not granted, and undetermined (iOS) or denied while Android can still ask. Errors mean no offer. Shared by the Home and order offers through offerNotificationPromptsrc/shared/utils/notification-utils.tsx:76
Loading
Requesting permission · Primary button loading and disabledsrc/app/(modals)/notification-permission.tsx:218
Success
Granted · OS permission granted; modal closessrc/app/(modals)/notification-permission.tsx:125
Error
Notifications Disabled · Ordinary denial (OS can still ask later): warning toast, copy from notifications.permission.disabled_toast_*; closes after 3 ssrc/app/(modals)/notification-permission.tsx:143
Error
Unable to request permission · Danger toast titled Error when the request throws; modal closessrc/app/(modals)/notification-permission.tsx:159
Edge
Dismissal is remembered · Not now, swipe, back or any removal marks the prompt as shown so it does not returnsrc/app/(modals)/notification-permission.tsx:102
Edge
800 ms removal guard · Blocks removal briefly so a data refetch cannot pop the modal before it is seensrc/app/(modals)/notification-permission.tsx:50
Edge
Idle · Title Stay in the loop with Turn on notifications and Not now; swipe blocked for 800 mssrc/app/(modals)/notification-permission.tsx:201
Loading
Requesting · Button loading while the OS dialog is opensrc/app/(modals)/notification-permission.tsx:114
Edge
Denied · Warning toast Notifications Disabled, then close; a final denial shows Open Settings insteadsrc/app/(modals)/notification-permission.tsx:130
Error
Request error · Danger toast, then closesrc/app/(modals)/notification-permission.tsx:161
Edge
Offer rules · Not if granted or dismissed; iOS undetermined only; Android denied with canAskAgainsrc/shared/utils/notification-utils.tsx:93
Edge
Every close goes Home · Even from developer settings; sets dismissal markersrc/app/(modals)/notification-permission.tsx:146
Edge
Offered on Home · A signed-in, ready account on the Home tab gets the ask once per session after 1.5 s, unless a token is already registered, the prompt was dismissed, or the OS decidedsrc/features/notifications/hooks/use-offer-notifications-on-home.ts:28
Edge
Blocked by the OS · Denied and the OS will not ask again: title Notifications are turned off, primary button Open Settings (open-settings-button) replaces Turn on notificationssrc/app/(modals)/notification-permission.tsx:200
Edge
Second denial swaps to Open Settings · After the OS dialog is refused and isBlockedBySystem is true, the modal stays open and flips to the blocked layout instead of a toastsrc/app/(modals)/notification-permission.tsx:136
Success
Open Settings · Linking.openSettings, then the modal closes and the dismissal marker is writtensrc/app/(modals)/notification-permission.tsx:175

Captured states

Know when your order ships, Offer rule (iOS)Know when your order ships, Offer rule (Android)
Offer rule
Know when your order ships, Granted (iOS)Know when your order ships, Granted (Android)
Granted
Know when your order ships, Notifications Disabled (Android)
Notifications Disabled
Know when your order ships, Dismissal is remembered (iOS)Know when your order ships, Dismissal is remembered (Android)
Dismissal is remembered
Know when your order ships, Blocked by the OS (iOS)Know when your order ships, Blocked by the OS (Android)
Blocked by the OS
Know when your order ships, Second denial swaps to Open Settings (iOS)Know when your order ships, Second denial swaps to Open Settings (Android)
Second denial swaps to Open Settings
Know when your order ships, Open Settings (iOS)Know when your order ships, Open Settings (Android)
Open Settings

Notifications

Notifications (iOS)Notifications (Android)
Screen(app)/notifications

Notifications

Inbox with category filters, swipe delete with undo, infinite scroll. Live subscription, so no pull to refresh.

src/app/(app)/notifications/index.tsx

Entry

  • Home bell with unread badge
  • Profile menu
  • Push tap fallback
  • Deep link

Exits

  • Row tap → resolved destination
  • Swipe or trash → delete with undo
  • Sign in → auth sheet
  • Filter chips

States · 15

Gate
Sign in to view notifications · Guest empty statesrc/features/notifications/components/notifications-list-screen.tsx:132
Loading
Notification skeleton · First page loading, 6 rowssrc/features/notifications/components/notifications-list-screen.tsx:142
Error
Couldn't load notifications · Timeout; Try again redrives sessionsrc/features/notifications/components/notifications-list-screen.tsx:158
Empty
All caught up · No notifications at all; chips hiddensrc/features/notifications/components/notifications-list-screen.tsx:175
Empty
No notifications in this category · Filter yields none after the auto-load gives up; chips staysrc/features/notifications/components/notifications-list-screen.tsx:206
Success
Populated inbox · FlashList; loads 20 more on end reached; chips All, Orders, Rewards, Promotions, Reminders, Accountsrc/features/notifications/components/notifications-list-screen.tsx:233
Loading
Loading more · Footer spinner while next page loadssrc/features/notifications/components/notifications-list-screen.tsx:235
Edge
Unread dot persists · markAllAsRead fires once but dots stay until tappedsrc/features/notifications/hooks/use-notification-inbox.ts:139
Edge
Row without destination · No chevron, tap does nothing (general type)src/features/notifications/components/notification-row.tsx:77
Edge
System and general only under All · Types with no catalog category show under All only; chips are the five catalog categoriessrc/features/notifications/utils/notification-sections.ts:27
Edge
Admin rows hidden · Types starting admin. filtered server-sidepackages/backend/convex/notification/queries.ts:63
Loading
Looking for more in this category · A filter with fewer than 10 matches keeps pulling older pages; the empty state waits behind a spinner and the line Looking for more in this categorysrc/features/notifications/components/notifications-list-screen.tsx:194
Edge
Filter auto-loads older pages · MIN_FILTER_MATCHES 10, stops at 120 loaded; the filter runs on the client over all-type pagessrc/features/notifications/utils/notification-sections.ts:52
Edge
Delete as screen reader action · Each row is one accessible element with a custom delete action (VoiceOver rotor, TalkBack menu) matching the swipesrc/features/notifications/components/notification-row.tsx:289
Edge
No pull to refresh · The RefreshControl was removed: the list is a live Convex subscriptionsrc/features/notifications/components/notifications-list-screen.tsx:78

Captured states

Notifications, Sign in to view notifications (iOS)Notifications, Sign in to view notifications (Android)
Sign in to view notifications
Notifications, All caught up (iOS)Notifications, All caught up (Android)
All caught up
Notifications, No notifications in this category (iOS)Notifications, No notifications in this category (Android)
No notifications in this category
Notifications, Populated inbox (iOS)Notifications, Populated inbox (Android)
Populated inbox
Notifications, Row without destination (iOS)Notifications, Row without destination (Android)
Row without destination
Notifications, Looking for more in this category (Android)
Looking for more in this category

Notification deleted

Wireframe

Notification deleted

Needs data: Needs inbox rows on the QA account

InlineNotificationDeleteUndo

Notification deleted

Soft delete with 4 second undo toast

src/features/notifications/hooks/use-notification-inbox.ts

Entry

  • Swipe or trash tap on a row

Exits

  • Tap toast → restore row
  • Timeout → delete runs

States · 3

Success
Notification deleted, tap to undo · Row hidden; mutation runs after 4ssrc/features/notifications/hooks/use-notification-inbox.ts:206
Error
Could not delete notification · Mutation failed; row restoredsrc/features/notifications/hooks/use-notification-inbox.ts:190
Edge
Leaving flushes deletes · Pending deletes run immediately on leavesrc/features/notifications/hooks/use-notification-inbox.ts:221

Captured states

Notification deleted, Notification deleted, tap to undo (iOS)Notification deleted, Notification deleted, tap to undo (Android)
Notification deleted, tap to undo

Notification

Wireframe

Notification

Needs data: Needs an inbox row with detail content

Screen(app)/notifications/detail/[id]

Notification

Rich dashboard-authored notice with hero, HTML body and one CTA

src/app/(app)/notifications/detail/[id].tsx

Entry

  • Inbox row with detail content
  • Deep link

Exits

  • Back → inbox
  • CTA → in-app path or external URL

States · 8

Loading
Loading notification · Query undefinedsrc/app/(app)/notifications/detail/[id].tsx:87
Error
Unable to load notification · Null result: bad id, other user, deleted or admin typesrc/app/(app)/notifications/detail/[id].tsx:108
Success
Loaded with hero image · Image, overlay and white back chevronsrc/app/(app)/notifications/detail/[id].tsx:165
Success
Loaded without image · Compact back button rowsrc/app/(app)/notifications/detail/[id].tsx:182
Edge
New badge · Stays visible after auto mark-as-readsrc/app/(app)/notifications/detail/[id].tsx:245
Edge
Invalid CTA path · Logged and ignoredsrc/app/(app)/notifications/detail/[id].tsx:127
Edge
CTA label fallback · Uses View Details when no actionLabelsrc/app/(app)/notifications/detail/[id].tsx:293
Edge
Plain notification fallback · No rich content: the title falls back to the push title and the body to the push textsrc/app/(app)/notifications/detail/[id].tsx:160

Captured states

Notification, Unable to load notification (iOS)Notification, Unable to load notification (Android)
Unable to load notification
Notification, Loaded with hero image (iOS)Notification, Loaded with hero image (Android)
Loaded with hero image
Notification, Invalid CTA path (iOS)Notification, Invalid CTA path (Android)
Invalid CTA path
Notification, Plain notification fallback (iOS)Notification, Plain notification fallback (Android)
Plain notification fallback

Notification Preferences

Notification Preferences (iOS)Notification Preferences (Android)
Modal(modals)/notification-preferences

Notification Preferences

Toggle push and four notification categories. Categories come from the backend catalog; account messages have no switch.

src/app/(modals)/notification-preferences.tsx

Entry

  • Settings > Preferences

Exits

  • Sign in → auth sheet
  • Open Settings (OS blocked) → system settings
  • Close modal

States · 11

Gate
Sign in to manage preferences · Guestsrc/app/(modals)/notification-preferences.tsx:182
Edge
OS permission refused · Master switch on without OS permission: request fails and the setting is not saved. A warning toast shows only when the denial is not final; a final denial shows the Open Settings bannersrc/app/(modals)/notification-preferences.tsx:105
Success
Push enabled or disabled toast · Master switch saved; toast Push notifications enabled or disabledsrc/app/(modals)/notification-preferences.tsx:123
Error
Could not save preferences · Save failedsrc/app/(modals)/notification-preferences.tsx:132
Edge
Categories off while push off · Hint to enable push first; rows dim to 0.6 and switches disablesrc/app/(modals)/notification-preferences.tsx:306
Edge
Account messages have no switch · Order updates, Loyalty & rewards, Promotions & offers and Expiry reminders map to catalog categories; the account category (service messages) has no switch and cannot be opted out ofsrc/shared/utils/notification-preference-mapping.ts:15
Edge
Preferences affect push only · In-app inbox still shows disabled typespackages/backend/convex/notification/policies.ts
Loading
Loading your preferences · Centered spinner (progressbar role) until the backend answers; no default toggles are shownsrc/app/(modals)/notification-preferences.tsx:193
Edge
Push blocked by the OS · Banner Notifications are blocked with Open Settings (open-settings-button) above the master switchsrc/app/(modals)/notification-preferences.tsx:221
Edge
Toggle opens Settings · Turning push on while the OS will not ask again opens Settings instead of requestingsrc/app/(modals)/notification-preferences.tsx:95
Edge
Other disabled types are kept · Saving a toggle keeps disabled types no toggle owns (account messages, unknown types)src/app/(modals)/notification-preferences.tsx:115

Captured states

Notification Preferences, OS permission refused (Android)
OS permission refused
Notification Preferences, Push enabled or disabled toast (Android)
Push enabled or disabled toast
Notification Preferences, Push blocked by the OS (iOS)Notification Preferences, Push blocked by the OS (Android)
Push blocked by the OS
Notification Preferences, Toggle opens Settings (iOS)Notification Preferences, Toggle opens Settings (Android)
Toggle opens Settings

Push notification tap

Wireframe

Push notification tap

Not reachable on a device: Needs a real push delivery and an OS-level tap

RedirectPushTap

Push notification tap

Maps a tapped OS notification to a screen

src/features/notifications/services/notification-navigation-handler.ts

Entry

  • System notification tap: foreground, background,

Exits

  • Order or payment → order detail or Orders
  • Loyalty, reward, campaign → Loyalty tab
  • Voucher → My Discounts
  • Promo → product or Home
  • System, announcement → Home
  • General, error → inbox

States · 4

Success
Routed to typed screen · deepLink allowlisted, else detail page, else route built from typesrc/features/notifications/services/notification-navigation-handler.ts:275
Edge
Fallback to inbox · General or unknown typesrc/features/notifications/services/notification-routes.ts
Error
Navigation error · Any thrown error lands in inboxsrc/features/notifications/services/notification-service.ts:650
Success
Opens detail page for rich content · A push whose notification has detail content opens /notifications/detail/[id], like an inbox tap. A valid deepLink still winssrc/features/notifications/services/notification-navigation-handler.ts:260

On this page