A mobile application that connects users with restaurants to rescue surplus food at discounted prices, reducing food waste while saving money.
Backend Repository: Lefty Backend - Express.js API server
Lefty is a cross-platform mobile app built with Expo and React Native that enables:
- Users: Discover nearby discounted meals from restaurants
- Merchants: List surplus meals with special pricing
- Framework: Expo (React Native)
- Language: TypeScript
- State Management: React Context API
- Navigation: React Navigation
- UI: Native Components + Custom Styling
- Image Upload: Direct AWS S3 Upload
- Maps: Leaflet (Web), React Native Maps (Native)
- Auth: JWT + Secure Storage
- Node.js 18+ and npm/yarn
- Expo CLI:
npm install -g expo-cli - iOS Simulator (Mac) or Android Emulator
- Expo Go App (for mobile testing)
# Navigate to frontend directory
cd lefty-app
# Install dependencies
npm install
# or with yarn
yarn installCreate a .env file in the lefty-app directory:
EXPO_PUBLIC_API_URL=http://localhost:3000
EXPO_PUBLIC_AWS_ACCESS_KEY_ID=your_aws_key
EXPO_PUBLIC_AWS_SECRET_ACCESS_KEY=your_aws_secret
EXPO_PUBLIC_AWS_REGION=ap-southeast-2
EXPO_PUBLIC_AWS_S3_BUCKET=lefty-mealbox-images# Start Expo development server
npm start
# or
expo startThis will display options to:
- Press
ifor iOS simulator - Press
afor Android emulator - Scan QR code with Expo Go app on physical device
# Build for iOS
expo build:ios
# Build for Android
expo build:androidnpm start
# Then press 'w' in the terminallefty-app/
├── src/
│ ├── screens/ # Screen components
│ │ ├── SplashScreen.tsx # App welcome screen
│ │ ├── Login.tsx # User login
│ │ ├── Register.tsx # User registration
│ │ ├── HomeTabsScreen.tsx # Main user navigation
│ │ ├── MapScreen.native.tsx # Map view (mobile)
│ │ ├── MapScreen.web.tsx # Map view (web)
│ │ ├── ProductScreen.tsx # Product details
│ │ ├── SetUpMerchant.tsx # Merchant profile setup
│ │ ├── MerchantDashboard.tsx # Merchant product listing
│ │ └── ProductForm.tsx # Add/edit products
│ ├── components/ # Reusable components
│ ├── contexts/ # React Context
│ │ └── auth-context.tsx # Authentication context
│ ├── api/ # API client & methods
│ │ ├── client.ts # Axios instance
│ │ └── merchant.ts # Merchant API
│ ├── services/ # Business logic
│ │ └── s3.service.ts # AWS S3 upload
│ └── assets/ # Images, fonts, etc.
├── app.json # Expo configuration
├── package.json
└── tsconfig.json
Launch screen with app branding, features overview, and call-to-action button.
File: src/screens/SplashScreen.tsx
Interactive map showing nearby restaurants with available discounted meals. Users can:
- View merchants on map
- See meal details and pricing
- Filter by category
- Place orders
Files:
- Mobile:
src/screens/MapScreen.native.tsx - Web:
src/screens/MapScreen.web.tsx
Form for merchants to add new discounted meal listings with:
- Image upload to AWS S3
- Product details (name, description, prices)
- Quantity and pickup times
- Real-time validation
- Success/error feedback modals
File: src/screens/ProductForm.tsx
Management interface for merchants to view and manage their listed meals:
- Display all active products
- Show current pricing and quantity
- Edit or delete products
- View order status
File: src/screens/MerchantDashboard.tsx
The app uses JWT-based authentication with secure token storage:
// Login
await signIn(email, password);
// Register
await signUp({ name, email, password, role: 'user' | 'merchant' });
// Token stored in:
// - SecureStore (iOS/Android)
// - localStorage (Web)Images are uploaded directly to AWS S3 from the frontend:
- User selects image via image picker
- Frontend generates unique S3 key
- Direct PUT upload to S3 bucket
- Returns public S3 URL
- URL stored in database
import { uploadImageToS3 } from '@/services/s3.service';
const imageUrl = await uploadImageToS3(selectedImage, merchantId);The app communicates with backend API at EXPO_PUBLIC_API_URL:
POST /auth/register- User registrationPOST /auth/login- User loginPOST /merchants/setup- Merchant profile setupPOST /merchants/mealboxes- Create meal listingPUT /merchants/mealboxes- Update meal listingGET /merchants/mealboxes/:id- Get merchant's mealsGET /merchants/me- Get current merchant profile
Changes to TypeScript/JSX files automatically reload in development mode. No need to restart the server.
# Open Expo DevTools
# Press 'j' in terminal for JavaScript debugger
# Press 'd' for Expo DevTools menuUse platform-specific file extensions:
FileName.native.tsx- iOS/Android onlyFileName.web.tsx- Web onlyFileName.tsx- Both
# Kill process on port 3000
lsof -ti:3000 | xargs kill -9npm start -- --clear
# or
expo start --clear# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install- Images are optimized before upload to S3
- List virtualization for large product lists
- Lazy loading of screens
- Efficient re-renders with React.memo
- Sensitive data stored in SecureStore (native) or localStorage (web)
- JWT tokens included in API headers
- Direct S3 upload with temporary signed URLs
- CORS-enabled S3 bucket for public access
- No API keys exposed in frontend code
- iOS: iOS 13.4+
- Android: Android 5.0+
- Web: Modern browsers (Chrome, Safari, Firefox, Edge)
- Create feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open Pull Request
- Infrastructure: Docker Compose setup for local development
For issues or questions, please open an issue in the repository.
MIT License - See LICENSE file for details



