Pārlūkot izejas kodu

user filter + map filter

Viktoriia 4 nedēļas atpakaļ
vecāks
revīzija
a64532d9de

+ 14 - 5
App.tsx

@@ -4,6 +4,9 @@ import { QueryClientProvider } from '@tanstack/react-query';
 import { NavigationContainer } from '@react-navigation/native';
 import { queryClient } from 'src/utils/queryClient';
 import * as Sentry from '@sentry/react-native';
+import { GestureHandlerRootView } from 'react-native-gesture-handler';
+import { SheetProvider } from 'react-native-actions-sheet';
+import { SafeAreaProvider } from 'react-native-safe-area-context';
 
 import Route from './Route';
 import { ConnectionProvider } from 'src/contexts/ConnectionContext';
@@ -112,11 +115,17 @@ const linking = {
 
 const App = () => {
   return (
-    <QueryClientProvider client={queryClient}>
-      <ErrorProvider>
-        <InnerApp />
-      </ErrorProvider>
-    </QueryClientProvider>
+    <GestureHandlerRootView style={{ flex: 1 }}>
+      <SafeAreaProvider>
+        <SheetProvider>
+          <QueryClientProvider client={queryClient}>
+            <ErrorProvider>
+              <InnerApp />
+            </ErrorProvider>
+          </QueryClientProvider>
+        </SheetProvider>
+      </SafeAreaProvider>
+    </GestureHandlerRootView>
   );
 };
 

+ 262 - 0
src/components/SelectSheet/index.tsx

@@ -0,0 +1,262 @@
+import React, { useRef, useState, useCallback } from 'react';
+import {
+  View,
+  Text,
+  TouchableOpacity,
+  StyleSheet,
+  StyleProp,
+  ViewStyle,
+  FlatList,
+  TextInput,
+  Dimensions,
+} from 'react-native';
+import ActionSheet, { ActionSheetRef } from 'react-native-actions-sheet';
+import ChevronIcon from 'assets/icons/travels-screens/down-arrow.svg';
+import { Colors } from 'src/theme';
+
+export interface SelectSheetProps<T extends Record<string, any>> {
+  data: T[];
+  labelField: keyof T;
+  valueField: keyof T;
+  value?: T[keyof T] | null;
+  onChange: (item: T) => void;
+  placeholder?: string;
+  searchable?: boolean;
+  searchPlaceholder?: string;
+  disabled?: boolean;
+  style?: StyleProp<ViewStyle>;
+  renderItem?: (item: T, isSelected: boolean) => React.ReactNode;
+  name?: string;
+  hideTitle?: boolean;
+  initialSnapPoint?: number;
+}
+
+export const SelectSheet = <T extends Record<string, any>>({
+  data,
+  labelField,
+  valueField,
+  value,
+  onChange,
+  placeholder = 'Select...',
+  searchable = false,
+  searchPlaceholder = 'Search...',
+  disabled = false,
+  style,
+  renderItem,
+  name,
+  hideTitle = false,
+  initialSnapPoint = 70
+}: SelectSheetProps<T>) => {
+  const sheetRef = useRef<ActionSheetRef>(null);
+  const [query, setQuery] = useState('');
+
+  const selectedItem =
+    value != null ? data.find((item) => item[valueField] === value) : null;
+
+  const filteredData =
+    searchable && query.trim()
+      ? data.filter((item) =>
+        String(item[labelField]).toLowerCase().includes(query.toLowerCase())
+      )
+      : data;
+
+  const handleSelect = useCallback(
+    (item: T) => {
+      sheetRef.current?.hide();
+      onChange(item);
+    },
+    [onChange]
+  );
+
+  const handleOpen = useCallback(() => {
+    if (disabled) return;
+    setQuery('');
+    sheetRef.current?.show();
+  }, [disabled]);
+
+  return (
+    <>
+      <TouchableOpacity
+        onPress={handleOpen}
+        activeOpacity={disabled ? 1 : 0.7}
+        style={[styles.trigger, disabled && styles.triggerDisabled, style]}
+      >
+        <Text
+          style={[
+            styles.triggerText,
+            !selectedItem && styles.placeholderText,
+          ]}
+          numberOfLines={1}
+        >
+          {selectedItem ? String(selectedItem[labelField]) : placeholder}
+        </Text>
+        <ChevronIcon width={12} height={12} fill={Colors.TEXT_GRAY} style={styles.chevron} />
+      </TouchableOpacity>
+
+      <ActionSheet
+        ref={sheetRef}
+        gestureEnabled
+        closeOnTouchBackdrop
+        snapPoints={[initialSnapPoint, 100]}
+        initialSnapIndex={0}
+        defaultOverlayOpacity={0.4}
+        containerStyle={styles.sheetContainer}
+        onClose={() => setQuery('')}
+      >
+        <View style={styles.sheetContent}>
+          {!hideTitle && <Text style={styles.sheetTitle}>{placeholder}</Text>}
+
+          {searchable && (
+            <View style={styles.searchWrapper}>
+              <TextInput
+                style={styles.searchInput}
+                placeholder={searchPlaceholder}
+                placeholderTextColor={Colors.LIGHT_GRAY}
+                value={query}
+                onChangeText={setQuery}
+                autoCorrect={false}
+                clearButtonMode="while-editing"
+              />
+            </View>
+          )}
+
+          <FlatList
+            data={filteredData}
+            keyExtractor={(item: T, i: number) => String(item[valueField] ?? i)}
+            keyboardShouldPersistTaps="handled"
+            style={styles.list}
+            contentContainerStyle={styles.listContent}
+            initialNumToRender={20}
+            renderItem={({ item }: { item: T }) => {
+              const isSelected = item[valueField] === value;
+              if (renderItem) {
+                return (
+                  <TouchableOpacity onPress={() => handleSelect(item)} activeOpacity={0.7}>
+                    {renderItem(item, isSelected)}
+                  </TouchableOpacity>
+                );
+              }
+              return (
+                <TouchableOpacity
+                  style={styles.option}
+                  onPress={() => handleSelect(item)}
+                  activeOpacity={0.7}
+                >
+                  <Text
+                    style={[styles.optionText, isSelected && styles.optionTextSelectedWeight]}
+                    numberOfLines={1}
+                  >
+                    {String(item[labelField])}
+                  </Text>
+                  {isSelected && (
+                    <View style={styles.checkmark}>
+                      <Text style={styles.checkmarkText}>✓</Text>
+                    </View>
+                  )}
+                </TouchableOpacity>
+              );
+            }}
+          />
+        </View>
+      </ActionSheet>
+    </>
+  );
+}
+
+const styles = StyleSheet.create({
+  trigger: {
+    height: 40,
+    backgroundColor: Colors.FILL_LIGHT,
+    borderRadius: 8,
+    paddingHorizontal: 12,
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-between',
+  },
+  triggerDisabled: {
+    opacity: 0.5,
+  },
+  triggerText: {
+    flex: 1,
+    fontSize: 15,
+    color: Colors.DARK_BLUE,
+    marginRight: 6,
+  },
+  placeholderText: {
+    color: Colors.TEXT_GRAY,
+  },
+  sheetContent: {
+    height: Dimensions.get('window').height * 0.9,
+    backgroundColor: Colors.WHITE,
+    borderTopLeftRadius: 20,
+    borderTopRightRadius: 20,
+    overflow: 'hidden',
+  },
+  sheetContainer: {
+    height: '90%',
+    backgroundColor: Colors.WHITE,
+    borderTopLeftRadius: 20,
+    borderTopRightRadius: 20,
+  },
+  indicator: {
+    width: 44,
+    height: 5,
+    borderRadius: 3,
+    backgroundColor: Colors.LIGHT_GRAY,
+    marginTop: 8,
+  },
+  sheetTitle: {
+    fontSize: 18,
+    fontWeight: '700',
+    color: Colors.DARK_BLUE,
+    paddingVertical: 12,
+    paddingHorizontal: 24,
+    textAlign: 'center',
+    borderBottomWidth: StyleSheet.hairlineWidth,
+    borderBottomColor: Colors.DARK_LIGHT,
+  },
+  searchWrapper: {
+    paddingHorizontal: 16,
+    paddingVertical: 12,
+  },
+  searchInput: {
+    height: 44,
+    backgroundColor: Colors.FILL_LIGHT,
+    borderRadius: 6,
+    paddingHorizontal: 16,
+    fontSize: 16,
+    color: Colors.DARK_BLUE,
+  },
+  list: {
+    flex: 1,
+  },
+  listContent: {
+    paddingBottom: 40,
+    paddingTop: 8,
+  },
+  option: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 24,
+    paddingVertical: 16,
+  },
+  optionText: {
+    flex: 1,
+    fontSize: 16,
+    color: Colors.DARK_BLUE,
+  },
+  optionTextSelectedWeight: {
+    fontWeight: '700',
+  },
+  checkmark: {
+    marginLeft: 12,
+  },
+  checkmarkText: {
+    fontSize: 18,
+    color: Colors.DARK_BLUE,
+    fontWeight: '700',
+  },
+  chevron: {
+    marginLeft: 2,
+  },
+});

+ 1 - 0
src/components/index.ts

@@ -24,3 +24,4 @@ export * from './ScaleBar';
 export * from './MultiSelectorCountries';
 export * from './TabViewWrapper';
 export * from './CustomImageViewer';
+export * from './SelectSheet';

+ 933 - 920
src/screens/InAppScreens/MapScreen/FilterModal/index.tsx

