import React, { useState, useEffect, useRef } from 'react' import { Dimensions, StyleSheet, View, Platform } from 'react-native'; import MapView, { PROVIDER_DEFAULT, PROVIDER_GOOGLE, Marker, Region, } from 'react-native-maps' import Geocoder from 'react-native-geocoding'; import { useLanguage, useConfig } from 'ordering-components/native' import { GoogleMapsParams } from '../../types'; import Alert from '../../providers/AlertProvider' import { OIcon } from '../shared'; export const GoogleMap = (props: GoogleMapsParams) => { const { location, handleChangeAddressMap, maxLimitLocation, readOnly, markerTitle, saveLocation, setSaveLocation, handleToggleMap, locations, isSetInputs } = props const [, t] = useLanguage() const [configState] = useConfig() const { width, height } = Dimensions.get('window'); const ASPECT_RATIO = width / height; const [markerPosition, setMarkerPosition] = useState({ latitude: locations ? locations[2].lat : location.lat, longitude: locations ? locations[2].lng : location.lng }) const [region, setRegion] = useState({ latitude: location.lat, longitude: location.lng, latitudeDelta: 0.0010, longitudeDelta: 0.0010 * ASPECT_RATIO }) let mapRef = useRef(null) const googleMapsApiKey = configState?.configs?.google_maps_api_key?.value const center = { lat: location?.lat, lng: location?.lng } const [alertState, setAlertState] = useState<{ open: boolean, content: Array, key?: string | null }>({ open: false, content: [], key: null }) const mapErrors: any = { ERROR_NOT_FOUND_ADDRESS: 'Sorry, we couldn\'t find an address', ERROR_MAX_LIMIT_LOCATION_TO: 'Sorry, You can only set the position to' } let MARKERS = locations && locations.map((location: { lat: number, lng: number }) => { return { latitude: location.lat, longitude: location.lng } }) const geocodePosition = (pos: { latitude: number, longitude: number }) => { Geocoder.from({ latitude: pos.latitude, longitude: pos.longitude }).then(({ results }: any) => { let zipcode = null if (results && results.length > 0) { for (const component of results[0].address_components) { const addressType = component.types[0] if (addressType === 'postal_code') { zipcode = component.short_name break } } let data = null const details = { geometry: { location: { lat: pos.latitude, lng: pos.longitude } } } if (isSetInputs) { data = { address: results[0]?.formatted_address, location: results[0]?.geometry?.location, zipcode, place_id: results[0]?.place_id, } } handleChangeAddressMap && handleChangeAddressMap(data, details) setSaveLocation && setSaveLocation(false) handleToggleMap && handleToggleMap() } else { setMapErrors && setMapErrors('ERROR_NOT_FOUND_ADDRESS') } }).catch((err: any) => { setMapErrors && setMapErrors(err.message) }) } const validateResult = (curPos: { latitude: number, longitude: number }) => { const loc1 = center const loc2 = curPos const distance = calculateDistance(loc1, loc2) if (!maxLimitLocation) { geocodePosition(curPos) setMarkerPosition(curPos) setRegion({ ...region, longitude: curPos.longitude, latitude: curPos.latitude }) return } if (distance <= maxLimitLocation) { setMarkerPosition(curPos) setRegion({ ...region, longitude: curPos.longitude, latitude: curPos.latitude }) } else { setMapErrors && setMapErrors('ERROR_MAX_LIMIT_LOCATION') setMarkerPosition({ latitude: center.lat, longitude: center.lng }) } } const calculateDistance = (pointA: { lat: number, lng: number }, pointB: { latitude: number, longitude: number }) => { const lat1 = pointA.lat; const lon1 = pointA.lng; const lat2 = pointB.latitude; const lon2 = pointB.longitude; const R = 6371e3; const φ1 = lat1 * (Math.PI / 180); const φ2 = lat2 * (Math.PI / 180); const Δφ = (lat2 - lat1) * (Math.PI / 180); const Δλ = (lon2 - lon1) * (Math.PI / 180); const a = (Math.sin(Δφ / 2) * Math.sin(Δφ / 2)) + ((Math.cos(φ1) * Math.cos(φ2)) * (Math.sin(Δλ / 2) * Math.sin(Δλ / 2))); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); const distance = R * c; return distance; } const handleChangeRegion = (coordinates: Region) => { validateResult(coordinates) } const closeAlert = () => { setAlertState({ open: false, content: [] }) } const setMapErrors = (errKey: string) => { setAlertState({ open: true, content: !(errKey === 'ERROR_MAX_LIMIT_LOCATION_TO') ? [t(errKey, mapErrors[errKey])] : [`${t(errKey, mapErrors[errKey])} ${maxLimitLocation} ${t('METTERS', 'meters')}`], key: errKey }) } const fitAllMarkers = () => { mapRef.current.fitToCoordinates(MARKERS, { edgePadding: { top: 80, right: 80, bottom: 80, left: 80 }, animated: true, }); } useEffect(() => { Geocoder.init(googleMapsApiKey) }, []) useEffect(() => { if (saveLocation) { geocodePosition(markerPosition) } }, [saveLocation]) useEffect(() => { const interval = setInterval(() => { if (mapRef.current && locations) { fitAllMarkers() } }, 1000) return () => clearInterval(interval) }, [locations]) useEffect(() => { if(!locations) return locations[0] = {...locations[0], lat: location.lat, lng: location.lng} MARKERS = locations && locations.map((location: { lat: number, lng: number }) => { return { latitude: location.lat, longitude: location.lng } }) }, [location]) return ( <> handleChangeRegion(coordinates) : () => { }} zoomTapEnabled zoomEnabled zoomControlEnabled cacheEnabled moveOnMarkerPress ref={mapRef} > {locations ? ( <> {MARKERS && MARKERS.map((location: { latitude: number, longitude: number }, i: number) => ( { } ))} ) : ( )} ) } const styles = StyleSheet.create({ map: { ...StyleSheet.absoluteFillObject, } })