import { useEffect, useState } from "react"; import { Platform, StyleSheet } from "react-native"; import MapView, { Marker, PROVIDER_DEFAULT } from "react-native-maps"; import MapViewDirections from "react-native-maps-directions"; import { icons } from "@/constants"; import { useFetch } from "@/lib/fetch"; import { calculateDriverTimes, calculateRegion, generateMarkersFromData, } from "@/lib/map"; import { useDriverStore, useLocationStore, useServiceStore } from "@/store"; import type { Driver, MarkerData } from "@/types/type"; // react-native-maps sizes itself from a real style object, so give it explicit // dimensions rather than relying on percentage classNames resolving to 0. const styles = StyleSheet.create({ map: { ...StyleSheet.absoluteFillObject, borderRadius: 16 }, }); // "mutedStandard" is an Apple Maps type. Android's MapManager looks the value // up in a fixed table and unboxes the result into an int, so an unrecognised // name is a null Integer -> NullPointerException, and the map never draws. const MAP_TYPE = Platform.OS === "ios" ? "mutedStandard" : "standard"; // showsPointsOfInterest is iOS-only; on Android the same muting is done with a // style array, so both platforms get the same clean base map. const MUTED_POI_STYLE = [ { featureType: "poi", elementType: "labels", stylers: [{ visibility: "off" }], }, { featureType: "transit", elementType: "labels.icon", stylers: [{ visibility: "off" }], }, ]; export const Map = () => { const { userLatitude, userLongitude, destinationLatitude, destinationLongitude, } = useLocationStore(); const { service } = useServiceStore(); const { selectedDriver, setDrivers } = useDriverStore(); // Online drivers of the selected service near the rider. Falls back to a // Beirut center when the rider's position isn't resolved yet so the map // still populates instead of sitting empty. const lat = userLatitude ?? 33.8938; const lng = userLongitude ?? 35.5018; const { data: drivers, error } = useFetch( `/(api)/driver/nearby?service=${service}&lat=${lat}&lng=${lng}`, ); const [markers, setMarkers] = useState([]); const region = calculateRegion({ userLatitude, userLongitude, destinationLatitude, destinationLongitude, }); useEffect(() => { if (Array.isArray(drivers)) { if (!userLatitude || !userLongitude) return; const newMarkers = generateMarkersFromData({ data: drivers, userLatitude, userLongitude, }); setMarkers(newMarkers); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [drivers, userLatitude, userLongitude]); useEffect(() => { if (markers.length > 0 && destinationLatitude && destinationLongitude) { calculateDriverTimes({ markers, userLatitude, userLongitude, destinationLatitude, destinationLongitude, service, }).then((driversWithTimes) => { setDrivers((driversWithTimes as MarkerData[]) ?? []); }); } }, [ markers, destinationLatitude, destinationLongitude, userLatitude, userLongitude, setDrivers, service, ]); // The map itself never waits on the driver list or the location fix: drivers // are an overlay, and calculateRegion falls back to Beirut without coords. // Previously either one failing replaced the whole map with a spinner or an // error line, which read as "the map didn't load". if (error) console.log("[MAP_DRIVERS]: ", error); return ( {markers.map((marker) => ( ))} {userLatitude && userLongitude && destinationLatitude && destinationLongitude && ( <> )} ); };