Ver Fonte

changed map on Trips - Add Region Screen

Viktoriia há 7 meses atrás
pai
commit
5072e0a7ea
1 ficheiros alterados com 156 adições e 151 exclusões
  1. 156 151
      src/screens/InAppScreens/TravelsScreen/AddRegionsScreen/index.tsx

+ 156 - 151
src/screens/InAppScreens/TravelsScreen/AddRegionsScreen/index.tsx

@@ -1,39 +1,68 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import { View, Text, Platform, TouchableOpacity } from 'react-native';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { View, Text, TouchableOpacity } from 'react-native';
 import { SafeAreaView } from 'react-native-safe-area-context';
-import MapView, { Geojson, UrlTile } from 'react-native-maps';
-import * as turf from '@turf/turf';
-import { Feature } from '@turf/turf';
 import { useNavigation } from '@react-navigation/native';
+import * as turf from '@turf/turf';
+import MapLibreGL, { CameraRef, MapViewRef } from '@maplibre/maplibre-react-native';
 
 import { Header, Modal, FlatList as List } from 'src/components';
 
-import { FASTEST_MAP_HOST } from 'src/constants';
+import { VECTOR_MAP_HOST } from 'src/constants';
 import { Colors } from 'src/theme';
-import { findRegionInDataset } from 'src/utils/mapHelpers';
-import { calculateMapRegion } from '../utils/calculateRegion';
-import { FeatureCollection } from 'src/types/map';
 import { NAVIGATION_PAGES } from 'src/types';
 import { RegionAddData } from '../utils/types';
 import { useGetRegionsForTripsQuery } from '@api/trips';
+import { useGetListRegionsQuery } from '@api/regions';
 import { styles } from './styles';
 
-import regionsGeojson from '../../../../../assets/geojson/nm2022.json';
 import SearchSvg from '../../../../../assets/icons/search.svg';
 import SaveSvg from '../../../../../assets/icons/travels-screens/save.svg';
 
