diff options
author | Santo Cariotti <santo@dcariotti.me> | 2024-08-31 16:45:39 +0200 |
---|---|---|
committer | Santo Cariotti <santo@dcariotti.me> | 2024-08-31 16:45:39 +0200 |
commit | 6a99bf48f8f46f6d50e93286ee158c5bf9112819 (patch) | |
tree | 1c16450e05d204aa57b9d6eac7f49f44c6492151 | |
parent | bafd0b8c5ddd6f769a834618de8b03688f0fd835 (diff) |
Show alert details
-rw-r--r-- | app/(tabs)/alerts/[id].tsx | 189 | ||||
-rw-r--r-- | app/(tabs)/index.tsx | 2 |
2 files changed, 179 insertions, 12 deletions
diff --git a/app/(tabs)/alerts/[id].tsx b/app/(tabs)/alerts/[id].tsx index cc425db..9dba92a 100644 --- a/app/(tabs)/alerts/[id].tsx +++ b/app/(tabs)/alerts/[id].tsx @@ -6,16 +6,44 @@ import { import ParallaxScrollView from '@/components/ParallaxScrollView'; import { ThemedText } from '@/components/ThemedText'; import { ThemedView } from '@/components/ThemedView'; -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useEffect, useRef } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useFocusEffect } from '@react-navigation/native'; -import { router, useLocalSearchParams } from 'expo-router'; +import { Link, router, useLocalSearchParams } from 'expo-router'; +import MapView, { Polygon, Region } from 'react-native-maps'; +import { Ionicons } from '@expo/vector-icons'; +import { useColorScheme } from '@/hooks/useColorScheme.web'; +import { Colors } from '@/constants/Colors'; + +interface AlertData { + id: string; + userId: string; + createdAt: string; + area: string; + extendedArea: string; + level: string; +} + +interface PolygonCoordinates { + latitude: number; + longitude: number; +} export default function AlertIdScreen() { - const [token, setToken] = useState(''); - const [userId, setUserId] = useState(''); + const [token, setToken] = useState<string>(''); + const [userId, setUserId] = useState<string>(''); + const [alert, setAlert] = useState<AlertData | null>(null); + const [region, setRegion] = useState<Region>({ + latitude: 44.49738301084014, + longitude: 11.356121722966094, + latitudeDelta: 0.03, + longitudeDelta: 0.03, + }); + const [polygon, setPolygon] = useState<PolygonCoordinates[]>([]); + const [extendedPolygon, setExtendedPolygon] = useState<PolygonCoordinates[]>([]); + const mapRef = useRef<MapView | null>(null); - const checkAuth = async () => { + const checkAuth = useCallback(async () => { const storedToken = Platform.OS === 'web' ? localStorage.getItem('token') @@ -40,26 +68,165 @@ export default function AlertIdScreen() { ] ); } - }; + }, []); + + const fetchAlert = useCallback(async (id: string) => { + if (!token || !userId) return; + + try { + const response = await fetch( + `${process.env.EXPO_PUBLIC_API_URL}/graphql`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: `{ alerts(id: ${id}) { id, userId, createdAt, area, extendedArea, level } }`, + }), + } + ); + + const data = await response.json(); + + if (data.errors) { + Alert.alert('Error', 'Error fetching data'); + } else if (data.data.alerts && data.data.alerts.length > 0) { + const alertData = data.data.alerts[0]; + const coordinatesString = alertData.area.substring(9, alertData.area.length - 2); + const coordinates = coordinatesString + .split(',') + .map((coord: string) => coord.trim().split(' ')) + .map((pair: string[]) => ({ + longitude: parseFloat(pair[0]), + latitude: parseFloat(pair[1]), + })); + + const extendedCoordinatesString = alertData.extendedArea.substring(9, alertData.extendedArea.length - 2); + const extendedCoordinates = extendedCoordinatesString + .split(',') + .map((coord: string) => coord.trim().split(' ')) + .map((pair: string[]) => ({ + longitude: parseFloat(pair[0]), + latitude: parseFloat(pair[1]), + })); + + setAlert(alertData); + setPolygon(coordinates); + setExtendedPolygon(extendedCoordinates); + setRegion({ + latitude: coordinates[0]?.latitude || region.latitude, + longitude: coordinates[0]?.longitude || region.longitude, + latitudeDelta: 0.05, + longitudeDelta: 0.05, + }); + } else { + Alert.alert('Error', 'No data found'); + router.push('/alerts/index'); + } + } catch (err) { + console.error('Fetch Map Data Error:', err); + } + }, [token, userId, region.latitude, region.longitude]); useFocusEffect( useCallback(() => { checkAuth(); - }, []) + }, [checkAuth]) ); - const { id } = useLocalSearchParams(); + useEffect(() => { + if (typeof id === 'string') { + fetchAlert(id); + } + }, [id, fetchAlert]); + + useEffect(() => { + if (mapRef.current && region) { + mapRef.current.animateToRegion(region, 1000); + } + }, [region]); + + const formatDate = (timestamp: string) => { + const date = new Date(parseInt(timestamp, 10) * 1000); + return `${date.toDateString()} ${date.getHours()}:${(date.getMinutes() < 10 ? '0' : '') + date.getMinutes()}`; + }; + + const theme = useColorScheme() ?? 'light'; return ( <ParallaxScrollView> - <ThemedView> - <ThemedText>{ id }</ThemedText> - </ThemedView> + {alert === null ? ( + <ThemedView> + <ThemedText>Loading...</ThemedText> + </ThemedView> + ) : ( + <> + <ThemedView style={styles.dateRow}> + <Ionicons + name="chevron-back-outline" + size={18} + color="#0a7ea4" + style={styles.icon} + /> + <Link href="/alerts"> + <ThemedText type="link">Alerts list</ThemedText> + </Link> + </ThemedView> + <ThemedView> + <MapView + ref={mapRef} + initialRegion={region} + style={styles.map} + > + <Polygon + coordinates={polygon} + strokeColor="#c0392b" + fillColor="rgba(192, 57, 43, 0.4)" + /> + <Polygon + coordinates={extendedPolygon} + strokeColor="#c0392b" + fillColor="rgba(192, 57, 43, 0.4)" + /> + </MapView> + </ThemedView> + <ThemedView style={styles.dateRow}> + <Ionicons + name="calendar-outline" + size={18} + color={theme === 'light' ? Colors.light.text : Colors.dark.text} + style={styles.icon} + /> + <ThemedText>{formatDate(alert.createdAt)}</ThemedText> + </ThemedView> + <ThemedView style={styles.dateRow}> + <Ionicons + name="alert-circle-outline" + size={18} + color={theme === 'light' ? Colors.light.text : Colors.dark.text} + style={styles.icon} + /> + <ThemedText>{alert.level}</ThemedText> + </ThemedView> + </> + )} </ParallaxScrollView> ); } const styles = StyleSheet.create({ + map: { + height: 400, + }, + dateRow: { + flexDirection: 'row', + alignItems: 'center', + }, + icon: { + marginRight: 8, + }, }); diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 48c47b4..960a502 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -166,7 +166,7 @@ export default function HomeScreen() { initialRegion={region} style={styles.map} > - <Marker coordinate={coordinates} title="Start Point" /> + <Marker coordinate={coordinates} title="Me" /> </MapView> </View> </> |