|
@@ -1,11 +1,13 @@
|
|
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
-import { View, Text, TouchableOpacity } from 'react-native';
|
|
|
+import { View, Text, TouchableOpacity, ActivityIndicator, Platform, Linking } from 'react-native';
|
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
|
import { useNavigation } from '@react-navigation/native';
|
|
|
import * as turf from '@turf/turf';
|
|
|
import * as MapLibreRN from '@maplibre/maplibre-react-native';
|
|
|
+import * as Location from 'expo-location';
|
|
|
+import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
|
|
|
|
|
-import { Header, Modal, FlatList as List } from 'src/components';
|
|
|
+import { Header, Modal, FlatList as List, WarningModal } from 'src/components';
|
|
|
|
|
|
import { VECTOR_MAP_HOST } from 'src/constants';
|
|
|
import { Colors } from 'src/theme';
|
|
@@ -17,6 +19,7 @@ import { styles } from './styles';
|
|
|
|
|
|
import SearchSvg from '../../../../../assets/icons/search.svg';
|
|
|
import SaveSvg from '../../../../../assets/icons/travels-screens/save.svg';
|
|
|
+import LocationIcon from 'assets/icons/location.svg';
|
|
|
|
|
|
const generateFilter = (ids: number[]) => {
|
|
|
return ids?.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
|
|
@@ -50,6 +53,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
|
|
|
const { data } = useGetRegionsForTripsQuery(true);
|
|
|
const { data: regionsList } = useGetListRegionsQuery(true);
|
|
|
const navigation = useNavigation();
|
|
|
+ const tabBarHeight = useBottomTabBarHeight();
|
|
|
|
|
|
const [regions, setRegions] = useState<RegionAddData[] | null>(null);
|
|
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
|
@@ -61,6 +65,10 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
|
|
|
const cameraRef = useRef<MapLibreRN.CameraRef>(null);
|
|
|
|
|
|
const [filterSelectedRegions, setFilterSelectedRegions] = useState<any[]>(generateFilter([]));
|
|
|
+ const [isLocationLoading, setIsLocationLoading] = useState(false);
|
|
|
+ const [location, setLocation] = useState<any | null>(null);
|
|
|
+ const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
|
|
|
+ const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (data && data.regions) {
|
|
@@ -190,6 +198,54 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
|
|
|
[selectedRegions, regions]
|
|
|
);
|
|
|
|
|
|
+ const handleGetLocation = async () => {
|
|
|
+ setIsLocationLoading(true);
|
|
|
+ try {
|
|
|
+ let { status, canAskAgain } = await Location.getForegroundPermissionsAsync();
|
|
|
+ const isServicesEnabled = await Location.hasServicesEnabledAsync();
|
|
|
+
|
|
|
+ if (status === 'granted' && isServicesEnabled) {
|
|
|
+ await getLocation();
|
|
|
+ } else if (!canAskAgain || !isServicesEnabled) {
|
|
|
+ setOpenSettingsVisible(true);
|
|
|
+ } else {
|
|
|
+ setAskLocationVisible(true);
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ setIsLocationLoading(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const getLocation = async () => {
|
|
|
+ try {
|
|
|
+ let currentLocation = await Location.getCurrentPositionAsync({
|
|
|
+ accuracy: Location.Accuracy.Balanced
|
|
|
+ });
|
|
|
+ setLocation(currentLocation.coords);
|
|
|
+
|
|
|
+ if (currentLocation.coords) {
|
|
|
+ cameraRef.current?.flyTo(
|
|
|
+ [currentLocation.coords.longitude, currentLocation.coords.latitude],
|
|
|
+ 1000
|
|
|
+ );
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching user location:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleAcceptPermission = async () => {
|
|
|
+ setAskLocationVisible(false);
|
|
|
+ let { status, canAskAgain } = await Location.requestForegroundPermissionsAsync();
|
|
|
+ const isServicesEnabled = await Location.hasServicesEnabledAsync();
|
|
|
+
|
|
|
+ if (status === 'granted' && isServicesEnabled) {
|
|
|
+ getLocation();
|
|
|
+ } else if (!canAskAgain || !isServicesEnabled) {
|
|
|
+ setOpenSettingsVisible(true);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<SafeAreaView style={{ height: '100%' }} edges={['top']}>
|
|
|
<View style={styles.wrapper}>
|
|
@@ -257,7 +313,41 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
|
|
|
belowLayerID="nm-regions-line-layer"
|
|
|
/>
|
|
|
) : null}
|
|
|
+
|
|
|
+ {location && (
|
|
|
+ <MapLibreRN.UserLocation
|
|
|
+ animated={true}
|
|
|
+ showsUserHeadingIndicator={true}
|
|
|
+ onPress={async () => {
|
|
|
+ const currentZoom = await mapRef.current?.getZoom();
|
|
|
+ const newZoom = (currentZoom || 0) + 2;
|
|
|
+
|
|
|
+ cameraRef.current?.setCamera({
|
|
|
+ centerCoordinate: [location.longitude, location.latitude],
|
|
|
+ zoomLevel: newZoom,
|
|
|
+ animationDuration: 500,
|
|
|
+ animationMode: 'flyTo'
|
|
|
+ });
|
|
|
+ }}
|
|
|
+ ></MapLibreRN.UserLocation>
|
|
|
+ )}
|
|
|
</MapLibreRN.MapView>
|
|
|
+
|
|
|
+ <TouchableOpacity
|
|
|
+ onPress={handleGetLocation}
|
|
|
+ style={[
|
|
|
+ styles.cornerButton,
|
|
|
+ styles.bottomButton,
|
|
|
+ styles.bottomRightButton,
|
|
|
+ { bottom: 20 }
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ {isLocationLoading ? (
|
|
|
+ <ActivityIndicator size="small" color={Colors.DARK_BLUE} />
|
|
|
+ ) : (
|
|
|
+ <LocationIcon />
|
|
|
+ )}
|
|
|
+ </TouchableOpacity>
|
|
|
</View>
|
|
|
{regionPopupVisible && regionData && (
|
|
|
<View style={styles.popupWrapper}>
|
|
@@ -279,6 +369,32 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
|
|
|
}}
|
|
|
/>
|
|
|
</Modal>
|
|
|
+
|
|
|
+ <WarningModal
|
|
|
+ type={'success'}
|
|
|
+ isVisible={openSettingsVisible}
|
|
|
+ onClose={() => setOpenSettingsVisible(false)}
|
|
|
+ action={async () => {
|
|
|
+ const isServicesEnabled = await Location.hasServicesEnabledAsync();
|
|
|
+
|
|
|
+ if (!isServicesEnabled) {
|
|
|
+ Platform.OS === 'ios'
|
|
|
+ ? Linking.openURL('app-settings:')
|
|
|
+ : Linking.sendIntent('android.settings.LOCATION_SOURCE_SETTINGS');
|
|
|
+ } else {
|
|
|
+ Platform.OS === 'ios' ? Linking.openURL('app-settings:') : Linking.openSettings();
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ message="NomadMania app needs location permissions to function properly. Open settings?"
|
|
|
+ />
|
|
|
+
|
|
|
+ <WarningModal
|
|
|
+ type={'success'}
|
|
|
+ isVisible={askLocationVisible}
|
|
|
+ onClose={() => setAskLocationVisible(false)}
|
|
|
+ action={handleAcceptPermission}
|
|
|
+ message="To use this feature we need your permission to access your location. If you press OK your system will ask you to approve location sharing with NomadMania app."
|
|
|
+ />
|
|
|
</SafeAreaView>
|
|
|
);
|
|
|
};
|