ProjectR Docs
Screen MapMobile app

Shop & search

Mobile app: every screen, state and flow in Shop & search.

8 screens and overlays, 49 states, 1 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

Browse to product

Step 1
Home (iOS)Home (Android)
Home shows banners, categories and recently viewed
Tap a category card
Step 2
Shop (iOS)Shop (Android)
Shop grid with category chips
Tap a product
Step 3
Product detail (iOS)Product detail (Android)
Product detail opens

Branches and edge cases

Successfrom step 1
Campaign page (iOS)Campaign page (Android)
Banner opens a campaign
Successfrom step 1
Product list (iOS)Product list (Android)
Banner opens a product list
Successfrom step 1
Loyalty (iOS)Loyalty (Android)
Banner opens the Loyalty tab
Edgefrom step 1
Home (iOS)Home (Android)
Banner http link: system browser (no screen)
Edgefrom step 1
Search, Trending Searches fallback (iOS)Search, Trending Searches fallback (Android)
Search pill: recent and trending
Successfrom step 1
Search, Results with sort pills (iOS)Search, Results with sort pills (Android)
Search with results
Emptyfrom step 1
Search, No products found for query (iOS)Search, No products found for query (Android)
Search with no match
Emptyfrom step 2
Shop, No products found (iOS)Shop, No products found (Android)
Filters leave nothing
Edgefrom step 2
Product list, All Products id (iOS)Product list, All Products id (Android)
Product list: tap product
Flow diagram

Screens and states

Shop

Shop (iOS)Shop (Android)
Screen(app)/(tabs)/shop

Shop

All products grid with category chips, filter chips and a local search field

src/app/(app)/(tabs)/shop/index.tsx

Entry

  • Tab bar
  • Home category card
  • Wishlist empty CTA Start shopping
  • Deep link

Exits

  • Product card → product page
  • Heart → wishlist toggle
  • Category chip → refilter in place
  • Filter chips → filter sheets

States · 14

Loading
Initial skeleton grid · Products query undefined with nothing on screensrc/features/product-list/hooks/use-product-list-state.ts:154
Loading
Filtering overlay · Refiltering while products are already shown; spinner over 80% backgroundsrc/features/product-list/components/ui/filtering-overlay.tsx:17
Empty
No products found · No results; "Try adjusting your filters or check back later", chips stay tappablesrc/features/product-list/components/ui/no-results-state.tsx:29
Loading
Loading more footer · Next page of 50 loading; footer reads "Loading more..."src/features/product-list/components/ui/product-loading-footer.tsx:17
Edge
Scroll to top button · Appears after 300 px of scrollsrc/features/product-list/components/product-list-layout.tsx:87
Loading
Category chip skeleton · Five skeleton tiles while collections undefinedsrc/features/product-list/components/composed/category-carousel.tsx:125
Empty
Category row hidden · Zero collectionssrc/features/product-list/components/composed/category-carousel.tsx:143
Edge
Sold out products listed · Grid does not filter availability; image greyed with Sold out overlay, badges hiddensrc/shared/components/product/product-card/hero-image.tsx:102
Error
Error state unreachable · Screen passes error null, so the Failed to load state never renderssrc/app/(app)/(tabs)/shop/index.tsx:109
Error
Render crash fallback · Thrown render error caught by ProductListErrorBoundarysrc/shared/components/error/product-list-error-boundary.tsx:32
Error
Category tab crash · TabErrorBoundary says "The Category tab" and shows raw error messagesrc/shared/components/error/tab-error-boundary.tsx:59
Edge
Local search debounce · 300 ms debounce, separate from global search, saves no recent searchessrc/features/product-list/hooks/use-product-list-state.ts:68
Gate
Signed out heart · Heart opens the sign-in sheetsrc/shared/hooks/use-wishlist-set.ts:124
Offline
Offline skeleton stays · No dedicated offline stateunverified

Captured states

Shop, No products found (iOS)Shop, No products found (Android)
No products found

Product list

Product list (iOS)Product list (Android)
Screen(app)/(tabs)/shop/product-list/[id]

Product list

Category or banner filtered product list that keeps the tab bar

src/app/(app)/(tabs)/shop/product-list/[id].tsx

Entry

  • Home banner of type product list
  • Empty bag Start shopping
  • Deep link

Exits

  • Cancel → Shop tab
  • Product card → product page
  • Filter chips → filter sheets

