summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2024-08-31 16:45:39 +0200
committerSanto Cariotti <santo@dcariotti.me>2024-08-31 16:45:39 +0200
commit6a99bf48f8f46f6d50e93286ee158c5bf9112819 (patch)
tree1c16450e05d204aa57b9d6eac7f49f44c6492151
parentbafd0b8c5ddd6f769a834618de8b03688f0fd835 (diff)
Show alert details
-rw-r--r--app/(tabs)/alerts/[id].tsx189
-rw-r--r--app/(tabs)/index.tsx2
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>
</>