A React Native + TypeScript mobile app for real-time location tracking and geofence-based attendance check-in.
This project now achieves the full end goal:
- real-time GPS tracking
- map-based location visualization
- 100m office geofence validation
- check-in only inside geofence
- local attendance persistence
- history screen with grouped records and stats
- robust permission, GPS-disabled, and offline handling
App Icon |
![]() Splash Screen |
![]() Home Screen |
![]() Dark Mode |
![]() Hindi Language |
![]() Inside Office |
![]() Confirm Check-In |
![]() Checked In |
![]() History |
![]() No Internet |
![]() Location Denied |
![]() Location Blocked |
![]() Outside Office |
![]() Inside Office |
![]() History |
| Requirement | Status | Implementation |
|---|---|---|
| Real-time location tracking | Achieved | watchPosition and one-shot location flow in src/hooks/useLocation.ts |
| Map integration | Achieved | Google provider map with marker + geofence circle in src/components/home/HomeMapSection.tsx |
| Geofence config (100m) | Achieved | OFFICE_LOCATION and GEOFENCE_RADIUS_METERS in src/config/constants.ts |
| Attendance check-in only inside geofence | Achieved | Guarded check-in flow in src/screens/HomeScreen.tsx + src/hooks/useAttendance.ts |
| Local data storage | Achieved | AsyncStorage-based record persistence in src/utils/storageUtils.ts |
| Attendance history screen | Achieved | Grouped history + clear-all flow in src/screens/HistoryScreen.tsx |
| Error and edge-case handling | Achieved | Denied/blocked permission handling, GPS disabled modal, offline banner/badge |
- Real-time tracking using
@react-native-community/geolocation - Geofence calculation using Haversine distance (
src/utils/geofenceUtils.ts) - Accuracy-aware inside check using effective distance (
distance - accuracy) - Home screen with:
- office and user markers
- geofence radius circle
- dynamic geofence status
- refresh location action with icon animation
- check-in confirmation and success/failure alert modals
- Permission states:
deniedflow with retry/grant actionblockedflow with open-settings action
- GPS disabled handling with location-settings deep-link action
- Offline state handling with banner and map badge
- Attendance history:
- grouped by date
- stats (today, this week, all time)
- manual pull-to-refresh
- clear-all confirmation
- Theme mode support (light/dark/system) with persistence
- i18n language switching (English/Hindi) with persistence
- Path aliases for clean imports (Babel + TypeScript)
- React Native 0.85.0
- React 19
- TypeScript
- React Navigation (Bottom Tabs)
react-native-maps@react-native-community/geolocationreact-native-permissions@react-native-async-storage/async-storage@react-native-community/netinforeact-i18next+ i18next
npm installcd ios
pod install
cd ..The project currently uses a placeholder string GP_KEY in native files.
Replace it with your real Google Maps API key.
Android:
- file:
android/app/src/main/AndroidManifest.xml - replace:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="GP_KEY" />with:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_GOOGLE_MAPS_API_KEY" />iOS:
- file:
ios/CheckPoint/AppDelegate.swift - replace:
GMSServices.provideAPIKey("GP_KEY")with:
GMSServices.provideAPIKey("YOUR_GOOGLE_MAPS_API_KEY")Edit src/config/constants.ts:
export const OFFICE_LOCATION = {
latitude: 23.048439,
longitude: 72.524228,
name: 'Your Office Name',
address: 'Your Office Address',
};
export const GEOFENCE_RADIUS_METERS = 100;npm run android
# or
npm run iosDistance is computed with the Haversine formula.
The app uses:
distance: raw Haversine distanceeffectiveDistance:max(0, distance - accuracy)
Check-in is allowed when:
- First denial: app shows denied flow with Grant Permission action
- Repeated denial / blocked state: app shows blocked flow with Open Settings action
- GPS disabled: app shows GPS modal with Open Location Settings and Retry
- App foreground resume: permission state is re-synced
- Languages: English and Hindi (
src/locales/en.json,src/locales/hi.json) - Persisted language selection via AsyncStorage
- Light/dark/system theme with persisted mode in
src/theme/ThemeContext.tsx
Scripts:
npm run start
npm run android
npm run ios
npm run type-check
npm run lintCurrent codebase is TypeScript-first and alias-based for maintainability.
- Add check-out flow and working-hours summaries
- Add monthly analytics charts and export options (CSV/PDF)
- Add remote sync API with conflict resolution (offline-first)
- Add battery-optimized adaptive tracking modes













