A comprehensive React Native app built with Expo to help users quit or reduce sugar intake through a structured 90-day program, craving tracking, and AI-powered coaching.
- 90-Day Sugar Reset Program: Structured phases (detox, rebalance, sustain)
- Craving Log: Track triggers, intensity, and outcomes with optimistic updates
- Food Scanner: Barcode scanning and photo classification with AI swap suggestions
- Healthy Recipes: Searchable recipe database with nutrition info
- Insights Dashboard: Streak tracking, craving heatmaps, and weekly AI coaching
- Local Notifications: Smart scheduling with quiet hours
- Developer Tools: Mock API configuration and request monitoring
- Framework: Expo Managed Workflow (React Native)
- Language: TypeScript
- Routing: expo-router
- State Management: Zustand
- Data Fetching: React Query
- Styling: NativeWind (Tailwind CSS)
- Forms: Formik + Zod validation
- Database: SQLite with expo-sqlite
- Storage: expo-secure-store
- Camera: expo-camera + expo-barcode-scanner
- Charts: victory-native + react-native-svg
- Notifications: expo-notifications (local only)
- Testing: jest-expo + @testing-library/react-native
- Node.js 18+
- Expo CLI:
npm install -g @expo/cli - iOS Simulator (Mac) or Android Emulator
# Clone and install
git clone <repository-url>
cd BetterU
npm install
# Start development server
npm start
# Run on specific platform
npm run ios
npm run android
npm run webThe app will automatically:
- Initialize SQLite database
- Load seed data (recipes, program days, nutrition items)
- Navigate to onboarding for new users
app/ # Expo Router pages
โโโ (tabs)/ # Main tab navigation
โโโ onboarding/ # User onboarding flow
โโโ dev/ # Developer tools
โโโ scan/ # Camera scanning results
โโโ recipes/ # Recipe details
โโโ cravings/ # Craving log forms
src/
โโโ api/ # API client and mock handlers
โ โโโ mock/handlers/ # Mock API responses
โ โโโ ApiClient.ts # Main API client with error simulation
โ โโโ endpoints.ts # API endpoint constants
โโโ store/ # Zustand state management
โโโ lib/ # Utilities and database
โ โโโ db/ # SQLite schema and seeds
โ โโโ notifications.ts
โ โโโ storage.ts
โโโ features/ # Feature-specific components
โโโ assets/seed/ # JSON seed data
โโโ types/ # TypeScript definitions
โโโ tests/ # Unit and integration tests
The app uses a mock API system for Phase 1. Configure via Developer Tools or app.json:
{
"expo": {
"extra": {
"USE_MOCK_API": true,
"MOCK_FAIL_RATE": 0.05,
"MOCK_TIMEOUT_RATE": 0.05
}
}
}Navigate to Settings โ Developer Tools to:
- Toggle mock API on/off
- Adjust error simulation rates
- Reset seed data
- View API request logs (last 20 requests)
UI Component โ React Query โ ApiClient โ Mock Handlers โ Local Response
โ
Zustand Store โ SQLite Database
- Artificial Latency: 350-700ms delays
- Error Simulation: Configurable fail/timeout rates
- Request Logging: Track all API calls for debugging
- Optimistic Updates: Immediate UI updates with rollback on failure
# Unit tests
npm test
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverage- Unit Tests: Zustand stores, utilities, mock API behaviors
- Integration Tests: Onboarding flow, craving log, barcode scanning
- Mocked Dependencies: All Expo modules and external libraries
- Goal selection (quit vs reduce sugar)
- Dietary restrictions
- Craving trigger times
- Profile creation via mock API
- Navigation to main app
- View current day's challenge
- Complete micro-tasks
- Track streak progress
- Handle relapses gracefully
- Log craving with trigger/intensity
- Record outcome (resisted/consumed/swapped)
- Optimistic UI updates
- Rollback on API failure
- Camera permission request
- Barcode scan or photo capture
- Mock nutrition analysis
- AI-generated healthy swaps
- Detailed nutrition comparison
The app is designed for easy backend integration:
// Switch from mock to real API
apiClient.updateConfig({ useMockApi: false });
// Real API implementation
async makeRequest(method, endpoint, data) {
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
method,
headers: { 'Authorization': `Bearer ${token}` },
body: JSON.stringify(data)
});
return response.json();
}- SQLite remains for offline capability
- Add sync mechanisms for server backup
- Implement conflict resolution
- Add auth screens and flows
- Integrate with backend auth system
- Secure token management
"You are BetterU Coach. Be supportive, concise, action-first. Never shame. Suggest hydration, fiber, protein, movement, mindful craving pauses. Prefer affordable, local foods. Keep responses short. If mention health symptoms, add a brief non-medical disclaimer."
"Generate 3 snacks + 2 drinks low-added-sugar. Include ingredients, <=4 steps, macros (kcal, protein, sugar, fiber), and a one-line reason why it satisfies the craving. Keep โค260 tokens."
"Return 5 bullet insights, a <=60 word motivational paragraph, and 1 small behavior challenge. Reframe lapses as learning."
Camera not working
- Check permissions in device settings
- Restart Expo development server
- Clear Expo cache:
expo r -c
SQLite errors
- Reset app data via Developer Tools
- Check seed data format in
src/assets/seed/
Mock API not responding
- Verify
USE_MOCK_API: truein config - Check Developer Tools for request logs
- Ensure mock handlers exist for endpoints
Enable detailed logging:
// In ApiClient.ts
console.log('API Request:', method, endpoint, data);
console.log('API Response:', response);MIT License - see LICENSE file for details.
- Fork the repository
- 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
- Follow TypeScript strict mode
- Use provided ESLint configuration
- Write tests for new features
- Keep functions under 3 parameters
- Use object parameters for complex functions
- Maintain mock API compatibility
BetterU - Empowering healthier choices, one day at a time. ๐