Back To All Projects
Mobile AppYeti Restaurant (Davis, CA)

Yeti Restaurant - Mobile Food Ordering App (iOS & Android)

A cross-platform mobile food ordering application for Yeti Restaurant in Davis, CA, built with Expo SDK 56, Expo Router, React Native, and TanStack Query. Features dynamic menu modifiers, offline query persistence, address autofill, timezone-aware order scheduling, and seamless payment checkout.

Yeti Restaurant - Mobile Food Ordering App (iOS & Android)
React NativeExpo SDK 56Expo RouterTypeScriptTanStack QueryExpo FileSystemReanimated 4AsyncStorageReact Native Safe Area ContextREST API

Building a Native Mobile Food Ordering App for Yeti Restaurant

Mobile food ordering apps require a level of responsiveness and friction-free interaction that standard mobile web browsers simply cannot deliver.

When ordering authentic Nepalese and Indian cuisine from Yeti Restaurant in Davis, CA, customers expect instant menu navigation, seamless dish customization (such as spice preferences and optional add-ons), address autofill, order scheduling, and clear status updates—all without mandatory account registration walls.

To solve this, I designed and built a native mobile application using React Native, Expo SDK 56, Expo Router, and TanStack Query. The app delivers a high-performance offline-first experience, native gesture-driven bottom sheets, localized address management, and a robust timezone-aware order scheduling system.

The application is currently live and published on the Apple App Store (iOS) for Yeti Restaurant in Davis, California. The application codebase is also fully compatible with Android, though it has not yet been published to the Google Play Store.

Yeti Restaurant Mobile App Menu Screen


Technical Highlights & Architecture

  • Expo SDK 56 & Expo Router: Modern file-based navigation architecture with typed routes, enabling seamless tab transitions, modal sheets, and deep-linkable order detail screens.
  • Offline-First Storage Engine: Custom React Query persister built on top of expo-file-system, allowing full menu caching and instant cold starts even with low or absent mobile connectivity.
  • Timezone-Aware Schedule Engine: Custom operational hours calculator enforcing America/Los_Angeles timezone logic, 15-minute slot generation, ASAP fallback, and weekly closure enforcement.
  • Frictionless Local Autofill: Zero-registration guest checkout powered by local device file storage (autofill_data.json), persisting contact details and delivery addresses.
  • Anonymous Device Order Tracking: Unique persistent device GUID generated and retained across sessions to track historical orders without requiring traditional user accounts.
  • Responsive Layout Stability: Dynamic font-scale capping (maxFontSizeMultiplier) preventing UI element distortion or overflow when OS accessibility font scaling is enabled.

Modeling Dynamic Menu Items & Modifiers

Restaurant dishes are highly customizable. A single curry or momo order often requires mandatory selections (e.g., Spice Level) and optional add-ons (e.g., Extra Chutney or Naan Bread) that directly alter the final price.

[ Chicken Tikka Masala ]
   ├── Spice Level (Required, Max 1)
   │     ├── Mild
   │     ├── Medium ($0.00)
   │     ├── Hot ($0.00)
   │     └── Extra Hot ($0.00)
   └── Choice of Protein / Add-ons (Optional)
         ├── Extra Garlic Naan (+$3.50)
         └── Extra Basmati Rice (+$2.50)

In the mobile app, dishes and modifier groups are parsed from the backend API into strongly typed structures.

When a customer selects an item, an interactive bottom sheet opens using react-native-reanimated. The sheet enforces modifier rules in real time:

  • Required Groups: The “Add to Cart” button remains disabled until all mandatory modifier categories (e.g., Spice Level) are selected.
  • Selection Limits: Prevents selecting more than the maximum permitted items per group.
  • Dynamic Pricing: Calculates total item cost live as add-ons are toggled on or off.
export type ProductModifier = {
  id: string;
  name: string;
  is_required: string;
  limit: string;
  items: ProductModifierItem[];
};

This guarantees client-side data integrity before items enter the cart payload.


Timezone-Aware Order Scheduling

Yeti Restaurant operates on specific daily schedules in Davis, California (Pacific Time Zone), and is closed on Mondays. Mobile devices placing orders could be set to any local system timezone or device clock.

To eliminate scheduling errors, the app includes a dedicated schedule validation engine that forces calculations into America/Los_Angeles time:

+-------------------------------------------------------------------------+
| Schedule Mode | Availability Criteria                                   |
+-------------------------------------------------------------------------+
| ASAP          | Available during active operating hours (11:30 AM-9:30 PM)|
| Today         | Generates 15-min intervals up to closing (21:30)        |
| Later         | Future operating days (skips Monday closed days)        |
+-------------------------------------------------------------------------+

Scheduling Logic Highlights:

  1. ASAP Mode: Enabled only when current Pacific Time falls between store opening (11:30 AM) and store closing (9:30 PM).
  2. Today Mode: Generates 15-minute incremental time slots starting from either the current time snapped to the next 15-minute mark (if open) or opening time (if ordered before store hours).
  3. Closing Day Safeguard: Automatically blocks ordering if the selected date falls on a configured closing day (Mondays).

Offline-First Data Architecture & Persistence