+MapLibreGL.setAccessToken(null);
+
+const generateFilter = (ids: number[]) => {
+  return ids?.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
+};
+
+let nm_regions = {
+  id: 'regions',
+  type: 'fill',
+  source: 'regions',
+  'source-layer': 'regions',
+  style: {
+    fillColor: 'rgba(15, 63, 79, 0)'
+  },
+  filter: ['all'],
+  maxzoom: 16
+};
+
+let selected_region = {
+  id: 'selected_region',
+  type: 'fill',
+  source: 'regions',
+  'source-layer': 'regions',
+  style: {
+    fillColor: 'rgba(237, 147, 52, 0.7)'
+  },
+  maxzoom: 12
+};
+
 const AddRegionsScreen = ({ route }: { route: any }) => {
   const { regionsParams }: { regionsParams: RegionAddData[] } = route.params;
   const { data } = useGetRegionsForTripsQuery(true);
+  const { data: regionsList } = useGetListRegionsQuery(true);
   const navigation = useNavigation();
 
   const [regions, setRegions] = useState<RegionAddData[] | null>(null);
   const [isModalVisible, setIsModalVisible] = useState(false);
-  const [selectedRegions, setSelectedRegions] = useState<FeatureCollection[]>([]);
+  const [selectedRegions, setSelectedRegions] = useState<any[]>([]);
   const [regionsToSave, setRegionsToSave] = useState<RegionAddData[]>([]);
   const [regionData, setRegionData] = useState<RegionAddData | null>(null);
   const [regionPopupVisible, setRegionPopupVisible] = useState(false);
-  const mapRef = useRef<MapView>(null);
+  const mapRef = useRef<MapViewRef>(null);
+  const cameraRef = useRef<CameraRef>(null);
+
+  const [filterSelectedRegions, setFilterSelectedRegions] = useState<any[]>(generateFilter([]));
 
   useEffect(() => {
     if (data && data.regions) {
@@ -41,34 +70,18 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
     }
   }, [data]);
 
+  useEffect(() => {
+    const ids = selectedRegions.map((region) => region.id);
+    setFilterSelectedRegions(generateFilter(ids));
+  }, [selectedRegions]);
+
   useEffect(() => {
     const addRegionsAsync = async () => {
       if (regionsParams) {
-        const promises = regionsParams.map((param) => {
-          const foundRegion: Feature | undefined = (
-            regionsGeojson as FeatureCollection
-          ).features.find((region) => region.properties?.id === param.id);
-          if (foundRegion) {
-            setRegionsToSave((prevRegions) => [...prevRegions, param]);
-            return {
-              type: 'FeatureCollection',
-              features: [
-                {
-                  geometry: foundRegion.geometry,
-                  properties: foundRegion.properties,
-                  type: 'Feature'
-                }
-              ]
-            };
-          }
-          return null;
-        });
-
-        const results = await Promise.all(promises);
-        const validRegions = results.filter(Boolean);
+        setRegionsToSave((prevRegions) => [...prevRegions, ...regionsParams]);
 
         setSelectedRegions(
-          (prevSelectedRegions) => [...prevSelectedRegions, ...validRegions] as FeatureCollection[]
+          (prevSelectedRegions) => [...prevSelectedRegions, ...regionsParams] as any
         );
       }
     };
@@ -77,35 +90,30 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
   }, [regionsParams]);
 
   const addRegionFromSearch = async (searchRegion: RegionAddData) => {
-    const foundRegion = (regionsGeojson as FeatureCollection).features.find(
-      (region) => region.properties?.id === searchRegion.id
-    );
-
-    if (foundRegion) {
-      const regionIndex = selectedRegions.findIndex(
-        (region) => region.features[0].properties?.id === searchRegion.id
-      );
-      const regionFromApi = regions?.find((region) => region.id === searchRegion.id);
-
-      if (regionIndex < 0 && regionFromApi) {
-        const newRegion = {
-          type: 'FeatureCollection',
-          features: [
-            {
-              geometry: foundRegion.geometry,
-              properties: foundRegion.properties,
-              type: 'Feature'
-            }
-          ]
-        };
-
-        setSelectedRegions([...selectedRegions, newRegion as FeatureCollection]);
-        setRegionsToSave((prevRegions) => [...prevRegions, regionFromApi]);
-        setRegionPopupVisible(true);
-
-        const bounds = turf.bbox(foundRegion);
-        const region = calculateMapRegion(bounds);
-        mapRef.current?.animateToRegion(region, 1000);
+    const regionIndex = selectedRegions.findIndex((region) => region.id === searchRegion.id);
+    const regionFromApi = regions?.find((region) => region.id === searchRegion.id);
+
+    if (regionIndex < 0 && regionFromApi) {
+      const newRegion = {
+        id: searchRegion.id,
+        name: searchRegion.name
+      };
+
+      setSelectedRegions([...selectedRegions, newRegion] as any);
+      setRegionsToSave((prevRegions) => [...prevRegions, regionFromApi]);
+      setRegionPopupVisible(true);
+
+      if (regionsList) {
+        const region = regionsList.data.find((region) => region.id === searchRegion.id);
+        if (region) {
+          const bounds = turf.bbox(region.bbox);
+          cameraRef.current?.fitBounds(
+            [bounds[2], bounds[3]],
+            [bounds[0], bounds[1]],
+            [50, 50, 50, 50],
+            600
+          );
+        }
       }
     }
   };
@@ -129,77 +137,63 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
   };
 
   const handleMapPress = useCallback(
-    async (event: {
-      nativeEvent: { coordinate: { latitude: any; longitude: any }; action?: string };
-    }) => {
-      if (event.nativeEvent?.action === 'polygon-press') return;
-
-      const { latitude, longitude } = event.nativeEvent.coordinate;
-      const point = turf.point([longitude, latitude]);
-
-      let foundRegion = regionsGeojson ? findRegionInDataset(regionsGeojson, point) : null;
-
-      if (foundRegion) {
-        const id = foundRegion.properties?.id;
-
-        const newRegion = {
-          type: 'FeatureCollection',
-          features: [
-            {
-              geometry: foundRegion.geometry,
-              properties: foundRegion.properties,
-              type: 'Feature'
-            }
-          ]
-        };
+    async (event: any) => {
+      if (!mapRef.current) return;
 
-        const regionIndex = selectedRegions.findIndex(
-          (region) => region.features[0].properties?.id === id
+      try {
+        const { screenPointX, screenPointY } = event.properties;
+
+        const { features } = await mapRef.current.queryRenderedFeaturesAtPoint(
+          [screenPointX, screenPointY],
+          undefined,
+          ['regions']
         );
 
-        if (regionIndex >= 0) {
-          const newSelectedRegions = [...selectedRegions];
-          newSelectedRegions.splice(regionIndex, 1);
-          setSelectedRegions(newSelectedRegions);
-          setRegionsToSave(regionsToSave.filter((region) => region.id !== id));
-          setRegionPopupVisible(false);
-          return;
-        } else {
-          setSelectedRegions([...selectedRegions, newRegion] as FeatureCollection[]);
-        }
+        if (features?.length) {
+          const selectedRegion = features[0];
 
-        handleSetRegionData(id);
-        setRegionPopupVisible(true);
+          if (selectedRegion.properties) {
+            const id = selectedRegion.properties.id;
 
-        const bounds = turf.bbox(foundRegion);
-        const region = calculateMapRegion(bounds);
+            const regionIndex = selectedRegions.findIndex((region) => region.id === id);
+
+            if (regionIndex >= 0) {
+              const newSelectedRegions = [...selectedRegions];
+              newSelectedRegions.splice(regionIndex, 1);
+              setSelectedRegions(newSelectedRegions);
+              setRegionsToSave(regionsToSave.filter((region) => region.id !== id));
+              setRegionPopupVisible(false);
+              return;
+            } else {
+              setSelectedRegions([...selectedRegions, selectedRegion.properties] as any);
+            }
 
-        mapRef.current?.animateToRegion(region, 1000);
+            handleSetRegionData(id);
+            setRegionPopupVisible(true);
+
+            if (regionsList) {
+              const region = regionsList.data.find((region) => region.id === id);
+              if (region) {
+                const bounds = turf.bbox(region.bbox);
+                cameraRef.current?.fitBounds(
+                  [bounds[2], bounds[3]],
+                  [bounds[0], bounds[1]],
+                  [50, 50, 50, 50],
+                  600
+                );
+              }
+            }
+          }
+        }
+      } catch (error) {
+        console.error('Failed to get coordinates on AddRegionsScreen', error);
       }
     },
     [selectedRegions, regions]
   );
 
-  function renderGeoJSON() {
-    if (!selectedRegions || !selectedRegions.length) return null;
-
-    return selectedRegions.map((region, index) => (
-      <Geojson
-        key={index}
-        geojson={region as any}
-        fillColor="rgba(237, 147, 52, 0.5)"
-        strokeColor={Colors.ORANGE}
-        strokeWidth={Platform.OS == 'android' ? 2 : 1}
-        zIndex={3}
-        tracksViewChanges={false}
-      />
-    ));
-  }
-
-  const renderedGeoJSON = useMemo(() => renderGeoJSON(), [selectedRegions]);
-
   return (
-    <SafeAreaView style={{ height: '100%' }}>
+    <SafeAreaView style={{ height: '100%' }} edges={['top']}>
       <View style={styles.wrapper}>
         <Header label={'Add Regions'} />
         <View style={styles.searchContainer}>
@@ -221,40 +215,51 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
       </View>
 
       <View style={styles.container}>
-        <MapView
+        <MapLibreGL.MapView
           ref={mapRef}
           style={styles.map}
-          showsMyLocationButton={false}
-          showsCompass={false}
-          zoomControlEnabled={false}
-          mapType={Platform.OS == 'android' ? 'none' : 'standard'}
-          maxZoomLevel={15}
-          minZoomLevel={0}
-          initialRegion={{
-            latitude: 0,
-            longitude: 0,
-            latitudeDelta: 180,
-            longitudeDelta: 180
-          }}
+          styleJSON={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
+          rotateEnabled={false}
+          attributionEnabled={false}
           onPress={handleMapPress}
         >
-          <UrlTile
-            urlTemplate={`${FASTEST_MAP_HOST}/tiles_osm/{z}/{x}/{y}`}
-            maximumZ={15}
-            maximumNativeZ={13}
-            shouldReplaceMapContent
-            minimumZ={0}
+          <MapLibreGL.Camera ref={cameraRef} />
+
+          <MapLibreGL.LineLayer
+            id="nm-regions-line-layer"
+            sourceID={nm_regions.source}
+            sourceLayerID={nm_regions['source-layer']}
+            filter={nm_regions.filter as any}
+            maxZoomLevel={nm_regions.maxzoom}
+            style={{
+              lineColor: 'rgba(14, 80, 109, 1)',
+              lineWidth: ['interpolate', ['linear'], ['zoom'], 0, 0.2, 4, 1, 5, 1.5, 12, 3],
+              lineWidthTransition: { duration: 300, delay: 0 }
+            }}
+            belowLayerID="waterway-name"
           />
-          <UrlTile
-            urlTemplate={`${FASTEST_MAP_HOST}/tiles_nm/grid/{z}/{x}/{y}`}
-            maximumZ={15}
-            maximumNativeZ={13}
-            shouldReplaceMapContent
-            minimumZ={0}
-            opacity={0.3}
+          <MapLibreGL.FillLayer
+            id={nm_regions.id}
+            sourceID={nm_regions.source}
+            sourceLayerID={nm_regions['source-layer']}
+            filter={nm_regions.filter as any}
+            style={nm_regions.style}
+            maxZoomLevel={nm_regions.maxzoom}
+            belowLayerID="nm-regions-line-layer"
           />
-          {renderedGeoJSON}
-        </MapView>
+
+          {selectedRegions && selectedRegions.length > 0 ? (
+            <MapLibreGL.FillLayer
+              id={selected_region.id}
+              sourceID={nm_regions.source}
+              sourceLayerID={nm_regions['source-layer']}
+              filter={filterSelectedRegions as any}
+              style={selected_region.style}
+              maxZoomLevel={selected_region.maxzoom}
+              belowLayerID="nm-regions-line-layer"
+            />
+          ) : null}
+        </MapLibreGL.MapView>
       </View>
       {regionPopupVisible && regionData && (
         <View style={styles.popupWrapper}>