diff --git a/packages/app/components/card/LargeCard.tsx b/packages/app/components/card/LargeCard.tsx index 822c979b5..1868503cf 100644 --- a/packages/app/components/card/LargeCard.tsx +++ b/packages/app/components/card/LargeCard.tsx @@ -126,13 +126,10 @@ const loadStyles = (theme: any) => { flexDirection: 'column', alignItems: 'center', textAlign: 'center', - padding: - Platform.OS === 'web' - ? currentTheme.size.cardPadding - : currentTheme.size.mobilePadding, + padding: Platform.OS === 'web' ? '5%' : currentTheme.size.mobilePadding, paddingHorizontal: currentTheme.padding.paddingInside, marginBottom: 20, - height: Platform.OS === 'web' ? 650 : '23%', + height: Platform.OS === 'web' ? 'calc(min( 80vh, 80vw))' : '23%', minHeight: 350, overflow: 'hidden', }, diff --git a/packages/app/components/destination/index.tsx b/packages/app/components/destination/index.tsx index dd849ec66..5f53f18ca 100644 --- a/packages/app/components/destination/index.tsx +++ b/packages/app/components/destination/index.tsx @@ -1,11 +1,8 @@ -import React from 'react'; +import React, { Suspense } from 'react'; import { Platform, ScrollView, View } from 'react-native'; -import { RButton, RStack, RText as OriginalRText } from '@packrat/ui'; +import { RButton, RText as OriginalRText } from '@packrat/ui'; import useTheme from '../../hooks/useTheme'; -import { MapContainer } from 'app/components/map'; -import { defaultShape } from '../../utils/mapFunctions'; import LargeCard from '../card/LargeCard'; -import WeatherCard from '../weather/WeatherCard'; import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons'; import useCustomStyles from 'app/hooks/useCustomStyles'; import { @@ -16,6 +13,7 @@ import { useGEOLocationSearch } from 'app/hooks/geojson'; import { PlacesAutocomplete } from '../PlacesAutocomplete/PlacesAutocomplete'; import { useRouter } from 'app/hooks/router'; import { WeatherData } from 'app/components/weather/WeatherData'; +import { Map } from 'app/modules/map'; const RText: any = OriginalRText; @@ -91,7 +89,7 @@ export const DestinationPage = () => { } as any, }); - const shape = geoJSON ?? defaultShape; + const shape = geoJSON; interface SearchResult { properties: { @@ -129,7 +127,7 @@ export const DestinationPage = () => { } }; - const map = () => ; + const map = () => ; return ( @@ -187,7 +185,7 @@ export const DestinationPage = () => { geoJSON={geoJSON} selectedSearchResult={currentDestination} /> - {/* ( { ContentComponent={map} contentProps={{ shape }} type="map" - /> */} + /> )} diff --git a/packages/app/components/map/Map.tsx b/packages/app/components/map/Map.tsx deleted file mode 100644 index e80bbe1ce..000000000 --- a/packages/app/components/map/Map.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { MAPBOX_ACCESS_TOKEN } from '@packrat/config'; -import { useWebMap } from 'app/hooks/map/useWebMap'; -import useCustomStyles from 'app/hooks/useCustomStyles'; -import mapboxgl from 'mapbox-gl'; -import React, { FC, useState } from 'react'; -import { Modal, View } from 'react-native'; -import { isPolygonOrMultiPolygon } from '../../utils/mapFunctions'; -import MapButtonsOverlay from './MapButtonsOverlay'; -import MapPreview from './MapPreview'; -import useGpxUpload from './useGpxUpload'; -import { MapProps } from './models'; - -mapboxgl.accessToken = MAPBOX_ACCESS_TOKEN; - -const DESTINATION = 'destination'; -const TRIP = 'trip'; -const WebMap: FC = ({ shape: shapeProp }) => { - const [downloadable, setDownloadable] = useState(false); - const styles = useCustomStyles(loadStyles); - const { - shape, - setShape, - showModal, - mapFullscreen, - enableFullScreen, - disableFullScreen, - handleChangeMapStyle, - fetchLocation, - openMaps, - fetchGpxDownload, - downloading, - mapContainer, - } = useWebMap({ shape: shapeProp }); - - const handleGpxUpload = useGpxUpload(setShape); - - const element = ( - - {showModal || isPolygonOrMultiPolygon(shape) ? ( - - ) : ( - - )} - - - ); - - // TODO: Fix this. The modal is not working as expected. - // return element; - - return ( - <> - - {element} - - {!showModal && element} - - ); - - // return showModal ? ( - // - // {element} - // - // ) : ( - // element - // ); -}; - -const loadStyles = () => ({ - container: { - alignItems: 'center', - justifyContent: 'center', - width: '100%', - borderRadius: 10, - }, - map: { - width: '100%', - minHeight: '100vh', // Adjust the height to your needs - }, - modal: { - alignItems: 'center', - }, -}); - -export default WebMap; diff --git a/packages/app/components/map/MapContainer.native.tsx b/packages/app/components/map/MapContainer.native.tsx deleted file mode 100644 index a739fb64e..000000000 --- a/packages/app/components/map/MapContainer.native.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; - -import { View, Platform } from 'react-native'; -import { isObjectEmpty } from '../../utils/isObjectEmpty'; -import { defaultShape } from '../../utils/mapFunctions'; -import useTheme from '../../hooks/useTheme'; -import NativeMap from './Map'; -import useCustomStyles from 'app/hooks/useCustomStyles'; - -export function MapContainer({ shape }) { - const { enableDarkMode, enableLightMode, isDark, isLight, currentTheme } = - useTheme(); - const styles = useCustomStyles(loadStyles); - if (!shape || isObjectEmpty(shape)) { - shape = defaultShape; - } - - if (Platform.OS === 'android' || Platform.OS === 'ios') { - return ( - - - - ); - } -} - -export default MapContainer; - -const loadStyles = () => ({ - webContainer: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - height: 'fit-content', - }, - nativeContainer: { - width: '100%', - marginBottom: 20, - paddingHorizontal: 5, - }, -}); diff --git a/packages/app/components/map/MapContainer.tsx b/packages/app/components/map/MapContainer.tsx deleted file mode 100644 index 58f15f0dc..000000000 --- a/packages/app/components/map/MapContainer.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; - -import { View, Platform } from 'react-native'; - -import WebMap from './Map'; -import { isObjectEmpty } from '../../utils/isObjectEmpty'; -import { defaultShape } from '../../utils/mapFunctions'; -import useCustomStyles from 'app/hooks/useCustomStyles'; - -export function MapContainer({ shape }) { - if (!shape || isObjectEmpty(shape)) { - shape = defaultShape; - } - const styles = useCustomStyles(loadStyles); - - if (Platform.OS === 'web') { - return ( - - - - ); - } -} - -export default MapContainer; - -const loadStyles = () => ({ - webContainer: { - alignItems: 'center', - justifyContent: 'center', - overflow: 'hidden', - marginVertical: 10, - width: '100%', - height: 400, - borderRadius: 10, - }, -}); diff --git a/packages/app/components/map/MapPreview.tsx b/packages/app/components/map/MapPreview.tsx deleted file mode 100644 index 2c1385239..000000000 --- a/packages/app/components/map/MapPreview.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { RImage } from '@packrat/ui'; -import { useProcessedShape, useMapPreviewData } from './useMapPreview'; -import { useAuthUserToken } from 'app/modules/auth'; -export default function MapPreview({ shape }) { - const processedShape = useProcessedShape(shape); - const { token } = useAuthUserToken(); - const mapPreviewData: any = useMapPreviewData(shape, processedShape); - - if (!mapPreviewData) return null; - - return ( - - ); -} diff --git a/packages/app/components/map/index.tsx b/packages/app/components/map/index.tsx deleted file mode 100644 index b8f49b1eb..000000000 --- a/packages/app/components/map/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export * from './MapContainer'; -export { default as Map } from './Map'; diff --git a/packages/app/components/trip/TripCard.tsx b/packages/app/components/trip/TripCard.tsx index 03b452298..e55e4826d 100644 --- a/packages/app/components/trip/TripCard.tsx +++ b/packages/app/components/trip/TripCard.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { RCard as OriginalRCard, RParagraph as OriginalRParagraph, @@ -10,7 +11,7 @@ import useCustomStyles from 'app/hooks/useCustomStyles'; import useTheme from '../../hooks/useTheme'; import { theme } from '../../theme/index'; import Carousel from '../carousel'; -import MapContainer from '../map/MapContainer'; +import { Map } from '@packrat/map'; import { PlacesAutocomplete } from '../PlacesAutocomplete/PlacesAutocomplete'; interface TripCardProps { @@ -101,11 +102,11 @@ export default function TripCard({ Loading.... ) : ( - + ) ) : isSearch ? ( // - //because handle select is not defined here + // because handle select is not defined here ) : ( diff --git a/packages/app/components/trip/TripCards/TripMapCard.tsx b/packages/app/components/trip/TripCards/TripMapCard.tsx index aebc2588e..69e00e388 100644 --- a/packages/app/components/trip/TripCards/TripMapCard.tsx +++ b/packages/app/components/trip/TripCards/TripMapCard.tsx @@ -1,14 +1,14 @@ import { ErrorBoundary, RStack, RText } from '@packrat/ui'; -import MapContainer from 'app/components/map/MapContainer'; +import { Map } from '@packrat/map'; import useTheme from 'app/hooks/useTheme'; import { TripCardBase } from './TripCardBase'; import { FontAwesome5 } from '@expo/vector-icons'; import React from 'react'; -type TripMapCardProps = { +interface TripMapCardProps { isLoading?: boolean; shape: any; -}; +} export const TripMapCard = ({ isLoading, shape }: TripMapCardProps) => { const { currentTheme } = useTheme(); @@ -31,7 +31,7 @@ export const TripMapCard = ({ isLoading, shape }: TripMapCardProps) => { ) : ( - + )} diff --git a/packages/app/hooks/map/index.ts b/packages/app/hooks/map/index.ts deleted file mode 100644 index eff47360c..000000000 --- a/packages/app/hooks/map/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { useWebMap } from './useWebMap'; -export { useNativeMap } from './useNativeMap'; diff --git a/packages/app/modules/map/index.ts b/packages/app/modules/map/index.ts new file mode 100644 index 000000000..e7e7a361d --- /dev/null +++ b/packages/app/modules/map/index.ts @@ -0,0 +1 @@ +export * from './widgets'; diff --git a/packages/app/modules/map/widgets/Map.tsx b/packages/app/modules/map/widgets/Map.tsx new file mode 100644 index 000000000..aa036af0f --- /dev/null +++ b/packages/app/modules/map/widgets/Map.tsx @@ -0,0 +1,21 @@ +import React, { type FC } from 'react'; +import { Map as LibMap } from '@packrat/map'; +import { StyleSheet, View } from 'react-native'; + +interface MapProps { + shape: any; +} + +export const Map: FC = ({ shape }) => { + return ; +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + map: { + width: '100%', + height: '100%', + }, +}); diff --git a/packages/app/modules/map/widgets/index.ts b/packages/app/modules/map/widgets/index.ts new file mode 100644 index 000000000..80f496a5a --- /dev/null +++ b/packages/app/modules/map/widgets/index.ts @@ -0,0 +1 @@ +export { Map } from './Map'; diff --git a/packages/app/package.json b/packages/app/package.json index ed82bad5b..0c7c004a9 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -32,6 +32,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@hookform/resolvers": "^3.3.4", "@packrat/crosspath": "*", + "@packrat/map": "*", "@packrat/ui": "*", "@packrat/validations": "*", "@react-native-async-storage/async-storage": "^1.23.1", diff --git a/packages/app/screens/maps/index.tsx b/packages/app/screens/maps/index.tsx index f89f39109..863cf76ba 100644 --- a/packages/app/screens/maps/index.tsx +++ b/packages/app/screens/maps/index.tsx @@ -1,13 +1,13 @@ import { Modal, Text, View, Image } from 'react-native'; import { offlineManager } from '@rnmapbox/maps'; -import { useState, useCallback } from 'react'; +import React, { useState, useCallback } from 'react'; import { useFocusEffect } from 'expo-router'; import { TouchableOpacity } from 'react-native-gesture-handler'; import useTheme from 'app/hooks/useTheme'; import { api } from 'app/constants/api'; import { RButton, RScrollView, RStack } from '@packrat/ui'; import useCustomStyles from 'app/hooks/useCustomStyles'; -import { Map } from 'app/components/map'; +import { Map } from '@packrat/map'; import { useAuthUserToken, useUserQuery } from 'app/modules/auth'; import type OfflinePack from '@rnmapbox/maps/lib/typescript/src/modules/offline/OfflinePack'; import { disableScreen } from 'app/hoc/disableScreen'; diff --git a/packages/app/utils/isObjectEmpty.ts b/packages/app/utils/isObjectEmpty.ts index c3fc4f793..175cfd801 100644 --- a/packages/app/utils/isObjectEmpty.ts +++ b/packages/app/utils/isObjectEmpty.ts @@ -4,6 +4,6 @@ * @param {Object} obj - The object to check. * @return {boolean} - True if the object is empty, false otherwise. */ -export function isObjectEmpty(obj: Object): boolean { +export function isObjectEmpty(obj: Record): boolean { return Object.keys(obj).length === 0; } diff --git a/packages/map/.eslintrc.js b/packages/map/.eslintrc.js new file mode 100644 index 000000000..bee952fb0 --- /dev/null +++ b/packages/map/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['../../.eslintrc-front.js'], +}; diff --git a/packages/map/README.md b/packages/map/README.md new file mode 100644 index 000000000..c98013d05 --- /dev/null +++ b/packages/map/README.md @@ -0,0 +1,28 @@ +# @packrat/map + +A cross platform map with mapbox + +## Installation + +```sh +npm install @packrat/map +``` + +## Usage + + +```js +import { Map } from '@packrat/map'; + +// ... +return ( + // ... + + // ... +) +``` + + +## License + +MIT diff --git a/packages/map/package.json b/packages/map/package.json new file mode 100755 index 000000000..c5ddc8be6 --- /dev/null +++ b/packages/map/package.json @@ -0,0 +1,36 @@ +{ + "files": [ + "types", + "dist" + ], + "main": "src/index.tsx", + "module:jsx": "src", + "name": "@packrat/map", + "dependencies": { + "@expo/vector-icons": "^14.0.0", + "@packrat/config": "*", + "@packrat/ui": "*", + "@react-native-community/geolocation": "^3.0.6", + "@rnmapbox/maps": "^10.1.29", + "@tmcw/togeojson": "^5.7.0", + "expo-document-picker": "~11.10.1", + "expo-file-system": "~16.0.9", + "file-saver": "^2.0.5", + "leaflet": "^1.9.4", + "mapbox-gl": "1.13.3", + "react": "*", + "react-dom": "*", + "react-leaflet": "^4.2.1", + "react-native": "*", + "togpx": "^0.5.4", + "xmldom": "^0.6.0" + }, + "private": true, + "sideEffects": [ + "*.css" + ], + "version": "0.0.1", + "devDependencies": { + "@types/leaflet": "^1" + } +} diff --git a/packages/app/components/map/Map.native.tsx b/packages/map/src/Map.native.tsx similarity index 96% rename from packages/app/components/map/Map.native.tsx rename to packages/map/src/Map.native.tsx index 8af80cb33..22c022103 100644 --- a/packages/app/components/map/Map.native.tsx +++ b/packages/map/src/Map.native.tsx @@ -6,6 +6,7 @@ import { Modal, Alert, Linking, + StyleSheet, } from 'react-native'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import Mapbox from '@rnmapbox/maps'; @@ -19,7 +20,6 @@ import { import { MAPBOX_ACCESS_TOKEN } from '@packrat/config'; -import { theme } from '../../theme'; import { isLineString, isPoint, @@ -28,16 +28,15 @@ import { multiPolygonBounds, validateCoordinates, validateShape, -} from '../../utils/mapFunctions'; +} from './utils/mapFunctions'; import MapButtonsOverlay from './MapButtonsOverlay'; import { gpx as toGeoJSON } from '@tmcw/togeojson'; -import { useNativeMap } from 'app/hooks/map/useNativeMap'; -import useCustomStyles from 'app/hooks/useCustomStyles'; +import { useNativeMap } from './hooks/useNativeMap'; import * as DocumentPicker from 'expo-document-picker'; import * as FileSystem from 'expo-file-system'; import { DOMParser } from 'xmldom'; -import { MapProps } from './models'; +import { type MapPropsLegacy } from './models'; import { useUserQuery } from 'app/modules/auth'; import { useUpdateUser } from 'app/modules/user'; @@ -66,7 +65,7 @@ const RInput: any = OriginalRInput; Mapbox.setWellKnownTileServer(Platform.OS === 'android' ? 'Mapbox' : 'mapbox'); Mapbox.setAccessToken(MAPBOX_ACCESS_TOKEN); -const NativeMap: React.FC = ({ +const NativeMap: React.FC = ({ shape: shapeProp, onExitFullScreen, mapName: predefinedMapName, @@ -76,7 +75,7 @@ const NativeMap: React.FC = ({ const { user, refetch } = useUserQuery(); console.log({ user }); const updateUser = useUpdateUser(); - const styles = useCustomStyles(loadStyles); + const styles = StyleSheet.create(loadStyles); const { camera, mapViewRef, @@ -153,7 +152,7 @@ const NativeMap: React.FC = ({ [mapName.toLowerCase()]: downloadOptions, }, }) - .then(() => refetch()) + .then(async () => refetch()) .then(() => { onDownload(downloadOptions); }) @@ -429,7 +428,7 @@ const NativeMap: React.FC = ({ ); }; -const loadStyles = () => ({ +const loadStyles = { page: { flex: 1, flexDirection: 'column', @@ -469,7 +468,7 @@ const loadStyles = () => ({ position: 'absolute', bottom: 10, right: 10, - backgroundColor: theme.colors.primary, + backgroundColor: 'blue', // theme.colors.primary, borderRadius: 50, width: 45, height: 45, @@ -477,10 +476,10 @@ const loadStyles = () => ({ alignItems: 'center', }, mapNameFieldErrorMessage: { - color: theme.colors.error, + color: 'red', // theme.colors.error, fontStyle: 'italic', fontSize: 12, }, -}); +}; export default NativeMap; diff --git a/packages/map/src/Map.tsx b/packages/map/src/Map.tsx new file mode 100644 index 000000000..179e093ea --- /dev/null +++ b/packages/map/src/Map.tsx @@ -0,0 +1,13 @@ +import React, { type FC } from 'react'; +import { type MapProps } from './models'; +import { MapContainer, GeoJSON } from 'react-leaflet'; + +const WebMap: FC = ({ shape }) => { + return ( + + + + ); +}; + +export default WebMap; diff --git a/packages/app/components/map/MapButtonsOverlay.tsx b/packages/map/src/MapButtonsOverlay.tsx similarity index 69% rename from packages/app/components/map/MapButtonsOverlay.tsx rename to packages/map/src/MapButtonsOverlay.tsx index 15404eb8f..ed9f710e4 100644 --- a/packages/app/components/map/MapButtonsOverlay.tsx +++ b/packages/map/src/MapButtonsOverlay.tsx @@ -6,6 +6,7 @@ import { Modal, View, Alert, + StyleSheet, Platform, } from 'react-native'; import { @@ -13,9 +14,7 @@ import { MaterialCommunityIcons, FontAwesome5, } from '@expo/vector-icons'; -import useTheme from '../../hooks/useTheme'; -import { mapboxStyles } from '../../utils/mapFunctions'; -import useCustomStyles from 'app/hooks/useCustomStyles'; +import { mapboxStyles } from './utils/mapFunctions'; interface MapButtonsOverlayProps { mapFullscreen: boolean; @@ -47,9 +46,7 @@ const MapButtonsOverlay = ({ navigateToMaps, }: MapButtonsOverlayProps) => { const [showStyleOptions, setShowStyleOptions] = useState(false); - const { enableDarkMode, enableLightMode, isDark, isLight, currentTheme } = - useTheme(); - const styles = useCustomStyles(loadStyles); + const styles = StyleSheet.create(loadStyles); const handleStyleOptionPress = () => { setShowStyleOptions(!showStyleOptions); }; @@ -61,7 +58,7 @@ const MapButtonsOverlay = ({ * @return {type} undefined */ const handleStyleSelection = (style) => { - handleChangeMapStyle(style); + handleChangeMapStyle?.call(style); setShowStyleOptions(false); }; @@ -194,7 +191,7 @@ const MapButtonsOverlay = ({ position: 'absolute', bottom: 80, right: 10, - backgroundColor: currentTheme.colors.white, + backgroundColor: 'white', borderRadius: 30, zIndex: 1, }} @@ -236,110 +233,107 @@ const MapButtonsOverlay = ({ ); }; -const loadStyles = (theme) => { - const { currentTheme } = theme; - return { - container: { - alignItems: 'center', - justifyContent: 'center', - height: 400, - width: '100%', - borderRadius: 10, - }, - map: { - width: '100%', - minHeight: '100vh', // Adjust the height to your needs - }, - stylePicker: { - // Style Picker Button - position: 'absolute', - top: 10, - left: 10, - width: 40, - height: 40, - alignItems: 'center', - justifyContent: 'center', - borderRadius: 20, - backgroundColor: currentTheme.colors.white, - }, - styleModalContainer: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - backgroundColor: 'rgba(0, 0, 0, 0.5)', - }, - styleModalContent: { - backgroundColor: currentTheme.colors.white, - borderRadius: 8, - padding: 10, - }, - styleOption: { - paddingVertical: 8, - paddingHorizontal: 16, - }, - styleOptionText: { - fontSize: 16, - fontWeight: 'bold', - }, - locationButton: { - alignItems: 'center', - justifyContent: 'center', - width: 40, - height: 40, - position: 'absolute', - bottom: 30, - right: 10, - backgroundColor: currentTheme.colors.white, - borderRadius: 30, - zIndex: 1, - }, - headerBtnView: { - justifyContent: 'center', - alignItems: 'center', - borderRadius: 30, - marginTop: 30, - backgroundColor: currentTheme.colors.white, - }, - enterFullScreenBtn: { - width: 40, - height: 40, - position: 'absolute', - bottom: 10, - right: 10, - }, - exitFullscreenBtn: { - width: 40, - height: 40, - position: 'absolute', - top: 10, - right: 10, - }, - fullScreen: { - width: Platform.OS == 'web' ? '25%' : '70%', - height: 40, - padding: 10, - backgroundColor: currentTheme.colors.white, - position: 'absolute', - bottom: 30, - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'center', - alignSelf: 'center', - borderRadius: 20, - }, - downloadIcon: { - width: 21, - height: 21, - }, - downloadText: { - fontSize: 15, - fontWeight: '500', - marginRight: 8, - }, - modal: { - alignItems: 'center', - }, - }; -}; +const loadStyles = { + container: { + alignItems: 'center', + justifyContent: 'center', + height: 400, + width: '100%', + borderRadius: 10, + }, + map: { + width: '100%', + minHeight: '100%', // Adjust the height to your needs + }, + stylePicker: { + // Style Picker Button + position: 'absolute', + top: 10, + left: 10, + width: 40, + height: 40, + alignItems: 'center', + justifyContent: 'center', + borderRadius: 20, + backgroundColor: 'white', + }, + styleModalContainer: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'rgba(0, 0, 0, 0.5)', + }, + styleModalContent: { + backgroundColor: 'white', + borderRadius: 8, + padding: 10, + }, + styleOption: { + paddingVertical: 8, + paddingHorizontal: 16, + }, + styleOptionText: { + fontSize: 16, + fontWeight: 'bold', + }, + locationButton: { + alignItems: 'center', + justifyContent: 'center', + width: 40, + height: 40, + position: 'absolute', + bottom: 30, + right: 10, + backgroundColor: 'white', + borderRadius: 30, + zIndex: 1, + }, + headerBtnView: { + justifyContent: 'center', + alignItems: 'center', + borderRadius: 30, + marginTop: 30, + backgroundColor: 'white', + }, + enterFullScreenBtn: { + width: 40, + height: 40, + position: 'absolute', + bottom: 10, + right: 10, + }, + exitFullscreenBtn: { + width: 40, + height: 40, + position: 'absolute', + top: 10, + right: 10, + }, + fullScreen: { + width: Platform.OS == 'web' ? '25%' : '70%', + height: 40, + padding: 10, + backgroundColor: 'white', + position: 'absolute', + bottom: 30, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + alignSelf: 'center', + borderRadius: 20, + }, + downloadIcon: { + width: 21, + height: 21, + }, + downloadText: { + fontSize: 15, + fontWeight: '500', + marginRight: 8, + }, + modal: { + alignItems: 'center', + }, +} as const; export default MapButtonsOverlay; diff --git a/packages/map/src/MapPreview.tsx b/packages/map/src/MapPreview.tsx new file mode 100644 index 000000000..1fe9c5f15 --- /dev/null +++ b/packages/map/src/MapPreview.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { RImage } from '@packrat/ui'; +import { useProcessedShape, useMapPreviewData } from './hooks/useMapPreview'; +import { useGetObjectUrlFromImageUri } from './hooks/useGetObjectUrlFromImageUri'; + +export default function MapPreview({ shape }: { shape: unknown }) { + const processedShape = useProcessedShape(shape); + const mapPreviewData = useMapPreviewData(shape, processedShape); + const uri = useGetObjectUrlFromImageUri(mapPreviewData?.uri || null); + + if (!mapPreviewData || !uri) return null; + + return ( + + ); +} diff --git a/packages/map/src/hooks/useCustomStyles.ts b/packages/map/src/hooks/useCustomStyles.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/map/src/hooks/useGetObjectUrlFromImageUri.ts b/packages/map/src/hooks/useGetObjectUrlFromImageUri.ts new file mode 100644 index 000000000..1d2741304 --- /dev/null +++ b/packages/map/src/hooks/useGetObjectUrlFromImageUri.ts @@ -0,0 +1,36 @@ +import { useEffect, useState } from 'react'; +import { useAuthUserToken } from 'app/modules/auth'; + +export const useGetObjectUrlFromImageUri = (imageURI: string | null) => { + const { token } = useAuthUserToken(); + const [imageObjectURL, setImageObjectURL] = useState(null); + + useEffect(() => { + if (!imageURI) { + return; + } + const fetchImage = async () => { + try { + const response = await fetch(imageURI, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + + if (response.ok) { + const blob = await response.blob(); + const imgURL = URL.createObjectURL(blob); + setImageObjectURL(imgURL); + } else { + console.error('Failed to fetch image'); + } + } catch (error) { + console.error('Error:', error); + } + }; + + fetchImage(); + }, [imageURI, token]); + + return imageObjectURL; +}; diff --git a/packages/app/components/map/useGpxUpload.tsx b/packages/map/src/hooks/useGpxUpload.ts similarity index 100% rename from packages/app/components/map/useGpxUpload.tsx rename to packages/map/src/hooks/useGpxUpload.ts diff --git a/packages/app/components/map/useMapPreview.tsx b/packages/map/src/hooks/useMapPreview.ts similarity index 93% rename from packages/app/components/map/useMapPreview.tsx rename to packages/map/src/hooks/useMapPreview.ts index b0a418b16..ac8cc33a3 100644 --- a/packages/app/components/map/useMapPreview.tsx +++ b/packages/map/src/hooks/useMapPreview.ts @@ -4,13 +4,11 @@ import { isPolygonOrMultiPolygon, processShapeData, isPoint, -} from '../../utils/mapFunctions'; -import { api } from '../../constants/api'; +} from '../utils/mapFunctions'; +import { API_URL } from '@packrat/config'; import { useState, useEffect } from 'react'; -interface Feature { - [key: string]: any; -} +type Feature = Record; interface MapPreviewData { isPoint: boolean; @@ -90,7 +88,7 @@ const useMapPreviewData = (shape, processedShape) => { coordinates: [lng, lat], } = shape.features[0].geometry; - const mapPreviewEndpoint = `${api}/mapPreview`; + const mapPreviewEndpoint = `${API_URL}/mapPreview`; const data = { isPoint: isPoint(shape), diff --git a/packages/app/hooks/map/useNativeMap.ts b/packages/map/src/hooks/useNativeMap.ts similarity index 98% rename from packages/app/hooks/map/useNativeMap.ts rename to packages/map/src/hooks/useNativeMap.ts index 8e695be0e..15bd69e12 100644 --- a/packages/app/hooks/map/useNativeMap.ts +++ b/packages/map/src/hooks/useNativeMap.ts @@ -1,5 +1,5 @@ import Geolocation from '@react-native-community/geolocation'; -import { offlineManager, MapView } from '@rnmapbox/maps'; +import { offlineManager, type MapView } from '@rnmapbox/maps'; import { useCallback, useEffect, useRef, useState } from 'react'; import { Alert, Dimensions } from 'react-native'; import { @@ -8,7 +8,7 @@ import { getShapeSourceBounds, mapboxStyles, validateShape, -} from '../../utils/mapFunctions'; +} from '../utils/mapFunctions'; interface Location { longitude: number; diff --git a/packages/app/hooks/map/useWebMap.ts b/packages/map/src/hooks/useWebMap.ts similarity index 99% rename from packages/app/hooks/map/useWebMap.ts rename to packages/map/src/hooks/useWebMap.ts index a8acbfd31..36f7a73dd 100644 --- a/packages/app/hooks/map/useWebMap.ts +++ b/packages/map/src/hooks/useWebMap.ts @@ -13,8 +13,8 @@ import { mapboxStyles, multiPolygonBounds, processShapeData, -} from 'app/utils/mapFunctions'; -import { saveFile } from 'app/utils/fileSaver/fileSaver.web'; +} from '../utils/mapFunctions'; +import { saveFile } from '../utils/fileSaver/fileSaver.web'; // Hook to handle state management const useMapState = (shapeProp) => { diff --git a/packages/map/src/index.tsx b/packages/map/src/index.tsx new file mode 100644 index 000000000..59f4accdf --- /dev/null +++ b/packages/map/src/index.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { View } from 'react-native'; +import { isObjectEmpty } from './utils/isObjectEmpty'; +import { defaultShape } from './utils/mapFunctions'; +import PlatformMap from './Map'; +import type { MapPropsLegacy } from './models'; + +export const Map: React.FC = ({ + shape, // : shapeProp, + onExitFullScreen, + mapName: predefinedMapName, + forceFullScreen = false, + shouldEnableDownload = true, +}) => { + if (!shape || isObjectEmpty(shape)) { + shape = defaultShape; + } + + return ( + + ); +}; + +export default Map; + +const loadStyles = () => ({ + webContainer: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + overflow: 'hidden', + marginVertical: 10, + width: '100%', + height: 'fit-content', + // height: 400, + borderRadius: 10, + }, + nativeContainer: { + width: '100%', + marginBottom: 20, + paddingHorizontal: 5, + }, +}); diff --git a/packages/app/components/map/models.ts b/packages/map/src/models.ts similarity index 75% rename from packages/app/components/map/models.ts rename to packages/map/src/models.ts index adb61cd02..64dd67570 100644 --- a/packages/app/components/map/models.ts +++ b/packages/map/src/models.ts @@ -1,7 +1,11 @@ -export interface MapProps { +export interface MapPropsLegacy { shape: any; onExitFullScreen?: () => void; forceFullScreen?: boolean; shouldEnableDownload?: boolean; mapName?: string; } + +export interface MapProps { + shape: any; +} diff --git a/packages/map/src/types.ts b/packages/map/src/types.ts new file mode 100644 index 000000000..d904ab09f --- /dev/null +++ b/packages/map/src/types.ts @@ -0,0 +1,5 @@ +import type { ImageStyle, TextStyle, ViewStyle } from 'react-native'; + +export type NamedStyles = { + [P in keyof T]: ViewStyle | TextStyle | ImageStyle; +}; diff --git a/packages/app/utils/fileSaver/fileSaver.native.ts b/packages/map/src/utils/fileSaver/fileSaver.native.ts similarity index 100% rename from packages/app/utils/fileSaver/fileSaver.native.ts rename to packages/map/src/utils/fileSaver/fileSaver.native.ts diff --git a/packages/app/utils/fileSaver/fileSaver.web.ts b/packages/map/src/utils/fileSaver/fileSaver.web.ts similarity index 100% rename from packages/app/utils/fileSaver/fileSaver.web.ts rename to packages/map/src/utils/fileSaver/fileSaver.web.ts diff --git a/packages/map/src/utils/isObjectEmpty.ts b/packages/map/src/utils/isObjectEmpty.ts new file mode 100644 index 000000000..c3fc4f793 --- /dev/null +++ b/packages/map/src/utils/isObjectEmpty.ts @@ -0,0 +1,9 @@ +/** + * Determines if an object is empty. + * + * @param {Object} obj - The object to check. + * @return {boolean} - True if the object is empty, false otherwise. + */ +export function isObjectEmpty(obj: Object): boolean { + return Object.keys(obj).length === 0; +} diff --git a/packages/map/src/utils/mapFunctions.ts b/packages/map/src/utils/mapFunctions.ts new file mode 100644 index 000000000..be1301fb3 --- /dev/null +++ b/packages/map/src/utils/mapFunctions.ts @@ -0,0 +1,452 @@ +import * as Location from 'expo-location'; + +const defaultShape = { + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [ + [-77.044211, 38.852924], + [-77.045659, 38.860158], + [-77.044232, 38.862326], + [-77.040879, 38.865454], + [-77.039936, 38.867698], + [-77.040338, 38.86943], + [-77.04264, 38.872528], + [-77.03696, 38.878424], + [-77.032309, 38.87937], + [-77.030056, 38.880945], + [-77.027645, 38.881779], + [-77.026946, 38.882645], + [-77.026942, 38.885502], + [-77.028054, 38.887449], + [-77.02806, 38.892088], + [-77.03364, 38.892108], + [-77.033643, 38.899926], + ], + }, + }, + ], +}; + +/** + * Normalize the coordinates. + * + * @param {array} coordinates - The coordinates to be normalized. + * @return {array} The normalized coordinates. + */ +function normalizeCoordinates(coordinates) { + // check if coordinates are nested, flip them if so + if (typeof coordinates[0][0] === 'number') { + // If first value is greater than 90, it's likely in the format of (longitude, latitude) + if (coordinates[0][0] > 90) { + return coordinates.map((coordinate) => [coordinate[1], coordinate[0]]); + } + return coordinates; + } + // if not nested, nest them + // If first value is greater than 90, it's likely in the format of (longitude, latitude) + if (coordinates[0] > 90) { + return [[coordinates[1], coordinates[0]]]; + } + return [[coordinates[0], coordinates[1]]]; +} + +/** + * Converts a Photon GeoJSON object to a Shape object. + * + * @param {object} photonGeoJson - The Photon GeoJSON object to convert. + * @return {object} The converted Shape object. + */ +function convertPhotonGeoJsonToShape(photonGeoJson) { + return { + type: 'FeatureCollection', + features: [photonGeoJson], + }; +} + +/** + * Calculates the minimum and maximum longitude and latitude coordinates of a given shape. + * + * @param {object} shape - The shape object containing the coordinates. + * @return {array} An array representing the minimum and maximum longitude and latitude coordinates. + */ +function getShapeSourceBounds(shape) { + let minLng = Infinity; + let maxLng = -Infinity; + let minLat = Infinity; + let maxLat = -Infinity; + shape.features[0].geometry.coordinates.forEach((coord) => { + const lng = coord[0]; + const lat = coord[1]; + + if (lng < minLng) { + minLng = lng; + } + if (lng > maxLng) { + maxLng = lng; + } + if (lat < minLat) { + minLat = lat; + } + if (lat > maxLat) { + maxLat = lat; + } + }); + + return [ + [minLng, minLat], + [maxLng, maxLat], + ]; +} + +/** + * Handles the shape source load and calculates the zoom level based on the width and height. + * + * @param {object} shape - The shape object containing the coordinates. + * @param {number} width - The width of the shape. + * @param {number} height - The height of the shape. + * @return {number|null} The calculated zoom level or null if there are no coordinates. + */ +function handleShapeSourceLoad(shape, width, height) { + if (shape?.features[0]?.geometry?.coordinates?.length > 1) { + let bounds = getShapeSourceBounds(shape); + if (bounds && bounds[0] && bounds[1]) { + bounds = [bounds[0].concat(bounds[1])]; + return calculateZoomLevel(bounds[0], { width, height }); + } + } + return null; +} + +/** + * Calculates the latitude in radians. + * + * @param {number} lat - The latitude in degrees. + * @return {number} The latitude in radians. + */ +function latRad(lat) { + const sin = Math.sin((lat * Math.PI) / 180); + const radX2 = Math.log((1 + sin) / (1 - sin)) / 2; + return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2; +} + +/** + * Calculates the zoom level of a map based on the size of the map in pixels, + * the size of the world in pixels, and a fraction. + * + * @param {number} mapPx - The size of the map in pixels. + * @param {number} worldPx - The size of the world in pixels. + * @param {number} fraction - The fraction used for the calculation. + * @return {number} The calculated zoom level. + */ +function zoom(mapPx, worldPx, fraction) { + return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2); +} + +/** + * Calculates the zoom level for a given map based on the provided bounds and map dimensions. + * + * @param {Array} bounds - The bounds of the map in the format [south, west, north, east]. + * @param {Object} mapDim - The dimensions of the map in the format {height: number, width: number}. + * @return {number} The calculated zoom level for the map. + */ +function calculateZoomLevel(bounds, mapDim) { + const WORLD_DIM = { height: 256, width: 256 }; + const ne = { lat: bounds[2], lng: bounds[3] }; + const sw = { lat: bounds[0], lng: bounds[1] }; + + const latFraction = (latRad(ne.lat) - latRad(sw.lat)) / Math.PI; + + const lngDiff = ne.lng - sw.lng; + const lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360; + + const latZoom = zoom(mapDim.height, WORLD_DIM.height, Math.abs(latFraction)); + const lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction); + + return latZoom; +} + +/** + * Finds the center of a trail based on its shape coordinates. + * + * @param {object} shape - The shape object containing trail coordinates. + * @return {array} The center coordinates of the trail. + */ +function findTrailCenter(shape) { + console.log('Finding trail center...', shape); + const trailCoords = shape?.features[0]?.geometry?.coordinates; + + // Flatten the coordinates array for Polygon geometries + + let avgLatitude; + let avgLongitude; + let flattenedCoords; + if (trailCoords[0][0] === undefined) { + avgLongitude = trailCoords[0]; + avgLatitude = trailCoords[1]; + } else if (Array.isArray(trailCoords[0][0][0])) { + flattenedCoords = trailCoords[0].flat(); + + const latitudes = flattenedCoords.map((coord) => coord[1]); + const longitudes = flattenedCoords.map((coord) => coord[0]); + + avgLatitude = latitudes.reduce((a, b) => a + b, 0) / latitudes.length; + avgLongitude = longitudes.reduce((a, b) => a + b, 0) / longitudes.length; + } else { + flattenedCoords = trailCoords[0]; + + const latitudes = flattenedCoords.map((coord) => coord[1]); + const longitudes = flattenedCoords.map((coord) => coord[0]); + + avgLatitude = latitudes.reduce((a, b) => a + b, 0) / latitudes.length; + avgLongitude = longitudes.reduce((a, b) => a + b, 0) / longitudes.length; + } + + console.log('Average latitude:', avgLatitude); + console.log('Average longitude:', avgLongitude); + + return [avgLongitude, avgLatitude]; +} + +/** + * Process the shape data by transforming LineString features into Points. + * + * @param {Object} shape - The shape data to be processed. + * @return {Object} The processed shape data. + */ +const processShapeData = (shape) => { + const processedShape = { ...shape }; + processedShape.features = []; + + shape.features.forEach((feature) => { + if (feature.geometry.type === 'LineString') { + // Make sure coordinates are in the correct format + feature.geometry.coordinates = ensure2DArray( + feature.geometry.coordinates, + ); + + const points = feature.geometry.coordinates.map((coord, index) => { + return { + type: 'Feature', + properties: { + // Add a `meta` property to the first and last points + meta: + index === 0 || index === feature.geometry.coordinates.length - 1 + ? 'end' + : 'middle', + }, + geometry: { + type: 'Point', + coordinates: coord, + }, + }; + }); + + processedShape.features.push(...points); + + // Keep the original LineString feature + processedShape.features.push(feature); + } + }); + + return processedShape; +}; + +/** + * Ensure the input array is a 2D array. + * + * @param {Array} arr - The input array. + * @return {Array} - The 2D array. + */ +const ensure2DArray = (arr) => { + // If the first element of the array is not an array itself, add an additional array layer + if (!Array.isArray(arr[0])) { + return [arr]; + } + // If the array is already 2D, return it as is + return arr; +}; + +const mapboxStyles = [ + { label: 'Outdoors', style: 'mapbox://styles/mapbox/outdoors-v11' }, + { label: 'Street', style: 'mapbox://styles/mapbox/streets-v11' }, + { label: 'Light', style: 'mapbox://styles/mapbox/light-v10' }, + { label: 'Dark', style: 'mapbox://styles/mapbox/dark-v10' }, + { label: 'Satellite', style: 'mapbox://styles/mapbox/satellite-v9' }, + { + label: 'Satellite Street', + style: 'mapbox://styles/mapbox/satellite-streets-v11', + }, +]; + +/** + * Retrieves the current location asynchronously. + * + * @return {Promise} The current location object. + */ +const getLocation = async () => { + const { status } = await Location.requestForegroundPermissionsAsync(); + + if (status !== 'granted') { + alert('Permission to access location was denied'); + return; + } + + const location = await Location.getCurrentPositionAsync({}); + + return location; +}; + +/** + * Checks if a shape is downloadable. + * + * @param {Object} shape - The shape object to check. + * @return {boolean} Returns true if the shape is downloadable, false otherwise. + */ +const isShapeDownloadable = (shape) => { + return shape?.features[0]?.geometry?.coordinates?.length >= 1; +}; + +/** + * Checks if the given shape is a point. + * + * @param {Object} shape - The shape object to be checked. + * @return {boolean} Returns true if the shape is a point, otherwise returns false. + */ +const isPoint = (shape) => { + return shape?.features[0]?.geometry?.type === 'Point'; +}; +/** + * Checks if the given shape is a LineString. + * + * @param {Object} shape - The shape object to be checked. + * @return {boolean} Returns true if the shape is a LineString, otherwise false. + */ +const isLineString = (shape) => { + return shape?.features[0]?.geometry?.type === 'LineString'; +}; + +/** + * Checks if the given shape is a Polygon or MultiPolygon. + * + * @param {object} shape - The shape object to be checked. + * @return {boolean} Returns true if the shape is a Polygon or MultiPolygon, otherwise returns false. + */ +const isPolygonOrMultiPolygon = (shape) => { + return ( + shape?.features[0]?.geometry?.type === 'MultiPolygon' || + shape?.features[0]?.geometry?.type === 'MultiPolygon' + ); +}; + +/** + * Calculates the bounds of a multipolygon. + * + * @param {object} multipolygonData - The multipolygon data. + * @return {array} The center longitude and latitude of the bounds. + */ +const multiPolygonBounds = (multipolygonData) => { + let coordinates = multipolygonData.geometry.coordinates[0]; + if (multipolygonData.geometry.type === 'MultiPolygon') { + coordinates = coordinates[0]; + } + let minX = Infinity; + let maxX = -Infinity; + let minY = Infinity; + let maxY = -Infinity; + + for (const [lng, lat] of coordinates) { + minX = Math.min(minX, lng); + maxX = Math.max(maxX, lng); + minY = Math.min(minY, lat); + maxY = Math.max(maxY, lat); + } + + const centerLng = (minX + maxX) / 2; + const centerLat = (minY + maxY) / 2; + + return [centerLng, centerLat]; +}; + +const validateCoordinates = (coordinates: any) => { + if (!Array.isArray(coordinates)) { + throw new Error('Invalid coordinates: Must be an array.'); + } + coordinates.forEach((coord) => { + if (!Array.isArray(coord)) { + if (typeof coord !== 'number') { + throw new Error( + 'Invalid coordinates: Each coordinate must be a number.', + ); + } + } else { + validateCoordinates(coord); + } + }); +}; + +const validateGeoJSON = (geojson: any) => { + if (!geojson || typeof geojson !== 'object') { + throw new Error('Invalid GeoJSON: Data is not an object.'); + } + if (!geojson.type) { + throw new Error('Invalid GeoJSON: Missing "type" property.'); + } + if (!geojson.features || !Array.isArray(geojson.features)) { + throw new Error('Invalid GeoJSON: Missing or invalid "features" property.'); + } + + geojson.features.forEach((feature) => { + try { + if (feature.geometry && feature.geometry.coordinates) { + if (feature.geometry.type === 'Point') { + validateCoordinates(feature.geometry.coordinates); + } else if ( + feature.geometry.type === 'LineString' || + feature.geometry.type === 'Polygon' + ) { + feature.geometry.coordinates.forEach(validateCoordinates); + } else if (feature.geometry.type === 'MultiPolygon') { + feature.geometry.coordinates.forEach((polygon) => { + polygon.forEach(validateCoordinates); + }); + } + } + } catch (e) { + throw new Error(e); + } + }); +}; + +const validateShape = (shape: any) => { + try { + validateGeoJSON(shape); + } catch (error) { + throw new Error(`Invalid shape: ${error.message}`); + } +}; + +export { + defaultShape, + getShapeSourceBounds, + handleShapeSourceLoad, + latRad, + zoom, + calculateZoomLevel, + findTrailCenter, + processShapeData, + mapboxStyles, + getLocation, + isShapeDownloadable, + convertPhotonGeoJsonToShape, + isPoint, + isLineString, + isPolygonOrMultiPolygon, + multiPolygonBounds, + validateGeoJSON, + validateShape, + validateCoordinates, +}; diff --git a/packages/map/tsconfig.json b/packages/map/tsconfig.json new file mode 100644 index 000000000..bb3fc4e85 --- /dev/null +++ b/packages/map/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base", // not set up yet + "include": ["src"], + "compilerOptions": { + "composite": true, + "jsx": "react-jsx" + }, + "references": [] +} diff --git a/server/src/controllers/mapPreview/index.ts b/server/src/controllers/mapPreview/index.ts index 812eb66ac..d27224b72 100644 --- a/server/src/controllers/mapPreview/index.ts +++ b/server/src/controllers/mapPreview/index.ts @@ -28,15 +28,13 @@ const getMapPreview = async (ctx: Context) => { } const newResponse = new Response(response.body, { + status: 200, headers: { 'Content-Type': 'image/png', }, }); - console.log('newResponse', newResponse); - - // return newResponse; - return ctx.json(newResponse, 200); + return newResponse; } catch (error) { console.log(error); return ctx.json({ error: error.message }, 400); diff --git a/yarn.lock b/yarn.lock index 88f32c3fd..b4dff4837 100644 --- a/yarn.lock +++ b/yarn.lock @@ -891,7 +891,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.25.4": +"@babel/plugin-transform-async-generator-functions@npm:^7.24.3, @babel/plugin-transform-async-generator-functions@npm:^7.25.4": version: 7.25.4 resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.4" dependencies: @@ -940,7 +940,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-class-properties@npm:^7.25.4": +"@babel/plugin-transform-class-properties@npm:^7.24.1, @babel/plugin-transform-class-properties@npm:^7.25.4": version: 7.25.4 resolution: "@babel/plugin-transform-class-properties@npm:7.25.4" dependencies: @@ -1135,7 +1135,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.7": +"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.1, @babel/plugin-transform-logical-assignment-operators@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.7" dependencies: @@ -1232,7 +1232,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.7": +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.1, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.7" dependencies: @@ -1244,7 +1244,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.24.7": +"@babel/plugin-transform-numeric-separator@npm:^7.24.1, @babel/plugin-transform-numeric-separator@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.7" dependencies: @@ -1267,7 +1267,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.12.13, @babel/plugin-transform-object-rest-spread@npm:^7.24.7": +"@babel/plugin-transform-object-rest-spread@npm:^7.12.13, @babel/plugin-transform-object-rest-spread@npm:^7.24.5, @babel/plugin-transform-object-rest-spread@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.7" dependencies: @@ -1293,7 +1293,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-optional-catch-binding@npm:^7.24.7": +"@babel/plugin-transform-optional-catch-binding@npm:^7.24.1, @babel/plugin-transform-optional-catch-binding@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.7" dependencies: @@ -1305,7 +1305,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.24.7, @babel/plugin-transform-optional-chaining@npm:^7.24.8": +"@babel/plugin-transform-optional-chaining@npm:^7.24.5, @babel/plugin-transform-optional-chaining@npm:^7.24.7, @babel/plugin-transform-optional-chaining@npm:^7.24.8": version: 7.24.8 resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8" dependencies: @@ -1437,7 +1437,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.24.7": +"@babel/plugin-transform-regenerator@npm:^7.20.0, @babel/plugin-transform-regenerator@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-transform-regenerator@npm:7.24.7" dependencies: @@ -6252,7 +6252,7 @@ __metadata: languageName: unknown linkType: soft -"@packrat/config@workspace:packages/config": +"@packrat/config@npm:*, @packrat/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@packrat/config@workspace:packages/config" languageName: unknown @@ -6271,6 +6271,31 @@ __metadata: languageName: unknown linkType: soft +"@packrat/map@npm:*, @packrat/map@workspace:packages/map": + version: 0.0.0-use.local + resolution: "@packrat/map@workspace:packages/map" + dependencies: + "@expo/vector-icons": "npm:^14.0.0" + "@packrat/config": "npm:*" + "@packrat/ui": "npm:*" + "@react-native-community/geolocation": "npm:^3.0.6" + "@rnmapbox/maps": "npm:^10.1.29" + "@tmcw/togeojson": "npm:^5.7.0" + "@types/leaflet": "npm:^1" + expo-document-picker: "npm:~11.10.1" + expo-file-system: "npm:~16.0.9" + file-saver: "npm:^2.0.5" + leaflet: "npm:^1.9.4" + mapbox-gl: "npm:1.13.3" + react: "npm:*" + react-dom: "npm:*" + react-leaflet: "npm:^4.2.1" + react-native: "npm:*" + togpx: "npm:^0.5.4" + xmldom: "npm:^0.6.0" + languageName: unknown + linkType: soft + "@packrat/playwright@workspace:packages/playwright": version: 0.0.0-use.local resolution: "@packrat/playwright@workspace:packages/playwright" @@ -7397,6 +7422,17 @@ __metadata: languageName: node linkType: hard +"@react-leaflet/core@npm:^2.1.0": + version: 2.1.0 + resolution: "@react-leaflet/core@npm:2.1.0" + peerDependencies: + leaflet: ^1.9.0 + react: ^18.0.0 + react-dom: ^18.0.0 + checksum: 10/12ce28b85cf6712a1a7b7c49466b941fc619bc7b1535308bc5711a35f7e89eb16298babfd62f6b3a92e64abf94dcf517b2bc460f59fcf20599821bc6ab3b3048 + languageName: node + linkType: hard + "@react-native-aria/button@npm:^0.2.4": version: 0.2.7 resolution: "@react-native-aria/button@npm:0.2.7" @@ -7624,6 +7660,18 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-clean@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-clean@npm:14.0.0" + dependencies: + "@react-native-community/cli-tools": "npm:14.0.0" + chalk: "npm:^4.1.2" + execa: "npm:^5.0.0" + fast-glob: "npm:^3.3.2" + checksum: 10/b92fc7dea5921f9874a726bab6f4ce3ab5623b083900991bf63097b38891d253cb440919e88e854cb550992b048aaaf4d50812a6d066d61af87f6a0b27a28b74 + languageName: node + linkType: hard + "@react-native-community/cli-config@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-config@npm:12.3.6" @@ -7638,6 +7686,20 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-config@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-config@npm:14.0.0" + dependencies: + "@react-native-community/cli-tools": "npm:14.0.0" + chalk: "npm:^4.1.2" + cosmiconfig: "npm:^9.0.0" + deepmerge: "npm:^4.3.0" + fast-glob: "npm:^3.3.2" + joi: "npm:^17.2.1" + checksum: 10/2dfc24b8b771ebff9b622eb320908ed6f568eb21dee268bf8f9da97f45a74001543783a9db5083195162443118ff7418033b60bc6593956b6a78643c5bb5f8f4 + languageName: node + linkType: hard + "@react-native-community/cli-debugger-ui@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-debugger-ui@npm:12.3.6" @@ -7647,6 +7709,24 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-debugger-ui@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-debugger-ui@npm:14.0.0" + dependencies: + serve-static: "npm:^1.13.1" + checksum: 10/485b2de5e615e27e58ef8f84acf60b18259b3326d7688449392147ec876d970166f20f91ce7dd8718c9e002739b42694589f3271a2117bee98992cfded568754 + languageName: node + linkType: hard + +"@react-native-community/cli-debugger-ui@npm:14.0.0-alpha.11": + version: 14.0.0-alpha.11 + resolution: "@react-native-community/cli-debugger-ui@npm:14.0.0-alpha.11" + dependencies: + serve-static: "npm:^1.13.1" + checksum: 10/5b837674aa9993a89bde1ee23e406c11cd0d8b19916ae7621b1ef0880bb3222ecfa222f272c9046c210276af06a6dfdf8b0b9abd2ca5e6bc4223ca4f79b9c2fe + languageName: node + linkType: hard + "@react-native-community/cli-doctor@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-doctor@npm:12.3.6" @@ -7671,6 +7751,30 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-doctor@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-doctor@npm:14.0.0" + dependencies: + "@react-native-community/cli-config": "npm:14.0.0" + "@react-native-community/cli-platform-android": "npm:14.0.0" + "@react-native-community/cli-platform-apple": "npm:14.0.0" + "@react-native-community/cli-platform-ios": "npm:14.0.0" + "@react-native-community/cli-tools": "npm:14.0.0" + chalk: "npm:^4.1.2" + command-exists: "npm:^1.2.8" + deepmerge: "npm:^4.3.0" + envinfo: "npm:^7.13.0" + execa: "npm:^5.0.0" + node-stream-zip: "npm:^1.9.1" + ora: "npm:^5.4.1" + semver: "npm:^7.5.2" + strip-ansi: "npm:^5.2.0" + wcwidth: "npm:^1.0.1" + yaml: "npm:^2.2.1" + checksum: 10/cdad0e5da75e93b08b0fc3109c603fb00f3aa187406f57fa336ac74ad55aba8bc3479f375c0e417d4787cc406db94fde9c3cf8d0602745925cb6e1df31223aa0 + languageName: node + linkType: hard + "@react-native-community/cli-hermes@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-hermes@npm:12.3.6" @@ -7697,6 +7801,34 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-platform-android@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-platform-android@npm:14.0.0" + dependencies: + "@react-native-community/cli-tools": "npm:14.0.0" + chalk: "npm:^4.1.2" + execa: "npm:^5.0.0" + fast-glob: "npm:^3.3.2" + fast-xml-parser: "npm:^4.2.4" + logkitty: "npm:^0.7.1" + checksum: 10/f8ec2e4a02689a1e151f4ce9f7ccbca4b9f9fd564159efa91ee72678668aeccebf636d39c7a10a5232553a96f00e48a796e50bd1cccaedc7ff08e9a1201e05e9 + languageName: node + linkType: hard + +"@react-native-community/cli-platform-apple@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-platform-apple@npm:14.0.0" + dependencies: + "@react-native-community/cli-tools": "npm:14.0.0" + chalk: "npm:^4.1.2" + execa: "npm:^5.0.0" + fast-glob: "npm:^3.3.2" + fast-xml-parser: "npm:^4.2.4" + ora: "npm:^5.4.1" + checksum: 10/b90d8a84ad03a36c26adb7f28a4e0fab4315eec76c0d66ef9685f044e09082070370922efcc881a8a2d12c0b0640204446745aefb00928b44ef5ba68ab742c01 + languageName: node + linkType: hard + "@react-native-community/cli-platform-ios@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-platform-ios@npm:12.3.6" @@ -7711,6 +7843,15 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-platform-ios@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-platform-ios@npm:14.0.0" + dependencies: + "@react-native-community/cli-platform-apple": "npm:14.0.0" + checksum: 10/e85dc3600c7d6a443502e47e8af2eed98756dcca2aaf418a312bf3b7ec69fb49db7aa8e63318cdf5920219e5fff47cbc819ffa5d9bdc32726bed6b2d280cfe80 + languageName: node + linkType: hard + "@react-native-community/cli-plugin-metro@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-plugin-metro@npm:12.3.6" @@ -7735,6 +7876,40 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-server-api@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-server-api@npm:14.0.0" + dependencies: + "@react-native-community/cli-debugger-ui": "npm:14.0.0" + "@react-native-community/cli-tools": "npm:14.0.0" + compression: "npm:^1.7.1" + connect: "npm:^3.6.5" + errorhandler: "npm:^1.5.1" + nocache: "npm:^3.0.1" + pretty-format: "npm:^26.6.2" + serve-static: "npm:^1.13.1" + ws: "npm:^6.2.3" + checksum: 10/1f769abb4bba47a4fa8598add1ba75345d5d8664a0d6877543046924abbfa5c2df9c01378ae7a2d65fdc7db3e6d9718db9f93f39a0a9291610467350e5a42359 + languageName: node + linkType: hard + +"@react-native-community/cli-server-api@npm:14.0.0-alpha.11": + version: 14.0.0-alpha.11 + resolution: "@react-native-community/cli-server-api@npm:14.0.0-alpha.11" + dependencies: + "@react-native-community/cli-debugger-ui": "npm:14.0.0-alpha.11" + "@react-native-community/cli-tools": "npm:14.0.0-alpha.11" + compression: "npm:^1.7.1" + connect: "npm:^3.6.5" + errorhandler: "npm:^1.5.1" + nocache: "npm:^3.0.1" + pretty-format: "npm:^26.6.2" + serve-static: "npm:^1.13.1" + ws: "npm:^6.2.3" + checksum: 10/a689e88022d48e255cb196197cf0976b39bf4422821943e4f918cd2bfcc8952324b54b1983c8fcf42da03ba6b1be810ffa90b0d0e76a34be4f47237a9ae9420e + languageName: node + linkType: hard + "@react-native-community/cli-tools@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-tools@npm:12.3.6" @@ -7753,6 +7928,42 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-tools@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-tools@npm:14.0.0" + dependencies: + appdirsjs: "npm:^1.2.4" + chalk: "npm:^4.1.2" + execa: "npm:^5.0.0" + find-up: "npm:^5.0.0" + mime: "npm:^2.4.1" + open: "npm:^6.2.0" + ora: "npm:^5.4.1" + semver: "npm:^7.5.2" + shell-quote: "npm:^1.7.3" + sudo-prompt: "npm:^9.0.0" + checksum: 10/84219934553287072b284ff524a10c554ccd5e31a0e8237f59999d1e3eb07441baf1083f6be71bd206c76a5c061b936eb1ff8dc2fd32cbda23aa0776358a6000 + languageName: node + linkType: hard + +"@react-native-community/cli-tools@npm:14.0.0-alpha.11": + version: 14.0.0-alpha.11 + resolution: "@react-native-community/cli-tools@npm:14.0.0-alpha.11" + dependencies: + appdirsjs: "npm:^1.2.4" + chalk: "npm:^4.1.2" + execa: "npm:^5.0.0" + find-up: "npm:^5.0.0" + mime: "npm:^2.4.1" + open: "npm:^6.2.0" + ora: "npm:^5.4.1" + semver: "npm:^7.5.2" + shell-quote: "npm:^1.7.3" + sudo-prompt: "npm:^9.0.0" + checksum: 10/2cbdeda1b189fbd4a61621b9e2c8c47801d8e764d1475305abbb09e27d1d493326e8a216a8d41ab0091ab9615bf01189d4e3c970d864f468f9d41a9195c3a5c0 + languageName: node + linkType: hard + "@react-native-community/cli-types@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli-types@npm:12.3.6" @@ -7762,6 +7973,15 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli-types@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli-types@npm:14.0.0" + dependencies: + joi: "npm:^17.2.1" + checksum: 10/a0e4b26da8cc600d133b60f7a74fc1375144f974bf7d453b197091e65af0e69ac0bad42eb957da6c27364c82f1126d4a6bc6b0352ea838366679fac940df9729 + languageName: node + linkType: hard + "@react-native-community/cli@npm:12.3.6": version: 12.3.6 resolution: "@react-native-community/cli@npm:12.3.6" @@ -7790,6 +8010,32 @@ __metadata: languageName: node linkType: hard +"@react-native-community/cli@npm:14.0.0": + version: 14.0.0 + resolution: "@react-native-community/cli@npm:14.0.0" + dependencies: + "@react-native-community/cli-clean": "npm:14.0.0" + "@react-native-community/cli-config": "npm:14.0.0" + "@react-native-community/cli-debugger-ui": "npm:14.0.0" + "@react-native-community/cli-doctor": "npm:14.0.0" + "@react-native-community/cli-server-api": "npm:14.0.0" + "@react-native-community/cli-tools": "npm:14.0.0" + "@react-native-community/cli-types": "npm:14.0.0" + chalk: "npm:^4.1.2" + commander: "npm:^9.4.1" + deepmerge: "npm:^4.3.0" + execa: "npm:^5.0.0" + find-up: "npm:^5.0.0" + fs-extra: "npm:^8.1.0" + graceful-fs: "npm:^4.1.3" + prompts: "npm:^2.4.2" + semver: "npm:^7.5.2" + bin: + rnc-cli: build/bin.js + checksum: 10/ae6ec29f015704aaf2ddaa60be822d277644787e4d788a13fb9de0c80e3b39e313d8ac05fac2512761b04c3d89d86b58ffb97f90067764932921288c084f5c22 + languageName: node + linkType: hard + "@react-native-community/geolocation@npm:^3.0.6": version: 3.3.0 resolution: "@react-native-community/geolocation@npm:3.3.0" @@ -7849,6 +8095,15 @@ __metadata: languageName: node linkType: hard +"@react-native/babel-plugin-codegen@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/babel-plugin-codegen@npm:0.75.2" + dependencies: + "@react-native/codegen": "npm:0.75.2" + checksum: 10/1ca1fa22053ee1dcfe051dd64dce990d0ef7369465902feb5523a116ea72abb0683b5a665c578a8b9c8cd6ef449a267788fa2488f2777eec3c48faf0d76271aa + languageName: node + linkType: hard + "@react-native/babel-preset@npm:0.73.21, @react-native/babel-preset@npm:^0.73.18": version: 0.73.21 resolution: "@react-native/babel-preset@npm:0.73.21" @@ -7901,6 +8156,61 @@ __metadata: languageName: node linkType: hard +"@react-native/babel-preset@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/babel-preset@npm:0.75.2" + dependencies: + "@babel/core": "npm:^7.20.0" + "@babel/plugin-proposal-export-default-from": "npm:^7.0.0" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.0" + "@babel/plugin-syntax-export-default-from": "npm:^7.0.0" + "@babel/plugin-syntax-flow": "npm:^7.18.0" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.0.0" + "@babel/plugin-syntax-optional-chaining": "npm:^7.0.0" + "@babel/plugin-transform-arrow-functions": "npm:^7.0.0" + "@babel/plugin-transform-async-generator-functions": "npm:^7.24.3" + "@babel/plugin-transform-async-to-generator": "npm:^7.20.0" + "@babel/plugin-transform-block-scoping": "npm:^7.0.0" + "@babel/plugin-transform-class-properties": "npm:^7.24.1" + "@babel/plugin-transform-classes": "npm:^7.0.0" + "@babel/plugin-transform-computed-properties": "npm:^7.0.0" + "@babel/plugin-transform-destructuring": "npm:^7.20.0" + "@babel/plugin-transform-flow-strip-types": "npm:^7.20.0" + "@babel/plugin-transform-for-of": "npm:^7.0.0" + "@babel/plugin-transform-function-name": "npm:^7.0.0" + "@babel/plugin-transform-literals": "npm:^7.0.0" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.1" + "@babel/plugin-transform-modules-commonjs": "npm:^7.0.0" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.0.0" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.1" + "@babel/plugin-transform-numeric-separator": "npm:^7.24.1" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.5" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.1" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.5" + "@babel/plugin-transform-parameters": "npm:^7.0.0" + "@babel/plugin-transform-private-methods": "npm:^7.22.5" + "@babel/plugin-transform-private-property-in-object": "npm:^7.22.11" + "@babel/plugin-transform-react-display-name": "npm:^7.0.0" + "@babel/plugin-transform-react-jsx": "npm:^7.0.0" + "@babel/plugin-transform-react-jsx-self": "npm:^7.0.0" + "@babel/plugin-transform-react-jsx-source": "npm:^7.0.0" + "@babel/plugin-transform-regenerator": "npm:^7.20.0" + "@babel/plugin-transform-runtime": "npm:^7.0.0" + "@babel/plugin-transform-shorthand-properties": "npm:^7.0.0" + "@babel/plugin-transform-spread": "npm:^7.0.0" + "@babel/plugin-transform-sticky-regex": "npm:^7.0.0" + "@babel/plugin-transform-typescript": "npm:^7.5.0" + "@babel/plugin-transform-unicode-regex": "npm:^7.0.0" + "@babel/template": "npm:^7.0.0" + "@react-native/babel-plugin-codegen": "npm:0.75.2" + babel-plugin-transform-flow-enums: "npm:^0.0.2" + react-refresh: "npm:^0.14.0" + peerDependencies: + "@babel/core": "*" + checksum: 10/46de9a9cbd8e7c31c1e725fb9efa2be1f06dd8dd06c3c4595784607da684e5a4ca137833cc7169cc2da7d1703dac2449a3802514fe7ab7346959322fa09757f0 + languageName: node + linkType: hard + "@react-native/codegen@npm:0.73.3": version: 0.73.3 resolution: "@react-native/codegen@npm:0.73.3" @@ -7918,6 +8228,24 @@ __metadata: languageName: node linkType: hard +"@react-native/codegen@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/codegen@npm:0.75.2" + dependencies: + "@babel/parser": "npm:^7.20.0" + glob: "npm:^7.1.1" + hermes-parser: "npm:0.22.0" + invariant: "npm:^2.2.4" + jscodeshift: "npm:^0.14.0" + mkdirp: "npm:^0.5.1" + nullthrows: "npm:^1.1.1" + yargs: "npm:^17.6.2" + peerDependencies: + "@babel/preset-env": ^7.1.6 + checksum: 10/9970ef151f40160f71cd6d0f1a09e37a4cbb9c892f03a9c1e88ad247772943dc6e4e03ebfe8a10ee6fa7c10aa9f751d104fb08b4c6d166c9cc1fe4753b1ebdab + languageName: node + linkType: hard + "@react-native/community-cli-plugin@npm:0.73.17": version: 0.73.17 resolution: "@react-native/community-cli-plugin@npm:0.73.17" @@ -7937,6 +8265,26 @@ __metadata: languageName: node linkType: hard +"@react-native/community-cli-plugin@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/community-cli-plugin@npm:0.75.2" + dependencies: + "@react-native-community/cli-server-api": "npm:14.0.0-alpha.11" + "@react-native-community/cli-tools": "npm:14.0.0-alpha.11" + "@react-native/dev-middleware": "npm:0.75.2" + "@react-native/metro-babel-transformer": "npm:0.75.2" + chalk: "npm:^4.0.0" + execa: "npm:^5.1.1" + metro: "npm:^0.80.3" + metro-config: "npm:^0.80.3" + metro-core: "npm:^0.80.3" + node-fetch: "npm:^2.2.0" + querystring: "npm:^0.2.1" + readline: "npm:^1.3.0" + checksum: 10/13ceea24365350b5ee528cd2654cfe764900296c186e8704bc86f4a8bda649fb154f752a32f3c29a5d9b425c44b692e8f754013d1b6db843f686038f80f8799a + languageName: node + linkType: hard + "@react-native/debugger-frontend@npm:0.73.3": version: 0.73.3 resolution: "@react-native/debugger-frontend@npm:0.73.3" @@ -7944,6 +8292,13 @@ __metadata: languageName: node linkType: hard +"@react-native/debugger-frontend@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/debugger-frontend@npm:0.75.2" + checksum: 10/2026c679fec3fe61f41d2c27cbc7ffb33a60e11578f773252c132e41f4872ab4c271390667f79e646fe6af4b0073ab1fe26528bab6709ddc74f7836654882ab5 + languageName: node + linkType: hard + "@react-native/dev-middleware@npm:0.73.8, @react-native/dev-middleware@npm:^0.73.6": version: 0.73.8 resolution: "@react-native/dev-middleware@npm:0.73.8" @@ -7963,6 +8318,26 @@ __metadata: languageName: node linkType: hard +"@react-native/dev-middleware@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/dev-middleware@npm:0.75.2" + dependencies: + "@isaacs/ttlcache": "npm:^1.4.1" + "@react-native/debugger-frontend": "npm:0.75.2" + chrome-launcher: "npm:^0.15.2" + chromium-edge-launcher: "npm:^0.2.0" + connect: "npm:^3.6.5" + debug: "npm:^2.2.0" + node-fetch: "npm:^2.2.0" + nullthrows: "npm:^1.1.1" + open: "npm:^7.0.3" + selfsigned: "npm:^2.4.1" + serve-static: "npm:^1.13.1" + ws: "npm:^6.2.2" + checksum: 10/326ce1ba04ad99a1e9bcc5d7b2fde23d0162ebe0ecae5bc4bca5f9431e80963ae54949bd868b52d0b8b146b17b79134530602dcbda048895121c683f696c0c6a + languageName: node + linkType: hard + "@react-native/gradle-plugin@npm:0.73.4": version: 0.73.4 resolution: "@react-native/gradle-plugin@npm:0.73.4" @@ -7970,6 +8345,13 @@ __metadata: languageName: node linkType: hard +"@react-native/gradle-plugin@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/gradle-plugin@npm:0.75.2" + checksum: 10/0b9ab824959db4da7ac29de9a285402cf3540e1ba1ef38c34f23389119393975d7a5463b65443d6c1e4f6618e3829b600e51ed0f05603b7f4649ce24f0f0b89e + languageName: node + linkType: hard + "@react-native/js-polyfills@npm:0.73.1": version: 0.73.1 resolution: "@react-native/js-polyfills@npm:0.73.1" @@ -7977,6 +8359,13 @@ __metadata: languageName: node linkType: hard +"@react-native/js-polyfills@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/js-polyfills@npm:0.75.2" + checksum: 10/de7f2e0e2a52d142d5068a99fb2fd29eb6a6aced3336295ef967e374681e0e36183ef859fbdb5bfa3cba724f1c2f83f42702b1824c27f6876fb999028fe0c919 + languageName: node + linkType: hard + "@react-native/metro-babel-transformer@npm:0.73.15": version: 0.73.15 resolution: "@react-native/metro-babel-transformer@npm:0.73.15" @@ -7991,6 +8380,20 @@ __metadata: languageName: node linkType: hard +"@react-native/metro-babel-transformer@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/metro-babel-transformer@npm:0.75.2" + dependencies: + "@babel/core": "npm:^7.20.0" + "@react-native/babel-preset": "npm:0.75.2" + hermes-parser: "npm:0.22.0" + nullthrows: "npm:^1.1.1" + peerDependencies: + "@babel/core": "*" + checksum: 10/4f5be3a0bd871c1f147afaa06febeb55f6c8e7cb229b2eeb569a9790fe06a335ead99543ff0b72a09cdaa46932729871f78f67d072cecd362158a69fe091285e + languageName: node + linkType: hard + "@react-native/normalize-color@npm:^2.0.0, @react-native/normalize-color@npm:^2.1.0": version: 2.1.0 resolution: "@react-native/normalize-color@npm:2.1.0" @@ -8005,6 +8408,13 @@ __metadata: languageName: node linkType: hard +"@react-native/normalize-colors@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/normalize-colors@npm:0.75.2" + checksum: 10/bbf7038e191785eacfb90765c92ebd6007f9fb55b8efb5a67e3438627238f83181b09b293deb1978cca615041f74b2c034a5ad335ac025c4ce663d7d72619ca1 + languageName: node + linkType: hard + "@react-native/normalize-colors@npm:^0.74.1": version: 0.74.87 resolution: "@react-native/normalize-colors@npm:0.74.87" @@ -8024,6 +8434,23 @@ __metadata: languageName: node linkType: hard +"@react-native/virtualized-lists@npm:0.75.2": + version: 0.75.2 + resolution: "@react-native/virtualized-lists@npm:0.75.2" + dependencies: + invariant: "npm:^2.2.4" + nullthrows: "npm:^1.1.1" + peerDependencies: + "@types/react": ^18.2.6 + react: "*" + react-native: "*" + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10/674c3295fe7cc701c1559383f7844825c2142f652ae8fb649bf65819c0477a89ff3fd7434983d08382ff1ee347bd36fc85585ab3b33904a781e78468fe2dba4c + languageName: node + linkType: hard + "@react-native/virtualized-lists@npm:^0.72.4": version: 0.72.8 resolution: "@react-native/virtualized-lists@npm:0.72.8" @@ -11779,6 +12206,13 @@ __metadata: languageName: node linkType: hard +"@types/geojson@npm:*, @types/geojson@npm:^7946.0, @types/geojson@npm:^7946.0.10, @types/geojson@npm:^7946.0.7": + version: 7946.0.14 + resolution: "@types/geojson@npm:7946.0.14" + checksum: 10/ae511bee6488ae3bd5a3a3347aedb0371e997b14225b8983679284e22fa4ebd88627c6e3ff8b08bf4cc35068cb29310c89427311ffc9322c255615821a922e71 + languageName: node + linkType: hard + "@types/geojson@npm:7946.0.8": version: 7946.0.8 resolution: "@types/geojson@npm:7946.0.8" @@ -11786,13 +12220,6 @@ __metadata: languageName: node linkType: hard -"@types/geojson@npm:^7946.0, @types/geojson@npm:^7946.0.10, @types/geojson@npm:^7946.0.7": - version: 7946.0.14 - resolution: "@types/geojson@npm:7946.0.14" - checksum: 10/ae511bee6488ae3bd5a3a3347aedb0371e997b14225b8983679284e22fa4ebd88627c6e3ff8b08bf4cc35068cb29310c89427311ffc9322c255615821a922e71 - languageName: node - linkType: hard - "@types/glob@npm:*": version: 8.1.0 resolution: "@types/glob@npm:8.1.0" @@ -11933,6 +12360,15 @@ __metadata: languageName: node linkType: hard +"@types/leaflet@npm:^1": + version: 1.9.12 + resolution: "@types/leaflet@npm:1.9.12" + dependencies: + "@types/geojson": "npm:*" + checksum: 10/ff6dce2f613b97bdc3ceb929e6eeaaa8bef8bbafdf9758935b1d679cbaf76360e366080d77e42da58e41aac146434c5d18c70ec919d37e01e0592f0a4f2e967e + languageName: node + linkType: hard + "@types/linkify-it@npm:^5": version: 5.0.0 resolution: "@types/linkify-it@npm:5.0.0" @@ -13592,6 +14028,7 @@ __metadata: "@fortawesome/react-fontawesome": "npm:^0.2.0" "@hookform/resolvers": "npm:^3.3.4" "@packrat/crosspath": "npm:*" + "@packrat/map": "npm:*" "@packrat/ui": "npm:*" "@packrat/validations": "npm:*" "@react-native-async-storage/async-storage": "npm:^1.23.1" @@ -16146,6 +16583,20 @@ __metadata: languageName: node linkType: hard +"chromium-edge-launcher@npm:^0.2.0": + version: 0.2.0 + resolution: "chromium-edge-launcher@npm:0.2.0" + dependencies: + "@types/node": "npm:*" + escape-string-regexp: "npm:^4.0.0" + is-wsl: "npm:^2.2.0" + lighthouse-logger: "npm:^1.0.0" + mkdirp: "npm:^1.0.4" + rimraf: "npm:^3.0.2" + checksum: 10/9c58094cb6f149f8b9aae6937c5e60fee3cdf7e43a6902d8d70d2bc18878a0479f1637a5b44f6fbec5c84aa52972fc3ccba61b9984a584f3d98700e247d4ad94 + languageName: node + linkType: hard + "chromium-edge-launcher@npm:^1.0.0": version: 1.0.0 resolution: "chromium-edge-launcher@npm:1.0.0" @@ -17069,6 +17520,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^9.0.0": + version: 9.0.0 + resolution: "cosmiconfig@npm:9.0.0" + dependencies: + env-paths: "npm:^2.2.1" + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/8bdf1dfbb6fdb3755195b6886dc0649a3c742ec75afa4cb8da7b070936aed22a4f4e5b7359faafe03180358f311dbc300d248fd6586c458203d376a40cc77826 + languageName: node + linkType: hard + "create-ecdh@npm:^4.0.0": version: 4.0.4 resolution: "create-ecdh@npm:4.0.4" @@ -18642,7 +19110,7 @@ __metadata: languageName: node linkType: hard -"env-paths@npm:^2.2.0": +"env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" checksum: 10/65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e @@ -18663,7 +19131,7 @@ __metadata: languageName: node linkType: hard -"envinfo@npm:^7.10.0": +"envinfo@npm:^7.10.0, envinfo@npm:^7.13.0": version: 7.13.0 resolution: "envinfo@npm:7.13.0" bin: @@ -23345,6 +23813,13 @@ __metadata: languageName: node linkType: hard +"hermes-estree@npm:0.22.0": + version: 0.22.0 + resolution: "hermes-estree@npm:0.22.0" + checksum: 10/58b4aaea36d6eee070e0e29a8e90896800b78ae779a9f819a215aec8000146728d2e1d20dc8504a6bbd6d47afc905067721ee520abd5a057c4265e92941f5cc6 + languageName: node + linkType: hard + "hermes-estree@npm:0.23.0": version: 0.23.0 resolution: "hermes-estree@npm:0.23.0" @@ -23377,6 +23852,15 @@ __metadata: languageName: node linkType: hard +"hermes-parser@npm:0.22.0": + version: 0.22.0 + resolution: "hermes-parser@npm:0.22.0" + dependencies: + hermes-estree: "npm:0.22.0" + checksum: 10/7ae8f9a8bd9880dcb0eeb3b4efa053112a9820bdbd8cf3a500cf6192bf44501b29cd7d3b4ef03ca43d0060b348b57c0d4cab5ebb2939ba46a5327c76ac86dc99 + languageName: node + linkType: hard + "hermes-parser@npm:0.23.0": version: 0.23.0 resolution: "hermes-parser@npm:0.23.0" @@ -23914,7 +24398,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -26296,6 +26780,13 @@ __metadata: languageName: node linkType: hard +"leaflet@npm:^1.9.4": + version: 1.9.4 + resolution: "leaflet@npm:1.9.4" + checksum: 10/7b6a74d503980961a85bdabebf9d1162c26db0e88195800ceea311682b653d621718f2ada3c9aab903a735af9862c9ae278ba550d4429acbd954d43449cd0d77 + languageName: node + linkType: hard + "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -31915,19 +32406,17 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:18.2.0": - version: 18.2.0 - resolution: "react-dom@npm:18.2.0" +"react-devtools-core@npm:^5.3.1": + version: 5.3.1 + resolution: "react-devtools-core@npm:5.3.1" dependencies: - loose-envify: "npm:^1.1.0" - scheduler: "npm:^0.23.0" - peerDependencies: - react: ^18.2.0 - checksum: 10/ca5e7762ec8c17a472a3605b6f111895c9f87ac7d43a610ab7024f68cd833d08eda0625ce02ec7178cc1f3c957cf0b9273cdc17aa2cd02da87544331c43b1d21 + shell-quote: "npm:^1.6.1" + ws: "npm:^7" + checksum: 10/247056e0cbb791f4e181f9331b0ab945feb1a770f5f76c9899d7a2d429afd20bcd69763af38e9eb881ac6f5a961dc7f07ee146babaa4111612747c68102dfa13 languageName: node linkType: hard -"react-dom@npm:^18.2.0": +"react-dom@npm:*, react-dom@npm:^18.2.0": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -31939,6 +32428,18 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:18.2.0": + version: 18.2.0 + resolution: "react-dom@npm:18.2.0" + dependencies: + loose-envify: "npm:^1.1.0" + scheduler: "npm:^0.23.0" + peerDependencies: + react: ^18.2.0 + checksum: 10/ca5e7762ec8c17a472a3605b6f111895c9f87ac7d43a610ab7024f68cd833d08eda0625ce02ec7178cc1f3c957cf0b9273cdc17aa2cd02da87544331c43b1d21 + languageName: node + linkType: hard + "react-dropzone@npm:^14.2.3": version: 14.2.3 resolution: "react-dropzone@npm:14.2.3" @@ -32009,6 +32510,19 @@ __metadata: languageName: node linkType: hard +"react-leaflet@npm:^4.2.1": + version: 4.2.1 + resolution: "react-leaflet@npm:4.2.1" + dependencies: + "@react-leaflet/core": "npm:^2.1.0" + peerDependencies: + leaflet: ^1.9.0 + react: ^18.0.0 + react-dom: ^18.0.0 + checksum: 10/01cee12dc32e86d0153c989894fdba1c5c50fa41ad8d712352fa616f7b0dd32844aa17bb06c66f7569133675e2946c669090b4c496610cce3fa37c22254ca89f + languageName: node + linkType: hard + "react-native-action-button@npm:^2.8.5": version: 2.8.5 resolution: "react-native-action-button@npm:2.8.5" @@ -32396,6 +32910,60 @@ __metadata: languageName: node linkType: hard +"react-native@npm:*": + version: 0.75.2 + resolution: "react-native@npm:0.75.2" + dependencies: + "@jest/create-cache-key-function": "npm:^29.6.3" + "@react-native-community/cli": "npm:14.0.0" + "@react-native-community/cli-platform-android": "npm:14.0.0" + "@react-native-community/cli-platform-ios": "npm:14.0.0" + "@react-native/assets-registry": "npm:0.75.2" + "@react-native/codegen": "npm:0.75.2" + "@react-native/community-cli-plugin": "npm:0.75.2" + "@react-native/gradle-plugin": "npm:0.75.2" + "@react-native/js-polyfills": "npm:0.75.2" + "@react-native/normalize-colors": "npm:0.75.2" + "@react-native/virtualized-lists": "npm:0.75.2" + abort-controller: "npm:^3.0.0" + anser: "npm:^1.4.9" + ansi-regex: "npm:^5.0.0" + base64-js: "npm:^1.5.1" + chalk: "npm:^4.0.0" + event-target-shim: "npm:^5.0.1" + flow-enums-runtime: "npm:^0.0.6" + glob: "npm:^7.1.1" + invariant: "npm:^2.2.4" + jest-environment-node: "npm:^29.6.3" + jsc-android: "npm:^250231.0.0" + memoize-one: "npm:^5.0.0" + metro-runtime: "npm:^0.80.3" + metro-source-map: "npm:^0.80.3" + mkdirp: "npm:^0.5.1" + nullthrows: "npm:^1.1.1" + pretty-format: "npm:^26.5.2" + promise: "npm:^8.3.0" + react-devtools-core: "npm:^5.3.1" + react-refresh: "npm:^0.14.0" + regenerator-runtime: "npm:^0.13.2" + scheduler: "npm:0.24.0-canary-efb381bbf-20230505" + semver: "npm:^7.1.3" + stacktrace-parser: "npm:^0.1.10" + whatwg-fetch: "npm:^3.0.0" + ws: "npm:^6.2.2" + yargs: "npm:^17.6.2" + peerDependencies: + "@types/react": ^18.2.6 + react: ^18.2.0 + peerDependenciesMeta: + "@types/react": + optional: true + bin: + react-native: cli.js + checksum: 10/9b0c315c20708e3ebcf8e6d0534e7a8811bf79930f3f2630e73b60a0e8d13d8bda2db69432d46ff2a612b27a6be851c0334b7099c44c51999324d1979243341c + languageName: node + linkType: hard + "react-native@npm:0.73.6": version: 0.73.6 resolution: "react-native@npm:0.73.6" @@ -32603,21 +33171,21 @@ __metadata: languageName: node linkType: hard -"react@npm:18.2.0": - version: 18.2.0 - resolution: "react@npm:18.2.0" +"react@npm:*, react@npm:^18.2.0": + version: 18.3.1 + resolution: "react@npm:18.3.1" dependencies: loose-envify: "npm:^1.1.0" - checksum: 10/b9214a9bd79e99d08de55f8bef2b7fc8c39630be97c4e29d7be173d14a9a10670b5325e94485f74cd8bff4966ef3c78ee53c79a7b0b9b70cba20aa8973acc694 + checksum: 10/261137d3f3993eaa2368a83110466fc0e558bc2c7f7ae7ca52d94f03aac945f45146bd85e5f481044db1758a1dbb57879e2fcdd33924e2dde1bdc550ce73f7bf languageName: node linkType: hard -"react@npm:^18.2.0": - version: 18.3.1 - resolution: "react@npm:18.3.1" +"react@npm:18.2.0": + version: 18.2.0 + resolution: "react@npm:18.2.0" dependencies: loose-envify: "npm:^1.1.0" - checksum: 10/261137d3f3993eaa2368a83110466fc0e558bc2c7f7ae7ca52d94f03aac945f45146bd85e5f481044db1758a1dbb57879e2fcdd33924e2dde1bdc550ce73f7bf + checksum: 10/b9214a9bd79e99d08de55f8bef2b7fc8c39630be97c4e29d7be173d14a9a10670b5325e94485f74cd8bff4966ef3c78ee53c79a7b0b9b70cba20aa8973acc694 languageName: node linkType: hard @@ -33701,7 +34269,7 @@ __metadata: languageName: node linkType: hard -"selfsigned@npm:^2.0.1, selfsigned@npm:^2.1.1": +"selfsigned@npm:^2.0.1, selfsigned@npm:^2.1.1, selfsigned@npm:^2.4.1": version: 2.4.1 resolution: "selfsigned@npm:2.4.1" dependencies: @@ -33770,7 +34338,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.0.0, semver@npm:^7.1.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.1, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0": +"semver@npm:^7.0.0, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.1, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0": version: 7.6.3 resolution: "semver@npm:7.6.3" bin: @@ -38381,7 +38949,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^6.2.2": +"ws@npm:^6.2.2, ws@npm:^6.2.3": version: 6.2.3 resolution: "ws@npm:6.2.3" dependencies: