SMACKZ Mobile App
SMACKZ-MOBILE is the customer-facing mobile application for ordering food from SMACKZ restaurants. It is a React Native CLI (bare workflow) app targeting both iOS and Android.
Tech Stack
| Component | Technology |
|---|---|
| Framework | React Native CLI (bare, not Expo) |
| Language | TypeScript |
| State | Zustand (local state), React Query (server state) |
| Auth | Firebase Phone Auth (@react-native-firebase/auth) |
| Navigation | React Navigation |
Authentication
Mobile users authenticate exclusively via phone OTP:
- User enters their phone number
- Firebase sends an OTP via SMS (or uses a pre-configured test number)
- User enters the 6-digit code
- Firebase returns an ID token
- The app calls
POST /auth/login/mobile/:restaurantIdwith the token - If the user is new, they complete a registration form (first name, last name, optional email)
Test phone numbers bypass real SMS delivery but use the exact same auth flow, so there are no separate "fake login" code paths.
Multi-Restaurant Support
A single phone number can be registered with multiple restaurants. The backend uses base62-encoded Firebase custom claims (m claim) to track restaurant memberships. When a user opens a restaurant's app, the auth flow scopes them to that specific restaurant.
Key Features
- Phone-based authentication with OTP
- Restaurant-specific branding and themes
- Menu browsing with search
- Cart management with serving size selection
- Checkout (pickup or delivery, scheduled or ASAP, offer application)
- Order placement and real-time status tracking
- Order history
- Loyalty points and offers
- Dynamic page rendering (shares logic with web via shared packages)
- Push notifications via Firebase Cloud Messaging (see Notifications)
Checkout
Checkout integrates order type (pickup / delivery), optional time scheduling, address selection, offer application, and payment.
Flow: CartScreen → CheckoutScreen (modal) with pickup/delivery toggle → conditional PickupScheduler or DeliveryAddressSection → OfferSection → OrderSummary → PLACE ORDER (POST /checkout) → PaymentWebViewScreen. The WebView listens for completed / failed / cancelled postMessages from the payment page.
Dining options are read from the active location (not the restaurant) following the 2026-04 location-scoped settings migration. The canonical key is pickup (the legacy takeAway alias was removed).
Payment URL: ${PAYMENT_URL}/?orderId=...&userId=...&restaurantId=...&token=...&theme=... (Cloudflare Pages, theme light or dark). On success the cart is cleared, checkout state is reset, and the app navigates to the Orders tab.
| Component | Purpose |
|---|---|
OrderTypeToggle |
Pickup/delivery switch |
PickupScheduler |
Date chips + 30-min time slots |
DeliveryAddressSection + AddAddressSheet |
Address picker + add modal |
OfferSection |
Apply available offer |
OrderSummary |
Live recompute: subtotal − discount + tax + deliveryFee |
PaymentWebViewScreen |
Hosted payment page in a WebView |
Hooks: usePickupAvailability(timeZone), useAddresses(), useCreateAddress(), useCheckout(). Store: Zustand checkoutStore (orderType, selectedAddress, selectedOffer, selectedPickupTime, specialInstructions).
See SMACKZ-MOBILE/docs/Checkout-Implementation.md for the full spec.
Build & Release
Environment variables read at build time via react-native-config from .env: APP_ENV, RESTAURANT_ID, FIREBASE_ENV, GOOGLE_MAPS_API_KEY.
| Platform | Dev | Release |
|---|---|---|
| iOS | npm run ios (simulator), npm run ios -- --device |
Xcode Archive → Distribute → App Store Connect. Bump CFBundleVersion (every upload) + CFBundleShortVersionString (releases) in Info.plist. Swap GoogleService-Info.plist for the target Firebase env. |
| Android | npm run android |
./gradlew assembleRelease (APK) or ./gradlew bundleRelease (AAB for Play Store). Bump versionCode (every upload) + versionName in build.gradle. |
Metro: npm start, or npx react-native start --reset-cache after Babel changes.
A scripted release helper exists at scripts/prepare-release.sh — it prompts for platform, bumps versions, clears caches, cleans builds, and reinstalls Pods (iOS) or bundles AAB (Android).
Staging ships as a separate app with bundle IDs smackz-mobile.stg.co.smackz (iOS) and smackzmobile.stg.co.smackz (Android), against Firebase project smackz-platform-staging. Swap Firebase configs and verify Info.plist reversed client ID + GMSApiKey per environment.
Session Management
- Firebase ID tokens expire after approximately 1 hour
- On 401 responses, an Axios interceptor refreshes the token via
POST /auth/refresh - Tokens and user data are persisted in secure storage via Zustand
- If refresh fails, the user is redirected to the login screen
Branch Convention
Uses qa / staging / main branches. All development commits go to qa.
Key Files
SMACKZ-MOBILE/docs/Auth-Implementation.md-- Detailed auth PRD and technical specSMACKZ-MOBILE/docs/Checkout-Implementation.md-- Checkout flow, hooks, and componentsSMACKZ-MOBILE/docs/build.md-- Build, environment, and release processdocs/Auth-System.md-- Cross-project auth overview