ChopNow is a portfolio food ordering mobile app built with Expo, React Native, TypeScript, Appwrite, NativeWind, and Zustand. It presents a polished restaurant ordering experience with authentication, menu browsing, product customization, cart management, and profile editing.
This project is a portfolio/demo project. It is not a live commercial food delivery product.
ChopNow includes the core screens expected in a modern food ordering app:
- Authentication screens for sign in and sign up
- Home screen with promotional food offers
- Search screen with menu filtering and keyword search
- Product details screen with ratings, nutrition details, toppings, sides, quantity controls, and add-to-cart flow
- Cart screen with quantity updates, item removal, customizations, discount, delivery fee, and total summary
- Profile screen with editable profile details, avatar upload, and logout flow
- User authentication: Account creation and email/password sign in using Appwrite Auth.
- Appwrite database integration: Menu items, categories, and user profiles are fetched from Appwrite collections.
- Avatar upload: Users can update their profile photo from the device media library using Expo Image Picker and Appwrite Storage.
- Editable profile modal: Profile details can be edited from a slide-up modal with a success confirmation state.
- Food discovery: Users can browse offer categories, filter menu items, and search by keyword.
- Product customization: Product pages support toppings, side options, quantity selection, dynamic pricing, and nutrition display.
- Cart state management: Zustand powers cart operations including add, remove, increase quantity, decrease quantity, clear cart, total items, and total price.
- Toast feedback: Cart actions display lightweight toast messages.
- File-based routing: Expo Router organizes auth, tab, and product detail routes.
- Custom styling system: NativeWind and Tailwind config provide reusable colors, font families, and component utility classes.
- Custom fonts and assets: Quicksand and Rubik font assets are bundled with food imagery and app icons.
- Error monitoring setup: Sentry is configured for mobile error monitoring and replay support.
- Framework: Expo SDK 54, React Native 0.81
- Language: TypeScript
- Routing: Expo Router
- Styling: NativeWind, Tailwind CSS
- Backend as a service: Appwrite Auth, Databases, Storage, Avatars
- State management: Zustand
- Notifications: react-native-toast-message
- Media access: expo-image-picker
- Monitoring: Sentry React Native
- Fonts: Quicksand, Rubik
app/
(auth)/ Sign in and sign up routes
(tabs)/ Home, search, cart, and profile tab screens
product/[id].tsx Product details route
_layout.tsx Root layout, fonts, Sentry, auth bootstrap, Toast
components/
ui/ Shared button, input, header, cart button
cart-item.tsx Cart row and quantity controls
menu-card.tsx Menu grid item
product-details.tsx Product details UI helpers
search-bar.tsx Search input
filter.tsx Category filter chips
constants/
index.ts Images, icons, offers, toppings, sides
lib/
appwrite.ts Appwrite client, auth, profile, menu, storage helpers
useAppwrite.ts Reusable data-fetching hook
seed.ts Appwrite seed utilities
store/
auth.store.ts Authenticated user state
cart.store.ts Cart state and cart calculations
assets/
fonts/ Local font files
icons/ UI icon assets
images/ Food, auth, avatar, success, and app images- Node.js
- npm
- Expo CLI through
npx - Expo Go, Android Emulator, or iOS Simulator
- Appwrite project configured with Auth, Database, Collections, and Storage
npm installCreate a .env file in the project root and add your Appwrite values:
EXPO_PUBLIC_APPWRITE_ENDPOINT=
EXPO_PUBLIC_APPWRITE_PROJECT_ID=
EXPO_PUBLIC_APPWRITE_DATABASE_ID=
EXPO_PUBLIC_APPWRITE_BUCKET_ID=
SENTRY_AUTH_TOKEN=The app expects these Appwrite collection IDs in lib/appwrite.ts:
user
categories
menu
customizations
menu_customizations
cart
ordernpm run startThen choose one of the Expo options:
- Press
afor Android - Press
ifor iOS - Scan the QR code with Expo Go
Other available scripts:
npm run android
npm run ios
npm run web
npm run lintThis project uses Appwrite for:
- Creating users and storing a matching user profile document
- Signing users in with email/password sessions
- Fetching the authenticated user profile
- Fetching categories and menu items
- Fetching a single menu item by ID
- Updating profile fields
- Uploading avatar images to storage
- Saving the uploaded avatar URL on the user document
The user document shape used by the app:
{
accountId: string;
name: string;
email: string;
avatar: string;
phone?: string;
address_home?: string;
address_work?: string;
}Menu documents are expected to include fields such as:
{
name: string;
price: number;
image_url: string;
description: string;
calories: number;
protein: number;
rating: number;
type: string;
categories?: string;
}- A user signs up or signs in.
- The app loads the authenticated user and displays the tab navigation.
- The home screen presents promotional food categories.
- The search screen lets users browse, search, and filter menu items.
- A product can be opened, customized with toppings and sides, and added to cart.
- The cart calculates item totals, discount, and final total.
- The profile screen lets users update account details and avatar.
- This is a demo project.
- Payment and order fulfillment are not connected to a real checkout provider.
- Delivery location and delivery fee are static UI values.
- Sentry is configured in the app; use your own DSN/project settings before publishing.
- Appwrite credentials and Sentry tokens should stay in environment variables and should not be committed.