import React, { useCallback, useMemo, useRef, useState, useEffect, } from "react"; import { View, StyleSheet } from "react-native"; import Maplibre from "@maplibre/maplibre-react-native"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import { useNavigation } from "@react-navigation/native"; import MapView from "~/containers/Map/MapView"; import Camera from "~/containers/Map/Camera"; import LastKnownLocationMarker from "~/containers/Map/LastKnownLocationMarker"; import { BoundType, DEFAULT_ZOOM_LEVEL } from "~/containers/Map/constants"; import StepZoomButtonGroup from "~/containers/Map/StepZoomButtonGroup"; import Text from "~/components/Text"; import Loader from "~/components/Loader"; import { useTheme } from "~/theme"; import { defibsActions } from "~/stores"; import { getDefibAvailability } from "~/utils/dae/getDefibAvailability"; import useNearbyDefibs from "./useNearbyDefibs"; const STATUS_COLORS = { open: "#4CAF50", closed: "#F44336", unknown: "#9E9E9E", }; function defibsToGeoJSON(defibs) { return { type: "FeatureCollection", features: defibs.map((d) => { const { status } = getDefibAvailability(d.horaires_std, d.disponible_24h); return { type: "Feature", id: d.id, geometry: { type: "Point", coordinates: [d.longitude, d.latitude], }, properties: { id: d.id, nom: d.nom || "Défibrillateur", status, color: STATUS_COLORS[status], }, }; }), }; } function EmptyNoLocation() { const { colors } = useTheme(); return ( Localisation indisponible Activez la géolocalisation pour afficher les défibrillateurs sur la carte. ); } export default React.memo(function DAEListCarte() { const { colors } = useTheme(); const navigation = useNavigation(); const { defibs, loading, noLocation, hasLocation, isLastKnown, lastKnownTimestamp, coords, } = useNearbyDefibs(); const mapRef = useRef(); const cameraRef = useRef(); const [cameraKey, setCameraKey] = useState(1); const refreshCamera = useCallback(() => { setCameraKey(`${Date.now()}`); }, []); const hasCoords = coords && coords.latitude !== null && coords.longitude !== null; // Camera state — simple follow user const [followUserLocation] = useState(true); const [followUserMode] = useState(Maplibre.UserTrackingMode.Follow); const [zoomLevel, setZoomLevel] = useState(DEFAULT_ZOOM_LEVEL); const geoJSON = useMemo(() => defibsToGeoJSON(defibs), [defibs]); const onMarkerPress = useCallback( (e) => { const feature = e?.features?.[0]; if (!feature) return; const defibId = feature.properties?.id; const defib = defibs.find((d) => d.id === defibId); if (defib) { defibsActions.setSelectedDefib(defib); navigation.navigate("DAEItem"); } }, [defibs, navigation], ); if (noLocation && !hasLocation) { return ; } if (loading && defibs.length === 0 && !hasCoords) { return ; } return ( {geoJSON.features.length > 0 && ( )} {isLastKnown && hasCoords ? ( ) : ( )} ); }); const styles = StyleSheet.create({ container: { flex: 1, }, emptyContainer: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 32, }, emptyIcon: { marginBottom: 16, }, emptyTitle: { fontSize: 18, fontWeight: "600", textAlign: "center", marginBottom: 8, }, emptyText: { fontSize: 14, textAlign: "center", lineHeight: 20, }, });