Browse Source

conflict fixed

Viktoriia 5 tháng trước cách đây
mục cha
commit
2fdbf8ef45

+ 3 - 12
app.config.ts

@@ -24,9 +24,9 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
   owner: 'nomadmaniaou',
   scheme: 'nm',
   // Should be updated after every production release (deploy to AppStore/PlayMarket)
-  version: '2.0.28',
+  version: '2.0.30',
   // Should be updated after every dependency change
-  runtimeVersion: '1.5',
+  runtimeVersion: '1.6',
   orientation: 'portrait',
   icon: './assets/icon.png',
   userInterfaceStyle: 'light',
@@ -83,8 +83,6 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
         'Nomadmania app needs access to the documents folder to select files.',
       NSCameraUsageDescription: 'Nomadmania app needs access to the camera to record video.',
       NSLocationWhenInUseUsageDescription:
-        'NomadMania app needs access to your location to show relevant data.',
-      NSLocationAlwaysAndWhenInUseUsageDescription:
         'NomadMania app needs access to your location to show relevant data.'
     },
     privacyManifests: {
@@ -116,7 +114,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
       'CAMERA',
       'MODIFY_AUDIO_SETTINGS'
     ],
-    versionCode: 81 // next version submitted to Google Play needs to be higher than that 2.0.28
+    versionCode: 83 // next version submitted to Google Play needs to be higher than that 2.0.30
   },
   plugins: [
     [
@@ -162,12 +160,5 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
       }
     ],
     ['@maplibre/maplibre-react-native']
-    // [
-    //   'expo-location',
-    //   {
-    //     isIosBackgroundLocationEnabled: true,
-    //     isAndroidBackgroundLocationEnabled: true
-    //   }
-    // ]
   ]
 });

BIN
assets/icons/icon-clustered-users.png


+ 7 - 0
eas.json

@@ -31,6 +31,12 @@
         "ENV": "development"
       }
     },
+    "testflight": {
+      "channel": "development",
+      "env": {
+        "ENV": "production"
+      }
+    },
     "production": {
       "channel": "production",
       "android": {
@@ -51,6 +57,7 @@
     }
   },
   "submit": {
+    "testflight": {},
     "production": {}
   }
 }

+ 3 - 3
package.json

