Customer
Browse, cart, checkout, orders, account
Login Page
Page renders role indicator defaulting to "Customer" and shows mobile + password fields
Submitting with role=dealer in URL logs in as dealer successfully
Submit is blocked and validation error shown when mobile contains non-digit characters
Submit is blocked and validation error shown when mobile is fewer than 10 digits
Submit is blocked and validation error shown when password is too short
Error toast is displayed when login fails (wrong credentials)
Registration
Registration page renders with role defaulting to Customer
Referral mobile field is pre-filled and disabled when dealerref is present in URL
Valid customer registration submits successfully
Dealer registration redirects to the returned payment link
Supplier registration redirects to the returned payment link
Toast shown when supplier registration succeeds but no payment link is returned
Registration Pending
Registration pending page shows neutral status message and link back to login
Page does not crash when no query params are present
Forgot Password
Full forgot-password flow: request OTP → verify OTP → reset password
Auth Session & Cache
Login sets role and authenticated flag in store
Logout clears all auth state and React Query cache
Login as a NEW user clears cached data from previous session
Login as the SAME user (token refresh) preserves existing cache
Cross-tab login as different user triggers cache clear via storage event
Validation Schemas
Login schema accepts valid 10-digit mobile and min-length password
Login schema rejects mobile shorter than 10 digits
Login schema rejects password shorter than minimum length
Customer register schema accepts a valid complete registration
Customer register schema rejects missing required fields
Forgot password schema requires mobile + userType
OTP schema requires exactly 6 digits
Reset password schema requires passwords to match
Captcha (Turnstile)
Captcha token is empty on initial load
Setting token updates captcha state
Reset clears token and forces captcha re-render
Category Listing
Categories display correctly from API response
Empty/null/non-array API response returns empty category list
Category name falls back through text → categoryName → name → title → "Category N"
Product Listing & Price
Product list shows mrpPrice — no discount subtraction (dealer commission stays hidden)
No strikethrough price shown for customer (no customer discount)
All in-stock measurements/variants from API are displayed
Single variant synthesised correctly when API returns only one measurement
Variants are undefined when API returns no measurement data
Product detail page loads variants and gallery images from detail endpoint
Numeric measurement names (MySQL int) accepted without error
Seller Info
Seller card built from supplierDetails without duplicate address parts
"No return window" shown when seller has disabled returns
Cart Page
Loading spinner shown when cart is empty and data is loading
Empty state message shown when cart has no items
Cart items and order summary rendered when cart has entries
Checkout as unauthenticated user opens role-selection modal
Authenticated user goes directly to checkout without modal
Cart syncs with server on page load
Cart Item Behaviour
Adding a new product creates a new cart line
Adding same product+variant again increases quantity on existing line
Adding same product with different variant creates a separate line
Quantity capped at product stock maximum
Quantity below 1 is normalised to 1
Removing an item deletes it from the cart list
Removing unknown item ID does nothing (no-op)
Updating quantity changes line to target amount
Updating quantity above max caps at max
Clear cart empties all items
Pricing
Server-synced cart line uses server pricing
Unsynced (guest) cart line uses provisional GST split
Empty cart totals are all zero
Free-shipping items don't add shipping charge to total
Mixed paid + free-shipping lines totalled correctly
GST defaults to 18% when GST info absent from API
Place Order
Valid order placed successfully via /shop/checkout
Redirected to payment gateway when payment required
Callback URL returned as paymentLink when wallet covers full amount
Store pickup fields sent correctly when storeType=1
Network/API errors surface to the user
Successful order invalidates wallet balance and orders cache
Order List
Customer order list loads from /customer/orders with status filter
Empty order list shows empty state
Various API response shapes (tuple, envelope) all parsed correctly
Order Detail
Order detail loads and displays correctly
Order detail disabled when no orderId provided
Order detail returns null for missing/null data
Invoice URL retrieved for completed order
Invoice URL returns null when no URL field in response
Order Actions
Customer can cancel an order
Customer can raise a return request
Customer can cancel a return request
Order tracking loads timeline for given orderUUID
Tracking returns empty list when tracking data missing
Payment Status Page
Success state shown correctly when status=success
Pending/generic state shown when status param is missing
Failure state shown when status is not "success"
Custom message from query param overrides default copy
"Go to Login" link points to /login
Profile Schema Validation
Valid dealer profile accepted by schema
Missing first name rejected
Invalid email format rejected
Zipcode rejected if not exactly 6 digits
Zipcode with non-digit characters rejected
Blank Aadhaar number rejected
Aadhaar with wrong digit count rejected
Aadhaar with spaces (auto-cleaned) accepted
Blank PAN rejected
Valid PAN format (e.g. ABCDE1234F) accepted
Invalid PAN format rejected
Gender must be M / F / T for non-supplier role
Profile Actions
Profile loads with correct role data
Updating profile invalidates cache and reloads
Profile photo upload updates user record on success
Profile photo upload skips update when server returns no photo URL
Occupation, state, firm lookup lists load correctly
Change Password
Customer password changed via customer endpoint
New password matching old password rejected
Success message returned from server displayed
Default success message shown when server returns no message
Wallet Logs & Balance
Wallet transaction logs load correctly for customer
Wallet balance displayed correctly
Wallet balance shown from user record when logs are empty
Empty state shown when log API returns empty array
Error state + retry button shown when logs fetch fails
Balance returns 0 when walletAmt field missing from response
Wallet Table (Customer)
Wallet table shows: Order ID, Description, Sale Amount, Txn Charges, Net Amount, Balance, Date
Txn Charges cell highlighted in red when charges > 0
Txn Charges cell muted when charges = 0
Net Amount column labelled "Amount" for customer role
Clicking Order ID in ledger opens Order Details modal
Wallet Stats
Wallet stats show total spent + refunds + order count
Stats show zeros for empty wallet log
Mobile Card & Expanded Row
Mobile wallet card shows Txn Charges, Final Balance, Sale Amount, Date
Expanding row shows Txn Charges + Full Description + Exact Timestamp
Full Description row hidden when description is empty
"View Extra Details" toggles to "Hide Extra Details" on expand
Customer mobile card shows no commission info buttons
Withdrawal Service
Customer withdrawal list loads from /customer/withdrawals
Customer withdrawal request submitted to /customer/withdrawal-request
"Not found" / "no data" / "empty" API errors return empty list (no crash)
Auth/server errors are propagated (not swallowed)
Bank Management
Public bank list loads and is cached locally
Cached bank list returned without additional network call
Corrupt cache is ignored and data refetched
Customer bank accounts loaded from customer endpoint
IFSC code uppercased, primary flag coerced correctly
Map & Geocoding
Light tile served by default, dark tile in dark mode
@2x tile requested only on high-density screens
Reverse geocode builds readable address from OSM tags
Reverse geocode returns null when location carries no address
Reverse geocode returns null instead of crashing on network failure
Place search returns empty list on network failure (no crash)
IP location returns coordinates on success
IP location rejected for unroutable IP (success-false body)
Each geocoding call has a timeout (hung third-party can't block checkout)
Wishlist Store
Product added to wishlist successfully
Adding same product twice does not duplicate it
Product removed from wishlist by ID
Toggle adds product if absent, removes if present
Clear wishlist empties entire list
Wishlist persisted to localStorage for guest users
Wishlist storage key scoped to user ID after login
Contact & Site Info
Valid contact form submission accepted
Contact form rejected when name is too short
Contact form rejected when message is under 10 characters
Site info (call centre details) fetched and cached
Site info not re-fetched when already cached