|
@@ -20,12 +20,10 @@ import { Colors } from 'src/theme';
|
|
|
import { storage, StoreType } from 'src/storage';
|
|
import { storage, StoreType } from 'src/storage';
|
|
|
import * as turf from '@turf/turf';
|
|
import * as turf from '@turf/turf';
|
|
|
import * as Location from 'expo-location';
|
|
import * as Location from 'expo-location';
|
|
|
-import { Image as ExpoImage } from 'expo-image';
|
|
|
|
|
|
|
|
|
|
import SearchIcon from 'assets/icons/search.svg';
|
|
import SearchIcon from 'assets/icons/search.svg';
|
|
|
import LocationIcon from 'assets/icons/location.svg';
|
|
import LocationIcon from 'assets/icons/location.svg';
|
|
|
import CloseSvg from 'assets/icons/close.svg';
|
|
import CloseSvg from 'assets/icons/close.svg';
|
|
|
-import FilterIcon from 'assets/icons/filter.svg';
|
|
|
|
|
import ProfileIcon from 'assets/icons/bottom-navigation/profile.svg';
|
|
import ProfileIcon from 'assets/icons/bottom-navigation/profile.svg';
|
|
|
import RegionPopup from 'src/components/RegionPopup';
|
|
import RegionPopup from 'src/components/RegionPopup';
|
|
|
import { useRegion } from 'src/contexts/RegionContext';
|
|
import { useRegion } from 'src/contexts/RegionContext';
|
|
@@ -56,7 +54,6 @@ import SearchModal from './UniversalSearch';
|
|
|
import EditModal from '../TravelsScreen/Components/EditSlowModal';
|
|
import EditModal from '../TravelsScreen/Components/EditSlowModal';
|
|
|
import * as FileSystem from 'expo-file-system/legacy';
|
|
import * as FileSystem from 'expo-file-system/legacy';
|
|
|
|
|
|
|
|
-import CheckSvg from 'assets/icons/mark.svg';
|
|
|
|
|
import moment from 'moment';
|
|
import moment from 'moment';
|
|
|
import {
|
|
import {
|
|
|
usePostGetVisitedCountriesIdsQuery,
|
|
usePostGetVisitedCountriesIdsQuery,
|
|
@@ -87,11 +84,7 @@ import { useAvatarStore } from 'src/stores/avatarVersionStore';
|
|
|
import _ from 'lodash';
|
|
import _ from 'lodash';
|
|
|
import ScaleBar from 'src/components/ScaleBar';
|
|
import ScaleBar from 'src/components/ScaleBar';
|
|
|
import MessagesDot from 'src/components/MessagesDot';
|
|
import MessagesDot from 'src/components/MessagesDot';
|
|
|
-import {
|
|
|
|
|
- restartBackgroundLocationUpdates,
|
|
|
|
|
- startBackgroundLocationUpdates,
|
|
|
|
|
- stopBackgroundLocationUpdates
|
|
|
|
|
-} from 'src/utils/backgroundLocation';
|
|
|
|
|
|
|
+import { stopBackgroundLocationUpdates } from 'src/utils/backgroundLocation';
|
|
|
import { SheetManager } from 'react-native-actions-sheet';
|
|
import { SheetManager } from 'react-native-actions-sheet';
|
|
|
import MultipleSeriesModal from './MultipleSeriesModal';
|
|
import MultipleSeriesModal from './MultipleSeriesModal';
|
|
|
import { useSubscription } from 'src/screens/OfflineMapsScreen/useSubscription';
|
|
import { useSubscription } from 'src/screens/OfflineMapsScreen/useSubscription';
|
|
@@ -104,12 +97,12 @@ configureReanimatedLogger({
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const clusteredUsersIcon = require('assets/icons/icon-clustered-users.png');
|
|
const clusteredUsersIcon = require('assets/icons/icon-clustered-users.png');
|
|
|
-const defaultUserAvatar = require('assets/icon-user-share-location-solid.png');
|
|
|
|
|
const logo = require('assets/logo-world.png');
|
|
const logo = require('assets/logo-world.png');
|
|
|
-const defaultSeriesIcon = require('assets/series-default.png');
|
|
|
|
|
|
|
|
|
|
MapLibreRN.Logger.setLogLevel('error');
|
|
MapLibreRN.Logger.setLogLevel('error');
|
|
|
|
|
|
|
|
|
|
+const isValidNumber = (val: any) => typeof val === 'number' && !isNaN(val) && isFinite(val);
|
|
|
|
|
+
|
|
|
const sanitizeNomadsGeoJSON = (
|
|
const sanitizeNomadsGeoJSON = (
|
|
|
collection: GeoJSON.FeatureCollection
|
|
collection: GeoJSON.FeatureCollection
|
|
|
): GeoJSON.FeatureCollection => {
|
|
): GeoJSON.FeatureCollection => {
|
|
@@ -124,8 +117,7 @@ const sanitizeNomadsGeoJSON = (
|
|
|
|
|
|
|
|
const [lng, lat] = coords;
|
|
const [lng, lat] = coords;
|
|
|
if (lng == null || lat == null) return false;
|
|
if (lng == null || lat == null) return false;
|
|
|
- if (typeof lng !== 'number' || typeof lat !== 'number') return false;
|
|
|
|
|
- if (isNaN(lng) || isNaN(lat)) return false;
|
|
|
|
|
|
|
+ if (!isValidNumber(lng) || !isValidNumber(lat)) return false;
|
|
|
if (lng < -180 || lng > 180 || lat < -90 || lat > 90) return false;
|
|
if (lng < -180 || lng > 180 || lat < -90 || lat > 90) return false;
|
|
|
|
|
|
|
|
return true;
|
|
return true;
|
|
@@ -135,7 +127,8 @@ const sanitizeNomadsGeoJSON = (
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const generateFilter = (ids: number[]) => {
|
|
const generateFilter = (ids: number[]) => {
|
|
|
- return ids?.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
|
|
|
|
|
|
|
+ const validIds = ids?.filter(isValidNumber) || [];
|
|
|
|
|
+ return validIds.length ? ['any', ...validIds.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// to do refactor
|
|
// to do refactor
|
|
@@ -742,7 +735,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
countries: nomadsFilter.countries ? JSON.stringify(countriesFilter) : undefined
|
|
countries: nomadsFilter.countries ? JSON.stringify(countriesFilter) : undefined
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- onSuccess: (data) => {
|
|
|
|
|
|
|
+ onSuccess: (data: any) => {
|
|
|
if (data && data?.geojson) {
|
|
if (data && data?.geojson) {
|
|
|
setUsersCount(data.geojson.features?.length);
|
|
setUsersCount(data.geojson.features?.length);
|
|
|
const rawFiltered: GeoJSON.FeatureCollection = {
|
|
const rawFiltered: GeoJSON.FeatureCollection = {
|
|
@@ -778,10 +771,10 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
if (seriesVisited?.length) {
|
|
if (seriesVisited?.length) {
|
|
|
setSeriesVisitedFilter([
|
|
setSeriesVisitedFilter([
|
|
|
'all',
|
|
'all',
|
|
|
- ['any', ...seriesVisited.map((id) => ['==', 'id', id])],
|
|
|
|
|
|
|
+ ['any', ...seriesVisited.filter(isValidNumber).map((id) => ['==', 'id', id])],
|
|
|
[
|
|
[
|
|
|
'any',
|
|
'any',
|
|
|
- ...seriesFilter.groups.map((groupId: number) => {
|
|
|
|
|
|
|
+ ...seriesFilter.groups.filter(isValidNumber).map((groupId: number) => {
|
|
|
if (groupId === -1) {
|
|
if (groupId === -1) {
|
|
|
return ['==', 'must', 1];
|
|
return ['==', 'must', 1];
|
|
|
}
|
|
}
|
|
@@ -791,10 +784,10 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
]);
|
|
]);
|
|
|
setSeriesNotVisitedFilter([
|
|
setSeriesNotVisitedFilter([
|
|
|
'all',
|
|
'all',
|
|
|
- ['all', ...seriesVisited.map((id) => ['!=', 'id', id])],
|
|
|
|
|
|
|
+ ['all', ...seriesVisited.filter(isValidNumber).map((id) => ['!=', 'id', id])],
|
|
|
[
|
|
[
|
|
|
'any',
|
|
'any',
|
|
|
- ...seriesFilter.groups.map((groupId: number) => {
|
|
|
|
|
|
|
+ ...seriesFilter.groups.filter(isValidNumber).map((groupId: number) => {
|
|
|
if (groupId === -1) {
|
|
if (groupId === -1) {
|
|
|
return ['==', 'must', 1];
|
|
return ['==', 'must', 1];
|
|
|
}
|
|
}
|
|
@@ -805,7 +798,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
} else {
|
|
} else {
|
|
|
setSeriesNotVisitedFilter([
|
|
setSeriesNotVisitedFilter([
|
|
|
'any',
|
|
'any',
|
|
|
- ...seriesFilter.groups.map((groupId: number) => {
|
|
|
|
|
|
|
+ ...seriesFilter.groups.filter(isValidNumber).map((groupId: number) => {
|
|
|
if (groupId === -1) {
|
|
if (groupId === -1) {
|
|
|
return ['==', 'must', 1];
|
|
return ['==', 'must', 1];
|
|
|
}
|
|
}
|
|
@@ -816,17 +809,19 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
} else {
|
|
} else {
|
|
|
setSeriesVisitedFilter(
|
|
setSeriesVisitedFilter(
|
|
|
seriesVisited.length
|
|
seriesVisited.length
|
|
|
- ? ['any', ...seriesVisited.map((id) => ['==', 'id', id])]
|
|
|
|
|
|
|
+ ? ['any', ...seriesVisited.filter(isValidNumber).map((id) => ['==', 'id', id])]
|
|
|
: generateFilter([])
|
|
: generateFilter([])
|
|
|
);
|
|
);
|
|
|
setSeriesNotVisitedFilter(
|
|
setSeriesNotVisitedFilter(
|
|
|
- seriesVisited.length ? ['all', ...seriesVisited.map((id) => ['!=', 'id', id])] : ['all']
|
|
|
|
|
|
|
+ seriesVisited.length
|
|
|
|
|
+ ? ['all', ...seriesVisited.filter(isValidNumber).map((id) => ['!=', 'id', id])]
|
|
|
|
|
+ : ['all']
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
}, [seriesVisited, seriesFilter]);
|
|
}, [seriesVisited, seriesFilter]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- if (route.params?.lon && route.params?.lat) {
|
|
|
|
|
|
|
+ if (isValidNumber(route.params?.lon) && isValidNumber(route.params?.lat)) {
|
|
|
setMarkerCoords([route.params.lon, route.params.lat]);
|
|
setMarkerCoords([route.params.lon, route.params.lat]);
|
|
|
const timeoutId = setTimeout(() => {
|
|
const timeoutId = setTimeout(() => {
|
|
|
cameraController.setCamera({
|
|
cameraController.setCamera({
|
|
@@ -1180,11 +1175,19 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- if (initialRegion && !route.params?.id) {
|
|
|
|
|
|
|
+ if (
|
|
|
|
|
+ initialRegion &&
|
|
|
|
|
+ !route.params?.id &&
|
|
|
|
|
+ isValidNumber(initialRegion.longitude) &&
|
|
|
|
|
+ isValidNumber(initialRegion.latitude)
|
|
|
|
|
+ ) {
|
|
|
const timeoutId = setTimeout(() => {
|
|
const timeoutId = setTimeout(() => {
|
|
|
cameraController.setCamera({
|
|
cameraController.setCamera({
|
|
|
centerCoordinate: [initialRegion.longitude, initialRegion.latitude],
|
|
centerCoordinate: [initialRegion.longitude, initialRegion.latitude],
|
|
|
- zoomLevel: Math.log2(360 / initialRegion.latitudeDelta),
|
|
|
|
|
|
|
+ zoomLevel:
|
|
|
|
|
+ isValidNumber(initialRegion.latitudeDelta) && initialRegion.latitudeDelta > 0
|
|
|
|
|
+ ? Math.log2(360 / initialRegion.latitudeDelta)
|
|
|
|
|
+ : 0,
|
|
|
animationDuration: 500,
|
|
animationDuration: 500,
|
|
|
animationMode: 'flyTo'
|
|
animationMode: 'flyTo'
|
|
|
});
|
|
});
|
|
@@ -1300,14 +1303,16 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
: setUserData({ type: 'nm', id: +foundRegion });
|
|
: setUserData({ type: 'nm', id: +foundRegion });
|
|
|
if (regionsList && regionsList.data) {
|
|
if (regionsList && regionsList.data) {
|
|
|
const region = regionsList.data.find((region) => region.id === +foundRegion);
|
|
const region = regionsList.data.find((region) => region.id === +foundRegion);
|
|
|
- if (region) {
|
|
|
|
|
|
|
+ if (region && region.bbox) {
|
|
|
const bounds = turf.bbox(region.bbox);
|
|
const bounds = turf.bbox(region.bbox);
|
|
|
- cameraController.fitBounds(
|
|
|
|
|
- [bounds[2], bounds[3]],
|
|
|
|
|
- [bounds[0], bounds[1]],
|
|
|
|
|
- [10, 10, 50, 10],
|
|
|
|
|
- 1000
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ if (bounds.every(isValidNumber)) {
|
|
|
|
|
+ cameraController.fitBounds(
|
|
|
|
|
+ [bounds[2], bounds[3]],
|
|
|
|
|
+ [bounds[0], bounds[1]],
|
|
|
|
|
+ [10, 10, 50, 10],
|
|
|
|
|
+ 1000
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} else if (tableName === 'countries') {
|
|
} else if (tableName === 'countries') {
|
|
@@ -1323,14 +1328,16 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
: setUserData({ type: 'countries', id: +foundRegion });
|
|
: setUserData({ type: 'countries', id: +foundRegion });
|
|
|
if (countriesList && countriesList.data) {
|
|
if (countriesList && countriesList.data) {
|
|
|
const region = countriesList.data.find((region) => region.id === +foundRegion);
|
|
const region = countriesList.data.find((region) => region.id === +foundRegion);
|
|
|
- if (region) {
|
|
|
|
|
|
|
+ if (region && region.bbox) {
|
|
|
const bounds = turf.bbox(region.bbox);
|
|
const bounds = turf.bbox(region.bbox);
|
|
|
- cameraController.fitBounds(
|
|
|
|
|
- [bounds[2], bounds[3]],
|
|
|
|
|
- [bounds[0], bounds[1]],
|
|
|
|
|
- [10, 10, 50, 10],
|
|
|
|
|
- 1000
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ if (bounds.every(isValidNumber)) {
|
|
|
|
|
+ cameraController.fitBounds(
|
|
|
|
|
+ [bounds[2], bounds[3]],
|
|
|
|
|
+ [bounds[0], bounds[1]],
|
|
|
|
|
+ [10, 10, 50, 10],
|
|
|
|
|
+ 1000
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
@@ -1346,14 +1353,16 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
: setUserData({ type: 'dare', id: +foundRegion });
|
|
: setUserData({ type: 'dare', id: +foundRegion });
|
|
|
if (dareList && dareList.data) {
|
|
if (dareList && dareList.data) {
|
|
|
const region = dareList.data.find((region) => region.id === +foundRegion);
|
|
const region = dareList.data.find((region) => region.id === +foundRegion);
|
|
|
- if (region) {
|
|
|
|
|
|
|
+ if (region && region.bbox) {
|
|
|
const bounds = turf.bbox(region.bbox);
|
|
const bounds = turf.bbox(region.bbox);
|
|
|
- cameraController.fitBounds(
|
|
|
|
|
- [bounds[2], bounds[3]],
|
|
|
|
|
- [bounds[0], bounds[1]],
|
|
|
|
|
- [10, 10, 50, 10],
|
|
|
|
|
- 1000
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ if (bounds.every(isValidNumber)) {
|
|
|
|
|
+ cameraController.fitBounds(
|
|
|
|
|
+ [bounds[2], bounds[3]],
|
|
|
|
|
+ [bounds[0], bounds[1]],
|
|
|
|
|
+ [10, 10, 50, 10],
|
|
|
|
|
+ 1000
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1527,14 +1536,16 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
|
|
|
|
|
if (regionsList && regionsList.data) {
|
|
if (regionsList && regionsList.data) {
|
|
|
const region = regionsList.data.find((region) => region.id === +id);
|
|
const region = regionsList.data.find((region) => region.id === +id);
|
|
|
- if (region) {
|
|
|
|
|
|
|
+ if (region && region.bbox) {
|
|
|
const bounds = turf.bbox(region.bbox);
|
|
const bounds = turf.bbox(region.bbox);
|
|
|
- cameraController.fitBounds(
|
|
|
|
|
- [bounds[2], bounds[3]],
|
|
|
|
|
- [bounds[0], bounds[1]],
|
|
|
|
|
- [10, 10, 50, 10],
|
|
|
|
|
- 1000
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ if (bounds.every(isValidNumber)) {
|
|
|
|
|
+ cameraController.fitBounds(
|
|
|
|
|
+ [bounds[2], bounds[3]],
|
|
|
|
|
+ [bounds[0], bounds[1]],
|
|
|
|
|
+ [10, 10, 50, 10],
|
|
|
|
|
+ 1000
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} else if (type === 'countries') {
|
|
} else if (type === 'countries') {
|
|
@@ -1551,14 +1562,16 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
|
|
|
|
|
if (countriesList && countriesList.data) {
|
|
if (countriesList && countriesList.data) {
|
|
|
const region = countriesList.data.find((region) => region.id === +id);
|
|
const region = countriesList.data.find((region) => region.id === +id);
|
|
|
- if (region) {
|
|
|
|
|
|
|
+ if (region && region.bbox) {
|
|
|
const bounds = turf.bbox(region.bbox);
|
|
const bounds = turf.bbox(region.bbox);
|
|
|
- cameraController.fitBounds(
|
|
|
|
|
- [bounds[2], bounds[3]],
|
|
|
|
|
- [bounds[0], bounds[1]],
|
|
|
|
|
- [10, 10, 50, 10],
|
|
|
|
|
- 1000
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ if (bounds.every(isValidNumber)) {
|
|
|
|
|
+ cameraController.fitBounds(
|
|
|
|
|
+ [bounds[2], bounds[3]],
|
|
|
|
|
+ [bounds[0], bounds[1]],
|
|
|
|
|
+ [10, 10, 50, 10],
|
|
|
|
|
+ 1000
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
@@ -1575,14 +1588,16 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
|
|
|
|
|
if (dareList && dareList.data) {
|
|
if (dareList && dareList.data) {
|
|
|
const region = dareList.data.find((region) => region.id === +id);
|
|
const region = dareList.data.find((region) => region.id === +id);
|
|
|
- if (region) {
|
|
|
|
|
|
|
+ if (region && region.bbox) {
|
|
|
const bounds = turf.bbox(region.bbox);
|
|
const bounds = turf.bbox(region.bbox);
|
|
|
- cameraController.fitBounds(
|
|
|
|
|
- [bounds[2], bounds[3]],
|
|
|
|
|
- [bounds[0], bounds[1]],
|
|
|
|
|
- [10, 10, 50, 10],
|
|
|
|
|
- 1000
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ if (bounds.every(isValidNumber)) {
|
|
|
|
|
+ cameraController.fitBounds(
|
|
|
|
|
+ [bounds[2], bounds[3]],
|
|
|
|
|
+ [bounds[0], bounds[1]],
|
|
|
|
|
+ [10, 10, 50, 10],
|
|
|
|
|
+ 1000
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|