States · 4

Loading
Same loading and empty as Shop · Skeleton, filtering overlay, pagination and no results match the Shop tabsrc/app/(app)/(tabs)/shop/product-list/[id].tsx:97
Error
Render crash fallback · ProductListErrorBoundary wraps page; no TabErrorBoundary heresrc/app/(app)/(tabs)/shop/product-list/[id].tsx:151
Edge
Title stays after clearing filter · Category is only the initial filter; user can clear it, title stayssrc/app/(app)/(tabs)/shop/product-list/[id].tsx:46
Edge
All Products id · Id "all" is skipped as a filter and shows an unfiltered listsrc/features/product-list/hooks/use-product-list-state.ts:127

Captured states

Product list, All Products id (iOS)Product list, All Products id (Android)
All Products id

Something went wrong

Wireframe

Something went wrong

Not reachable on a device: Needs a render error in Shop

InlineProductListErrorBoundary

Something went wrong

Fallback for product list render errors with retry and navigation

src/shared/components/error/product-list-error-boundary.tsx

Entry

  • Shop tab render error
  • Product list render error

Exits

  • Try Again → retry, up to 3 times
  • Go Back → Shop tab
  • Go to Home → Home

States · 2

Error
Retry limit · Try Again allowed up to 3 retriessrc/shared/components/error/product-list-error-boundary.tsx:32
Edge
Details block gating unverified · Dev style details with retry counter; not confirmed gated on __DEV__src/shared/components/error/product-list-error-boundary.tsx:203

Filter

Filter (iOS)Filter (Android)
SheetMainFilterSheet

Filter

Filter hub with On Sale switch and rows for sort, category and price

src/features/product-list/components/filter-sheets/main-filter-sheet.tsx

Entry

  • Main filter button in chips row

Exits

  • Row tap → sub sheet, hub reopens after
  • Clear all → reset and close
  • Done → apply and close

States · 3

Edge
Price row value · Reads RM min to RM max, or empty when unsetsrc/features/product-list/components/filter-sheets/main-filter-sheet.tsx:73
Edge
Category falls back to All · Selected slug not found in collectionssrc/features/product-list/components/filter-sheets/main-filter-sheet.tsx:83
Edge
Swipe discards draft · Sheets edit a draft and commit only on Donesrc/features/product-list/components/filter-sheets/filter-bottom-sheet.tsx:33

Sort by

Sort by (iOS)Sort by (Android)
SheetSortFilterSheet

Sort by

Radio list of five sort options with reset to default

src/features/product-list/components/filter-sheets/sort-filter-sheet.tsx

Entry

  • Sort chip
  • Filter hub Sort by row

Exits

  • Done → apply sort
  • Swipe → discard

States · 1

Edge
Draft reseeded on open · Selection resets to the applied sort each timesrc/features/product-list/components/filter-sheets/sort-filter-sheet.tsx:30

Category

Category (iOS)Category (Android)
SheetEnhancedCategoryFilterSheet

Category

Radio list of All Categories plus every collection

src/features/product-list/components/filter-sheets/enhanced-category-filter-sheet.tsx

Entry

  • Category chip
  • Filter hub Category row

Exits

  • Done → apply category
  • Swipe → discard

States · 2

Loading
Collections spinner · Spinner while collections loadsrc/features/product-list/components/filter-sheets/enhanced-category-filter-sheet.tsx:72
Empty
No collections · No empty copy; only All Categories is listedsrc/features/product-list/components/filter-sheets/enhanced-category-filter-sheet.tsx:78

Price Range

Price Range (iOS)Price Range (Android)
SheetPriceFilterSheet

Price Range

Dual thumb slider between backend price bounds with RM readout

src/features/product-list/components/filter-sheets/price-filter-sheet.tsx

Entry

  • Price chip
  • Filter hub Price row

Exits

  • Done → apply range
  • Swipe → discard

States · 3

Edge
Default bounds · Range 0 to 2000 when backend bounds are unknownsrc/features/product-list/hooks/use-product-list-state.ts:247
Edge
Bounds update after load · A loading gap does not reset the slider boundssrc/features/product-list/hooks/use-product-list-state.ts:228
Edge
Bound stored only if changed · Apply keeps a bound only when it differs from the range endsrc/features/product-list/components/filter-sheets/price-filter-sheet.tsx:223

On this page