SolYield Mobile is a React Native app for solar field technicians to manage their daily work. Think of it as a digital toolbox that fits in their pocket:
- Schedule their day - See which solar sites they need to visit and when
- Check in at sites - Uses GPS to prove they actually visited the location
- Fill out inspection forms - Document what they found (with photos!)
- Generate reports - Create PDF reports on energy performance
- Work offline - All of this works without internet, then syncs when back online
The app is built for technicians who might be in remote areas with spotty cell service - the data they collect stays safe on their phone until they have a connection again.
| Category | Technology |
|---|---|
| Framework | React Native with Expo SDK 54 |
| Language | TypeScript (Strict Mode) |
| State Management | WatermelonDB (Single source of truth) |
| Navigation | Expo Router (File-based routing) |
| UI Framework | Material 3 + Material You + NativeWind |
| Offline Database | WatermelonDB |
| Maps | react-native-maps |
| Maps Note |
β οΈ Note on Maps: The app is configured to usereact-native-maps, but full testing on Android requires a Google Maps API key with billing enabled. To enable full map functionality:
- Create a Google Cloud project with billing enabled
- Enable the Maps SDK for Android
- Generate an API key and add it to
app.json| Charts | react-native-gifted-charts | | PDF Generation | expo-print | | Calendar | expo-calendar | | Location Services | expo-location | | Camera | expo-camera |
The application follows strict modular architecture principles:
- Separation of Concerns: UI components are isolated from business logic
- Single Responsibility: Each module serves one clear purpose
- Dependency Direction: UI depends on business logic, not vice versa
- Pure Functions: Utilities are stateless and fully testable
- Hook Abstraction: Database complexity hidden behind custom hooks
- Offline-First: All data operations work without network connectivity
βββββββββββββββββββββββββββββββββββββββββββ
β UI Layer (Presentation) β
β - Components (React) β
β - Screens (Pages) β
β - Styling (NativeWind + M3 Tokens) β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β uses
βββββββββββββββββββΌββββββββββββββββββββββββ
β Business Logic Layer β
β - Custom Hooks (useActivityManager) β
β - Utility Functions (activityUtils) β
β - Type Definitions β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β uses
βββββββββββββββββββΌββββββββββββββββββββββββ
β Data Layer (State) β
β - WatermelonDB (Single Source) β
β - Models (Site, Schedule, Activity) β
β - Observable Queries β
βββββββββββββββββββββββββββββββββββββββββββ
β - Type Definitions β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β uses
βββββββββββββββββββΌββββββββββββββββββββββββ
β Data Layer (State) β
β - WatermelonDB β
β - Models (Site, Schedule, Activity) β
βββββββββββββββββββββββββββββββββββββββββββ
Here's what the app can do, organized by what makes sense for the user:
Technicians need to know where they're going and when. This feature handles all that calendar business:
- Visit Schedule - Shows upcoming maintenance visits with date, time, and site details
- Calendar Sync - Connects to the phone's native calendar via
expo-calendarso visits appear alongside personal appointments - Custom Date/Time Pickers - Material You themed pickers for selecting dates and times
- Requiem Visits - Special visits that don't belong to a specific site (memorial visits, general site checks)
- Conflict Prevention - Won't let technicians book two visits at the same time (with a 5-minute buffer)
- Auto-Save - Form data saves automatically as they type, so nothing is lost if they get interrupted
Key Files:
app/(tabs)/schedule.tsx- Main schedule screenapp/add-visit.tsx- Form to add new visitsapp/components/M3DatePicker.tsx- Calendar-style date pickerapp/components/M3TimePicker.tsx- Wheel-style time picker
Every solar farm is a "site" in the app. This feature shows all sites and their details:
- Site List - All solar farms listed with capacity info and location coordinates
- Mini Map Preview - Each site card shows a small map (no API key needed)
- Site Details - Full page with site info, upcoming visits, and check-in button
- Navigation - Deep-links to Google Maps or Apple Maps for turn-by-turn directions
- Archival - Old sites can be archived (hidden from the main list but preserved in database)
Key Files:
app/(tabs)/sites.tsx- List of all sitesapp/site/[id].tsx- Individual site detailsapp/components/maps/MiniMapPreview.tsx- API-key-free map componentapp/components/maps/SiteMapWidget.tsx- Reusable map wrapper
When a technician arrives at a site, they need to prove they were there. The check-in system handles this:
Check-In:
- Uses GPS to get the technician's current location
- Calculates distance to the site using the Haversine formula (math that figures out distance between two points on Earth)
- Only allows check-in when within 50 meters of the site
- Automatically links the check-in to any scheduled visit for that day
- Creates an Activity record to track the visit in the activity feed
Check-Out:
- The check-in button becomes a check-out button once checked in
- Calculates how long they were at the site (duration)
- Shows duration as "2h 15m" format
- Marks the visit as completed in the database
Archival: After checking out, the app asks if they want to archive:
- "Archive This Visit?" - Keeps the record but hides it from the main list
- "Archive This Site?" - Only appears if there are no future visits scheduled
Technical Details:
- Uses battery-efficient single-shot GPS requests
- Falls back to last known position if GPS fails
- Stores timestamps in the database:
checked_in_at,checked_out_at,actual_duration_minutes
Key Files:
app/site/[id].tsx- Site detail with check-in/check-out buttonslib/hooks/useGeofencing.ts- GPS and distance calculationslib/hooks/useActivityManager.ts- Creates activity recordsdatabase/models/Schedule.ts- Stores check-in/out timestamps
The app shows maps in two ways:
Mini Map Preview (Default - No API Key Needed):
- Simple grid-based stylized map showing site location
- Shows a marker where the site is
- Works completely offline
- Used in site cards on the Sites list page
Full Navigation:
- When technicians need directions, tapping "Navigate" opens:
- Google Maps on Android
- Apple Maps on iOS
- Passes the site coordinates directly to the maps app
Technical Notes:
- Originally used a placeholder "expo-maps" package that has been removed
- Now uses
react-native-mapsdirectly - The map system is modular - easy to swap implementations
β οΈ Android Testing Note: Full testing on Android devices requires a Google Maps API key with billing enabled. The code is ready but hasn't been tested on a physical Android device with maps enabled due to the Google Cloud billing requirement.
Key Files:
app/components/maps/MiniMapPreview.tsx- Stylized grid mapapp/components/maps/SiteMapWidget.tsx- Wrapper componentapp/components/maps/NativeMapView.tsx- Full map viewapp/map-navigation.tsx- Turn-by-turn navigation screen
Benefits:
- Zero crashes: App works without any API keys
- Modular: Easy to swap to react-native-maps by setting environment variable
- Enhanced UX: Activity cards show rich context with inline maps
- Consistent: All map surfaces use same widget interface
- Future-ready: NativeMapView wrapper ready for real maps integration
Technicians and managers need to see how solar sites are performing:
Charts:
- Bar Chart - Shows daily energy generation (kWh) for each day of the month
- Pie Chart - Shows performance breakdown:
- Over-performing days (generating more than expected)
- Normal days
- Under-performing days
- Zero energy days (no generation)
- Stats Cards - Quick numbers: Average, Peak, and Total kWh
PDF Export:
- Generate a PDF report of the performance data
- Share via email, messaging apps, or save to files
- Uses
expo-printfor PDF generation
Key Files:
app/performance.tsx- Main analytics screenlib/utils/chartHelpers.ts- Transforms raw data into chart-friendly format
The app is built to work without internet. Here's how:
All data lives in WatermelonDB - an offline-first database that stores data right on the phone:
- Sites - All site information stored locally
- Schedules - Visit schedules persist without internet
- Activities - Activity log stays on device
- Inspection Forms - Filled forms save locally
When the phone gets internet back:
- App detects network status automatically
- Queues up any unsynced data
- Syncs in the background (every 10 minutes)
- Shows sync status in the UI
To keep things organized, the app has an archival system:
Visit Archival:
- After checking out, technicians can archive the visit
- Archived visits hide from the main list but stay in database
Site Archival:
- Sites can be archived when no future visits are scheduled
- Cascade Effect: Archiving a site also archives:
- All activities for that site
- All schedules for that site
- All inspection forms for that site
Database Fields:
sites.archived- Is the site archived?sites.archivedAt- When was it archived?schedules.archived- Is the visit archived?activities.archived- Is the activity archived?
Key Files:
lib/hooks/useOfflineSync.ts- Handles background syncdatabase/schema.ts- Database structuredatabase/models/Site.ts- Site model with archival methodslib/hooks/useSites.ts- Queries that filter out archived items
When technicians visit a site, they often need to document what they found. The inspection form handles this:
Form Features:
- Dynamic Fields - Different field types:
- Text boxes for notes
- Number inputs for measurements
- Dropdowns for predefined options
- Radio buttons for yes/no
- Checkboxes for multiple selections
- File uploads for photos
- Validation - Required fields won't let them submit empty
- Site Selection - Links form to a specific site
Key Files:
app/(tabs)/inspections.tsx- List of completed inspectionsapp/inspection-form.tsx- The form itselflib/hooks/useInspections.ts- Form management logiclib/hooks/useMaintenanceForm.ts- Database operations for forms
Technicians need to take photos as evidence:
- Take Photo - Uses phone camera via
expo-camera - Choose from Gallery - Pick existing photos via
expo-image-picker - Preview - See photos before submitting
- Multiple Photos - Can attach several photos to one form
Photos are stored as URIs in the database and persist offline.
The app is smart about syncing:
- Network Detection - Uses
@react-native-community/netinfoto know when online/offline - Status Banner - Shows "Offline" or "Syncing" in the UI
- Manual Refresh - Pull-to-refresh to force sync
- Retry Logic - If sync fails, tries again automatically
Key Files:
lib/hooks/useOfflineSync.ts- Main sync logiclib/hooks/useMaintenanceForm.ts- Form sync operations
The app uses Material You (Material Design 3) for a modern, consistent look:
The app dynamically picks colors from the phone's wallpaper:
- Android 12+ - Extracts colors from wallpaper for a personalized look
- iOS & Older Android - Falls back to a green "solar energy" color palette
- Light/Dark Mode - Automatically matches system settings
The app includes reusable components following Material 3 guidelines:
- M3DatePicker - Calendar grid for picking dates
- M3TimePicker - Wheel picker for times
- M3ErrorDialog - Styled error messages
- M3ConfirmDialog - Yes/No confirmation dialogs
- ActivityCard - Activity feed items with icons and colors
- StyledText - Typography component
Key Files:
-
lib/hooks/MaterialYouProvider.tsx- Global color provider -
lib/design/tokens.ts- Design token definitions -
lib/design/colorRoles.ts- Semantic color mappingreturn ( <View style={{ backgroundColor: colors.appBackground }}> <View style={{ backgroundColor: colors.surfaceBase }}> <Text style={{ color: colors.textPrimary }}>Hello ); }
#### M3 Design Tokens
- Typography system (Display, Headline, Title, Body, Label variants)
- Elevation system (Level 0-5 with Material shadows)
- Shape system (Rounded corner specifications)
- Motion system (Duration and easing functions)
- Spacing system (Consistent padding/margin scale)
**Key Files**:
- `lib/design/tokens.ts` - M3 design token definitions
- `lib/styles/m3.ts` - StyleSheet-based M3 implementations
#### Custom M3 Components
- M3DatePicker: Calendar grid with month/year navigation
- M3TimePicker: Hour/minute wheel picker with AM/PM toggle
- M3ErrorDialog: Validation dialog (error/warning/info/success types)
- M3AlertDialog: Generic alert dialog
- M3ConfirmDialog: Multi-button confirmation dialog
- ActivityCard: Activity display with Material You theming
- StyledText: Typography component with M3 variants
**Key Files**:
- `app/components/M3DatePicker.tsx`
- `app/components/M3TimePicker.tsx`
- `app/components/M3ErrorDialog.tsx`
- `app/components/M3AlertDialog.tsx`
- `app/components/M3ConfirmDialog.tsx`
- `app/components/ActivityCard.tsx`
- `app/components/StyledText.tsx`
## Project Structure
SolYield/
βββ app/ # Expo Router pages
β βββ (tabs)/ # Bottom tab navigation
β β βββ index.tsx # Dashboard/Home screen
β β βββ schedule.tsx # Visit schedule
β β βββ sites.tsx # Solar Sites list
β β βββ inspections.tsx # Inspections list
β β βββ \_layout.tsx # Tab bar layout
β βββ components/ # Reusable UI components
β β βββ maps/ # Map system
β β β βββ MiniMapPreview.tsx # Stylized grid map
β β β βββ SiteMapWidget.tsx # Map wrapper
β β β βββ NativeMapView.tsx # Full map view
β β βββ M3DatePicker.tsx # Material date picker
β β βββ M3TimePicker.tsx # Material time picker
β β βββ M3ErrorDialog.tsx # Error dialog
β β βββ ActivityCard.tsx # Activity display card
β β βββ StyledText.tsx # Typography wrapper
β βββ site/[id].tsx # Site details
β βββ inspection/[id].tsx # Inspection detail
β βββ inspection-form.tsx # New inspection form
β βββ performance.tsx # Charts & PDF export
β βββ map-navigation.tsx # GPS navigation
β βββ activities.tsx # Activity feed
β βββ add-visit.tsx # Add visit form
β βββ add-site.tsx # Add site form
β βββ \_layout.tsx # Root layout
βββ store/ # DEPRECATED - kept for compatibility
β βββ index.ts # Empty Redux config (unused)
βββ database/ # WatermelonDB
β βββ models/ # Data models
β β βββ Site.ts # Site model
β β βββ Schedule.ts # Schedule model
β β βββ Activity.ts # Activity model
β β βββ MaintenanceForm.ts # Inspection form model
β β βββ FormPhoto.ts # Photo model
β βββ schema.ts # Database schema
β βββ migrations.ts # Database migrations
β βββ index.ts # Database setup
βββ lib/ # Business logic
β βββ hooks/ # Custom React hooks
β β βββ MaterialYouProvider.tsx # Color theme provider
β β βββ useActivityManager.ts # Activity CRUD
β β βββ useMaintenanceForm.ts # Form CRUD
β β βββ useInspections.ts # Inspection hooks
β β βββ useOfflineSync.ts # Background sync
β β βββ useGeofencing.ts # GPS & distance
β β βββ useSiteManagement.ts # Site operations
β β βββ useScheduleManagement.ts # Visit operations
β βββ utils/ # Helper functions
β β βββ activityUtils.ts # Activity helpers
β β βββ dateFormatter.ts # Date formatting
β β βββ locationUtils.ts # GPS calculations
β β βββ chartHelpers.ts # Chart data
β βββ design/ # Design system
β β βββ tokens.ts # M3 tokens
β β βββ colorRoles.ts # Color mapping
β βββ config/ # Configuration
β βββ maps.ts # Map settings
βββ assets/ # Images & icons
βββ form_schema.ts # Inspection form definition
βββ package.json # Dependencies
βββ form_schema.js # Dynamic form schema
βββ schedule.js # Sample schedule data
βββ sites.js # Sample site data
βββ chart_data.js # Sample chart data
βββ performance_data.js # Sample performance data
βββ package.json # Dependencies
- Node.js 18 or higher
- npm or yarn package manager
- Expo CLI
- Android Studio (for Android development)
- Xcode (for iOS development, macOS only)
- Physical Android 12+ device (recommended for Material You testing)
# Clone the repository
git clone <repository-url>
cd Sol/SolYield
# Install dependencies
npm install
# Start development server
npm start
# Run on Android (requires connected device or emulator)
npm run android
# Run on iOS (requires macOS and Xcode)
npm run ios
# Alternative: Use Expo CLI directly
npx expo run:android
npx expo run:iosThe application works out-of-the-box without any API keys. To enable native maps in the future:
- Set environment variable in
.env:
EXPO_PUBLIC_ENABLE_NATIVE_MAPS=true- Add Google Maps API key to
app.json:
{
"android": {
"config": {
"googleMaps": {
"apiKey": "YOUR_GOOGLE_MAPS_API_KEY"
}
}
}
}# Start development server
npm start
# Run on Android device/emulator
npm run android
# Run on iOS device/simulator (macOS only)
npm run ios
# Run TypeScript type checking
npm run type-check
# Run ESLint
npm run lint
# Run Prettier formatter
npm run format
# Clear cache and restart
npm start --clear- Install EAS CLI globally:
npm install -g eas-cli- Login to Expo account:
eas login- Configure project (first time only):
eas build:configureEAS Build compiles your app in the cloud without requiring local Android Studio or Xcode setup.
Build APK for Android:
npm run build:android
# or directly:
eas build --platform android --profile productionBuild for iOS:
npm run build:ios
# or directly:
eas build --platform ios --profile productionBuild for Both Platforms:
npm run build:all
# or directly:
eas build --platform all --profile productionCheck Build Status:
eas build:listDownload Build: After build completes, EAS will provide a download link. You can also download from:
eas build:view <build-id>Android Release APK (Local):
npm run android:build
# This runs: cd android && ./gradlew clean && ./gradlew assembleRelease
# Output: android/app/build/outputs/apk/release/app-release.apkAndroid Release AAB (Local - for Google Play):
npm run android:bundle
# This runs: cd android && ./gradlew clean && ./gradlew bundleRelease
# Output: android/app/build/outputs/bundle/release/app-release.aabiOS Release (Local - macOS only):
npm run ios:release
# This runs: expo run:ios --configuration ReleaseThe project includes three build profiles:
-
development: Development client with fast refresh
- Output: APK (Android)
- Distribution: Internal testing
-
preview: Pre-production testing build
- Output: APK (Android)
- Distribution: Internal testing
-
production: Final production build
- Output: APK (Android) or AAB (for Google Play)
- Environment: NODE_ENV=production
- Console logs automatically removed via metro.config.js
Google Play Store requires AAB (Android App Bundle) format, but for direct distribution you may need APK. Here's how to convert:
1. Download bundletool:
wget https://github.com/google/bundletool/releases/latest/download/bundletool-all-1.15.6.jar
# Or download manually from: https://github.com/google/bundletool/releases2. Generate APKs from AAB:
java -jar bundletool-all-1.15.6.jar build-apks \
--bundle=app-release.aab \
--output=app-release.apks \
--mode=universal3. Extract Universal APK:
unzip app-release.apks -d output/
# The universal APK will be in: output/universal.apk4. Rename and use:
mv output/universal.apk SolYield-v1.3.0.apk1. Generate signed APKs for a specific device:
# Create debug keystore if you don't have one
keytool -genkey -v -keystore debug.keystore \
-alias androiddebugkey \
-keyalg RSA -keysize 2048 -validity 10000 \
-storepass android -keypass android
# Build APK set
java -jar bundletool-all-1.15.6.jar build-apks \
--bundle=app-release.aab \
--output=app-release.apks \
--ks=debug.keystore \
--ks-pass=pass:android \
--ks-key-alias=androiddebugkey \
--key-pass=pass:android2. Install directly to connected device:
java -jar bundletool-all-1.15.6.jar install-apks \
--apks=app-release.apksFor quick testing, you can use online tools (use with caution for production builds):
Note: Only use online converters for testing builds, never for production releases containing sensitive code or API keys.
app.json (Production Settings):
- Version: 1.3.0
- Bundle Identifier: com.solyield.mobile
- Adaptive Icon: Configured for Android
- Permissions: All required permissions defined
metro.config.js (Production Optimizations):
drop_console: true- Removes all console.log statements in production- Minification enabled automatically
tsconfig.json:
- Strict mode enabled
- Current status: β Zero TypeScript errors
Before building for production, run:
npm run prebuild
# This runs: npm run type-check && npm run lintCurrent Status:
- β TypeScript: 0 errors (strict mode)
β οΈ ESLint: Migration to v10 needed (non-blocking)
- Build AAB:
eas build --platform android --profile production- Submit to Google Play:
eas submit --platform android- Manual Upload:
- Go to: https://play.google.com/console
- Create app listing
- Upload AAB file
- Fill in store listing details
- Submit for review
- Build IPA:
eas build --platform ios --profile production- Submit to App Store:
eas submit --platform ios- Manual Upload:
- Open Xcode
- Use Transporter app to upload IPA
- Complete App Store Connect listing
- Submit for review
Update version before each build:
1. Update package.json:
{
"version": "1.4.0"
}2. Update app.json:
{
"expo": {
"version": "1.4.0",
"android": {
"versionCode": 4
},
"ios": {
"buildNumber": "4"
}
}
}Note:
versionis the user-facing version string (e.g., "1.4.0")versionCode(Android) must be an integer that increments with each releasebuildNumber(iOS) must be a string that increments with each release
1. Test APK locally:
# Install on connected device
adb install app-release.apk
# Or use EAS
eas build:run --platform android2. Verify production features:
- Check that console.log statements are removed
- Verify Material You dynamic colors work
- Test offline functionality (airplane mode)
- Test geofencing check-in/check-out
- Test archival workflow
- Verify all permissions work
- Test database migrations (v3 β v4)
3. Performance testing:
- Monitor app size (target: < 50MB)
- Check startup time (target: < 3 seconds)
- Test on low-end Android devices
- Verify smooth 60fps chart animations
Build fails with "Could not find bundletool":
# Install bundletool
npm install -g @android/bundletoolAPK won't install on device:
# Uninstall old version first
adb uninstall com.solyield.mobile
# Then reinstall
adb install app-release.apkMaterial You colors not working:
- Ensure testing on Android 12+ device
- Check that device wallpaper is set
- Verify app has permission to read wallpaper colors
Database migration errors:
- Clear app data before installing new version
- Or implement proper migration testing in pre-release
EAS Builds (Cloud):
- Download from EAS dashboard: https://expo.dev
- Or use CLI:
eas build:list
Local Builds:
- Android APK:
android/app/build/outputs/apk/release/app-release.apk - Android AAB:
android/app/build/outputs/bundle/release/app-release.aab - iOS IPA: Built via Xcode or
eas build
To test the Material You dynamic color system:
- Run the app on an Android 12+ device
- Change your device wallpaper
- Verify app colors update to match wallpaper palette
- Toggle between light and dark mode in system settings
- Verify proper color adaptation
To test offline functionality:
- Fill out an inspection form
- Enable airplane mode on the device
- Submit the form (should save locally)
- Close and reopen the app
- Verify form persisted
- Disable airplane mode
- Verify automatic sync indicator
To test geofencing:
- Navigate to a site detail screen
- Observe your current distance from the site
- Move closer than 50 meters to the site
- Verify "Check In" button becomes enabled
- Tap "Check In" to log your arrival
The app has been tuned for smooth performance:
- GPS Battery Optimization - Changed from 5-second/10-meter intervals to 15-second/50-meter intervals. Uses single-shot requests instead of continuous tracking
- Pre-calculated Metadata - Visit counts and last visit timestamps are calculated once when creating activities, not on every render (O(1) reads instead of O(n))
- FlatList Tuning - Increased batch sizes (
initialNumToRender: 8,maxToRenderPerBatch: 8) for smoother scrolling - Component Memoization - Used
useCallbackandReact.memoto prevent unnecessary re-renders - NativeWind Migration - Replaced StyleSheet with Tailwind CSS classes for better performance
- Single-Shot Location - GPS gets position once with fallback to last known position, no GPS spinning
- WatermelonDB - Single source of truth, no Redux
- Observable Queries - Data updates automatically when database changes
- Network Detection - Uses
@react-native-community/netinfoto detect online/offline status - Background Sync - Automatically syncs every 10 minutes when online
- No Dual State - Eliminated memory bloat from having both Redux and WatermelonDB
- Full type coverage across entire codebase
- Zero
anytypes (except necessary third-party interop) - Strict null checks enabled
- Interface-based contracts for all data models
| Change | Before | After |
|---|---|---|
| State Management | Redux + WatermelonDB | WatermelonDB only |
| GPS Interval | 5 seconds | 15 seconds |
| GPS Distance | 10 meters | 50 meters |
| FlatList Batches | 5 | 8 |
| Map Package | expo-maps (placeholder) | react-native-maps |
| Keep Awake | Causing errors | Blocked via resolutions |
- Pastel color palette for reduced eye strain
- High contrast text (WCAG AA compliant)
- Touch target sizes minimum 48dp
- Screen reader compatible labels
- Semantic HTML equivalents in React Native
| Dashboard | Schedule | Sites | Performance | Inspection |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
| Feature | Description |
|---|---|
| Dashboard | Material You themed home screen with dynamic colors, quick stats overview, recent activity feed, offline/online status indicator, and user profile icon |
| Schedule | Scheduled maintenance visits list with custom date/time pickers, calendar sync, conflict validation, requiem visit support, and check-in/out tracking |
| Sites | Interactive modular map with solar site markers, site list view with mini map previews, navigation integration, and archival system |
| Check-in/Check-out | Real-time GPS tracking, 50m geofence validation, automatic visit duration calculation, activity logging, and linked schedule updates |
| Archival System | Smart visit archival after check-out, site archival when no future visits exist, cascade archival of related data, and filtered queries |
| GPS Navigation | Real-time location tracking, distance and ETA display, geofencing validation, and external navigation deep-links |
| Performance | Bar chart for daily energy generation, pie chart for performance breakdown, stats cards (Average/Peak/Total kWh), and PDF export with sharing |
| Inspection | Dynamic form rendering from schema, site selection, multiple field types (text/number/dropdown/radio/checkbox/file), camera capture, offline status banner, and sync tracking |
| Inspection History | List of submitted inspections, sync status badges (Synced/Pending), form detail view, and image gallery support |
-
Static Performance Data: Performance analytics currently displays sample data from
performance_data.js. Integration with real-time energy monitoring systems is planned for future releases. -
WatermelonDB Sync: Sync-on-reconnect functionality is implemented with local state management. Full cloud sync with backend API requires server-side implementation.
-
iOS Material You: Dynamic color extraction is Android 12+ only. iOS and older Android versions fall back to a static green energy palette.
-
Google Maps on Android: The app is configured for
react-native-mapsbut hasn't been tested on physical Android devices because Google Maps SDK requires a billing-enabled Google Cloud account. The code is ready - you just need to:- Create a Google Cloud project
- Enable billing (credit card required)
- Enable Maps SDK for Android
- Generate an API key
- Add the key to
app.json
The app will work on iOS with Apple Maps without any additional setup.
- Real-time performance data integration with solar monitoring APIs
- Backend API integration for multi-user sync
- Push notifications for scheduled visits
- Advanced analytics with trend predictions
- Multi-language support
- Biometric authentication
- Export data to CSV/Excel formats
- Unit and integration test suite
- Google Maps API Integration: Full Android testing with Google Maps SDK (requires Google Cloud billing setup)
This project is proprietary. All rights reserved by SolYield. Unauthorized copying, distribution, or use is prohibited. See hackathon terms and conditions in AGENTS.md.
For technical questions or issues, contact the development team via the hackathon submission portal.
Built for the SolYield Mobile Migration Hackathon. Implements industry-standard libraries and follows React Native best practices as specified in the hackathon requirements.
- React Native Team - Framework and core libraries
- Expo Team - Managed workflow and developer tools
- Nozbe - WatermelonDB offline-first database
- Material Design Team - Design system guidelines
- react-native-maps - Map rendering
- react-native-gifted-charts - High-performance chart rendering
- react-native-material-you-colors - Dynamic color extraction
- react-native-reanimated - Smooth animations
- expo-print - PDF generation capabilities
- expo-camera - Camera integration
- expo-location - GPS and geofencing
Think of these like highway mile markers - they show how far we've come:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π MILE 0: THE START β
β Basic app structure with scheduling and site management β
β β See: Scheduling, Sites β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π£οΈ MILE 25: GETTING CONNECTED β
β Features that work better with internet β
β β See: Check-In System, Reports & Analytics β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β ποΈ MILE 50: GOING OFF-ROAD β
β Full offline capability - work anywhere β
β β See: Offline Mode, Inspection Forms, Camera & Photos β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π¨ MILE 75: THE BEAUTIFUL JOURNEY β
β Material You design with dynamic colors β
β β See: Design System β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π§ MILE 100: THE TUNE-UP β
β Performance optimizations and bug fixes β
β β See: Performance Optimizations, What's New in v1.4.0 β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π MILE 110: PRODUCTION READY β
β Current state - all systems operational β
β β See: Version History β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Mile 0: The Start The foundation of the app. Technicians can see their scheduled visits and browse solar sites. This is the baseline - everything else builds on top of this.
π£οΈ Mile 25: Getting Connected Features that work best with internet (but have offline fallbacks). The check-in system uses GPS to prove technicians were at sites. Reports and analytics let managers see performance data.
ποΈ Mile 50: Going Off-Road The app now works completely offline. All data is stored locally in WatermelonDB. Technicians can fill out inspection forms with photos in the middle of nowhere. When they get signal again, everything syncs automatically.
π¨ Mile 75: The Beautiful Journey Material You dynamic colors make the app feel native to each user's phone. The interface adapts to their wallpaper and theme preferences.
π§ Mile 100: The Tune-Up Performance optimizations and bug fixes. GPS battery optimization, pre-calculated data, FlatList tuning - all the invisible improvements that make the app feel smooth.
π Mile 110: Production Ready The current state. All features working together. Ready for real technicians to use in the field.
Current Version: 1.4.0
Version 1.4.0 (Current - Production Ready)
This version focused on performance optimizations and bug fixes:
-
β Complete State Migration:
- Removed Redux as the primary state management
- WatermelonDB is now the single source of truth
- Removed Redux Provider and PersistGate from app layout
- Deleted all Redux slices (activitySlice, maintenanceSlice, siteSlice, scheduleSlice)
- All data operations now go directly through WatermelonDB hooks
-
β GPS Battery Optimization:
- Changed location polling from 5 seconds / 10 meters to 15 seconds / 50 meters
- Single-shot GPS requests instead of continuous tracking
- Falls back to last known position if GPS fails
- Significant battery savings for technicians in the field
-
β Pre-calculated Metadata:
- When creating activities, now calculates previous visit count upfront
- Stores
previousVisitCountandlastVisitTimestampin activity metadata - Eliminates O(n) calculations on every render - now O(1) reads
-
β FlatList Optimizations:
- Increased
initialNumToRenderfrom 5 to 8 - Increased
maxToRenderPerBatchfrom 5 to 8 - Smoother scrolling on large lists
- Increased
-
β Component Memoization:
- Added
useCallbackto render functions in schedule, sites, activities screens - Added
React.memoto ActivityCard component - Prevents unnecessary re-renders
- Added
-
β NativeWind Migration:
- Replaced StyleSheet with Tailwind CSS classes in ActivityCard
- Better performance by moving style calculations to native thread
-
β Runtime Error Fixes:
- Added
resolutionsin package.json to block expo-keep-awake (was causing errors) - Fixed corrupted useGeofencing.ts file (had recursive UI component)
- Recreated corrupted MaintenanceForm model
- Added
-
β Map System Cleanup:
- Removed unused expo-maps dependency (was placeholder)
- Now uses react-native-maps exclusively
- Cleaner dependency tree
-
β Removed Mock Data:
- Eliminated auto-generated sample activities
- Prevents "production data leaks" with fake data
-
β New Database Fields:
- Added
activityIdfield to MaintenanceForm (links forms to activities) - Added
imagesfield for additional photos beyond site photo - Added
statusandisRequiemfields to ScheduleVisit type
- Added
Version 1.3.0 (Previous)
- β
Check-in/Check-out System: Complete implementation with geofence validation
- Links check-in to scheduled visits automatically
- Calculates actual visit duration (displayed as "Xh Ym")
- Creates Activity records for tracking
- Updates Schedule model with check-in/out timestamps and activity ID
- β
Archival System: Intelligent visit and site archival workflow
- "Archive This Visit?" dialog after check-out
- "Archive This Site?" dialog when no future visits exist
- Cascade archival of all related data (activities, schedules, forms)
- Filtered queries exclude archived items by default
- Separate hooks for viewing archived data
- β
Database Migration v3 β v4: Added check-in/out tracking fields
schedules.checked_in_at(timestamp)schedules.checked_out_at(timestamp)schedules.actual_duration_minutes(number)schedules.activity_id(string)
- β
Activity Management Overhaul:
- Activities now generate and return IDs for linking to schedules
- Fixed TypeScript errors across useActivities, useInspections
- β All Alert.alert Replaced: Consistent M3ErrorDialog usage throughout app
- β Zero TypeScript Errors: Full type safety in strict mode
- β Production Build Ready: EAS configuration verified
- Added M3ErrorDialog for validation errors (replacing Alert.alert)
- Fixed M3ErrorDialog onDismiss prop to be optional
- Fixed schedule conflict validation with 5-minute buffer
- Improved form state preservation with AsyncStorage auto-save (500ms debounce)
- Enhanced ActivityCard component verified clickable with proper navigation
Version 1.2.0
- Modular map system with API-key-free implementation
- Enhanced activity cards with contextual information
- Mini map previews in sites list
Version 1.1.0
- Material You dynamic colors system
- Full light/dark mode support
- StatusBar and NavigationBar theming
Version 1.0.0
- Initial MVP release with core scheduling, sites, and offline features
Think of these like highway mile markers - they show how far we've come:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π MILE 0: THE START β
β Basic app structure with scheduling and site management β
β β See: Scheduling, Sites β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π£οΈ MILE 25: GETTING CONNECTED β
β Features that work better with internet β
β β See: Check-In System, Reports & Analytics β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β ποΈ MILE 50: GOING OFF-ROAD β
β Full offline capability - work anywhere β
β β See: Offline Mode, Inspection Forms, Camera & Photos β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π¨ MILE 75: THE BEAUTIFUL JOURNEY β
β Material You design with dynamic colors β
β β See: Design System β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π§ MILE 100: THE TUNE-UP β
β Performance optimizations and bug fixes β
β β See: Performance Optimizations, What's New in v1.4.0 β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β π MILE 110: PRODUCTION READY β
β Current state - all systems operational β
β β See: Version History β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Mile 0: The Start The foundation of the app. Technicians can see their scheduled visits and browse solar sites. This is the baseline - everything else builds on top of this.
π£οΈ Mile 25: Getting Connected Features that work best with internet (but have offline fallbacks). The check-in system uses GPS to prove technicians were at sites. Reports and analytics let managers see performance data.
ποΈ Mile 50: Going Off-Road The app now works completely offline. All data is stored locally in WatermelonDB. Technicians can fill out inspection forms with photos in the middle of nowhere. When they get signal again, everything syncs automatically.
π¨ Mile 75: The Beautiful Journey Material You dynamic colors make the app feel native to each user's phone. The interface adapts to their wallpaper and theme preferences.
π§ Mile 100: The Tune-Up Performance optimizations and bug fixes. GPS battery optimization, pre-calculated data, FlatList tuning - all the invisible improvements that make the app feel smooth.
π Mile 110: Production Ready The current state. All features working together. Ready for real technicians to use in the field.




