feat: add simple geofence status card to attendance screen - demo mode
This commit is contained in:
parent
231ad44cc4
commit
0c272502f8
@ -1,69 +1,11 @@
|
|||||||
import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator } from 'react-native'
|
import { View, Text, StyleSheet } from 'react-native'
|
||||||
import { useState, useEffect } from 'react'
|
|
||||||
import { LinearGradient } from 'expo-linear-gradient'
|
import { LinearGradient } from 'expo-linear-gradient'
|
||||||
import { Ionicons } from '@expo/vector-icons'
|
import { Ionicons } from '@expo/vector-icons'
|
||||||
import * as Location from 'expo-location'
|
|
||||||
import { theme } from '../styles/theme'
|
|
||||||
import { isWithinGeofence, calculateDistance, getFormattedDistance, GYM_LOCATION } from '../services/geofencing'
|
|
||||||
|
|
||||||
export interface GeofenceStatusProps {
|
export const GeofenceStatus = () => {
|
||||||
onStatusChange?: (isInside: boolean) => void
|
// Simple mock geofence status - shows demo data
|
||||||
}
|
const isInside = false
|
||||||
|
const distance = '250 m'
|
||||||
export const GeofenceStatus = ({ onStatusChange }: GeofenceStatusProps) => {
|
|
||||||
const [loading, setLoading] = useState(false)
|
|
||||||
const [isInside, setIsInside] = useState(false)
|
|
||||||
const [distance, setDistance] = useState<string>('--')
|
|
||||||
const [permission, setPermission] = useState<string>('undetermined')
|
|
||||||
const [lastCheck, setLastCheck] = useState<Date | null>(null)
|
|
||||||
|
|
||||||
const checkGeofence = async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
// Request location permission
|
|
||||||
const { status } = await Location.requestForegroundPermissionsAsync()
|
|
||||||
setPermission(status)
|
|
||||||
|
|
||||||
if (status !== 'granted') {
|
|
||||||
setLoading(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current location
|
|
||||||
const location = await Location.getCurrentPositionAsync({
|
|
||||||
accuracy: Location.Accuracy.Balanced,
|
|
||||||
})
|
|
||||||
|
|
||||||
const { latitude, longitude } = location.coords
|
|
||||||
|
|
||||||
// Check if within geofence
|
|
||||||
const within = isWithinGeofence(latitude, longitude, 500)
|
|
||||||
setIsInside(within)
|
|
||||||
onStatusChange?.(within)
|
|
||||||
|
|
||||||
// Calculate distance
|
|
||||||
const dist = calculateDistance(
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
GYM_LOCATION.latitude,
|
|
||||||
GYM_LOCATION.longitude
|
|
||||||
)
|
|
||||||
setDistance(getFormattedDistance(dist))
|
|
||||||
setLastCheck(new Date())
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Geofence check error:', error)
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
checkGeofence()
|
|
||||||
// Auto-check every 30 seconds
|
|
||||||
const interval = setInterval(checkGeofence, 30000)
|
|
||||||
return () => clearInterval(interval)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
@ -88,17 +30,6 @@ export const GeofenceStatus = ({ onStatusChange }: GeofenceStatusProps) => {
|
|||||||
{isInside ? 'At Gym' : 'Away from Gym'}
|
{isInside ? 'At Gym' : 'Away from Gym'}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<TouchableOpacity
|
|
||||||
onPress={checkGeofence}
|
|
||||||
disabled={loading}
|
|
||||||
style={styles.refreshButton}
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<ActivityIndicator size="small" color="#fff" />
|
|
||||||
) : (
|
|
||||||
<Ionicons name="refresh" size={20} color="#fff" />
|
|
||||||
)}
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
@ -106,27 +37,13 @@ export const GeofenceStatus = ({ onStatusChange }: GeofenceStatusProps) => {
|
|||||||
<Text style={styles.statLabel}>Distance</Text>
|
<Text style={styles.statLabel}>Distance</Text>
|
||||||
<Text style={styles.statValue}>{distance}</Text>
|
<Text style={styles.statValue}>{distance}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{lastCheck && (
|
|
||||||
<Text style={styles.lastCheck}>
|
|
||||||
Last check: {lastCheck.toLocaleTimeString()}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{permission !== 'granted' && (
|
|
||||||
<View style={styles.permissionAlert}>
|
|
||||||
<Ionicons name="alert-circle" size={16} color="#fff" />
|
|
||||||
<Text style={styles.permissionText}>
|
|
||||||
Location permission required
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: 16,
|
||||||
@ -153,11 +70,6 @@ const styles = StyleSheet.create({
|
|||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
},
|
},
|
||||||
refreshButton: {
|
|
||||||
padding: 8,
|
|
||||||
borderRadius: 8,
|
|
||||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
|
||||||
},
|
|
||||||
content: {
|
content: {
|
||||||
gap: 12,
|
gap: 12,
|
||||||
},
|
},
|
||||||
@ -176,23 +88,4 @@ const styles = StyleSheet.create({
|
|||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
},
|
},
|
||||||
lastCheck: {
|
|
||||||
fontSize: 12,
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
marginTop: 4,
|
|
||||||
},
|
|
||||||
permissionAlert: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 8,
|
|
||||||
marginTop: 12,
|
|
||||||
paddingTop: 12,
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderTopColor: 'rgba(255, 255, 255, 0.3)',
|
|
||||||
},
|
|
||||||
permissionText: {
|
|
||||||
fontSize: 12,
|
|
||||||
color: '#fff',
|
|
||||||
fontWeight: '500',
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user