To ensure fast load times and a resilient user experience on mobile networks, the application implements an offline-first caching layer using TanStack React Query paired with expo-file-system v56.

[ App Launch ]

      ├───> Read Cached Query Snapshot (expo-file-system document storage)
      │        └── Instant Render of Categories & Menu Items (0ms delay)

      └───> NetInfo & AppState Event Listeners
               └── Background Refetch from API (yetirestaurants.com/api)

Key Implementation Details:

  • FileSystem Storage Adapter: Custom persister serializes React Query cache into JSON files using Expo’s FileSystem API (Paths.document), avoiding native bridge overhead.
  • Network Reconnection Handling: Listens to @react-native-community/netinfo state updates to trigger refetchOnReconnect when the user regains internet service.
  • AppState Focus Refetching: Uses React Native’s AppState listener to re-validate store hours and active promotions whenever the app returns to the foreground.

Frictionless Address Management & Local Autofill

Requiring users to create accounts before placing a food order causes high cart abandonment. The Yeti Restaurant mobile app bypasses login screens entirely while maintaining user convenience.

Customer profiles (Name, Phone, Email) and delivery addresses are persisted on the local device using a specialized autofillContext:

[ Local Device Storage: autofill_data.json ]
   ├── Saved Profile (First Name, Last Name, Email, Phone)
   └── Saved Addresses [
         ├── Home (Street, Apt, City, State, Zip)
         └── Work (Street, Apt, City, State, Zip)
       ]

When checking out:

  • Contact information automatically populates input fields.
  • Tapping a saved delivery address pre-fills street address, apartment details, and zip code.
  • Addresses can be added, updated, or removed at any time through a dedicated sheet interface.

Anonymous Device-Tied Order History

Since users do not log into traditional accounts, order history must still be tracked securely so customers can view past receipts and active order statuses.

The application generates a persistent, unique Device GUID stored locally on the device file system:

// Persistent device identifier generation
export async function getOrCreateDeviceId(): Promise<string> {
  const file = new File(Paths.document, 'device_id.txt');
  if (file.exists) {
    const existing = await file.text();
    if (existing.trim()) return existing.trim();
  }
  const newId =
    'dev_' +
    Math.random().toString(36).substring(2, 15) +
    Date.now().toString(36);
  file.write(newId);
  return newId;
}

When an order is submitted, the deviceId is attached to the payload. When opening the Order History tab, the app fetches all past transactions linked to that device ID, providing a complete receipt history with status tracking without asking the user for a password.


Cross-Platform UI & Typography Stability

On mobile platforms (especially iOS and Android), users can adjust system accessibility font sizes. Standard React Native layouts can break or experience text clipping when font scales become too large.

To preserve the visual design while maintaining accessibility, the app enforces a font scale cap across all global Text and TextInput primitives:

const FONT_SCALE_CAP = 1.3;
for (const Component of [Text, TextInput] as unknown as ScalableComponent[]) {
  Component.defaultProps = Component.defaultProps || {};
  Component.defaultProps.maxFontSizeMultiplier = FONT_SCALE_CAP;
}

This ensures fixed-height action buttons, tab headers, and card rows maintain clean alignment across diverse device sizes.


Live App Store & Platform Availability

The mobile app was built, tested, and published using Expo Application Services (EAS Build & Submit).

  • App Name: Yeti Restaurant Davis, CA
  • Bundle ID: com.bhagwan99.yetirestaurant
  • iOS Platform: Live and published on the Apple App Store
  • Android Platform: Fully compatible cross-platform build (Expo SDK 56) — Not yet published on the Google Play Store
  • Location: Davis, CA 95616

Project Showcase Gallery

Click any screenshot to launch the full-screen interactive lightbox viewer

Home & Menu Exploration
Enlarge

Home & Menu Exploration

Browse Himalayan, Nepalese, and Indian dishes with category filtering, search, and live operating status.

Dish Customization & Modifiers
Enlarge

Dish Customization & Modifiers

Interactive bottom sheet for configuring spice levels, required selections, add-ons, and special instructions.

Cart & Price Calculation
Enlarge

Cart & Price Calculation

Real-time cart validation, pickup vs delivery mode, discount calculation, and modifier summary.

Timezone-Aware Order Scheduling
Enlarge

Timezone-Aware Order Scheduling

ASAP, Today, or Later time slot selection enforcing store operating hours in Pacific Time.

Seamless Guest Checkout
Enlarge

Seamless Guest Checkout

Zero-registration checkout with saved address autofill, custom tips, and fast order placement.

Saved Addresses & Profile Autofill
Enlarge

Saved Addresses & Profile Autofill

Manage saved delivery addresses and contact information locally without mandatory logins.

Anonymous Device Order History
Enlarge

Anonymous Device Order History

Device-tied persistent order tracking with detailed receipt breakdown and historical status updates.

Live Order Detail & Receipt
Enlarge

Live Order Detail & Receipt

View order status, store contact info, receipt breakdown, and fulfillment schedule.

Exclusive Deals & Special Offers
Enlarge

Exclusive Deals & Special Offers

Browse current discounts, promotional vouchers, and special restaurant meal deals.