@@ -13,10 +13,11 @@
   },
   "dependencies": {
     "@expo/config-plugins": "^8.0.8",
-    "@maplibre/maplibre-react-native": "^10.0.0-alpha.22",
+    "@maplibre/maplibre-react-native": "^10.0.0",
     "@react-native-clipboard/clipboard": "^1.14.2",
     "@react-native-community/datetimepicker": "8.0.1",
     "@react-native-community/netinfo": "11.3.1",
+    "@react-native-picker/picker": "2.7.5",
     "@react-navigation/bottom-tabs": "^6.5.11",
     "@react-navigation/drawer": "^6.6.15",
     "@react-navigation/material-top-tabs": "^6.6.5",
@@ -47,7 +48,6 @@
     "expo-splash-screen": "~0.27.5",
     "expo-sqlite": "^14.0.6",
     "expo-status-bar": "~1.12.1",
-    "expo-task-manager": "^11.8.2",
     "expo-updates": "~0.25.24",
     "formik": "^2.4.5",
     "moment": "^2.29.4",
@@ -57,7 +57,7 @@
     "react-native": "0.74.5",
     "react-native-actions-sheet": "^0.9.7",
     "react-native-animated-pagination-dot": "^0.4.0",
-    "react-native-calendars": "^1.1304.1",
+    "react-native-calendars": "1.1304.1",
     "react-native-color-matrix-image-filters": "^7.0.1",
     "react-native-device-detection": "^0.2.1",
     "react-native-document-picker": "^9.3.1",

+ 12 - 2
src/components/MapButton/index.tsx

@@ -8,9 +8,16 @@ interface MapButtonProps {
   icon: React.ComponentType<SvgProps> | null;
   text: string;
   active?: boolean;
+  children?: React.ReactNode;
 }
 
-const MapButton: React.FC<MapButtonProps> = ({ onPress, icon: Icon, text, active = false }) => {
+const MapButton: React.FC<MapButtonProps> = ({
+  onPress,
+  icon: Icon,
+  text,
+  active = false,
+  children
+}) => {
   const isSmallScreen = Dimensions.get('window').width < 383;
   const iconSize = isSmallScreen ? 14 : 16;
 
@@ -36,7 +43,9 @@ const MapButton: React.FC<MapButtonProps> = ({ onPress, icon: Icon, text, active
       }}
       onPress={onPress}
     >
-      {Icon && <Icon fill={active ? Colors.WHITE : Colors.DARK_BLUE} width={iconSize} height={iconSize} />}
+      {Icon && (
+        <Icon fill={active ? Colors.WHITE : Colors.DARK_BLUE} width={iconSize} height={iconSize} />
+      )}
       <Text
         style={{
           color: active ? Colors.WHITE : Colors.DARK_BLUE,
@@ -46,6 +55,7 @@ const MapButton: React.FC<MapButtonProps> = ({ onPress, icon: Icon, text, active
       >
         {text}
       </Text>
+      {children}
     </TouchableOpacity>
   );
 };

+ 4 - 2
src/components/MessagesDot/index.tsx

@@ -5,11 +5,13 @@ import { Colors } from 'src/theme';
 const MessagesDot = ({
   messagesCount,
   right = 0,
-  top = -2
+  top = -2,
+  fullNumber = false
 }: {
   messagesCount: number;
   right?: DimensionValue;
   top?: DimensionValue;
+  fullNumber?: boolean;
 }) => {
   return (
     <View
@@ -36,7 +38,7 @@ const MessagesDot = ({
       >
         {messagesCount > 0 && (
           <Text style={{ fontFamily: 'montserrat-700', fontSize: 10, color: Colors.WHITE }}>
-            {messagesCount > 99 ? '99+' : messagesCount}
+            {messagesCount > 99 && !fullNumber ? '99+' : messagesCount}
           </Text>
         )}
       </View>

+ 3 - 3
src/database/tilesService/index.ts

@@ -1,5 +1,5 @@
 import * as FileSystem from 'expo-file-system';
-import MapLibreGL from '@maplibre/maplibre-react-native';
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
 
 import { VECTOR_MAP_HOST } from 'src/constants';
 
@@ -27,7 +27,7 @@ async function setupOfflineRegion(): Promise<void> {
     const minZoom = 0;
     const maxZoom = 6;
 
-    const existingPacks = await MapLibreGL.offlineManager.getPacks();
+    const existingPacks = await MapLibreRN.OfflineManager.getPacks();
     const pack = existingPacks.find((pack) => pack.name === PACK_NAME);
 
     if (pack) {
@@ -36,7 +36,7 @@ async function setupOfflineRegion(): Promise<void> {
         pack.resume();
       }
     } else {
-      await MapLibreGL.offlineManager.createPack(
+      await MapLibreRN.OfflineManager.createPack(
         {
           name: PACK_NAME,
           bounds,

+ 7 - 1
src/modules/api/location/location-api.ts

@@ -15,6 +15,10 @@ export interface PostIsFeatureActiveReturn extends ResponseType {
   active: boolean;
 }
 
+export interface PostGetUserCountReturn extends ResponseType {
+  count: number;
+}
+
 export const locationApi = {
   getSettings: (token: string) =>
     request.postForm<PostGetSettingsReturn>(API.GET_LOCATION_SETTINGS, { token }),
@@ -25,5 +29,7 @@ export const locationApi = {
   getUsersLocation: (token: string) =>
     request.postForm<PostGetUsersLocationReturn>(API.GET_USERS_LOCATION, { token }),
   isFeatureActive: (token: string) =>
-    request.postForm<PostIsFeatureActiveReturn>(API.IS_FEATURE_ACTIVE, { token })
+    request.postForm<PostIsFeatureActiveReturn>(API.IS_FEATURE_ACTIVE, { token }),
+  getUsersCount: (token: string) =>
+    request.postForm<PostGetUserCountReturn>(API.GET_USERS_COUNT, { token })
 };

+ 2 - 1
src/modules/api/location/location-query-keys.tsx

@@ -3,5 +3,6 @@ export const locationQueryKeys = {
   setSettings: () => ['location', 'setSettings'],
   updateLocation: () => ['location', 'updateLocation'],
   getUsersLocation: (token: string) => ['location', 'getUsersLocation', token],
-  isFeatureActive: (token: string) => ['location', 'isFeatureActive', token]
+  isFeatureActive: (token: string) => ['location', 'isFeatureActive', token],
+  getUsersCount: (token: string) => ['location', 'getUsersCount', token]
 };

+ 1 - 0
src/modules/api/location/queries/index.ts

@@ -3,3 +3,4 @@ export * from './use-post-set-settings';
 export * from './use-post-update-location';
 export * from './use-post-get-users-location';
 export * from './use-post-is-feature-active';
+export * from './use-post-get-users-on-map-count';

+ 17 - 0
src/modules/api/location/queries/use-post-get-users-on-map-count.tsx

@@ -0,0 +1,17 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { locationQueryKeys } from '../location-query-keys';
+import { locationApi, type PostGetUserCountReturn } from '../location-api';
+
+import type { BaseAxiosError } from '../../../../types';
+
+export const usePostGetUsersCountQuery = (token: string, enabled: boolean) => {
+  return useQuery<PostGetUserCountReturn, BaseAxiosError>({
+    queryKey: locationQueryKeys.getUsersCount(token),
+    queryFn: async () => {
+      const response = await locationApi.getUsersCount(token);
+      return response.data;
+    },
+    enabled
+  });
+};

+ 6 - 12
src/screens/InAppScreens/MapScreen/FilterModal/index.tsx

@@ -47,7 +47,8 @@ const FilterModal = ({
   isPublicView,
   isLogged = true,
   showNomads,
-  setShowNomads
+  setShowNomads,
+  usersOnMapCount
 }: {
   isFilterVisible: string | null;
   setIsFilterVisible: (filterType: string | null) => void;
@@ -62,6 +63,7 @@ const FilterModal = ({
   isLogged: boolean;
   showNomads?: boolean;
   setShowNomads?: (showNomads: boolean) => void;
+  usersOnMapCount?: number | null;
 }) => {
   const token = storage.get('token', StoreType.STRING) as string;
   const { data: locationSettings } = usePostGetSettingsQuery(token, isLogged && !isPublicView);
@@ -467,15 +469,7 @@ const FilterModal = ({
     return (
       <View style={[styles.sceneContainer, { flex: 0 }]}>
         <View style={styles.textContainer}>
-          <Text style={styles.textWithIcon}>
-            Your location is shared each time you launch the app and whenever you press the{'  '}
-            <View style={styles.icon}>
-              <LocationIcon width={12} height={12} />
-            </View>
-            {'  '}
-            button.
-          </Text>
-          <Text style={styles.text}>Your location is shared with ~250m radius precision.</Text>
+          <Text style={styles.text}>The location is shared with 1 km radius precision.</Text>
         </View>
         <TouchableOpacity
           style={[
@@ -495,7 +489,7 @@ const FilterModal = ({
               height={20}
             />
             <Text style={[styles.buttonLabel, !isSharing ? { color: Colors.LIGHT_GRAY } : {}]}>
-              Show nomads
+              Show Nomads - {usersOnMapCount} online
             </Text>
           </View>
           <View>
@@ -522,7 +516,7 @@ const FilterModal = ({
         >
           <View style={styles.alignStyle}>
             <SharingIcon fill={Colors.DARK_BLUE} width={20} height={20} />
-            <Text style={styles.buttonLabel}>Share location</Text>
+            <Text style={styles.buttonLabel}>Share location to see others</Text>
           </View>
           <View>
             <Switch

+ 6 - 6
src/screens/InAppScreens/MapScreen/MarkerItem/index.tsx

@@ -5,7 +5,7 @@ import { styles } from './styles';
 import { Colors } from 'src/theme';
 
 import CheckSvg from 'assets/icons/mark.svg';
-import MapLibreGL, { PointAnnotationRef } from '@maplibre/maplibre-react-native';
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
 import { Position } from '@turf/turf';
 
 const MarkerItem = ({
@@ -17,7 +17,7 @@ const MarkerItem = ({
   toggleSeries: (item: any) => void;
   token: string;
 }) => {
-  const calloutRef = useRef<PointAnnotationRef>(null);
+  const calloutRef = useRef<MapLibreRN.PointAnnotationRef>(null);
   useEffect(() => {
     if (Platform.OS === 'android' && calloutRef.current) {
       calloutRef.current?.refresh();
@@ -26,7 +26,7 @@ const MarkerItem = ({
   return (
     <>
       {Platform.OS === 'ios' ? (
-        <MapLibreGL.PointAnnotation
+        <MapLibreRN.PointAnnotation
           id="selected_marker_callout"
           coordinate={marker.coordinates}
           anchor={{ x: 0.5, y: 1 }}
@@ -70,9 +70,9 @@ const MarkerItem = ({
               </TouchableOpacity>
             </View>
           </View>
-        </MapLibreGL.PointAnnotation>
+        </MapLibreRN.PointAnnotation>
       ) : (
-        <MapLibreGL.PointAnnotation
+        <MapLibreRN.PointAnnotation
           id="selected_marker_callout"
           coordinate={marker.coordinates}
           anchor={{ x: 0.5, y: 0.9 }}
@@ -119,7 +119,7 @@ const MarkerItem = ({
               </TouchableOpacity>
             </View>
           </View>
-        </MapLibreGL.PointAnnotation>
+        </MapLibreRN.PointAnnotation>
       )}
     </>
   );

+ 21 - 1
src/screens/InAppScreens/MapScreen/UniversalSearch/index.tsx

@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
 import { View, Text, TouchableOpacity, Image } from 'react-native';
 import { TabView, TabBar } from 'react-native-tab-view';
 import ReactModal from 'react-native-modal';
@@ -11,6 +11,7 @@ import { NAVIGATION_PAGES } from 'src/types';
 import { API_HOST } from 'src/constants';
 import { Loading, WarningModal } from 'src/components';
 import { StoreType, storage } from 'src/storage';
+import MessagesDot from 'src/components/MessagesDot';
 
 const SearchModal = ({
   searchVisible,
@@ -41,6 +42,20 @@ const SearchModal = ({
   } | null>(null);
   const [warningVisible, setWarningVisible] = useState(false);
 
+  useEffect(() => {
+    if (!searchData) return;
+
+    if (searchData['users'] && searchData['users'].length > 0) {
+      setIndex(0);
+    } else if (searchData['regions'] && searchData['regions'].length > 0) {
+      setIndex(1);
+    } else if (searchData['dare'] && searchData['dare'].length > 0) {
+      setIndex(2);
+    } else {
+      setIndex(0);
+    }
+  }, [searchData]);
+
   const renderItem = ({ item }: { item: any }) => {
     const [name, ...rest] = item.name?.split(/ – | - /);
     const subname = rest?.join(' - ');
@@ -186,6 +201,11 @@ const SearchModal = ({
                   {route.title}
                 </Text>
               )}
+              renderBadge={({ route }) =>
+                searchData?.[route.key] && searchData?.[route.key].length > 0 ? (
+                  <MessagesDot messagesCount={searchData?.[route.key].length} top={4} />
+                ) : null
+              }
             />
           )}
         />

+ 1 - 1
src/screens/InAppScreens/MapScreen/UniversalSearch/styles.tsx

@@ -55,7 +55,7 @@ export const styles = StyleSheet.create({
   modalContainer: {
     backgroundColor: 'white',
     borderRadius: 15,
-    paddingHorizontal: 16,
+    paddingHorizontal: '4%',
     gap: 12,
     paddingVertical: 16,
     height: '80%'

+ 6 - 6
src/screens/InAppScreens/MapScreen/UserItem/index.tsx

@@ -3,14 +3,14 @@ import { View, Image, Text, TouchableOpacity, Platform } from 'react-native';
 
 import { Colors } from 'src/theme';
 
-import MapLibreGL, { PointAnnotationRef } from '@maplibre/maplibre-react-native';
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
 import { useNavigation } from '@react-navigation/native';
 import { NAVIGATION_PAGES } from 'src/types';
 import moment from 'moment';
 import { styles } from '../MarkerItem/styles';
 
 const UserItem = ({ marker }: { marker: any }) => {
-  const calloutUserRef = useRef<PointAnnotationRef>(null);
+  const calloutUserRef = useRef<MapLibreRN.PointAnnotationRef>(null);
   const navigation = useNavigation();
 
   useEffect(() => {
@@ -37,7 +37,7 @@ const UserItem = ({ marker }: { marker: any }) => {
   return (
     <>
       {Platform.OS === 'ios' ? (
-        <MapLibreGL.PointAnnotation
+        <MapLibreRN.PointAnnotation
           id={marker.id.toString()}
           coordinate={marker.coordinates}
           anchor={{ x: 0.5, y: 0 }}
@@ -98,9 +98,9 @@ const UserItem = ({ marker }: { marker: any }) => {
               </TouchableOpacity>
             </View>
           </View>
-        </MapLibreGL.PointAnnotation>
+        </MapLibreRN.PointAnnotation>
       ) : (
-        <MapLibreGL.PointAnnotation
+        <MapLibreRN.PointAnnotation
           id="selected_user_callout"
           coordinate={marker.coordinates}
           anchor={{ x: 0.5, y: 1.1 }}
@@ -158,7 +158,7 @@ const UserItem = ({ marker }: { marker: any }) => {
               </TouchableOpacity>
             </View>
           </View>
-        </MapLibreGL.PointAnnotation>
+        </MapLibreRN.PointAnnotation>
       )}
     </>
   );

+ 76 - 86
src/screens/InAppScreens/MapScreen/index.tsx

@@ -13,7 +13,7 @@ import {
 } from 'react-native';
 import React, { useEffect, useRef, useState, useCallback } from 'react';
 
-import MapLibreGL, { CameraRef, MapViewRef, ShapeSourceRef } from '@maplibre/maplibre-react-native';
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
 import { styles } from './style';
 import { SafeAreaView } from 'react-native-safe-area-context';
 import { Colors } from 'src/theme';
@@ -68,8 +68,8 @@ import { useGetIconsQuery, usePostSetToggleItem } from '@api/series';
 import MarkerItem from './MarkerItem';
 import {
   usePostGetSettingsQuery,
+  usePostGetUsersCountQuery,
   usePostGetUsersLocationQuery,
-  usePostIsFeatureActiveQuery,
   usePostUpdateLocationMutation
 } from '@api/location';
 import UserItem from './UserItem';
@@ -83,17 +83,14 @@ import MapButton from 'src/components/MapButton';
 import { useAvatarStore } from 'src/stores/avatarVersionStore';
 import _ from 'lodash';
 import ScaleBar from 'src/components/ScaleBar';
-// import {
-//   startBackgroundLocationUpdates,
-//   stopBackgroundLocationUpdates
-// } from 'src/utils/backgroundLocation';
+import MessagesDot from 'src/components/MessagesDot';
 
+const clusteredUsersIcon = require('assets/icons/icon-clustered-users.png');
 const defaultUserAvatar = require('assets/icon-user-share-location-solid.png');
 const logo = require('assets/logo-ua.png');
 const defaultSeriesIcon = require('assets/series-default.png');
 
-MapLibreGL.setAccessToken(null);
-MapLibreGL.Logger.setLogLevel('error');
+MapLibreRN.Logger.setLogLevel('error');
 
 const generateFilter = (ids: number[]) => {
   return ids?.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
@@ -276,7 +273,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
   const netInfo = useConnection();
   const { avatarVersion } = useAvatarStore();
 
-  const { data: isFeatureActive } = usePostIsFeatureActiveQuery(token, !!token && isConnected);
+  const { data: usersOnMapCount } = usePostGetUsersCountQuery(token, !!token && isConnected);
   const { data: regionsList } = useGetListRegionsQuery(isConnected);
   const { data: countriesList } = useGetListCountriesQuery(isConnected);
   const { data: dareList } = useGetListDareQuery(isConnected);
@@ -625,24 +622,9 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
       ) {
         setShowNomads(false);
         storage.set('showNomads', false);
-        // await stopBackgroundLocationUpdates();
         return;
       }
 
-      // const bgStatus = await Location.getBackgroundPermissionsAsync();
-      // if (bgStatus.status !== 'granted') {
-      //   const { status } = await Location.requestBackgroundPermissionsAsync();
-      //   if (status === Location.PermissionStatus.GRANTED) {
-      //     await startBackgroundLocationUpdates();
-      //     console.log('[Permissions] Background granted');
-      //   } else {
-      //     console.log('[Permissions] Background denied');
-      //   }
-      // } else {
-      //   await startBackgroundLocationUpdates();
-      //   console.log('[Permissions] Background already granted');
-      // }
-
       try {
         let currentLocation = await Location.getCurrentPositionAsync({
           accuracy: Location.Accuracy.Balanced
@@ -689,9 +671,9 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
     }, [regionPopupVisible, navigation])
   );
 
-  const mapRef = useRef<MapViewRef>(null);
-  const cameraRef = useRef<CameraRef>(null);
-  const shapeSourceRef = useRef<ShapeSourceRef>(null);
+  const mapRef = useRef<MapLibreRN.MapViewRef>(null);
+  const cameraRef = useRef<MapLibreRN.CameraRef>(null);
+  const shapeSourceRef = useRef<MapLibreRN.ShapeSourceRef>(null);
 
   useEffect(() => {
     if (userInfo) {
@@ -913,19 +895,6 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
 
       if (status === 'granted' && isServicesEnabled) {
         await getLocation();
-        // const bgStatus = await Location.getBackgroundPermissionsAsync();
-        // if (bgStatus.status !== 'granted') {
-        //   const { status } = await Location.requestBackgroundPermissionsAsync();
-        //   if (status === Location.PermissionStatus.GRANTED) {
-        //     await startBackgroundLocationUpdates();
-        //     console.log('[Permissions] Background granted');
-        //   } else {
-        //     console.log('[Permissions] Background denied');
-        //   }
-        // } else {
-        //   await startBackgroundLocationUpdates();
-        //   console.log('[Permissions] Background already granted');
-        // }
       } else if (!canAskAgain || !isServicesEnabled) {
         setOpenSettingsVisible(true);
       } else {
@@ -1196,10 +1165,10 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
     <SafeAreaView style={{ height: '100%' }}>
       <StatusBar translucent backgroundColor="transparent" />
 
-      <MapLibreGL.MapView
+      <MapLibreRN.MapView
         ref={mapRef}
         style={styles.map}
-        styleJSON={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
+        mapStyle={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
         rotateEnabled={false}
         attributionEnabled={false}
         onPress={onMapPress}
@@ -1207,7 +1176,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
         onRegionIsChanging={handleMapChange}
         onRegionWillChange={_.debounce(handleMapChange, 200)}
       >
-        <MapLibreGL.Images
+        <MapLibreRN.Images
           images={images}
           onImageMissing={(image) => {
             if (processedImages.current.has(image)) {
@@ -1222,11 +1191,11 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           }}
         >
           <View />
-        </MapLibreGL.Images>
+        </MapLibreRN.Images>
 
         {type === 'regions' && (
           <>
-            <MapLibreGL.LineLayer
+            <MapLibreRN.LineLayer
               id="nm-regions-line-layer"
               sourceID={regions.source}
               sourceLayerID={regions['source-layer']}
@@ -1239,7 +1208,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               }}
               belowLayerID="waterway-name"
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={regions.id}
               sourceID={regions.source}
               sourceLayerID={regions['source-layer']}
@@ -1248,7 +1217,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               maxZoomLevel={regions.maxzoom}
               belowLayerID={regions_visited.id}
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={regions_visited.id}
               sourceID={regions_visited.source}
               sourceLayerID={regions_visited['source-layer']}
@@ -1261,7 +1230,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
         )}
         {type === 'countries' && (
           <>
-            <MapLibreGL.LineLayer
+            <MapLibreRN.LineLayer
               id="countries-line-layer"
               sourceID={countries.source}
               sourceLayerID={countries['source-layer']}
@@ -1274,7 +1243,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               }}
               belowLayerID="waterway-name"
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={countries.id}
               sourceID={countries.source}
               sourceLayerID={countries['source-layer']}
@@ -1283,7 +1252,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               maxZoomLevel={countries.maxzoom}
               belowLayerID={countries_visited.id}
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={countries_visited.id}
               sourceID={countries_visited.source}
               sourceLayerID={countries_visited['source-layer']}
@@ -1296,7 +1265,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
         )}
         {type === 'dare' && (
           <>
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={dare.id}
               sourceID={dare.source}
               sourceLayerID={dare['source-layer']}
@@ -1305,7 +1274,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               maxZoomLevel={dare.maxzoom}
               belowLayerID={dare_visited.id}
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={dare_visited.id}
               sourceID={dare_visited.source}
               sourceLayerID={dare_visited['source-layer']}
@@ -1317,7 +1286,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           </>
         )}
         {selectedRegion && type && (
-          <MapLibreGL.FillLayer
+          <MapLibreRN.FillLayer
             id={selected_region.id}
             sourceID={type}
             sourceLayerID={type}
@@ -1328,13 +1297,13 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           />
         )}
 
-        <MapLibreGL.VectorSource
+        <MapLibreRN.VectorSource
           id="nomadmania_series"
           tileUrlTemplates={[VECTOR_MAP_HOST + '/tiles/series/{z}/{x}/{y}.pbf']}
           onPress={handleMarkerPress}
         >
           {seriesFilter.status !== 1 && Object.keys(images).length > 0 ? (
-            <MapLibreGL.SymbolLayer
+            <MapLibreRN.SymbolLayer
               id={series_layer.id}
               sourceID={series_layer.source}
               sourceLayerID={series_layer['source-layer']}
@@ -1361,7 +1330,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           )}
 
           {seriesFilter.status !== 0 && Object.keys(images).length > 0 ? (
-            <MapLibreGL.SymbolLayer
+            <MapLibreRN.SymbolLayer
               id={series_visited.id}
               sourceID={series_visited.source}
               sourceLayerID={series_visited['source-layer']}
@@ -1386,10 +1355,10 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           ) : (
             <></>
           )}
-        </MapLibreGL.VectorSource>
+        </MapLibreRN.VectorSource>
 
         {nomads && showNomads && (
-          <MapLibreGL.ShapeSource
+          <MapLibreRN.ShapeSource
             ref={shapeSourceRef}
             tolerance={20}
             id="nomads"
@@ -1420,61 +1389,72 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
             cluster={true}
             clusterRadius={50}
           >
-            <MapLibreGL.CircleLayer
+            <MapLibreRN.SymbolLayer
               id="nomads_circle"
               filter={['has', 'point_count']}
               aboveLayerID={Platform.OS === 'android' ? 'place-continent' : undefined}
               style={{
-                circleRadius: [
+                iconImage: clusteredUsersIcon,
+                iconSize: [
                   'interpolate',
                   ['linear'],
                   ['get', 'point_count'],
                   0,
-                  15,
+                  0.33,
                   10,
-                  17,
+                  0.35,
                   20,
-                  19,
+                  0.37,
                   50,
-                  21,
+                  0.39,
                   75,
-                  23,
+                  0.41,
                   100,
-                  25
+                  0.43
                 ],
-                circleColor: 'rgba(237, 147, 52, 1)',
-                circleStrokeWidth: 2,
-                circleStrokeColor: '#FFFFFF',
-                circleOpacity: 1
+                iconAllowOverlap: true
               }}
-            />
-            <MapLibreGL.SymbolLayer
+            ></MapLibreRN.SymbolLayer>
+            <MapLibreRN.SymbolLayer
               id="nomads_count"
               filter={['has', 'point_count']}
               aboveLayerID={Platform.OS === 'android' ? 'nomads_circle' : undefined}
               style={{
-                textField: ['get', 'point_count'],
+                textField: [
+                  'case',
+                  ['<', ['get', 'point_count'], 1000],
+                  ['get', 'point_count'],
+                  ['concat', ['/', ['round', ['/', ['get', 'point_count'], 100]], 10], 'k']
+                ],
                 textFont: ['Noto Sans Bold'],
                 textSize: [
                   'interpolate',
                   ['linear'],
                   ['get', 'point_count'],
                   0,
-                  13,
+                  13.5,
                   20,
                   14,
                   75,
                   15
                 ],
                 textColor: '#FFFFFF',
-                textHaloColor: '#000000',
-                textHaloWidth: 1,
                 textAnchor: 'center',
-                textOffset: [0, 0],
+                textOffset: [
+                  'interpolate',
+                  ['linear'],
+                  ['get', 'point_count'],
+                  0,
+                  ['literal', [0, 0.85]],
+                  20,
+                  ['literal', [0, 0.92]],
+                  75,
+                  ['literal', [0, 1]]
+                ],
                 textAllowOverlap: true
               }}
             />
-            <MapLibreGL.SymbolLayer
+            <MapLibreRN.SymbolLayer
               id="nomads_symbol"
               filter={['!', ['has', 'point_count']]}
               aboveLayerID={Platform.OS === 'android' ? 'place-continent' : undefined}
@@ -1497,8 +1477,8 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
                 ],
                 iconAllowOverlap: true
               }}
-            ></MapLibreGL.SymbolLayer>
-          </MapLibreGL.ShapeSource>
+            ></MapLibreRN.SymbolLayer>
+          </MapLibreRN.ShapeSource>
         )}
 
         {selectedUser && <UserItem marker={selectedUser} />}
@@ -1506,9 +1486,9 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
         {selectedMarker && (
           <MarkerItem marker={selectedMarker} toggleSeries={toggleSeries} token={token} />
         )}
-        <MapLibreGL.Camera ref={cameraRef} />
+        <MapLibreRN.Camera ref={cameraRef} />
         {location && (
-          <MapLibreGL.UserLocation
+          <MapLibreRN.UserLocation
             animated={true}
             showsUserHeadingIndicator={true}
             onPress={async () => {
@@ -1524,9 +1504,9 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
             }}
           >
             {/* to do custom user location */}
-          </MapLibreGL.UserLocation>
+          </MapLibreRN.UserLocation>
         )}
-      </MapLibreGL.MapView>
+      </MapLibreRN.MapView>
 
       {center ? (
         <ScaleBar
@@ -1677,6 +1657,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               showsHorizontalScrollIndicator={false}
               contentContainerStyle={{
                 paddingHorizontal: 12,
+                paddingTop: 6,
                 gap: isSmallScreen ? 8 : 12,
                 flexDirection: 'row'
               }}
@@ -1699,7 +1680,6 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
                 text="Series"
                 active={seriesFilter.visible}
               />
-              {/* {isFeatureActive && isFeatureActive.active ? ( */}
               {token ? (
                 <MapButton
                   onPress={() => {
@@ -1709,7 +1689,16 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
                   icon={NomadsIcon}
                   text="Nomads"
                   active={showNomads}
-                />
+                >
+                  {usersOnMapCount && usersOnMapCount?.count > 0 ? (
+                    <MessagesDot
+                      messagesCount={usersOnMapCount.count}
+                      fullNumber={true}
+                      right={-10}
+                      top={-8}
+                    />
+                  ) : null}
+                </MapButton>
               ) : null}
             </ScrollView>
           </View>
@@ -1767,6 +1756,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
         showNomads={showNomads}
         isPublicView={false}
         isLogged={token ? true : false}
+        usersOnMapCount={token && usersOnMapCount?.count ? usersOnMapCount.count : null}
       />
       <EditModal
         isVisible={isEditSlowModalVisible}

+ 11 - 11
src/screens/InAppScreens/MessagesScreen/ChatScreen/index.tsx

@@ -1427,20 +1427,20 @@ const ChatScreen = ({ route }: { route: any }) => {
   };
 
   const renderInputToolbar = (props: any) => (
-    <View>
-      <InputToolbar
-        {...props}
-        renderActions={() => (
+    <InputToolbar
+      {...props}
+      renderActions={() =>
+        userType === 'normal' ? (
           <Actions
-            icon={() => <MaterialCommunityIcons name={'plus'} size={28} color={Colors.DARK_BLUE} />}
+            icon={() => <MaterialCommunityIcons name="plus" size={28} color={Colors.DARK_BLUE} />}
             onPressActionButton={openAttachmentsModal}
           />
-        )}
-        containerStyle={{
-          backgroundColor: Colors.FILL_LIGHT
-        }}
-      />
-    </View>
+        ) : null
+      }
+      containerStyle={{
+        backgroundColor: Colors.FILL_LIGHT
+      }}
+    />
   );
 
   const renderScrollToBottom = () => {

+ 26 - 14
src/screens/InAppScreens/MessagesScreen/Components/MoreModal.tsx

@@ -200,23 +200,35 @@ const MoreModal = () => {
             </Text>
           </TouchableOpacity>
 
-          <View style={styles.optionsContainer}>
-            <TouchableOpacity style={styles.option} onPress={handleMute}>
-              <Text style={styles.optionText}>{chatData.muted === 1 ? 'Unmute' : 'Mute'}</Text>
-              <BellSlashIcon fill={Colors.DARK_BLUE} />
-            </TouchableOpacity>
-          </View>
+          {chatData?.userType === 'normal' && (
+            <View style={styles.optionsContainer}>
+              <TouchableOpacity style={styles.option} onPress={handleMute}>
+                <Text style={styles.optionText}>{chatData.muted === 1 ? 'Unmute' : 'Mute'}</Text>
+                <BellSlashIcon fill={Colors.DARK_BLUE} />
+              </TouchableOpacity>
+            </View>
+          )}
 
           <View style={[styles.optionsContainer, { paddingVertical: 0, gap: 0 }]}>
-            <TouchableOpacity style={[styles.option, styles.dangerOption]} onPress={handleReport}>
-              <Text style={[styles.optionText, styles.dangerText]}>Report {name}</Text>
-              <MegaphoneIcon fill={Colors.RED} />
-            </TouchableOpacity>
+            {chatData?.userType === 'normal' && (
+              <>
+                <TouchableOpacity
+                  style={[styles.option, styles.dangerOption]}
+                  onPress={handleReport}
+                >
+                  <Text style={[styles.optionText, styles.dangerText]}>Report {name}</Text>
+                  <MegaphoneIcon fill={Colors.RED} />
+                </TouchableOpacity>
 
-            <TouchableOpacity style={[styles.option, styles.dangerOption]} onPress={handleBlock}>
-              <Text style={[styles.optionText, styles.dangerText]}>Block {name}</Text>
-              <BanIcon fill={Colors.RED} />
-            </TouchableOpacity>
+                <TouchableOpacity
+                  style={[styles.option, styles.dangerOption]}
+                  onPress={handleBlock}
+                >
+                  <Text style={[styles.optionText, styles.dangerText]}>Block {name}</Text>
+                  <BanIcon fill={Colors.RED} />
+                </TouchableOpacity>
+              </>
+            )}
 
             <TouchableOpacity style={[styles.option, styles.dangerOption]} onPress={handleDelete}>
               <Text style={[styles.optionText, styles.dangerText]}>Delete chat</Text>

+ 20 - 22
src/screens/InAppScreens/ProfileScreen/UsersMap/index.tsx

@@ -35,7 +35,7 @@ import { useGetUniversalSearch } from '@api/search';
 import { storage, StoreType } from 'src/storage';
 import { NAVIGATION_PAGES } from 'src/types';
 import { SafeAreaView } from 'react-native-safe-area-context';
-import MapLibreGL, { CameraRef, MapViewRef } from '@maplibre/maplibre-react-native';
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
 import {
   usePostGetVisitedCountriesIdsQuery,
   usePostGetVisitedDareIdsQuery,
@@ -49,8 +49,6 @@ import ScaleBar from 'src/components/ScaleBar';
 import _ from 'lodash';
 const defaultUserAvatar = require('assets/icon-user-share-location-solid.png');
 
-MapLibreGL.setAccessToken(null);
-
 const generateFilter = (ids: number[]) => {
   return ids.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
 };
@@ -155,8 +153,8 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
     year: moment().year()
   });
 
-  const mapRef = useRef<MapViewRef>(null);
-  const cameraRef = useRef<CameraRef>(null);
+  const mapRef = useRef<MapLibreRN.MapViewRef>(null);
+  const cameraRef = useRef<MapLibreRN.CameraRef>(null);
   const [isFilterVisible, setIsFilterVisible] = useState<string | null>(null);
   const [tilesType, setTilesType] = useState({ label: 'NM regions', value: 0 });
   const tilesTypes = [
@@ -365,10 +363,10 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
     <SafeAreaView style={{ height: '100%' }}>
       <StatusBar translucent backgroundColor="transparent" />
 
-      <MapLibreGL.MapView
+      <MapLibreRN.MapView
         ref={mapRef}
         style={styles.map}
-        styleJSON={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
+        mapStyle={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
         rotateEnabled={false}
         attributionEnabled={false}
         onRegionDidChange={() => {
@@ -381,7 +379,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
       >
         {type === 'regions' && (
           <>
-            <MapLibreGL.LineLayer
+            <MapLibreRN.LineLayer
               id="nm-regions-line-layer"
               sourceID={regions.source}
               sourceLayerID={regions['source-layer']}
@@ -394,7 +392,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
               }}
               belowLayerID="waterway-name"
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={regions.id}
               sourceID={regions.source}
               sourceLayerID={regions['source-layer']}
@@ -403,7 +401,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
               maxZoomLevel={regions.maxzoom}
               belowLayerID={regions_visited.id}
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={regions_visited.id}
               sourceID={regions_visited.source}
               sourceLayerID={regions_visited['source-layer']}
@@ -416,7 +414,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
         )}
         {type === 'countries' && (
           <>
-            <MapLibreGL.LineLayer
+            <MapLibreRN.LineLayer
               id="countries-line-layer"
               sourceID={countries.source}
               sourceLayerID={countries['source-layer']}
@@ -429,7 +427,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
               }}
               belowLayerID="waterway-name"
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={countries.id}
               sourceID={countries.source}
               sourceLayerID={countries['source-layer']}
@@ -438,7 +436,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
               maxZoomLevel={countries.maxzoom}
               belowLayerID={countries_visited.id}
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={countries_visited.id}
               sourceID={countries_visited.source}
               sourceLayerID={countries_visited['source-layer']}
@@ -451,7 +449,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
         )}
         {type === 'dare' && (
           <>
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={dare.id}
               sourceID={dare.source}
               sourceLayerID={dare['source-layer']}
@@ -460,7 +458,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
               maxZoomLevel={dare.maxzoom}
               belowLayerID={dare_visited.id}
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={dare_visited.id}
               sourceID={dare_visited.source}
               sourceLayerID={dare_visited['source-layer']}
@@ -473,8 +471,8 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
         )}
 
         {data.location_sharing && data.location_last_seen_location && data.own_profile !== 1 && (
-          <MapLibreGL.ShapeSource id="user_location" shape={locationFeature}>
-            <MapLibreGL.SymbolLayer
+          <MapLibreRN.ShapeSource id="user_location" shape={locationFeature}>
+            <MapLibreRN.SymbolLayer
               id="user_symbol"
               filter={['!', ['has', 'point_count']]}
               aboveLayerID={Platform.OS === 'android' ? 'place-continent' : undefined}
@@ -498,17 +496,17 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
                 iconAllowOverlap: true
               }}
             />
-          </MapLibreGL.ShapeSource>
+          </MapLibreRN.ShapeSource>
         )}
 
-        <MapLibreGL.Camera ref={cameraRef} />
+        <MapLibreRN.Camera ref={cameraRef} />
         {location && (
-          <MapLibreGL.UserLocation
+          <MapLibreRN.UserLocation
             animated={true}
             showsUserHeadingIndicator={true}
-          ></MapLibreGL.UserLocation>
+          ></MapLibreRN.UserLocation>
         )}
-      </MapLibreGL.MapView>
+      </MapLibreRN.MapView>
 
       {center ? (
         <ScaleBar zoom={zoom} latitude={center[1]} isVisible={isZooming} bottom={80} />

+ 10 - 12
src/screens/InAppScreens/TravelsScreen/AddRegionsScreen/index.tsx

@@ -3,7 +3,7 @@ import { View, Text, TouchableOpacity } from 'react-native';
 import { SafeAreaView } from 'react-native-safe-area-context';
 import { useNavigation } from '@react-navigation/native';
 import * as turf from '@turf/turf';
-import MapLibreGL, { CameraRef, MapViewRef } from '@maplibre/maplibre-react-native';
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
 
 import { Header, Modal, FlatList as List } from 'src/components';
 
@@ -18,8 +18,6 @@ import { styles } from './styles';
 import SearchSvg from '../../../../../assets/icons/search.svg';
 import SaveSvg from '../../../../../assets/icons/travels-screens/save.svg';
 
-MapLibreGL.setAccessToken(null);
-
 const generateFilter = (ids: number[]) => {
   return ids?.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
 };
@@ -59,8 +57,8 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
   const [regionsToSave, setRegionsToSave] = useState<RegionAddData[]>([]);
   const [regionData, setRegionData] = useState<RegionAddData | null>(null);
   const [regionPopupVisible, setRegionPopupVisible] = useState(false);
-  const mapRef = useRef<MapViewRef>(null);
-  const cameraRef = useRef<CameraRef>(null);
+  const mapRef = useRef<MapLibreRN.MapViewRef>(null);
+  const cameraRef = useRef<MapLibreRN.CameraRef>(null);
 
   const [filterSelectedRegions, setFilterSelectedRegions] = useState<any[]>(generateFilter([]));
 
@@ -215,17 +213,17 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
       </View>
 
       <View style={styles.container}>
-        <MapLibreGL.MapView
+        <MapLibreRN.MapView
           ref={mapRef}
           style={styles.map}
-          styleJSON={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
+          mapStyle={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
           rotateEnabled={false}
           attributionEnabled={false}
           onPress={handleMapPress}
         >
-          <MapLibreGL.Camera ref={cameraRef} />
+          <MapLibreRN.Camera ref={cameraRef} />
 
-          <MapLibreGL.LineLayer
+          <MapLibreRN.LineLayer
             id="nm-regions-line-layer"
             sourceID={nm_regions.source}
             sourceLayerID={nm_regions['source-layer']}
@@ -238,7 +236,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
             }}
             belowLayerID="waterway-name"
           />
-          <MapLibreGL.FillLayer
+          <MapLibreRN.FillLayer
             id={nm_regions.id}
             sourceID={nm_regions.source}
             sourceLayerID={nm_regions['source-layer']}
@@ -249,7 +247,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
           />
 
           {selectedRegions && selectedRegions.length > 0 ? (
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={selected_region.id}
               sourceID={nm_regions.source}
               sourceLayerID={nm_regions['source-layer']}
@@ -259,7 +257,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
               belowLayerID="nm-regions-line-layer"
             />
           ) : null}
-        </MapLibreGL.MapView>
+        </MapLibreRN.MapView>
       </View>
       {regionPopupVisible && regionData && (
         <View style={styles.popupWrapper}>

+ 10 - 12
src/screens/InAppScreens/TravelsScreen/EarthScreen/index.tsx

@@ -9,9 +9,7 @@ import { StoreType, storage } from 'src/storage';
 
 import { VECTOR_MAP_HOST } from 'src/constants';
 import { styles } from './styles';
-import MapLibreGL, { MapViewRef } from '@maplibre/maplibre-react-native';
-
-MapLibreGL.setAccessToken(null);
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
 
 let kye_fill = {
   id: 'kye_fill',
@@ -66,7 +64,7 @@ const EarthScreen = () => {
 
   const [filter, setFilter] = useState<any[]>(generateFilter([]));
 
-  const mapRef = useRef<MapViewRef>(null);
+  const mapRef = useRef<MapLibreRN.MapViewRef>(null);
 
   useEffect(() => {
     if (!data || !data.regions) return;
@@ -192,38 +190,38 @@ const EarthScreen = () => {
           { paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0 }
         ]}
       >
-        <MapLibreGL.MapView
+        <MapLibreRN.MapView
           ref={mapRef}
           style={styles.map}
-          styleJSON={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
+          mapStyle={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
           rotateEnabled={false}
           attributionEnabled={false}
           onPress={onMapPress}
         >
-          <MapLibreGL.ShapeSource id="kye" shape={kye as any}>
-            <MapLibreGL.LineLayer
+          <MapLibreRN.ShapeSource id="kye" shape={kye as any}>
+            <MapLibreRN.LineLayer
               id={kye_line.id}
               filter={kye_line.filter as any}
               maxZoomLevel={kye_line.maxzoom}
               style={kye_line.style as any}
               belowLayerID="waterway-name"
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={kye_fill.id}
               filter={['==', 'tt', '1']}
               style={kye_fill.style}
               maxZoomLevel={kye_fill.maxzoom}
               belowLayerID={kye_fill_visited.id}
             />
-            <MapLibreGL.FillLayer
+            <MapLibreRN.FillLayer
               id={kye_fill_visited.id}
               filter={filter as any}
               style={kye_fill_visited.style}
               maxZoomLevel={kye_fill_visited.maxzoom}
               belowLayerID={kye_line.id}
             />
-          </MapLibreGL.ShapeSource>
-        </MapLibreGL.MapView>
+          </MapLibreRN.ShapeSource>
+        </MapLibreRN.MapView>
       </View>
     </SafeAreaView>
   );

+ 2 - 2
src/screens/LocationSharingScreen/index.tsx

@@ -165,7 +165,7 @@ const LocationSharingScreen = ({ navigation }: { navigation: any }) => {
           {'  '}
           button.
         </Text>
-        <Text style={textStyles.text}>Your location is shared with ~250m radius precision.</Text>
+        <Text style={textStyles.text}>The location is shared with 1 km radius precision.</Text>
       </View>
       <TouchableOpacity
         style={[
@@ -179,7 +179,7 @@ const LocationSharingScreen = ({ navigation }: { navigation: any }) => {
       >
         <View style={styles.alignStyle}>
           <UsersIcon fill={Colors.DARK_BLUE} width={20} height={20} />
-          <Text style={styles.buttonLabel}>Share with everyone</Text>
+          <Text style={styles.buttonLabel}>Share location to see others</Text>
         </View>
         <View>
           <Switch

+ 2 - 0
src/types/api.ts

@@ -160,6 +160,7 @@ export enum API_ENDPOINT {
   IS_FEATURE_ACTIVE = 'is-feature-active',
   AUTHENTICATE = 'authenticate',
   REPORT_CONVERSATION = 'report-conversation',
+  GET_USERS_COUNT = 'get-users-on-map-count',
 }
 
 export enum API {
@@ -293,6 +294,7 @@ export enum API {
   IS_FEATURE_ACTIVE = `${API_ROUTE.LOCATION}/${API_ENDPOINT.IS_FEATURE_ACTIVE}`,
   AUTHENTICATE = `${API_ROUTE.USER}/${API_ENDPOINT.AUTHENTICATE}`,
   REPORT_CONVERSATION = `${API_ROUTE.CHAT}/${API_ENDPOINT.REPORT_CONVERSATION}`,
+  GET_USERS_COUNT = `${API_ROUTE.LOCATION}/${API_ENDPOINT.GET_USERS_COUNT}`,
 }
 
 export type BaseAxiosError = AxiosError;

+ 0 - 85
src/utils/backgroundLocation.ts

@@ -1,85 +0,0 @@
-import * as TaskManager from 'expo-task-manager';
-import * as Location from 'expo-location';
-import axios from 'axios';
-import { storage, StoreType } from 'src/storage';
-import { Platform } from 'react-native';
-import { API_URL } from 'src/constants';
-import { API } from 'src/types';
-
-const LOCATION_TASK_NAME = 'BACKGROUND_LOCATION_TASK';
-
-// TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
-//   if (error) {
-//     console.error('[BackgroundLocation] Task error:', error);
-//     return;
-//   }
-//   if (data) {
-//     const { locations } = data as any;
-//     if (locations && locations.length > 0) {
-//       const { coords, timestamp } = locations[0];
-
-//       console.log('[BackgroundLocation] New location:', coords);
-//       const token = storage.get('token', StoreType.STRING);
-
-//       if (!token) {
-//         return;
-//       }
-
-//       try {
-//         const response = await axios.postForm(
-//           API_URL + '/' + API.UPDATE_LOCATION,
-//           {
-//             token,
-//             lat: coords.latitude,
-//             lng: coords.longitude,
-//             background: LOCATION_TASK_NAME,
-//             location_timestamp: timestamp
-//           },
-//           {
-//             headers: {
-//               Platform: Platform.OS
-//             }
-//           }
-//         );
-//         console.log('[BackgroundLocation] Location sent:', response.data);
-//       } catch (sendError) {
-//         console.error('[BackgroundLocation] Sending location failed:', sendError);
-//       }
-//     }
-//   }
-//   console.log('[BackgroundLocation] TaskManager end');
-// });
-
-export const startBackgroundLocationUpdates = async () => {
-  const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME);
-  if (hasStarted) {
-    console.log('[BackgroundLocation] Already started...');
-    return;
-  }
-
-  await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
-    accuracy: Location.Accuracy.Highest,
-    // 10 minutes for Android
-    timeInterval: 10 * 60 * 1000,
-    showsBackgroundLocationIndicator: false,
-    pausesUpdatesAutomatically: false,
-    // banner on Android
-    foregroundService: {
-      notificationTitle: 'NomadMania tracking your location',
-      notificationBody: 'Location is used in background every 10 minutes.',
-      notificationColor: '#0F3F4F'
-    },
-    // iOS only
-    activityType: Location.ActivityType.Other
-  });
-
-  console.log('[BackgroundLocation] Started task');
-};
-
-export const stopBackgroundLocationUpdates = async () => {
-  const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME);
-  if (hasStarted) {
-    await Location.stopLocationUpdatesAsync(LOCATION_TASK_NAME);
-    console.log('[BackgroundLocation] Stopped task');
-  }
-};