@@ -1,4 +1,12 @@
-import React, { useEffect, useState } from 'react';
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+  forwardRef,
+  useImperativeHandle
+} from 'react';
 import {
   View,
   Text,
@@ -7,13 +15,14 @@ import {
   Switch,
   Dimensions,
   Platform,
-  Linking
+  Linking,
+  ScrollView
 } from 'react-native';
-import ReactModal from 'react-native-modal';
+import ActionSheet, { ActionSheetRef } from 'react-native-actions-sheet';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
 import { Colors } from 'src/theme';
 import { ModalStyles } from '../../TravellersScreen/Components/styles';
-import { Dropdown, MultiSelect } from 'react-native-searchable-dropdown-kj';
-import { Button, WarningModal } from 'src/components';
+import { Button, WarningModal, SelectSheet } from 'src/components';
 import { ButtonVariants } from 'src/types/components';
 import { styles } from './styles';
 import { usePostGetMapYearsQuery } from '@api/user';
@@ -46,989 +55,993 @@ import InfoIcon from 'assets/icons/info-solid.svg';
 import Tooltip from 'react-native-walkthrough-tooltip';
 import FriendsIcon from 'assets/icons/friend.svg';
 
-const FilterModal = ({
-  isFilterVisible,
-  setIsFilterVisible,
-  tilesTypes,
-  tilesType,
-  setTilesType,
-  setType,
-  userId,
-  setRegionsFilter,
-  setSeriesFilter,
-  setNomadsFilter,
-  isPublicView,
-  isLogged = true,
-  showNomads,
-  setShowNomads,
-  usersOnMapCount,
-  friendsOnTheMapCount,
-  isConnected = true,
-  isPremium
-}: {
-  isFilterVisible: string | null;
-  setIsFilterVisible: (filterType: string | null) => void;
-  tilesTypes: any[];
-  tilesType: any;
-  setTilesType: (item: any) => void;
-  setType: (type: any) => void;
-  userId: number;
-  setRegionsFilter: (data: { visitedLabel: 'in' | 'by'; year: number }) => void;
-  setSeriesFilter?: (filter: any) => void;
-  setNomadsFilter?: (filter: any) => void;
-  isPublicView: boolean;
-  isLogged: boolean;
-  showNomads?: boolean;
-  setShowNomads?: (showNomads: boolean) => void;
-  usersOnMapCount?: number | null;
-  friendsOnTheMapCount?: number | null;
-  isConnected?: boolean;
-  isPremium?: boolean;
-}) => {
-  const token = storage.get('token', StoreType.STRING) as string;
-  const { data: locationSettings } = usePostGetSettingsQuery(
-    token,
-    isLogged && !isPublicView && isConnected
-  );
-  const { data: countriesData } = usePostGetListOfCountriesForLocationDataQuery(
-    token,
-    isLogged && !isPublicView && isConnected
-  );
-  const { mutateAsync: setSettings } = usePostSetSettingsMutation();
-  const { mutateAsync: updateLocation } = usePostUpdateLocationMutation();
-  const [selectedYear, setSelectedYear] = useState<{ label: string; value: number } | null>(null);
-  const [allYears, setAllYears] = useState<{ label: string; value: number }[]>([]);
-  const [selectedVisible, setSelectedVisible] = useState({ label: 'visited by', value: 0 });
-  const visibleTypes = [
-    { label: 'visited by', value: 0 },
-    { label: 'visited in', value: 1 }
-  ];
-  const { data } = usePostGetMapYearsQuery(
-    token as string,
-    userId,
-    isLogged && isConnected ? true : false
-  );
-  const { data: seriesList } = useGetListQuery(isConnected ? true : false);
-  const [series, setSeries] = useState<{ label: string; value: number }[]>([]);
-  const [selectedSeries, setSelectedSeries] = useState<number[]>([]);
-  const [seriesVisible, setSeriesVisible] = useState(true);
-  const [selectedSeriesFilter, setSelectedSeriesFilter] = useState(-1);
-  const [selectedCountries, setSelectedCountries] = useState<any[]>([]);
-  const [friendsVisible, setFriendsVisible] = useState(false);
-  const [trustedVisible, setTrustedVisible] = useState(false);
-  const savedFilterSettings = !isPublicView
-    ? (storage.get('filterSettings', StoreType.STRING) as string)
-    : null;
-
-  const [isSharing, setIsSharing] = useState(false);
-  const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
-  const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
-  const [openSettingsBackgroundVisible, setOpenSettingsBackgroundVisible] =
-    useState<boolean>(false);
-  const [countrySelectorVisible, setCountrySelectorVisible] = useState(false);
-  const [countriesForSelector, setCountriesForSelector] = useState<
-    { country: number; name: string; count: number; flag: string | null }[]
-  >([]);
-  const [premiumModalVisible, setPremiumModalVisible] = useState(false);
-  const [toolTipVisible, setToolTipVisible] = useState<boolean>(false);
-  const [defaultYear, setDefaultYear] = useState({
-    label: moment().year().toString(),
-    value: moment().year()
-  });
-
-  useEffect(() => {
-    const syncSettings = async () => {
-      if (locationSettings) {
-        let { status } = await Location.getForegroundPermissionsAsync();
-        const isServicesEnabled = await Location.hasServicesEnabledAsync();
-
-        setIsSharing(locationSettings.sharing !== 0 && status === 'granted' && isServicesEnabled);
+export interface FilterModalRef {
+  openFilter: (type: string) => void;
+  closeFilter: () => void;
+}
+
+const FilterModal = forwardRef<
+  FilterModalRef,
+  {
+    tilesTypes: any[];
+    tilesType: any;
+    setTilesType: (item: any) => void;
+    setType: (type: any) => void;
+    userId: number;
+    setRegionsFilter: (data: { visitedLabel: 'in' | 'by'; year: number }) => void;
+    setSeriesFilter?: (filter: any) => void;
+    setNomadsFilter?: (filter: any) => void;
+    isPublicView: boolean;
+    isLogged: boolean;
+    showNomads?: boolean;
+    setShowNomads?: (showNomads: boolean) => void;
+    usersOnMapCount?: number | null;
+    friendsOnTheMapCount?: number | null;
+    isConnected?: boolean;
+    isPremium?: boolean;
+  }
+>(
+  (
+    {
+      tilesTypes,
+      tilesType,
+      setTilesType,
+      setType,
+      userId,
+      setRegionsFilter,
+      setSeriesFilter,
+      setNomadsFilter,
+      isPublicView,
+      isLogged = true,
+      showNomads,
+      setShowNomads,
+      usersOnMapCount,
+      friendsOnTheMapCount,
+      isConnected = true,
+      isPremium
+    },
+    ref
+  ) => {
+    const [isFilterVisible, setIsFilterVisible] = useState<string | null>(null);
+
+    useImperativeHandle(ref, () => ({
+      openFilter: (type: string) => {
+        setIsFilterVisible(type);
+        setTimeout(() => {
+          bottomSheetRef.current?.show();
+        }, 0);
+      },
+      closeFilter: () => {
+        bottomSheetRef.current?.hide();
       }
-    };
+    }));
+
+    const token = storage.get('token', StoreType.STRING) as string;
+    const { data: locationSettings } = usePostGetSettingsQuery(
+      token,
+      isLogged && !isPublicView && isConnected
+    );
+    const { data: countriesData } = usePostGetListOfCountriesForLocationDataQuery(
+      token,
+      isLogged && !isPublicView && isConnected
+    );
+    const { mutateAsync: setSettings } = usePostSetSettingsMutation();
+    const { mutateAsync: updateLocation } = usePostUpdateLocationMutation();
+    const [selectedYear, setSelectedYear] = useState<{ label: string; value: number } | null>(null);
+    const [allYears, setAllYears] = useState<{ label: string; value: number }[]>([]);
+    const [selectedVisible, setSelectedVisible] = useState({ label: 'visited by', value: 0 });
+    const visibleTypes = [
+      { label: 'visited by', value: 0 },
+      { label: 'visited in', value: 1 }
+    ];
+    const { data } = usePostGetMapYearsQuery(
+      token as string,
+      userId,
+      isLogged && isConnected ? true : false
+    );
+    const { data: seriesList } = useGetListQuery(isConnected ? true : false);
+    const [series, setSeries] = useState<{ label: string; value: number }[]>([]);
+    const [selectedSeries, setSelectedSeries] = useState<number[]>([]);
+    const [seriesVisible, setSeriesVisible] = useState(true);
+    const [selectedSeriesFilter, setSelectedSeriesFilter] = useState(-1);
+    const [selectedCountries, setSelectedCountries] = useState<any[]>([]);
+    const [friendsVisible, setFriendsVisible] = useState(false);
+    const [trustedVisible, setTrustedVisible] = useState(false);
+    const savedFilterSettings = !isPublicView
+      ? (storage.get('filterSettings', StoreType.STRING) as string)
+      : null;
+
+    const [isSharing, setIsSharing] = useState(false);
+    const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
+    const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
+    const [openSettingsBackgroundVisible, setOpenSettingsBackgroundVisible] =
+      useState<boolean>(false);
+    const [countrySelectorVisible, setCountrySelectorVisible] = useState(false);
+    const [countriesForSelector, setCountriesForSelector] = useState<
+      { country: number; name: string; count: number; flag: string | null }[]
+    >([]);
+    const [premiumModalVisible, setPremiumModalVisible] = useState(false);
+    const [toolTipVisible, setToolTipVisible] = useState<boolean>(false);
+    const [defaultYear, setDefaultYear] = useState({
+      label: moment().year().toString(),
+      value: moment().year()
+    });
+
+    const bottomSheetRef = useRef<ActionSheetRef>(null);
+    const insets = useSafeAreaInsets();
+    const windowHeight = Dimensions.get('window').height;
 
-    syncSettings();
-  }, [locationSettings]);
-
-  useEffect(() => {
-    if (countriesData && countriesData.countries) {
-      setCountriesForSelector(countriesData.countries.filter((country: any) => country.count > 0));
-    }
-  }, [countriesData]);
-
-  useEffect(() => {
-    const loadFilterSettings = () => {
-      try {
-        if (savedFilterSettings && isFilterVisible) {
-          const filterSettings = JSON.parse(savedFilterSettings);
-          setTilesType(filterSettings.tilesType);
-          setSelectedYear(filterSettings.selectedYear);
-          setSelectedVisible(filterSettings.selectedVisible);
-          setSelectedSeries(filterSettings.seriesFilter.groups);
-          setSeriesVisible(filterSettings.seriesFilter.visible);
-          setSelectedSeriesFilter(filterSettings.seriesFilter.status);
-          setSelectedCountries(filterSettings.nomadsFilter.countries || []);
-          setFriendsVisible(filterSettings.nomadsFilter.friends === 1);
-          setTrustedVisible(filterSettings.nomadsFilter.trusted === 1);
+    useEffect(() => {
+      const syncSettings = async () => {
+        if (locationSettings) {
+          let { status } = await Location.getForegroundPermissionsAsync();
+          const isServicesEnabled = await Location.hasServicesEnabledAsync();
+
+          setIsSharing(locationSettings.sharing !== 0 && status === 'granted' && isServicesEnabled);
+        }
+      };
+
+      syncSettings();
+    }, [locationSettings]);
+
+    useEffect(() => {
+      if (countriesData && countriesData.countries) {
+        setCountriesForSelector(
+          countriesData.countries.filter((country: any) => country.count > 0)
+        );
+      }
+    }, [countriesData]);
+
+    useEffect(() => {
+      const loadFilterSettings = () => {
+        try {
+          if (savedFilterSettings && isFilterVisible) {
+            const filterSettings = JSON.parse(savedFilterSettings);
+            setTilesType(filterSettings.tilesType);
+            setSelectedYear(filterSettings.selectedYear);
+            setSelectedVisible(filterSettings.selectedVisible);
+            setSelectedSeries(filterSettings.seriesFilter.groups);
+            setSeriesVisible(filterSettings.seriesFilter.visible);
+            setSelectedSeriesFilter(filterSettings.seriesFilter.status);
+            setSelectedCountries(filterSettings.nomadsFilter.countries || []);
+            setFriendsVisible(filterSettings.nomadsFilter.friends === 1);
+            setTrustedVisible(filterSettings.nomadsFilter.trusted === 1);
+          }
+        } catch (error) {
+          console.error('Failed to load filter settings', error);
         }
-      } catch (error) {
-        console.error('Failed to load filter settings', error);
+      };
+
+      if (!isPublicView && isLogged) {
+        loadFilterSettings();
       }
+    }, [savedFilterSettings, isFilterVisible]);
+
+    const handleCountrySelect = (
+      selectedItems: { country: number; name: string; count: number; flag: string | null }[]
+    ) => {
+      if (selectedItems.length > 0) {
+        setShowNomads && setShowNomads(false);
+        storage.set('showNomads', false);
+      }
+      setSelectedCountries(selectedItems);
+      setCountrySelectorVisible(false);
     };
 
-    if (!isPublicView && isLogged) {
-      loadFilterSettings();
-    }
-  }, [savedFilterSettings, isFilterVisible]);
+    const saveFilterSettings = async () => {
+      if (isLogged && !isPublicView) {
+        try {
+          const filterSettings = {
+            type:
+              tilesType.value === 2
+                ? 'dare'
+                : tilesType.value === 1
+                  ? 'countries'
+                  : tilesType.value === -1
+                    ? 'blank'
+                    : 'regions',
+            tilesType,
+            selectedYear,
+            selectedVisible,
+            seriesFilter: {
+              visible: seriesVisible,
+              groups: selectedSeries,
+              applied: true,
+              status: selectedSeriesFilter
+            },
+            nomadsFilter: {
+              friends: friendsVisible ? 1 : 0,
+              trusted: trustedVisible ? 1 : 0,
+              countries: selectedCountries
+            },
+            showNomads: showNomads
+          };
+          storage.set('filterSettings', JSON.stringify(filterSettings));
+        } catch (error) {
+          console.error('Failed to save filter settings', error);
+        }
+      }
+    };
 
-  const handleCountrySelect = (
-    selectedItems: { country: number; name: string; count: number; flag: string | null }[]
-  ) => {
-    if (selectedItems.length > 0) {
-      setShowNomads && setShowNomads(false);
-      storage.set('showNomads', false);
-    }
-    setSelectedCountries(selectedItems);
-    setCountrySelectorVisible(false);
-  };
-
-  const saveFilterSettings = async () => {
-    if (isLogged && !isPublicView) {
-      try {
-        const filterSettings = {
-          type:
-            tilesType.value === 2
-              ? 'dare'
-              : tilesType.value === 1
-                ? 'countries'
-                : tilesType.value === -1
-                  ? 'blank'
-                  : 'regions',
-          tilesType,
-          selectedYear,
-          selectedVisible,
-          seriesFilter: {
-            visible: seriesVisible,
-            groups: selectedSeries,
-            applied: true,
-            status: selectedSeriesFilter
-          },
-          nomadsFilter: {
-            friends: friendsVisible ? 1 : 0,
-            trusted: trustedVisible ? 1 : 0,
-            countries: selectedCountries
-          },
-          showNomads: showNomads
-        };
-        storage.set('filterSettings', JSON.stringify(filterSettings));
-      } catch (error) {
-        console.error('Failed to save filter settings', error);
+    useEffect(() => {
+      if (data && data.data && data.data.map_years) {
+        const years = data.data.map_years.filter((year) => year > 1900);
+        const formattedYears = years
+          .map((year) => ({ label: year.toString(), value: year }))
+          .reverse();
+        setAllYears(formattedYears);
+        formattedYears.length && !savedFilterSettings && setSelectedYear(formattedYears[0]);
+        formattedYears.length && setDefaultYear(formattedYears[0]);
       }
-    }
-  };
-
-  useEffect(() => {
-    if (data && data.data && data.data.map_years) {
-      const years = data.data.map_years.filter((year) => year > 1900);
-      const formattedYears = years
-        .map((year) => ({ label: year.toString(), value: year }))
-        .reverse();
-      setAllYears(formattedYears);
-      formattedYears.length && !savedFilterSettings && setSelectedYear(formattedYears[0]);
-      formattedYears.length && setDefaultYear(formattedYears[0]);
-    }
-  }, [data, savedFilterSettings]);
-
-  useEffect(() => {
-    if (seriesList?.data) {
-      setSeries(
-        seriesList.data.reduce(
-          (acc, item) => {
-            if (item.id < 0) {
-              const alreadyExists = acc.some((i) => i.value === -1);
-              if (alreadyExists) {
+    }, [data, savedFilterSettings]);
+
+    useEffect(() => {
+      if (seriesList?.data) {
+        setSeries(
+          seriesList.data.reduce(
+            (acc, item) => {
+              if (item.id < 0) {
+                const alreadyExists = acc.some((i) => i.value === -1);
+                if (alreadyExists) {
+                  return acc;
+                }
+
+                acc.push({
+                  label: 'Top of the tops',
+                  value: -1,
+                  icon: item.icon
+                });
+
                 return acc;
               }
 
               acc.push({
-                label: 'Top of the tops',
-                value: -1,
+                label: item.name,
+                value: item.id,
                 icon: item.icon
               });
 
               return acc;
-            }
+            },
+            [] as { label: string; value: number; icon: string }[]
+          )
+        );
+        !savedFilterSettings && setSelectedSeries(seriesList.data.map((item) => item.id));
+      }
+    }, [seriesList]);
 
-            acc.push({
-              label: item.name,
-              value: item.id,
-              icon: item.icon
-            });
+    useEffect(() => {
+      if (isFilterVisible && isFilterVisible === 'series') {
+        setSeriesFilter &&
+          setSeriesFilter({
+            visible: seriesVisible,
+            groups: selectedSeries,
+            applied: true,
+            status: selectedSeriesFilter
+          });
+        saveFilterSettings();
+      }
+    }, [selectedSeries, seriesVisible, selectedSeriesFilter]);
 
-            return acc;
-          },
-          [] as { label: string; value: number; icon: string }[]
-        )
-      );
-      !savedFilterSettings && setSelectedSeries(seriesList.data.map((item) => item.id));
-    }
-  }, [seriesList]);
-
-  useEffect(() => {
-    if (isFilterVisible && isFilterVisible === 'series') {
-      setSeriesFilter &&
-        setSeriesFilter({
-          visible: seriesVisible,
-          groups: selectedSeries,
-          applied: true,
-          status: selectedSeriesFilter
-        });
-      saveFilterSettings();
-    }
-  }, [selectedSeries, seriesVisible, selectedSeriesFilter]);
-
-  useEffect(() => {
-    if (isFilterVisible && isFilterVisible === 'nomads') {
-      setNomadsFilter &&
-        setNomadsFilter({
-          friends: friendsVisible ? 1 : 0,
-          trusted: trustedVisible ? 1 : 0,
-          countries: selectedCountries
-        });
-      saveFilterSettings();
-    }
-  }, [friendsVisible, trustedVisible, selectedCountries]);
-
-  useEffect(() => {
-    if (isFilterVisible && isFilterVisible === 'regions') {
-      try {
+    useEffect(() => {
+      if (isFilterVisible && isFilterVisible === 'nomads') {
+        setNomadsFilter &&
+          setNomadsFilter({
+            friends: friendsVisible ? 1 : 0,
+            trusted: trustedVisible ? 1 : 0,
+            countries: selectedCountries
+          });
         saveFilterSettings();
-        handleApplyFilter();
-        setType(
-          tilesType.value === 2
-            ? 'dare'
-            : tilesType.value === 1
-              ? 'countries'
-              : tilesType.value === -1
-                ? 'blank'
-                : 'regions'
-        );
-      } catch (error) {
-        console.error('Error applying filter:', error);
       }
-    }
-  }, [selectedYear, selectedVisible, tilesType]);
-
-  const handleApplyFilter = () => {
-    if (!isLogged) {
-      return;
-    }
-
-    if (selectedVisible.value === 0) {
-      if (tilesType.value === 0 || tilesType.value === 1) {
-        setRegionsFilter({
-          visitedLabel: 'by',
-          year: selectedYear && selectedYear.value ? selectedYear.value : moment().year()
-        });
+    }, [friendsVisible, trustedVisible, selectedCountries]);
+
+    useEffect(() => {
+      if (isFilterVisible && isFilterVisible === 'regions') {
+        try {
+          saveFilterSettings();
+          handleApplyFilter();
+          setType(
+            tilesType.value === 2
+              ? 'dare'
+              : tilesType.value === 1
+                ? 'countries'
+                : tilesType.value === -1
+                  ? 'blank'
+                  : 'regions'
+          );
+        } catch (error) {
+          console.error('Error applying filter:', error);
+        }
       }
-    } else {
-      if (tilesType.value === 0 || tilesType.value === 1) {
-        setRegionsFilter({
-          visitedLabel: 'in',
-          year: selectedYear && selectedYear.value ? selectedYear.value : moment().year()
-        });
+    }, [selectedYear, selectedVisible, tilesType]);
+
+    const handleApplyFilter = () => {
+      if (!isLogged) {
+        return;
       }
-    }
-  };
 
-  const handleCloseFilter = () => {
-    setIsFilterVisible(null);
-  };
+      if (selectedVisible.value === 0) {
+        if (tilesType.value === 0 || tilesType.value === 1) {
+          setRegionsFilter({
+            visitedLabel: 'by',
+            year: selectedYear && selectedYear.value ? selectedYear.value : moment().year()
+          });
+        }
+      } else {
+        if (tilesType.value === 0 || tilesType.value === 1) {
+          setRegionsFilter({
+            visitedLabel: 'in',
+            year: selectedYear && selectedYear.value ? selectedYear.value : moment().year()
+          });
+        }
+      }
+    };
 
-  const renderRegions = () => {
-    return (
-      <View style={styles.sceneContainer}>
-        <View style={styles.optionsContainer}>
-          <View style={styles.rowWrapper}>
-            <View style={[styles.dropdownWrapper, {}]}>
-              <Dropdown
-                style={[ModalStyles.dropdown, { width: '100%' }]}
-                placeholderStyle={ModalStyles.placeholderStyle}
-                selectedTextStyle={ModalStyles.selectedTextStyle}
-                containerStyle={ModalStyles.dropdownContent}
-                data={tilesTypes}
-                labelField="label"
-                valueField="value"
-                value={tilesType?.label}
-                placeholder={tilesType?.label}
-                onChange={(item) => {
-                  setTilesType(item);
-                }}
-              />
-            </View>
-          </View>
+    const handleCloseFilter = () => { };
 
-          {tilesType.value !== 2 && tilesType.value !== -1 && allYears.length && isLogged ? (
-            <View style={styles.rowWrapper}>
-              <View style={styles.dropdownWrapper}>
-                <Dropdown
-                  style={[ModalStyles.dropdown, { width: '100%' }]}
-                  placeholderStyle={ModalStyles.placeholderStyle}
-                  selectedTextStyle={ModalStyles.selectedTextStyle}
-                  containerStyle={ModalStyles.dropdownContent}
-                  data={visibleTypes}
-                  labelField="label"
-                  valueField="value"
-                  value={selectedVisible?.label}
-                  placeholder={selectedVisible?.label}
-                  onChange={(item) => {
-                    setSelectedVisible(item);
-                  }}
-                />
-              </View>
-              <View style={styles.dropdownWrapper}>
-                <Dropdown
-                  style={[ModalStyles.dropdown, { width: '100%' }]}
-                  placeholderStyle={ModalStyles.placeholderStyle}
-                  selectedTextStyle={ModalStyles.selectedTextStyle}
-                  containerStyle={ModalStyles.dropdownContent}
-                  data={allYears}
+    const renderRegions = () => {
+      return (
+        <View style={{ minHeight: 200, justifyContent: 'space-between' }}>
+          <View style={styles.optionsContainer}>
+            <View style={[styles.rowWrapper, {}]}>
+              <View style={[styles.dropdownWrapper, {}]}>
+                <SelectSheet
+                  style={[ModalStyles.dropdown, { width: '100%' }] as any}
+                  data={tilesTypes}
                   labelField="label"
                   valueField="value"
-                  value={selectedYear?.label}
-                  placeholder={selectedYear?.label}
-                  dropdownPosition="top"
+                  value={tilesType?.value}
+                  placeholder={tilesType?.label || 'NM regions'}
                   onChange={(item) => {
-                    setSelectedYear(item);
+                    setTilesType(item);
                   }}
+                  hideTitle={true}
+                  initialSnapPoint={45}
                 />
               </View>
             </View>
-          ) : null}
-        </View>
 
-        <Button
-          children="Reset"
-          onPress={() => {
-            setTilesType({ label: 'NM regions', value: 0 });
-            setSelectedVisible({
-              label: 'visited by',
-              value: 0
-            });
-            setSelectedYear(defaultYear);
-          }}
-          variant={ButtonVariants.OPACITY}
-          containerStyles={{
-            backgroundColor: Colors.WHITE,
-            borderWidth: 1,
-            borderColor: Colors.DARK_BLUE
-          }}
-          textStyles={{ color: Colors.DARK_BLUE }}
-        />
-      </View>
-    );
-  };
+            {tilesType.value !== 2 && tilesType.value !== -1 && allYears.length && isLogged ? (
+              <View style={styles.rowWrapper}>
+                <View style={styles.dropdownWrapper}>
+                  <SelectSheet
+                    style={[ModalStyles.dropdown, { width: '100%' }] as any}
+                    data={visibleTypes}
+                    labelField="label"
+                    valueField="value"
+                    value={selectedVisible?.value}
+                    placeholder={selectedVisible?.label || 'visited by'}
+                    onChange={(item) => {
+                      setSelectedVisible(item);
+                    }}
+                    hideTitle={true}
+                    initialSnapPoint={35}
+                  />
+                </View>
+                <View style={styles.dropdownWrapper}>
+                  <SelectSheet
+                    style={[ModalStyles.dropdown, { width: '100%' }] as any}
+                    data={allYears}
+                    labelField="label"
+                    valueField="value"
+                    value={selectedYear?.value}
+                    placeholder={selectedYear?.label || 'Year'}
+                    onChange={(item) => {
+                      setSelectedYear(item);
+                    }}
+                    hideTitle={true}
+                  />
+                </View>
+              </View>
+            ) : null}
+          </View>
 
-  const renderSeries = () => {
-    return (
-      <View style={styles.sceneContainer}>
-        <View style={styles.optionsContainer}>
-          <View style={[styles.row, { gap: 8 }]}>
-            <Switch
-              trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
-              thumbColor={Colors.WHITE}
-              onValueChange={setSeriesVisible}
-              value={seriesVisible}
-              style={{ transform: 'scale(0.8)' }}
+          <View style={{ marginTop: 'auto', marginBottom: 24 }}>
+            <Button
+              children="Reset"
+              onPress={() => {
+                setTilesType({ label: 'NM regions', value: 0 });
+                setSelectedVisible({
+                  label: 'visited by',
+                  value: 0
+                });
+                setSelectedYear(defaultYear);
+              }}
+              variant={ButtonVariants.OPACITY}
+              containerStyles={{
+                backgroundColor: Colors.WHITE,
+                borderWidth: 1,
+                borderColor: Colors.DARK_BLUE
+              }}
+              textStyles={{ color: Colors.DARK_BLUE }}
             />
-            <Text style={styles.textBold}>Show series</Text>
           </View>
+        </View>
+      );
+    };
 
-          {isLogged ? (
-            <View style={[styles.row, { justifyContent: 'space-between' }]}>
-              <TouchableOpacity style={styles.row} onPress={() => setSelectedSeriesFilter(-1)}>
-                <RadioButton.Android
-                  value="all"
-                  status={selectedSeriesFilter === -1 ? 'checked' : 'unchecked'}
-                  onPress={() => setSelectedSeriesFilter(-1)}
-                  color={Colors.DARK_BLUE}
-                />
-                <Text style={styles.textBold}>All items</Text>
-              </TouchableOpacity>
+    const renderSeries = () => {
+      const selectedCount = selectedSeries.length;
 
-              <TouchableOpacity style={styles.row} onPress={() => setSelectedSeriesFilter(1)}>
-                <RadioButton.Android
-                  value="visited"
-                  status={selectedSeriesFilter === 1 ? 'checked' : 'unchecked'}
-                  onPress={() => setSelectedSeriesFilter(1)}
-                  color={Colors.DARK_BLUE}
-                />
-                <Text style={styles.textBold}>Visited</Text>
+      return (
+        <View style={[styles.seriesSheetContainer]}>
+          <View style={[styles.optionsContainer, { paddingHorizontal: 16 }]}>
+            <View style={[styles.row, { gap: 8 }]}>
+              <Switch
+                trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
+                thumbColor={Colors.WHITE}
+                onValueChange={setSeriesVisible}
+                value={seriesVisible}
+                style={{ transform: 'scale(0.8)' }}
+              />
+              <Text style={styles.textBold}>Show series</Text>
+            </View>
+
+            {isLogged ? (
+              <View style={[styles.row, { justifyContent: 'space-between' }]}>
+                <TouchableOpacity style={styles.row} onPress={() => setSelectedSeriesFilter(-1)}>
+                  <RadioButton.Android
+                    value="all"
+                    status={selectedSeriesFilter === -1 ? 'checked' : 'unchecked'}
+                    onPress={() => setSelectedSeriesFilter(-1)}
+                    color={Colors.DARK_BLUE}
+                  />
+                  <Text style={styles.textBold}>All items</Text>
+                </TouchableOpacity>
+
+                <TouchableOpacity style={styles.row} onPress={() => setSelectedSeriesFilter(1)}>
+                  <RadioButton.Android
+                    value="visited"
+                    status={selectedSeriesFilter === 1 ? 'checked' : 'unchecked'}
+                    onPress={() => setSelectedSeriesFilter(1)}
+                    color={Colors.DARK_BLUE}
+                  />
+                  <Text style={styles.textBold}>Visited</Text>
+                </TouchableOpacity>
+
+                <TouchableOpacity style={styles.row} onPress={() => setSelectedSeriesFilter(0)}>
+                  <RadioButton.Android
+                    value="not-visited"
+                    status={selectedSeriesFilter === 0 ? 'checked' : 'unchecked'}
+                    onPress={() => setSelectedSeriesFilter(0)}
+                    color={Colors.DARK_BLUE}
+                  />
+                  <Text style={styles.textBold}>Not visited</Text>
+                </TouchableOpacity>
+              </View>
+            ) : null}
+
+            <View style={styles.seriesHeader}>
+              <Text style={styles.textBold}>Select series ({selectedCount} selected)</Text>
+            </View>
+
+            <View style={styles.seriesActions}>
+              <TouchableOpacity
+                style={styles.seriesActionBtn}
+                onPress={() => setSelectedSeries(series.map((item) => item.value))}
+              >
+                {/* <CheckSvg fill={Colors.DARK_BLUE} height={8} width={10} /> */}
+                <Text style={styles.seriesActionBtnText}>Select all</Text>
               </TouchableOpacity>
 
-              <TouchableOpacity style={styles.row} onPress={() => setSelectedSeriesFilter(0)}>
-                <RadioButton.Android
-                  value="not-visited"
-                  status={selectedSeriesFilter === 0 ? 'checked' : 'unchecked'}
-                  onPress={() => setSelectedSeriesFilter(0)}
-                  color={Colors.DARK_BLUE}
-                />
-                <Text style={styles.textBold}>Not visited</Text>
+              <TouchableOpacity
+                style={styles.seriesActionBtn}
+                onPress={() => setSelectedSeries([])}
+              >
+                {/* <CheckSvg fill={Colors.DARK_BLUE} height={8} width={10} /> */}
+                <Text style={styles.seriesActionBtnText}>Select none</Text>
               </TouchableOpacity>
             </View>
-          ) : null}
-
-          <MultiSelect
-            style={[ModalStyles.dropdown, { width: '100%' }]}
-            placeholderStyle={[ModalStyles.placeholderStyle]}
-            selectedTextStyle={ModalStyles.selectedTextStyle}
-            containerStyle={[ModalStyles.dropdownContent, {}]}
-            data={[
-              { label: 'Select all', value: 'all' },
-              { label: 'Select none', value: 'none' },
-              ...series
-            ]}
-            labelField="label"
-            valueField="value"
-            value={selectedSeries}
-            placeholder="Select series"
-            dropdownPosition="top"
-            activeColor="#E7E7E7"
-            search={true}
-            searchPlaceholder="Search"
-            inputSearchStyle={ModalStyles.search}
-            searchQuery={(keyword, item) =>
-              item.toLowerCase().includes(keyword.toLowerCase()) &&
-              item !== 'Select all' &&
-              item !== 'Select none'
-            }
-            flatListProps={{ initialNumToRender: 30, maxToRenderPerBatch: 10 }}
-            onChange={(item) => {
-              if (item.includes('all')) {
-                setSelectedSeries(series.map((item) => item.value));
-              } else if (item.includes('none')) {
-                setSelectedSeries([]);
-              } else {
-                setSelectedSeries(item);
-              }
-            }}
-            renderItem={(item) => (
-              <View style={styles.multiOption}>
-                <View style={[styles.row, { gap: 8, flex: 1 }]}>
-                  <Image source={{ uri: API_HOST + item.icon }} width={20} height={20} />
-                  <Text style={styles.optionText}>{item.label}</Text>
-                </View>
+          </View>
 
-                {selectedSeries.includes(item.value) && (
-                  <CheckSvg fill={Colors.DARK_BLUE} height={8} />
-                )}
-              </View>
-            )}
-            renderSelectedItem={(item, unSelect) => {
-              return null;
-            }}
-          />
+          <ScrollView style={{ flex: 1 }} contentContainerStyle={styles.seriesPillsContainer}>
+            {series.map((item) => {
+              const isSelected = selectedSeries.includes(item.value);
+              return (
+                <TouchableOpacity
+                  key={item.value}
+                  style={[
+                    styles.seriesPill,
+                    isSelected ? styles.seriesPillSelected : styles.seriesPillUnselected
+                  ]}
+                  onPress={() => {
+                    if (isSelected) {
+                      setSelectedSeries(selectedSeries.filter((v) => v !== item.value));
+                    } else {
+                      setSelectedSeries([...selectedSeries, item.value]);
+                    }
+                  }}
+                  activeOpacity={0.75}
+                >
+                  {(item as any).icon ? (
+                    <Image
+                      source={{ uri: API_HOST + (item as any).icon }}
+                      style={{
+                        width: 18,
+                        height: 18,
+                        tintColor: isSelected ? Colors.WHITE : Colors.DARK_BLUE
+                      }}
+                    />
+                  ) : null}
+                  <Text
+                    style={[
+                      styles.seriesPillText,
+                      isSelected ? styles.seriesPillTextSelected : styles.seriesPillTextUnselected
+                    ]}
+                  >
+                    {item.label}
+                  </Text>
+                </TouchableOpacity>
+              );
+            })}
+          </ScrollView>
+
+          <View
+            style={{ marginTop: 'auto', marginBottom: insets.bottom || 24, paddingHorizontal: 16 }}
+          >
+            <Button
+              children="Reset"
+              onPress={() => {
+                setSeriesVisible(true);
+                setSelectedSeries(series.map((item) => item.value));
+                setSelectedSeriesFilter(-1);
+              }}
+              variant={ButtonVariants.OPACITY}
+              containerStyles={{
+                backgroundColor: Colors.WHITE,
+                borderWidth: 1,
+                borderColor: Colors.DARK_BLUE,
+                marginTop: 8
+              }}
+              textStyles={{ color: Colors.DARK_BLUE }}
+            />
+          </View>
         </View>
+      );
+    };
 
-        <Button
-          children="Reset"
-          onPress={() => {
-            setSeriesVisible(true);
-            setSelectedSeries(series.map((item) => item.value));
-            setSelectedSeriesFilter(-1);
-          }}
-          variant={ButtonVariants.OPACITY}
-          containerStyles={{
-            backgroundColor: Colors.WHITE,
-            borderWidth: 1,
-            borderColor: Colors.DARK_BLUE
-          }}
-          textStyles={{ color: Colors.DARK_BLUE }}
-        />
-      </View>
-    );
-  };
-
-  const toggleSettingsSwitch = async () => {
-    if (!isSharing) {
-      handleGetLocation();
-    } else {
-      setIsSharing(false);
-      setSettings({ token, sharing: 0 });
+    const toggleSettingsSwitch = async () => {
+      if (!isSharing) {
+        handleGetLocation();
+      } else {
+        setIsSharing(false);
+        setSettings({ token, sharing: 0 });
+        setShowNomads && setShowNomads(false);
+        storage.set('showNomads', false);
+        setTrustedVisible(false);
+        setFriendsVisible(false);
+        setSelectedCountries([]);
+      }
+    };
+
+    const toggleTrustedSwitch = async () => {
+      if (!isPremium) {
+        setPremiumModalVisible(true);
+        return;
+      }
+      setShowNomads && setShowNomads(false);
+      storage.set('showNomads', false);
+      setTrustedVisible(!trustedVisible);
+    };
+
+    const toggleFriendsSwitch = async () => {
+      if (!isPremium) {
+        setPremiumModalVisible(true);
+        return;
+      }
       setShowNomads && setShowNomads(false);
       storage.set('showNomads', false);
-      setTrustedVisible(false);
-      setFriendsVisible(false);
-      setSelectedCountries([]);
-    }
-  };
-
-  const toggleTrustedSwitch = async () => {
-    if (!isPremium) {
-      setPremiumModalVisible(true);
-      return;
-    }
-    setShowNomads && setShowNomads(false);
-    storage.set('showNomads', false);
-    setTrustedVisible(!trustedVisible);
-  };
-
-  const toggleFriendsSwitch = async () => {
-    if (!isPremium) {
-      setPremiumModalVisible(true);
-      return;
-    }
-    setShowNomads && setShowNomads(false);
-    storage.set('showNomads', false);
-    setFriendsVisible(!friendsVisible);
-  };
-
-  const requestBackgroundPermissionSafe = async () => {
-    await new Promise((resolve) => setTimeout(resolve, 300));
-    return await Location.requestBackgroundPermissionsAsync();
-  };
-
-  const handleGetLocation = async () => {
-    let { status, canAskAgain } = await Location.getForegroundPermissionsAsync();
-    const isServicesEnabled = await Location.hasServicesEnabledAsync();
-
-    if (status === 'granted' && isServicesEnabled) {
-      const bgStatus = await Location.getBackgroundPermissionsAsync();
-      if (bgStatus.status !== 'granted') {
-        // const { status } = await requestBackgroundPermissionSafe();
-        // if (status === Location.PermissionStatus.GRANTED) {
-        //   await startBackgroundLocationUpdates();
-        // } else {
-        await stopBackgroundLocationUpdates();
-        // setOpenSettingsBackgroundVisible(true);
-        // }
+      setFriendsVisible(!friendsVisible);
+    };
+
+    const requestBackgroundPermissionSafe = async () => {
+      await new Promise((resolve) => setTimeout(resolve, 300));
+      return await Location.requestBackgroundPermissionsAsync();
+    };
+
+    const handleGetLocation = async () => {
+      let { status, canAskAgain } = await Location.getForegroundPermissionsAsync();
+      const isServicesEnabled = await Location.hasServicesEnabledAsync();
+
+      if (status === 'granted' && isServicesEnabled) {
+        const bgStatus = await Location.getBackgroundPermissionsAsync();
+        if (bgStatus.status !== 'granted') {
+          // const { status } = await requestBackgroundPermissionSafe();
+          // if (status === Location.PermissionStatus.GRANTED) {
+          //   await startBackgroundLocationUpdates();
+          // } else {
+          await stopBackgroundLocationUpdates();
+          // setOpenSettingsBackgroundVisible(true);
+          // }
+        } else {
+          // await startBackgroundLocationUpdates();
+        }
+
+        getLocation();
+      } else if (!canAskAgain || !isServicesEnabled) {
+        setOpenSettingsVisible(true);
       } else {
-        // await startBackgroundLocationUpdates();
+        setAskLocationVisible(true);
       }
+    };
 
-      getLocation();
-    } else if (!canAskAgain || !isServicesEnabled) {
-      setOpenSettingsVisible(true);
-    } else {
-      setAskLocationVisible(true);
-    }
-  };
-
-  const getLocation = async () => {
-    setIsSharing(true);
-    setSettings(
-      { token, sharing: 1 },
-      {
-        onSuccess: async () => {
-          let currentLocation = await Location.getCurrentPositionAsync({
-            accuracy: Location.Accuracy.Balanced
-          });
+    const getLocation = async () => {
+      setIsSharing(true);
+      setSettings(
+        { token, sharing: 1 },
+        {
+          onSuccess: async () => {
+            let currentLocation = await Location.getCurrentPositionAsync({
+              accuracy: Location.Accuracy.Balanced
+            });
 
-          updateLocation({
-            token,
-            lat: currentLocation.coords.latitude,
-            lng: currentLocation.coords.longitude
-          });
+            updateLocation({
+              token,
+              lat: currentLocation.coords.latitude,
+              lng: currentLocation.coords.longitude
+            });
+          }
         }
+      );
+      setShowNomads && setShowNomads(true);
+      storage.set('showNomads', true);
+    };
+
+    const handleAcceptPermission = async () => {
+      setAskLocationVisible(false);
+      let { status, canAskAgain } = await Location.requestForegroundPermissionsAsync();
+      const isServicesEnabled = await Location.hasServicesEnabledAsync();
+
+      if (status === 'granted' && isServicesEnabled) {
+        const bgStatus = await Location.getBackgroundPermissionsAsync();
+
+        if (bgStatus.status !== 'granted') {
+          // const { status } = await requestBackgroundPermissionSafe();
+          // if (status === Location.PermissionStatus.GRANTED) {
+          //   await startBackgroundLocationUpdates();
+          // } else {
+          await stopBackgroundLocationUpdates();
+          // setOpenSettingsBackgroundVisible(true);
+          // }
+        } else {
+          // await startBackgroundLocationUpdates();
+        }
+        getLocation();
+      } else if (!canAskAgain || !isServicesEnabled) {
+        setOpenSettingsVisible(true);
       }
-    );
-    setShowNomads && setShowNomads(true);
-    storage.set('showNomads', true);
-  };
-
-  const handleAcceptPermission = async () => {
-    setAskLocationVisible(false);
-    let { status, canAskAgain } = await Location.requestForegroundPermissionsAsync();
-    const isServicesEnabled = await Location.hasServicesEnabledAsync();
-
-    if (status === 'granted' && isServicesEnabled) {
-      const bgStatus = await Location.getBackgroundPermissionsAsync();
-
-      if (bgStatus.status !== 'granted') {
-        // const { status } = await requestBackgroundPermissionSafe();
-        // if (status === Location.PermissionStatus.GRANTED) {
-        //   await startBackgroundLocationUpdates();
-        // } else {
-        await stopBackgroundLocationUpdates();
-        // setOpenSettingsBackgroundVisible(true);
-        // }
-      } else {
-        // await startBackgroundLocationUpdates();
+    };
+
+    const toggleNomadsSwitch = () => {
+      if (!showNomads) {
+        setFriendsVisible(false);
+        setSelectedCountries([]);
       }
-      getLocation();
-    } else if (!canAskAgain || !isServicesEnabled) {
-      setOpenSettingsVisible(true);
-    }
-  };
-
-  const toggleNomadsSwitch = () => {
-    if (!showNomads) {
-      setFriendsVisible(false);
-      setSelectedCountries([]);
-    }
-    setShowNomads && setShowNomads(!showNomads);
-    storage.set('showNomads', !showNomads);
-  };
-
-  const renderNomads = () => {
-    return (
-      <View style={[styles.sceneContainer]}>
-        <View style={{ marginBottom: 16 }}>
-          <View style={styles.textContainer}>
-            <Text style={styles.text}>The location is shared with 1 km radius precision.</Text>
-            <Tooltip
-              isVisible={toolTipVisible}
-              content={
-                <View style={{ gap: 6 }}>
-                  <Text style={[styles.text, styles.boldText]}>
-                    At NomadMania, we respect your privacy.
-                  </Text>
-                  <Text style={[styles.text]}>
-                    If you choose to share your location, it will be used to show your current
-                    location to other users who also share theirs.
-                  </Text>
-                  <Text style={[styles.text]}>
-                    You can choose how you want to share your location:
-                  </Text>
-                  <View style={[styles.bulletItem]}>
-                    <Text style={styles.bulletIcon}>{'\u2022'}</Text>
-                    <Text style={[styles.text, { flex: 1 }]}>
-                      <Text style={styles.boldText}>Only when the app is open</Text> – Your location
-                      updates only when you open the app. This uses less battery but may be less
-                      accurate.
+      setShowNomads && setShowNomads(!showNomads);
+      storage.set('showNomads', !showNomads);
+    };
+
+    const renderNomads = () => {
+      return (
+        <View style={[styles.sceneContainer, { justifyContent: 'space-between' }]}>
+          <View style={{ marginBottom: 16 }}>
+            <View style={styles.textContainer}>
+              <Text style={styles.text}>The location is shared with 1 km radius precision.</Text>
+              <Tooltip
+                isVisible={toolTipVisible}
+                content={
+                  <View style={{ gap: 6 }}>
+                    <Text style={[styles.text, styles.boldText]}>
+                      At NomadMania, we respect your privacy.
                     </Text>
-                  </View>
-                  {/* <View style={styles.bulletItem}>
-                    <Text style={styles.bulletIcon}>{'\u2022'}</Text>
-                    <Text style={[styles.text, { flex: 1 }]}>
-                      <Text style={styles.boldText}>In the background</Text> – Your location stays
-                      up to date even when the app is closed. Other users see your latest location.
+                    <Text style={[styles.text]}>
+                      If you choose to share your location, it will be used to show your current
+                      location to other users who also share theirs.
                     </Text>
-                  </View> */}
-                  <Text style={[styles.text]}>
-                    You’re always in control, and you can change these settings anytime in the app{' '}
-                    <Text
-                      style={{ color: Colors.ORANGE }}
-                      onPress={() =>
-                        Platform.OS === 'ios'
-                          ? Linking.openURL('app-settings:')
-                          : Linking.openSettings()
-                      }
-                    >
-                      Settings
-                    </Text>{' '}
-                    section.
-                  </Text>
-                </View>
-              }
-              contentStyle={{ backgroundColor: Colors.WHITE }}
-              placement="top"
-              onClose={() => setToolTipVisible(false)}
-              backgroundColor="transparent"
-              allowChildInteraction={false}
+                    <Text style={[styles.text]}>
+                      You can choose how you want to share your location:
+                    </Text>
+                    <View style={[styles.bulletItem]}>
+                      <Text style={styles.bulletIcon}>{'\u2022'}</Text>
+                      <Text style={[styles.text, { flex: 1 }]}>
+                        <Text style={styles.boldText}>Only when the app is open</Text> – Your
+                        location updates only when you open the app. This uses less battery but may
+                        be less accurate.
+                      </Text>
+                    </View>
+                    <Text style={[styles.text]}>
+                      You're always in control, and you can change these settings anytime in the app{' '}
+                      <Text
+                        style={{ color: Colors.ORANGE }}
+                        onPress={() =>
+                          Platform.OS === 'ios'
+                            ? Linking.openURL('app-settings:')
+                            : Linking.sendIntent('android.settings.LOCATION_SOURCE_SETTINGS')
+                        }
+                      >
+                        Settings
+                      </Text>{' '}
+                      section.
+                    </Text>
+                  </View>
+                }
+                contentStyle={{ backgroundColor: Colors.WHITE }}
+                placement="top"
+                onClose={() => setToolTipVisible(false)}
+                backgroundColor="transparent"
+                allowChildInteraction={false}
+              >
+                <TouchableOpacity
+                  style={{ paddingHorizontal: 5 }}
+                  onPress={() => setToolTipVisible(true)}
+                  hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
+                >
+                  <InfoIcon fill={Colors.DARK_BLUE} width={20} height={20} />
+                </TouchableOpacity>
+              </Tooltip>
+            </View>
+
+            <TouchableOpacity
+              style={[
+                styles.alignStyle,
+                styles.buttonWrapper,
+                {
+                  justifyContent: 'space-between'
+                }
+              ]}
+              onPress={toggleSettingsSwitch}
             >
-              <TouchableOpacity
-                style={{ paddingHorizontal: 5 }}
-                onPress={() => setToolTipVisible(true)}
-                hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
+              <View style={styles.alignStyle}>
+                <SharingIcon fill={Colors.DARK_BLUE} width={20} height={20} />
+                <Text style={styles.buttonLabel}>Share my location to see others</Text>
+              </View>
+              <View>
+                <Switch
+                  trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
+                  thumbColor={Colors.WHITE}
+                  onValueChange={toggleSettingsSwitch}
+                  value={isSharing}
+                  style={{ transform: 'scale(0.8)' }}
+                />
+              </View>
+            </TouchableOpacity>
+
+            <TouchableOpacity
+              style={[
+                styles.alignStyle,
+                styles.buttonWrapper,
+                {
+                  justifyContent: 'space-between'
+                }
+              ]}
+              onPress={toggleNomadsSwitch}
+              disabled={!isSharing}
+            >
+              <View style={styles.alignStyle}>
+                <UsersIcon
+                  fill={isSharing ? Colors.DARK_BLUE : Colors.LIGHT_GRAY}
+                  width={20}
+                  height={20}
+                />
+                <Text style={[styles.buttonLabel, !isSharing ? { color: Colors.LIGHT_GRAY } : {}]}>
+                  Show all Nomads - {usersOnMapCount ? formatNumber(usersOnMapCount) : null} online
+                </Text>
+              </View>
+              <View>
+                <Switch
+                  trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
+                  thumbColor={Colors.WHITE}
+                  onValueChange={toggleNomadsSwitch}
+                  value={showNomads}
+                  style={{ transform: 'scale(0.8)' }}
+                  disabled={!isSharing}
+                />
+              </View>
+            </TouchableOpacity>
+
+            <View style={styles.divider} />
+
+            <TouchableOpacity
+              style={[
+                styles.alignStyle,
+                styles.buttonWrapper,
+                {
+                  justifyContent: 'space-between'
+                }
+              ]}
+              onPress={toggleFriendsSwitch}
+              disabled={!isSharing}
+            >
+              <View style={styles.alignStyle}>
+                <FriendsIcon
+                  fill={isSharing ? Colors.DARK_BLUE : Colors.LIGHT_GRAY}
+                  width={20}
+                  height={18}
+                />
+                <Text style={[styles.buttonLabel, !isSharing ? { color: Colors.LIGHT_GRAY } : {}]}>
+                  Show my friends -{' '}
+                  {friendsOnTheMapCount ? formatNumber(friendsOnTheMapCount) : null} online
+                </Text>
+              </View>
+              <View>
+                <Switch
+                  trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
+                  thumbColor={Colors.WHITE}
+                  onValueChange={toggleFriendsSwitch}
+                  value={friendsVisible}
+                  style={{ transform: 'scale(0.8)' }}
+                  disabled={!isSharing}
+                />
+              </View>
+            </TouchableOpacity>
+
+            <TouchableOpacity
+              style={styles.megaSelector}
+              onPress={() => {
+                if (!isPremium) {
+                  setPremiumModalVisible(true);
+                  return;
+                }
+                setCountrySelectorVisible(true);
+              }}
+              disabled={!isSharing}
+            >
+              <Text style={styles.megaButtonText}>Show Nomads from (select a country)</Text>
+              <ChevronIcon width={18} height={18} />
+            </TouchableOpacity>
+
+            {selectedCountries.length > 0 && (
+              <View
+                style={{
+                  flexDirection: 'row',
+                  alignItems: 'center',
+                  flexWrap: 'wrap',
+                  marginLeft: 12,
+                  gap: 6,
+                  marginVertical: 8
+                }}
               >
-                <InfoIcon fill={Colors.DARK_BLUE} width={20} height={20} />
-              </TouchableOpacity>
-            </Tooltip>
+                {selectedCountries.map((item) => (
+                  <View
+                    key={item.country}
+                    style={{
+                      marginLeft: -12
+                    }}
+                  >
+                    <Image
+                      source={{ uri: API_HOST + item.flag }}
+                      style={{
+                        width: 28,
+                        height: 28,
+                        borderRadius: 14,
+                        borderWidth: 0.5,
+                        borderColor: Colors.BORDER_LIGHT
+                      }}
+                    />
+                  </View>
+                ))}
+              </View>
+            )}
           </View>
 
-          <TouchableOpacity
-            style={[
-              styles.alignStyle,
-              styles.buttonWrapper,
-              {
-                justifyContent: 'space-between'
-              }
-            ]}
-            onPress={toggleSettingsSwitch}
-          >
-            <View style={styles.alignStyle}>
-              <SharingIcon fill={Colors.DARK_BLUE} width={20} height={20} />
-              <Text style={styles.buttonLabel}>Share my location to see others</Text>
-            </View>
-            <View>
-              <Switch
-                trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
-                thumbColor={Colors.WHITE}
-                onValueChange={toggleSettingsSwitch}
-                value={isSharing}
-                style={{ transform: 'scale(0.8)' }}
-              />
-            </View>
-          </TouchableOpacity>
-
-          <TouchableOpacity
-            style={[
-              styles.alignStyle,
-              styles.buttonWrapper,
-              {
-                justifyContent: 'space-between'
+          <View style={{ marginTop: 'auto', marginBottom: 24 }}>
+            <Button
+              children="Reset"
+              onPress={() => {
+                if (isSharing) {
+                  setFriendsVisible(false);
+                  setShowNomads && setShowNomads(true);
+                  storage.set('showNomads', true);
+                  setSelectedCountries([]);
+                } else {
+                  handleGetLocation();
+                }
+              }}
+              variant={ButtonVariants.OPACITY}
+              containerStyles={{
+                backgroundColor: Colors.WHITE,
+                borderWidth: 1,
+                borderColor: Colors.DARK_BLUE
+              }}
+              textStyles={{ color: Colors.DARK_BLUE }}
+            />
+          </View>
+
+          <MultiSelectorCountries
+            isVisible={countrySelectorVisible}
+            onClose={() => setCountrySelectorVisible(false)}
+            onSelect={handleCountrySelect}
+            data={countriesForSelector ?? []}
+            initialSelectedIds={selectedCountries.map((item) => parseInt(item.country))}
+          />
+
+          <WarningModal
+            type={'success'}
+            isVisible={premiumModalVisible}
+            message={
+              'This feature is available to Premium users. Premium account settings can be managed on our website.'
+            }
+            action={() => { }}
+            onClose={() => setPremiumModalVisible(false)}
+            title={'Premium Feature'}
+          />
+
+          <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."
+          />
+          <WarningModal
+            type={'success'}
+            isVisible={openSettingsVisible || openSettingsBackgroundVisible}
+            onClose={() => {
+              setOpenSettingsVisible(false);
+              setOpenSettingsBackgroundVisible(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();
               }
-            ]}
-            onPress={toggleNomadsSwitch}
-            disabled={!isSharing}
-          >
-            <View style={styles.alignStyle}>
-              <UsersIcon
-                fill={isSharing ? Colors.DARK_BLUE : Colors.LIGHT_GRAY}
-                width={20}
-                height={20}
-              />
-              <Text style={[styles.buttonLabel, !isSharing ? { color: Colors.LIGHT_GRAY } : {}]}>
-                Show all Nomads - {usersOnMapCount ? formatNumber(usersOnMapCount) : null} online
-              </Text>
-            </View>
-            <View>
-              <Switch
-                trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
-                thumbColor={Colors.WHITE}
-                onValueChange={toggleNomadsSwitch}
-                value={showNomads}
-                style={{ transform: 'scale(0.8)' }}
-                disabled={!isSharing}
-              />
-            </View>
-          </TouchableOpacity>
-
-          <View style={styles.divider} />
-
-          {/* <View style={{ flexDirection: 'row', alignItems: 'center', marginVertical: 12 }}>
-          <View style={styles.divider} />
-          <Text
-            style={{
-              color: Colors.DARK_BLUE,
-              fontSize: getFontSize(12),
-              fontWeight: '500',
-              paddingHorizontal: 4
             }}
-          >
-            Premium Features
-          </Text>
-          <View style={styles.divider} />
-        </View> */}
+            message={
+              openSettingsBackgroundVisible
+                ? "NomadMania app needs background location access to update your location automatically. Please select 'Always' in location permissions. Open settings?"
+                : 'NomadMania app needs location permissions to function properly. Open settings?'
+            }
+          />
+        </View>
+      );
+    };
 
-          {/* <TouchableOpacity
+    const renderScene = (filterKey: string | null) => {
+      switch (filterKey) {
+        case 'regions':
+          return renderRegions();
+        case 'series':
+          return renderSeries();
+        case 'nomads':
+          return renderNomads();
+        default:
+          return null;
+      }
+    };
+
+    const isSeriesFilter = isFilterVisible === 'series';
+    const sheetSnapPoints = useMemo(() => [100], []);
+
+    return (
+      <ActionSheet
+        key={isSeriesFilter ? 'series-sheet' : 'default-sheet'}
+        ref={bottomSheetRef}
+        snapPoints={sheetSnapPoints}
+        gestureEnabled
+        closeOnTouchBackdrop
+        defaultOverlayOpacity={0.2}
+        onClose={handleCloseFilter}
+        containerStyle={[styles.sheetBackground, isSeriesFilter ? { height: '100%' } : {}]}
+      >
+        <View
           style={[
-            styles.alignStyle,
-            styles.buttonWrapper,
             {
-              justifyContent: 'space-between'
-            }
+              paddingTop: 12,
+              height: isSeriesFilter ? windowHeight - insets.top : undefined
+            },
+            isFilterVisible === 'series' ? {} : { paddingHorizontal: 16 }
           ]}
-          onPress={toggleTrustedSwitch}
-          disabled={!isSharing}
         >
-          <View style={styles.alignStyle}>
-            <UsersIcon
-              fill={isSharing ? Colors.DARK_BLUE : Colors.LIGHT_GRAY}
-              width={20}
-              height={20}
-            />
-            <Text style={[styles.buttonLabel, !isSharing ? { color: Colors.LIGHT_GRAY } : {}]}>
-              Show trusted Nomads
-            </Text>
-          </View>
-          <View>
-            <Switch
-              trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
-              thumbColor={Colors.WHITE}
-              onValueChange={toggleTrustedSwitch}
-              value={trustedVisible}
-              style={{ transform: 'scale(0.8)' }}
-              disabled={!isSharing}
-            />
-          </View>
-        </TouchableOpacity> */}
-
-          <TouchableOpacity
-            style={[
-              styles.alignStyle,
-              styles.buttonWrapper,
-              {
-                justifyContent: 'space-between'
-              }
-            ]}
-            onPress={toggleFriendsSwitch}
-            disabled={!isSharing}
-          >
-            <View style={styles.alignStyle}>
-              <FriendsIcon
-                fill={isSharing ? Colors.DARK_BLUE : Colors.LIGHT_GRAY}
-                width={20}
-                height={18}
-              />
-              <Text style={[styles.buttonLabel, !isSharing ? { color: Colors.LIGHT_GRAY } : {}]}>
-                Show my friends - {friendsOnTheMapCount ? formatNumber(friendsOnTheMapCount) : null}{' '}
-                online
-              </Text>
-            </View>
-            <View>
-              <Switch
-                trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
-                thumbColor={Colors.WHITE}
-                onValueChange={toggleFriendsSwitch}
-                value={friendsVisible}
-                style={{ transform: 'scale(0.8)' }}
-                disabled={!isSharing}
-              />
-            </View>
-          </TouchableOpacity>
-
-          <TouchableOpacity
-            style={styles.megaSelector}
-            onPress={() => {
-              if (!isPremium) {
-                setPremiumModalVisible(true);
-                return;
-              }
-              setCountrySelectorVisible(true);
-            }}
-            disabled={!isSharing}
-          >
-            <Text style={styles.megaButtonText}>Show Nomads from (select a country)</Text>
-            <ChevronIcon width={18} height={18} />
-          </TouchableOpacity>
-
-          {selectedCountries.length > 0 && (
-            <View
-              style={{
-                flexDirection: 'row',
-                alignItems: 'center',
-                flexWrap: 'wrap',
-                marginLeft: 12,
-                gap: 6,
-                marginVertical: 8
-              }}
-            >
-              {selectedCountries.map((item) => (
-                <View
-                  key={item.country}
-                  style={{
-                    marginLeft: -12
-                  }}
-                >
-                  <Image
-                    source={{ uri: API_HOST + item.flag }}
-                    style={{
-                      width: 28,
-                      height: 28,
-                      borderRadius: 14,
-                      borderWidth: 0.5,
-                      borderColor: Colors.BORDER_LIGHT
-                    }}
-                  />
-                </View>
-              ))}
-            </View>
-          )}
+          {renderScene(isFilterVisible)}
         </View>
-
-        <Button
-          children="Reset"
-          onPress={() => {
-            if (isSharing) {
-              setFriendsVisible(false);
-              setShowNomads && setShowNomads(true);
-              storage.set('showNomads', true);
-              setSelectedCountries([]);
-            } else {
-              handleGetLocation();
-            }
-          }}
-          variant={ButtonVariants.OPACITY}
-          containerStyles={{
-            backgroundColor: Colors.WHITE,
-            borderWidth: 1,
-            borderColor: Colors.DARK_BLUE
-          }}
-          textStyles={{ color: Colors.DARK_BLUE }}
-        />
-
-        <MultiSelectorCountries
-          isVisible={countrySelectorVisible}
-          onClose={() => setCountrySelectorVisible(false)}
-          onSelect={handleCountrySelect}
-          data={countriesForSelector ?? []}
-          initialSelectedIds={selectedCountries.map((item) => parseInt(item.country))}
-        />
-
-        <WarningModal
-          type={'success'}
-          isVisible={premiumModalVisible}
-          message={
-            'This feature is available to Premium users. Premium account settings can be managed on our website.'
-          }
-          action={() => {}}
-          onClose={() => setPremiumModalVisible(false)}
-          title={'Premium Feature'}
-        />
-
-        <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."
-        />
-        <WarningModal
-          type={'success'}
-          isVisible={openSettingsVisible || openSettingsBackgroundVisible}
-          onClose={() => {
-            setOpenSettingsVisible(false);
-            setOpenSettingsBackgroundVisible(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={
-            openSettingsBackgroundVisible
-              ? "NomadMania app needs background location access to update your location automatically. Please select 'Always' in location permissions. Open settings?"
-              : 'NomadMania app needs location permissions to function properly. Open settings?'
-          }
-        />
-      </View>
+      </ActionSheet>
     );
-  };
-
-  const renderScene = (filterKey: string | null) => {
-    switch (filterKey) {
-      case 'regions':
-        return renderRegions();
-      case 'series':
-        return renderSeries();
-      case 'nomads':
-        return renderNomads();
-      default:
-        return null;
-    }
-  };
-
-  return (
-    <ReactModal
-      isVisible={!!isFilterVisible}
-      onBackdropPress={handleCloseFilter}
-      onBackButtonPress={handleCloseFilter}
-      style={styles.modal}
-      statusBarTranslucent={true}
-      presentationStyle="overFullScreen"
-    >
-      <View style={[styles.modalContainer, { minHeight: 260 }]}>
-        {renderScene(isFilterVisible)}
-      </View>
-    </ReactModal>
-  );
-};
+  }
+);
 
 export default FilterModal;

+ 79 - 2
src/screens/InAppScreens/MapScreen/FilterModal/styles.tsx

@@ -54,8 +54,6 @@ export const styles = StyleSheet.create({
   closeBtn: { backgroundColor: Colors.WHITE, borderColor: '#B7C6CB' },
   sceneContainer: {
     flexGrow: 1,
-    paddingVertical: 12,
-    marginBottom: 24,
     justifyContent: 'space-between'
   },
   row: { flexDirection: 'row', alignItems: 'center' },
@@ -137,5 +135,84 @@ export const styles = StyleSheet.create({
     width: '100%',
     marginVertical: 12,
     backgroundColor: Colors.DARK_LIGHT
+  },
+  seriesSheetContainer: {
+    flex: 1
+  },
+  seriesHeader: {
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    alignItems: 'center',
+    marginTop: 8
+  },
+  seriesSelectedCount: {
+    fontSize: 12,
+    color: Colors.TEXT_GRAY,
+    fontWeight: '500'
+  },
+  seriesActions: {
+    flexDirection: 'row',
+    gap: 8,
+  },
+  seriesActionBtn: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    backgroundColor: Colors.WHITE,
+    borderWidth: 1,
+    borderColor: Colors.DARK_BLUE,
+    borderRadius: 6,
+    paddingHorizontal: 12,
+    paddingVertical: 6,
+    gap: 6
+  },
+  seriesActionBtnText: {
+    color: Colors.DARK_BLUE,
+    fontSize: 12,
+    fontWeight: '600'
+  },
+  seriesPillsContainer: {
+    flexDirection: 'row',
+    flexWrap: 'wrap',
+    gap: 8,
+    paddingHorizontal: 16,
+    paddingBottom: 24
+  },
+  seriesPill: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 12,
+    paddingVertical: 8,
+    borderRadius: 24,
+    gap: 6,
+    maxWidth: '100%'
+  },
+  seriesPillSelected: {
+    backgroundColor: Colors.ORANGE,
+    borderWidth: 1,
+    borderColor: Colors.ORANGE
+  },
+  seriesPillUnselected: {
+    backgroundColor: Colors.WHITE,
+    borderWidth: 1,
+    borderColor: Colors.DARK_BLUE
+  },
+  seriesPillText: {
+    fontSize: 14,
+    fontWeight: '600',
+    flexShrink: 1
+  },
+  seriesPillTextSelected: {
+    color: Colors.WHITE
+  },
+  seriesPillTextUnselected: {
+    color: Colors.DARK_BLUE
+  },
+  sheetBackground: {
+    backgroundColor: Colors.WHITE,
+    borderRadius: 16
+  },
+  sheetHandle: {
+    backgroundColor: '#D1D1D6',
+    width: 40
   }
 });

+ 37 - 23
src/screens/InAppScreens/MapScreen/UsersListScreen/index.tsx

@@ -1,6 +1,6 @@
 import { NavigationProp } from '@react-navigation/native';
-import React, { FC, useCallback, useEffect, useState } from 'react';
-import { ActivityIndicator } from 'react-native';
+import React, { FC, useCallback, useEffect, useState, useRef } from 'react';
+import { ActivityIndicator, Dimensions, View } from 'react-native';
 import { Header, Loading, PageWrapper } from 'src/components';
 
 import { Colors } from 'src/theme';
@@ -13,7 +13,7 @@ import {
   useGetUsersWhoVisitetRegionMutation
 } from '@api/regions';
 import { Profile } from './Profile';
-import { RankingDropdown } from '../../TravellersScreen/utils/types';
+import { RankingDropdown, FilterModalRef } from '../../TravellersScreen/utils/types';
 import { dataRanking } from '../../TravellersScreen/utils';
 import { Ranking } from '../../TravellersScreen';
 import { useGetFriendsMutation } from '@api/friends';
@@ -44,7 +44,7 @@ const UsersListScreen: FC<Props> = ({ navigation, route }) => {
   const [selectedUsers, setSelectedUsers] = useState<any[]>([]);
   const [filteredUsers, setFilteredUsers] = useState<Ranking[]>([]);
   const isFromHere = route.params?.isFromHere;
-  const [isModalVisible, setModalVisible] = useState(false);
+  const filterRef = useRef<FilterModalRef>(null);
   const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
   const [masterCountries, setMasterCountries] = useState<any>([]);
   const [maxPages, setMaxPages] = useState(1);
@@ -367,8 +367,40 @@ const UsersListScreen: FC<Props> = ({ navigation, route }) => {
                 ? 'Completed'
                 : 'Been here'
         }
-        rightElement={<FilterButton onPress={() => setModalVisible(!isModalVisible)} />}
+        rightElement={<FilterButton onPress={() => filterRef.current?.toggle()} />}
       />
+
+      <View style={{ zIndex: 100 }}>
+        <View
+          style={{
+            position: 'absolute',
+            top: 0,
+            left: -Dimensions.get('window').width * 0.05,
+            width: Dimensions.get('window').width,
+            height: Dimensions.get('window').height,
+            overflow: 'hidden'
+          }}
+          pointerEvents="box-none"
+        >
+          <FilterModal
+            ref={filterRef}
+            applyFilter={(filterAge, filterRanking, filterCountry) => {
+              setConfirmedValueRanking(filterRanking);
+              setPage(0);
+              setFilter({
+                age: filterAge?.value ? +filterAge?.value : undefined,
+                ranking: filterRanking?.name,
+                country:
+                  filterCountry?.two && filterCountry?.two !== 'all'
+                    ? filterCountry?.two
+                    : undefined
+              });
+            }}
+            countriesData={masterCountries}
+            isCountryHidden={isFromHere}
+          />
+        </View>
+      </View>
       <FlashList
         viewabilityConfig={{
           waitForInteraction: true,
@@ -424,24 +456,6 @@ const UsersListScreen: FC<Props> = ({ navigation, route }) => {
         onEndReachedThreshold={0.2}
         ListFooterComponent={<ListFooter isLoading={isLoadingMore} />}
       />
-
-      <FilterModal
-        isModalVisible={isModalVisible}
-        setModalVisible={(value) => setModalVisible(value)}
-        applyFilter={(filterAge, filterRanking, filterCountry) => {
-          setConfirmedValueRanking(filterRanking);
-          setPage(0);
-          setFilter({
-            age: filterAge?.value ? +filterAge?.value : undefined,
-            ranking: filterRanking?.name,
-            country:
-              filterCountry?.two && filterCountry?.two !== 'all' ? filterCountry?.two : undefined
-          });
-          setModalVisible(false);
-        }}
-        countriesData={masterCountries}
-        isCountryHidden={isFromHere}
-      />
     </PageWrapper>
   );
 };

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

@@ -61,7 +61,7 @@ import {
   usePostGetVisitedRegionsIdsQuery,
   usePostGetVisitedSeriesIdsQuery
 } from '@api/maps';
-import FilterModal from './FilterModal';
+import FilterModal, { FilterModalRef } from './FilterModal';
 import { useGetListDareQuery } from '@api/myDARE';
 import { useGetIconsQuery, usePostSetToggleItem } from '@api/series';
 import MarkerItem from './MarkerItem';
@@ -409,7 +409,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
   const [isWarningModalVisible, setIsWarningModalVisible] = useState<boolean>(false);
   const [isEditSlowModalVisible, setIsEditSlowModalVisible] = useState<boolean>(false);
   const [isEditModalVisible, setIsEditModalVisible] = useState(false);
-  const [isFilterVisible, setIsFilterVisible] = useState<string | null>(null);
+  const filterModalRef = useRef<FilterModalRef>(null);
   const [isLocationLoading, setIsLocationLoading] = useState(false);
   const [premiumModalVisible, setPremiumModalVisible] = useState(false);
 
@@ -2325,7 +2325,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               <MapButton
                 onPress={() => {
                   try {
-                    setIsFilterVisible('regions');
+                    filterModalRef.current?.openFilter('regions');
                     closeCallout();
                   } catch (error) {
                     console.error('Error opening filter:', error);
@@ -2346,7 +2346,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               <MapButton
                 onPress={() => {
                   try {
-                    setIsFilterVisible('series');
+                    filterModalRef.current?.openFilter('series');
                     closeCallout();
                   } catch (error) {
                     console.error('Error opening filter:', error);
@@ -2360,7 +2360,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
                 <MapButton
                   onPress={() => {
                     try {
-                      setIsFilterVisible('nomads');
+                      filterModalRef.current?.openFilter('nomads');
                       closeCallout();
                     } catch (error) {
                       console.error('Error opening filter:', error);
@@ -2423,8 +2423,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
         updateNM={handleUpdateNM}
       />
       <FilterModal
-        isFilterVisible={isFilterVisible}
-        setIsFilterVisible={setIsFilterVisible}
+        ref={filterModalRef}
         tilesTypes={tilesTypes}
         tilesType={tilesType}
         setTilesType={setTilesType}

+ 35 - 23
src/screens/InAppScreens/MessagesScreen/MembersListScreen/index.tsx

@@ -1,5 +1,5 @@
-import React, { FC, useEffect, useState } from 'react';
-import { View, StyleSheet } from 'react-native';
+import React, { FC, useEffect, useState, useRef } from 'react';
+import { View, StyleSheet, Dimensions } from 'react-native';
 import { NavigationProp, useFocusEffect } from '@react-navigation/native';
 import { storage, StoreType } from 'src/storage';
 import { PageWrapper, Header, Input, WarningModal } from 'src/components';
@@ -10,7 +10,7 @@ import { FlashList } from '@shopify/flash-list';
 
 import SearchIcon from 'assets/icons/search.svg';
 import { dataRanking } from '../../TravellersScreen/utils';
-import { RankingDropdown } from '../../TravellersScreen/utils/types';
+import { RankingDropdown, FilterModalRef } from '../../TravellersScreen/utils/types';
 import { FilterButton, FilterModal } from '../../TravellersScreen/Components/FilterModal';
 import { usePostGetCountriesRanking } from '@api/ranking';
 import { Profile } from '../Components/Profile';
@@ -43,7 +43,7 @@ const MembersListScreen: FC<Props> = ({ navigation, route }) => {
   const { data: masterCountries } = usePostGetCountriesRanking();
 
   const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
-  const [isModalVisible, setModalVisible] = useState(false);
+  const filterRef = useRef<FilterModalRef>(null);
 
   useFocusEffect(() => {
     navigation.getParent()?.setOptions({
@@ -83,8 +83,38 @@ const MembersListScreen: FC<Props> = ({ navigation, route }) => {
     <PageWrapper>
       <Header
         label="Nomads"
-        rightElement={<FilterButton onPress={() => setModalVisible(!isModalVisible)} />}
+        rightElement={<FilterButton onPress={() => filterRef.current?.toggle()} />}
       />
+
+      <View style={{ zIndex: 100 }}>
+        <View
+          style={{
+            position: 'absolute',
+            top: 0,
+            left: -Dimensions.get('window').width * 0.05,
+            width: Dimensions.get('window').width,
+            height: Dimensions.get('window').height,
+            overflow: 'hidden'
+          }}
+          pointerEvents="box-none"
+        >
+          <FilterModal
+            ref={filterRef}
+            applyFilter={(filterAge, filterRanking, filterCountry) => {
+              setConfirmedValueRanking(filterRanking);
+              setFilteredData(
+                applyModalSort(
+                  (members?.settings as any) ?? [],
+                  filterAge,
+                  filterRanking ?? dataRanking[0],
+                  filterCountry
+                )
+              );
+            }}
+            countriesData={masterCountries ? masterCountries.data : []}
+          />
+        </View>
+      </View>
       <View style={styles.container}>
         <Input
           inputMode={'search'}
@@ -100,7 +130,6 @@ const MembersListScreen: FC<Props> = ({ navigation, route }) => {
             itemVisiblePercentThreshold: 50,
             minimumViewTime: 1000
           }}
-          estimatedItemSize={50}
           data={filteredData || []}
           renderItem={({ item, index }) => (
             <Profile
@@ -171,23 +200,6 @@ const MembersListScreen: FC<Props> = ({ navigation, route }) => {
         title={modalState.title}
       />
       <UserOptionsModal />
-      <FilterModal
-        isModalVisible={isModalVisible}
-        setModalVisible={(value) => setModalVisible(value)}
-        applyFilter={(filterAge, filterRanking, filterCountry) => {
-          setConfirmedValueRanking(filterRanking);
-          setFilteredData(
-            applyModalSort(
-              (members?.settings as any) ?? [],
-              filterAge,
-              filterRanking ?? dataRanking[0],
-              filterCountry
-            )
-          );
-          setModalVisible(false);
-        }}
-        countriesData={masterCountries ? masterCountries.data : []}
-      />
     </PageWrapper>
   );
 };

+ 38 - 24
src/screens/InAppScreens/ProfileScreen/MyFriendsScreen/index.tsx

@@ -1,13 +1,13 @@
 import { NavigationProp, useFocusEffect } from '@react-navigation/native';
 import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
-import { ActivityIndicator, View } from 'react-native';
+import { ActivityIndicator, Dimensions, View } from 'react-native';
 import { Header, HorizontalTabView, Loading } from 'src/components';
 
 import { Colors } from 'src/theme';
 import { FlashList, FlashListRef } from '@shopify/flash-list';
 import { StoreType, storage } from 'src/storage';
 import { FilterButton, FilterModal } from '../../TravellersScreen/Components/FilterModal';
-import { RankingDropdown } from '../../TravellersScreen/utils/types';
+import { RankingDropdown, FilterModalRef } from '../../TravellersScreen/utils/types';
 import { dataRanking } from '../../TravellersScreen/utils';
 import {
   useGetMyFriendsMutation,
@@ -37,7 +37,7 @@ const MyFriendsScreen: FC<Props> = ({ navigation }) => {
 
   const { mutateAsync: getMyFriends } = useGetMyFriendsMutation();
   const [loading, setLoading] = useState(true);
-  const [isModalVisible, setModalVisible] = useState(false);
+  const filterRef = useRef<FilterModalRef>(null);
   const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
   const [masterCountries, setMasterCountries] = useState<any>([]);
   const [maxPages, setMaxPages] = useState(1);
@@ -265,10 +265,44 @@ const MyFriendsScreen: FC<Props> = ({ navigation }) => {
       <View style={{ marginLeft: '5%', marginRight: '5%' }}>
         <Header
           label={'Friends'}
-          rightElement={<FilterButton onPress={() => setModalVisible(!isModalVisible)} />}
+          rightElement={<FilterButton onPress={() => filterRef.current?.toggle()} />}
         />
       </View>
 
+      <View style={{ zIndex: 100 }}>
+        <View
+          style={{
+            position: 'absolute',
+            top: 0,
+            left: 0,
+            width: Dimensions.get('window').width,
+            height: Dimensions.get('window').height,
+            overflow: 'hidden'
+          }}
+          pointerEvents="box-none"
+        >
+          <FilterModal
+            ref={filterRef}
+            applyFilter={(filterAge, filterRanking, filterCountry) => {
+              setConfirmedValueRanking(filterRanking);
+              setPage(0);
+              setFilter({
+                age: filterAge?.value ? +filterAge?.value : undefined,
+                ranking: filterRanking?.name,
+                country:
+                  filterCountry?.two && filterCountry?.two !== 'all'
+                    ? filterCountry?.two
+                    : undefined
+              });
+              if (!filterAge && !filterRanking && !filterCountry) {
+                fetchUsers();
+              }
+            }}
+            countriesData={masterCountries}
+          />
+        </View>
+      </View>
+
       <HorizontalTabView
         index={index}
         setIndex={setIndex}
@@ -344,26 +378,6 @@ const MyFriendsScreen: FC<Props> = ({ navigation }) => {
           </>
         )}
       />
-
-      <FilterModal
-        isModalVisible={isModalVisible}
-        setModalVisible={(value) => setModalVisible(value)}
-        applyFilter={(filterAge, filterRanking, filterCountry) => {
-          setConfirmedValueRanking(filterRanking);
-          setPage(0);
-          setFilter({
-            age: filterAge?.value ? +filterAge?.value : undefined,
-            ranking: filterRanking?.name,
-            country:
-              filterCountry?.two && filterCountry?.two !== 'all' ? filterCountry?.two : undefined
-          });
-          if (!filterAge && !filterRanking && !filterCountry) {
-            fetchUsers();
-          }
-          setModalVisible(false);
-        }}
-        countriesData={masterCountries}
-      />
     </SafeAreaView>
   );
 };

+ 157 - 112
src/screens/InAppScreens/TravellersScreen/Components/FilterModal.tsx

@@ -1,146 +1,191 @@
-import React, { FC, useState } from 'react';
-import Modal from 'react-native-modal';
-import { Dropdown } from 'react-native-searchable-dropdown-kj';
-import { Text, TouchableOpacity, View } from 'react-native';
+import React, { FC, useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
+import { TouchableOpacity, View, Animated, Easing } from 'react-native';
 
 import { ModalStyles } from './styles';
 import { Colors } from '../../../../theme';
 
-import { Button } from '../../../../components';
+import { Button, SelectSheet } from '../../../../components';
 import { ButtonVariants } from '../../../../types/components';
 
 import { dataAge, dataRanking } from '../utils';
 
-import CloseIcon from '../../../../../assets/icons/close.svg';
 import {
   filterAgeType,
   FilterButtonProps,
   filterCountryType,
   filterRankingType,
-  ModalProps
+  ModalProps,
+  FilterModalRef
 } from '../utils/types';
 import FilterIcon from '../../../../../assets/icons/filter.svg';
 import { useConnection } from 'src/contexts/ConnectionContext';
 
-export const FilterModal: FC<ModalProps> = ({
-  isModalVisible,
-  setModalVisible,
+export const FilterModal = forwardRef<FilterModalRef, ModalProps>(({
   countriesData,
   applyFilter,
   isCountryHidden
-}) => {
+}, ref) => {
   const netInfo = useConnection();
+
+  const [confirmedAge, setConfirmedAge] = useState<filterAgeType>(null);
+  const [confirmedRanking, setConfirmedRanking] = useState<filterRankingType>(null);
+  const [confirmedCountry, setConfirmedCountry] = useState<filterCountryType>(null);
+
   const [filterAge, setFilterAge] = useState<filterAgeType>(null);
   const [filterRanking, setFilterRanking] = useState<filterRankingType>(null);
   const [filterCountry, setFilterCountry] = useState<filterCountryType>(null);
 
+  const [isOpen, setIsOpen] = useState(false);
+  const slideAnim = useRef(new Animated.Value(-800)).current;
+
+  const [viewHeight, setViewHeight] = useState(600);
+
+  useImperativeHandle(ref, () => ({
+    toggle: () => {
+      if (isOpen) {
+        setFilterAge(confirmedAge);
+        setFilterRanking(confirmedRanking);
+        setFilterCountry(confirmedCountry);
+        setIsOpen(false);
+      } else {
+        setIsOpen(true);
+      }
+    },
+    open: () => setIsOpen(true),
+    close: () => {
+      setFilterAge(confirmedAge);
+      setFilterRanking(confirmedRanking);
+      setFilterCountry(confirmedCountry);
+      setIsOpen(false);
+    }
+  }));
+
+  useEffect(() => {
+    if (isOpen) {
+      Animated.spring(slideAnim, {
+        toValue: 0,
+        speed: 20,
+        bounciness: 2,
+        useNativeDriver: true,
+      }).start();
+    } else {
+      Animated.timing(slideAnim, {
+        toValue: -viewHeight - 50,
+        duration: 150,
+        easing: Easing.in(Easing.ease),
+        useNativeDriver: true,
+      }).start();
+    }
+  }, [isOpen, viewHeight]);
+
   return (
-    <Modal isVisible={isModalVisible}>
-      <View style={{ backgroundColor: 'white', borderRadius: 15 }}>
-        <View style={{ marginLeft: '5%', marginRight: '5%', marginTop: '5%', marginBottom: '10%' }}>
-          <View style={{ alignSelf: 'flex-end' }}>
-            <TouchableOpacity onPress={() => setModalVisible(!isModalVisible)}>
-              <CloseIcon />
-            </TouchableOpacity>
-          </View>
-          <View style={{ display: 'flex', alignItems: 'center' }}>
-            <Text style={{ color: Colors.DARK_BLUE, fontSize: 20, fontWeight: '700' }}>Filter</Text>
-            {!isCountryHidden && (
-              <Dropdown
-                style={[ModalStyles.dropdown, { width: '100%', marginTop: 20 }]}
-                placeholderStyle={ModalStyles.placeholderStyle}
-                selectedTextStyle={ModalStyles.selectedTextStyle}
-                containerStyle={ModalStyles.dropdownContent}
-                data={countriesData}
-                disable={!netInfo?.isInternetReachable}
-                labelField="name"
-                valueField="two"
-                value={filterCountry?.two}
-                placeholder="Country"
-                onChange={(item) => {
-                  setFilterCountry(item);
-                }}
-                search={true}
-                searchPlaceholder="Search"
-                autoScroll={false}
-                inputSearchStyle={ModalStyles.search}
-                flatListProps={{ initialNumToRender: 50, maxToRenderPerBatch: 10 }}
-                dropdownPosition="top"
-                keyboardAvoiding={false}
-              />
-            )}
+    <Animated.View
+      style={{
+        position: 'absolute',
+        top: 0,
+        left: 0,
+        right: 0,
+        zIndex: 200,
+        elevation: 200,
+        transform: [{ translateY: slideAnim }],
+      }}
+    >
+      <View
+        onLayout={(e) => setViewHeight(e.nativeEvent.layout.height)}
+        style={{
+          backgroundColor: 'white',
+          paddingTop: 15,
+          paddingBottom: 20,
+          paddingHorizontal: '5%',
+          borderBottomLeftRadius: 20,
+          borderBottomRightRadius: 20,
+          shadowColor: '#000',
+          shadowOffset: { width: 0, height: 4 },
+          shadowOpacity: 0.15,
+          shadowRadius: 10,
+          elevation: 8,
+        }}
+      >
+        <View style={{ display: 'flex', alignItems: 'center' }}>
+          {!isCountryHidden && (
+            <SelectSheet
+              style={[ModalStyles.dropdown, { width: '100%' }] as any}
+              data={countriesData}
+              disabled={!netInfo?.isInternetReachable}
+              labelField="name"
+              valueField="two"
+              value={filterCountry?.two ?? null}
+              placeholder="Country"
+              onChange={(item) => setFilterCountry(item)}
+              searchable={true}
+              searchPlaceholder="Search country..."
+            />
+          )}
 
-            <View style={[ModalStyles.ageAndRankingWrapper, isCountryHidden ? {marginTop: 20} : {}]}>
-              <Dropdown
-                style={ModalStyles.dropdown}
-                placeholderStyle={ModalStyles.placeholderStyle}
-                selectedTextStyle={ModalStyles.selectedTextStyle}
-                containerStyle={ModalStyles.dropdownContent}
-                data={dataRanking}
-                labelField="label"
-                valueField="value"
-                value={filterRanking?.value}
-                placeholder="Ranking"
-                onChange={(item) => {
-                  setFilterRanking(item);
-                }}
-              />
-              <Dropdown
-                style={ModalStyles.dropdown}
-                placeholderStyle={ModalStyles.placeholderStyle}
-                selectedTextStyle={ModalStyles.selectedTextStyle}
-                containerStyle={ModalStyles.dropdownContent}
-                data={dataAge}
-                disable={!netInfo?.isInternetReachable}
-                labelField="label"
-                valueField="value"
-                value={filterAge?.value}
-                placeholder="Age"
-                onChange={(item) => {
-                  setFilterAge(item);
-                }}
-              />
-            </View>
-            <View style={ModalStyles.buttonsWrapper}>
-              <Button
-                variant={ButtonVariants.OPACITY}
-                containerStyles={{
-                  borderColor: Colors.DARK_BLUE,
-                  backgroundColor: 'white',
-                  width: '45%'
-                }}
-                textStyles={{
-                  color: Colors.DARK_BLUE
-                }}
-                onPress={() => {
-                  setFilterAge(null);
-                  setFilterRanking(null);
-                  setFilterCountry(null);
-                }}
-                children={'Clear'}
-              />
-              <Button
-                variant={ButtonVariants.FILL}
-                containerStyles={{
-                  borderColor: Colors.DARK_BLUE,
-                  backgroundColor: Colors.DARK_BLUE,
-                  width: '45%'
-                }}
-                textStyles={{
-                  color: Colors.WHITE
-                }}
-                onPress={() => {
-                  applyFilter(filterAge, filterRanking, filterCountry);
-                }}
-                children={'Show'}
-              />
-            </View>
+          <View style={[ModalStyles.ageAndRankingWrapper, !isCountryHidden ? { marginTop: 20 } : {}]}>
+            <SelectSheet
+              style={ModalStyles.dropdown}
+              data={dataRanking}
+              labelField="label"
+              valueField="value"
+              value={filterRanking?.value ?? null}
+              placeholder="Ranking"
+              onChange={(item) => setFilterRanking(item)}
+            />
+            <SelectSheet
+              style={ModalStyles.dropdown}
+              data={dataAge}
+              disabled={!netInfo?.isInternetReachable}
+              labelField="label"
+              valueField="value"
+              value={filterAge?.value ?? null}
+              placeholder="Age"
+              onChange={(item) => setFilterAge(item)}
+            />
+          </View>
+          <View style={ModalStyles.buttonsWrapper}>
+            <Button
+              variant={ButtonVariants.OPACITY}
+              containerStyles={{
+                borderColor: Colors.DARK_BLUE,
+                backgroundColor: 'white',
+                width: '45%'
+              }}
+              textStyles={{
+                color: Colors.DARK_BLUE
+              }}
+              onPress={() => {
+                setFilterAge(null);
+                setFilterRanking(null);
+                setFilterCountry(null);
+              }}
+              children={'Clear'}
+            />
+            <Button
+              variant={ButtonVariants.FILL}
+              containerStyles={{
+                borderColor: Colors.DARK_BLUE,
+                backgroundColor: Colors.DARK_BLUE,
+                width: '45%'
+              }}
+              textStyles={{
+                color: Colors.WHITE
+              }}
+              onPress={() => {
+                setConfirmedAge(filterAge);
+                setConfirmedRanking(filterRanking);
+                setConfirmedCountry(filterCountry);
+                applyFilter(filterAge, filterRanking, filterCountry);
+                setIsOpen(false);
+              }}
+              children={'Show'}
+            />
           </View>
         </View>
       </View>
-    </Modal>
+    </Animated.View>
   );
-};
+});
 
 export const FilterButton: FC<FilterButtonProps> = ({ onPress }) => {
   return (

+ 35 - 23
src/screens/InAppScreens/TravellersScreen/InMemoriamScreen/index.tsx

@@ -1,5 +1,5 @@
-import React, { useCallback, useState } from 'react';
-import { FlatList } from 'react-native';
+import React, { useCallback, useState, useRef } from 'react';
+import { FlatList, View, Dimensions } from 'react-native';
 import { useFocusEffect } from '@react-navigation/native';
 import { usePostGetCountriesRankingMemoriam } from '@api/ranking';
 
@@ -10,7 +10,7 @@ import { Profile } from '../Components/Profile';
 import { FilterButton, FilterModal } from '../Components/FilterModal';
 
 import { applyModalSort, dataRanking } from '../utils';
-import { RankingDropdown } from '../utils/types';
+import { RankingDropdown, FilterModalRef } from '../utils/types';
 
 import type { Ranking } from '..';
 
@@ -19,7 +19,7 @@ const InMemoriamScreen = () => {
   const [isLoading, setIsLoading] = useState(true);
 
   const [filteredData, setFilteredData] = useState<Ranking[]>([]);
-  const [isModalActive, setIsModalActive] = useState(false);
+  const filterRef = useRef<FilterModalRef>(null);
   const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
 
   const { data: inMemoriamCountries } = usePostGetCountriesRankingMemoriam();
@@ -42,29 +42,41 @@ const InMemoriamScreen = () => {
 
   return (
     <PageWrapper>
-      <FilterModal
-        isModalVisible={isModalActive}
-        setModalVisible={(value) => setIsModalActive(value)}
-        applyFilter={(filterAge, filterRanking, filterCountry) => {
-          setConfirmedValueRanking(filterRanking);
-          setFilteredData(
-            applyModalSort(
-              memoriamRanking,
-              filterAge,
-              filterRanking ?? dataRanking[0],
-              filterCountry
-            )
-          );
-          setIsModalActive(false);
-        }}
-        countriesData={inMemoriamCountries ? inMemoriamCountries.data : []}
-      />
-
       <Header
         label="In Memoriam"
-        rightElement={<FilterButton onPress={() => setIsModalActive(!isModalActive)} />}
+        rightElement={<FilterButton onPress={() => filterRef.current?.toggle()} />}
       />
 
+      <View style={{ zIndex: 100 }} pointerEvents="box-none">
+        <View
+          style={{
+            position: 'absolute',
+            top: 0,
+            left: -Dimensions.get('window').width * 0.05,
+            width: Dimensions.get('window').width,
+            height: Dimensions.get('window').height,
+            overflow: 'hidden'
+          }}
+          pointerEvents="box-none"
+        >
+          <FilterModal
+            ref={filterRef}
+            applyFilter={(filterAge, filterRanking, filterCountry) => {
+              setConfirmedValueRanking(filterRanking);
+              setFilteredData(
+                applyModalSort(
+                  memoriamRanking,
+                  filterAge,
+                  filterRanking ?? dataRanking[0],
+                  filterCountry
+                )
+              );
+            }}
+            countriesData={inMemoriamCountries ? inMemoriamCountries.data : []}
+          />
+        </View>
+      </View>
+
       <FlatList
         showsVerticalScrollIndicator={false}
         data={filteredData.length > 0 ? filteredData : memoriamRanking}

+ 35 - 18
src/screens/InAppScreens/TravellersScreen/LPIRankingScreen/index.tsx

@@ -1,5 +1,5 @@
-import React, { useCallback, useState } from 'react';
-import { FlatList } from 'react-native';
+import React, { useCallback, useState, useRef } from 'react';
+import { FlatList, View, Dimensions } from 'react-native';
 import { useFocusEffect } from '@react-navigation/native';
 import { usePostGetCountriesRankingLPI } from '@api/ranking';
 
@@ -10,7 +10,7 @@ import { Profile } from '../Components/Profile';
 import { FilterButton, FilterModal } from '../Components/FilterModal';
 
 import { applyModalSort, dataRanking } from '../utils';
-import { RankingDropdown } from '../utils/types';
+import { RankingDropdown, FilterModalRef } from '../utils/types';
 
 import type { Ranking } from '..';
 
@@ -19,7 +19,7 @@ const LPIRankingScreen = () => {
   const [isLoading, setIsLoading] = useState(true);
 
   const [filteredData, setFilteredData] = useState<Ranking[]>([]);
-  const [isModalActive, setIsModalActive] = useState(false);
+  const filterRef = useRef<FilterModalRef>(null);
   const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
 
   const { data: lpiCountries } = usePostGetCountriesRankingLPI();
@@ -46,24 +46,41 @@ const LPIRankingScreen = () => {
 
   return (
     <PageWrapper>
-      <FilterModal
-        isModalVisible={isModalActive}
-        setModalVisible={(value) => setIsModalActive(value)}
-        applyFilter={(filterAge, filterRanking, filterCountry) => {
-          setConfirmedValueRanking(filterRanking);
-          setFilteredData(
-            applyModalSort(LPIRanking, filterAge, filterRanking ?? dataRanking[0], filterCountry)
-          );
-          setIsModalActive(false);
-        }}
-        countriesData={lpiCountries ? lpiCountries.data : []}
-      />
-
       <Header
         label="LPI Ranking"
-        rightElement={<FilterButton onPress={() => setIsModalActive(!isModalActive)} />}
+        rightElement={<FilterButton onPress={() => filterRef.current?.toggle()} />}
       />
 
+      <View style={{ zIndex: 100 }}>
+        <View
+          style={{
+            position: 'absolute',
+            top: 0,
+            left: -Dimensions.get('window').width * 0.05,
+            width: Dimensions.get('window').width,
+            height: Dimensions.get('window').height,
+            overflow: 'hidden'
+          }}
+          pointerEvents="box-none"
+        >
+          <FilterModal
+            ref={filterRef}
+            applyFilter={(filterAge, filterRanking, filterCountry) => {
+              setConfirmedValueRanking(filterRanking);
+              setFilteredData(
+                applyModalSort(
+                  LPIRanking,
+                  filterAge,
+                  filterRanking ?? dataRanking[0],
+                  filterCountry
+                )
+              );
+            }}
+            countriesData={lpiCountries ? lpiCountries.data : []}
+          />
+        </View>
+      </View>
+
       <FlatList
         data={filteredData.length > 0 ? filteredData : LPIRanking}
         showsVerticalScrollIndicator={false}

+ 34 - 22
src/screens/InAppScreens/TravellersScreen/MasterRankingScreen/index.tsx

@@ -1,5 +1,5 @@
-import React, { useEffect, useState } from 'react';
-import { TouchableOpacity, View, Text } from 'react-native';
+import React, { useEffect, useState, useRef } from 'react';
+import { TouchableOpacity, View, Text, Dimensions } from 'react-native';
 import { FlashList } from '@shopify/flash-list';
 
 import { useGetMaster, usePostGetCountriesRanking } from '@api/ranking';
@@ -8,7 +8,7 @@ import { Profile } from '../Components/Profile';
 import { FilterModal, FilterButton } from '../Components/FilterModal';
 
 import { dataRanking } from '../utils';
-import type { RankingDropdown } from '../utils/types';
+import type { RankingDropdown, FilterModalRef } from '../utils/types';
 
 import type { Ranking } from '..';
 
@@ -20,7 +20,7 @@ const MasterRankingScreen = () => {
   const { data: masterCountries } = usePostGetCountriesRanking();
 
   const [masterRanking, setMasterRanking] = useState<Ranking[]>([]);
-  const [isModalVisible, setModalVisible] = useState(false);
+  const filterRef = useRef<FilterModalRef>(null);
   const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
   const [filter, setFilter] = useState({
     age: 0,
@@ -52,26 +52,39 @@ const MasterRankingScreen = () => {
 
   return (
     <PageWrapper>
-      <FilterModal
-        isModalVisible={isModalVisible}
-        setModalVisible={(value) => setModalVisible(value)}
-        applyFilter={(filterAge, filterRanking, filterCountry) => {
-          setConfirmedValueRanking(filterRanking);
-          setFilter({
-            age: filterAge?.value ? +filterAge?.value : 0,
-            ranking: filterRanking ? filterRanking.name : dataRanking[0].name,
-            country: filterCountry?.two ? filterCountry.two?.toLowerCase() : 'ALL'
-          });
-          setPage(0);
-          setModalVisible(false);
-        }}
-        countriesData={masterCountries ? masterCountries.data : []}
-      />
-
       <Header
         label="Master Ranking"
-        rightElement={<FilterButton onPress={() => setModalVisible(!isModalVisible)} />}
+        rightElement={<FilterButton onPress={() => filterRef.current?.toggle()} />}
       />
+
+      <View style={{ zIndex: 100 }}>
+        <View
+          style={{
+            position: 'absolute',
+            top: -10,
+            left: -Dimensions.get('window').width * 0.05,
+            width: Dimensions.get('window').width,
+            height: Dimensions.get('window').height,
+            overflow: 'hidden'
+          }}
+          pointerEvents="box-none"
+        >
+          <FilterModal
+            ref={filterRef}
+            applyFilter={(filterAge, filterRanking, filterCountry) => {
+              setConfirmedValueRanking(filterRanking);
+              setFilter({
+                age: filterAge?.value ? +filterAge?.value : 0,
+                ranking: filterRanking ? filterRanking.name : dataRanking[0].name,
+                country: filterCountry?.two ? filterCountry.two?.toLowerCase() : 'ALL'
+              });
+              setPage(0);
+            }}
+            countriesData={masterCountries ? masterCountries.data : []}
+          />
+        </View>
+      </View>
+
       <View
         style={{
           marginTop: '-5%',
@@ -168,7 +181,6 @@ const MasterRankingScreen = () => {
               auth={item.auth}
             />
           )}
-          estimatedItemSize={80}
           viewabilityConfig={{
             waitForInteraction: true,
             itemVisiblePercentThreshold: 50,

+ 7 - 3
src/screens/InAppScreens/TravellersScreen/utils/types.ts

@@ -5,15 +5,19 @@ export type filterAgeType = {
   max: number;
 } | null;
 
-export type filterRankingType = { value: number; label: string, name: string } | null;
+export type filterRankingType = { value: number; label: string; name: string } | null;
 
 export type filterCountryType = { two: string; name: string } | null;
 
 export type RankingDropdown = { value: number; label: string };
 
+export interface FilterModalRef {
+  toggle: () => void;
+  open: () => void;
+  close: () => void;
+}
+
 export type ModalProps = {
-  isModalVisible: boolean;
-  setModalVisible: (value: boolean) => void;
   applyFilter: (
     filterAge: filterAgeType,
     filterRanking: filterRankingType,

+ 26 - 41
src/screens/InAppScreens/TravelsScreen/AddNewFixerScreen/index.tsx

@@ -9,11 +9,10 @@ import {
   KeyboardAvoidingView
 } from 'react-native';
 import { useNavigation } from '@react-navigation/native';
-import { Dropdown, MultiSelect } from 'react-native-searchable-dropdown-kj';
+import { MultiSelect } from 'react-native-searchable-dropdown-kj';
 import { Formik } from 'formik';
 import * as yup from 'yup';
-
-import { PageWrapper, Header, Input, CheckBox } from 'src/components';
+import { SelectSheet, PageWrapper, Header, Input, CheckBox } from 'src/components';
 import { StoreType, storage } from 'src/storage';
 import { Colors } from 'src/theme';
 import { NAVIGATION_PAGES } from 'src/types';
@@ -78,27 +77,27 @@ const AddNewFixerScreen = ({ route }: { route: any }) => {
 
   const initialData: FixerType = existingFixer
     ? {
-        month: existingFixer.month,
-        year: existingFixer.year,
-        selectedCountries: [route.params?.un_id],
-        name: existingFixer.name,
-        email: existingFixer.email,
-        phone: existingFixer.phone,
-        website: existingFixer.web,
-        comment: existingFixer.comment,
-        anonymous: existingFixer.anonymous === 1
-      }
+      month: existingFixer.month,
+      year: existingFixer.year,
+      selectedCountries: [route.params?.un_id],
+      name: existingFixer.name,
+      email: existingFixer.email,
+      phone: existingFixer.phone,
+      website: existingFixer.web,
+      comment: existingFixer.comment,
+      anonymous: existingFixer.anonymous === 1
+    }
     : {
-        month: month,
-        year: year,
-        selectedCountries: [],
-        name: '',
-        email: '',
-        phone: '',
-        website: '',
-        comment: '',
-        anonymous: false
-      };
+      month: month,
+      year: year,
+      selectedCountries: [],
+      name: '',
+      email: '',
+      phone: '',
+      website: '',
+      comment: '',
+      anonymous: false
+    };
 
   return (
     <Formik
@@ -163,37 +162,23 @@ const AddNewFixerScreen = ({ route }: { route: any }) => {
               <View>
                 <Text style={styles.title}>Date</Text>
                 <View style={[styles.row, { justifyContent: 'space-between' }]}>
-                  <Dropdown
-                    style={styles.dateSelector}
-                    placeholderStyle={styles.placeholderStyle}
-                    selectedTextStyle={styles.placeholderStyle}
-                    containerStyle={styles.dropdownContent}
+                  <SelectSheet
+                    style={styles.dateSelector as any}
                     data={months}
                     labelField="label"
                     valueField="value"
                     value={values.month}
                     placeholder="Month"
                     onChange={(item) => setFieldValue('month', item.value)}
-                    autoScroll={false}
-                    flatListProps={{ initialNumToRender: 50, maxToRenderPerBatch: 10 }}
                   />
-                  <Dropdown
-                    style={styles.dateSelector}
-                    placeholderStyle={styles.placeholderStyle}
-                    selectedTextStyle={styles.placeholderStyle}
-                    containerStyle={styles.dropdownContent}
+                  <SelectSheet
+                    style={styles.dateSelector as any}
                     data={years}
                     labelField="label"
                     valueField="value"
                     value={values.year}
                     placeholder="Year"
                     onChange={(item) => setFieldValue('year', item.value)}
-                    search={true}
-                    searchPlaceholder="Search"
-                    autoScroll={false}
-                    inputSearchStyle={styles.search}
-                    flatListProps={{ initialNumToRender: 50, maxToRenderPerBatch: 10 }}
-                    searchQuery={(keyword, item) => item.includes(keyword)}
                   />
                 </View>
               </View>

+ 35 - 24
src/screens/InAppScreens/TravelsScreen/ParticipantsListScreen/index.tsx

@@ -1,12 +1,12 @@
-import React, { FC, useEffect, useState } from 'react';
-import { View, StyleSheet } from 'react-native';
+import React, { FC, useEffect, useState, useRef } from 'react';
+import { View, StyleSheet, Dimensions } from 'react-native';
 import { NavigationProp } from '@react-navigation/native';
 import { PageWrapper, Header, Input, WarningModal } from 'src/components';
 import { FlashList } from '@shopify/flash-list';
 
 import SearchIcon from 'assets/icons/search.svg';
 import { applyModalSort, dataRanking } from '../../TravellersScreen/utils';
-import { RankingDropdown } from '../../TravellersScreen/utils/types';
+import { RankingDropdown, FilterModalRef } from '../../TravellersScreen/utils/types';
 import { Profile } from '../../MapScreen/UsersListScreen/Profile';
 import { FilterButton, FilterModal } from '../../TravellersScreen/Components/FilterModal';
 import { usePostGetCountriesRanking } from '@api/ranking';
@@ -28,7 +28,7 @@ const ParticipantsListScreen: FC<Props> = ({ navigation, route }) => {
   const [searchQuery, setSearchQuery] = useState('');
   const [filteredData, setFilteredData] = useState<any[]>([]);
   const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
-  const [isModalVisible, setModalVisible] = useState(false);
+  const filterRef = useRef<FilterModalRef>(null);
   const [modalState, setModalState] = useState({
     isWarningVisible: false,
     title: '',
@@ -84,8 +84,38 @@ const ParticipantsListScreen: FC<Props> = ({ navigation, route }) => {
     <PageWrapper>
       <Header
         label={interested ? 'Interested' : 'Going'}
-        rightElement={<FilterButton onPress={() => setModalVisible(!isModalVisible)} />}
+        rightElement={<FilterButton onPress={() => filterRef.current?.toggle()} />}
       />
+
+      <View style={{ zIndex: 100 }}>
+        <View
+          style={{
+            position: 'absolute',
+            top: 0,
+            left: -Dimensions.get('window').width * 0.05,
+            width: Dimensions.get('window').width,
+            height: Dimensions.get('window').height,
+            overflow: 'hidden'
+          }}
+          pointerEvents="box-none"
+        >
+          <FilterModal
+            ref={filterRef}
+            applyFilter={(filterAge, filterRanking, filterCountry) => {
+              setConfirmedValueRanking(filterRanking);
+              setFilteredData(
+                applyModalSort(
+                  allParticipants ?? [],
+                  filterAge,
+                  filterRanking ?? dataRanking[0],
+                  filterCountry
+                )
+              );
+            }}
+            countriesData={masterCountries ? masterCountries.data : []}
+          />
+        </View>
+      </View>
       <View style={styles.container}>
         <Input
           inputMode={'search'}
@@ -100,7 +130,6 @@ const ParticipantsListScreen: FC<Props> = ({ navigation, route }) => {
             itemVisiblePercentThreshold: 50,
             minimumViewTime: 1000
           }}
-          estimatedItemSize={50}
           data={filteredData || []}
           renderItem={({ item, index }) => (
             <Profile
@@ -150,24 +179,6 @@ const ParticipantsListScreen: FC<Props> = ({ navigation, route }) => {
           showsVerticalScrollIndicator={false}
         />
       </View>
-
-      <FilterModal
-        isModalVisible={isModalVisible}
-        setModalVisible={(value) => setModalVisible(value)}
-        applyFilter={(filterAge, filterRanking, filterCountry) => {
-          setConfirmedValueRanking(filterRanking);
-          setFilteredData(
-            applyModalSort(
-              allParticipants ?? [],
-              filterAge,
-              filterRanking ?? dataRanking[0],
-              filterCountry
-            )
-          );
-          setModalVisible(false);
-        }}
-        countriesData={masterCountries ? masterCountries.data : []}
-      />
       <OptionsModal />
       <WarningModal
         type={'delete'}