|
@@ -1,7 +1,6 @@
|
|
|
-import React, { useEffect, useState } from 'react';
|
|
|
-import { View, Text, TouchableOpacity, Image } from 'react-native';
|
|
|
+import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
+import { View, Text, TouchableOpacity, Image, Dimensions } from 'react-native';
|
|
|
import { TabView, TabBar } from 'react-native-tab-view';
|
|
|
-import ReactModal from 'react-native-modal';
|
|
|
import { FlashList } from '@shopify/flash-list';
|
|
|
import { useNavigation } from '@react-navigation/native';
|
|
|
|
|
@@ -10,8 +9,27 @@ import { styles } from './styles';
|
|
|
import { NAVIGATION_PAGES } from 'src/types';
|
|
|
import { API_HOST } from 'src/constants';
|
|
|
import { Loading, WarningModal } from 'src/components';
|
|
|
-import { StoreType, storage } from 'src/storage';
|
|
|
import MessagesDot from 'src/components/MessagesDot';
|
|
|
+import ActionSheet, { ActionSheetRef } from 'react-native-actions-sheet';
|
|
|
+
|
|
|
+export function TabViewDelayed({
|
|
|
+ children,
|
|
|
+ waitBeforeShow = 0
|
|
|
+}: {
|
|
|
+ children: React.ReactNode;
|
|
|
+ waitBeforeShow?: number;
|
|
|
+}) {
|
|
|
+ const [isShown, setIsShown] = useState(false);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const timer = setTimeout(() => {
|
|
|
+ setIsShown(true);
|
|
|
+ }, waitBeforeShow);
|
|
|
+ return () => clearTimeout(timer);
|
|
|
+ }, [waitBeforeShow]);
|
|
|
+
|
|
|
+ return isShown ? children : null;
|
|
|
+}
|
|
|
|
|
|
const SearchModal = ({
|
|
|
searchVisible,
|
|
@@ -31,6 +49,9 @@ const SearchModal = ({
|
|
|
token: string | undefined;
|
|
|
}) => {
|
|
|
const navigation = useNavigation();
|
|
|
+ const actionSheetRef = useRef<ActionSheetRef>(null);
|
|
|
+ const modalHeight = Dimensions.get('window').height * 0.75;
|
|
|
+
|
|
|
const [routes] = useState([
|
|
|
{ key: 'users', title: 'Nomads' },
|
|
|
{ key: 'regions', title: 'NM regions' },
|
|
@@ -42,6 +63,16 @@ const SearchModal = ({
|
|
|
} | null>(null);
|
|
|
const [warningVisible, setWarningVisible] = useState(false);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (searchVisible) {
|
|
|
+ actionSheetRef.current?.show();
|
|
|
+ } else {
|
|
|
+ if (actionSheetRef.current?.isOpen()) {
|
|
|
+ actionSheetRef.current?.hide();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [searchVisible]);
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
if (!searchData) return;
|
|
|
|
|
@@ -56,85 +87,88 @@ const SearchModal = ({
|
|
|
}
|
|
|
}, [searchData]);
|
|
|
|
|
|
- const renderItem = ({ item }: { item: any }) => {
|
|
|
- const [name, ...rest] = item.name?.split(/ – | - /);
|
|
|
- const subname = rest?.join(' - ');
|
|
|
+ const renderItem = useCallback(
|
|
|
+ ({ item }: { item: any }) => {
|
|
|
+ const [name, ...rest] = item.name?.split(/ – | - /);
|
|
|
+ const subname = rest?.join(' - ');
|
|
|
|
|
|
- return index === 0 ? (
|
|
|
- <TouchableOpacity
|
|
|
- style={{ paddingVertical: 12 }}
|
|
|
- onPress={() => {
|
|
|
- if (!token) {
|
|
|
- setWarningVisible(true);
|
|
|
- } else {
|
|
|
- handleCloseModal();
|
|
|
- navigation.navigate(
|
|
|
- ...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId: item.id }] as never)
|
|
|
- );
|
|
|
- }
|
|
|
- }}
|
|
|
- >
|
|
|
- <View style={styles.container}>
|
|
|
- <Image
|
|
|
- source={
|
|
|
- item.avatar
|
|
|
- ? { uri: API_HOST + item.avatar }
|
|
|
- : require('../../../../../assets/logo-ua.png')
|
|
|
+ return index === 0 ? (
|
|
|
+ <TouchableOpacity
|
|
|
+ style={{ paddingVertical: 12 }}
|
|
|
+ onPress={() => {
|
|
|
+ if (!token) {
|
|
|
+ setWarningVisible(true);
|
|
|
+ } else {
|
|
|
+ handleCloseModal();
|
|
|
+ navigation.navigate(
|
|
|
+ ...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId: item.id }] as never)
|
|
|
+ );
|
|
|
}
|
|
|
- style={styles.img}
|
|
|
- />
|
|
|
- <View style={styles.textContainer}>
|
|
|
- <Text style={styles.title}>{item.name}</Text>
|
|
|
- <View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
|
- <Image source={{ uri: API_HOST + item.flag1 }} style={styles.flagSmall} />
|
|
|
- {item.flag2 && item.flag2 !== item.flag1 && (
|
|
|
- <Image
|
|
|
- source={{ uri: API_HOST + item.flag2 }}
|
|
|
- style={[
|
|
|
- styles.flagSmall,
|
|
|
- {
|
|
|
- marginLeft: -6
|
|
|
- }
|
|
|
- ]}
|
|
|
- />
|
|
|
- )}
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- </TouchableOpacity>
|
|
|
- ) : (
|
|
|
- <TouchableOpacity
|
|
|
- style={{ paddingVertical: 12 }}
|
|
|
- onPress={() => {
|
|
|
- handleCloseModal();
|
|
|
- if (index === 1) {
|
|
|
- setShouldOpenModal({ id: item.id, type: 'regions' });
|
|
|
- } else {
|
|
|
- setShouldOpenModal({ id: item.id, type: 'places' });
|
|
|
- }
|
|
|
- }}
|
|
|
- >
|
|
|
- <View style={styles.container}>
|
|
|
- {item.flag1 && <Image source={{ uri: API_HOST + item.flag1 }} style={styles.img} />}
|
|
|
- {item.flag2 && (
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <View style={styles.container}>
|
|
|
<Image
|
|
|
- source={{ uri: API_HOST + item.flag2 }}
|
|
|
- style={[
|
|
|
- styles.img,
|
|
|
- {
|
|
|
- marginLeft: -20
|
|
|
- }
|
|
|
- ]}
|
|
|
+ source={
|
|
|
+ item.avatar
|
|
|
+ ? { uri: API_HOST + item.avatar }
|
|
|
+ : require('../../../../../assets/logo-ua.png')
|
|
|
+ }
|
|
|
+ style={styles.img}
|
|
|
/>
|
|
|
- )}
|
|
|
- <View style={styles.textContainer}>
|
|
|
- <Text style={styles.title}>{name}</Text>
|
|
|
- <Text style={styles.subTitle}>{subname}</Text>
|
|
|
+ <View style={styles.textContainer}>
|
|
|
+ <Text style={styles.title}>{item.name}</Text>
|
|
|
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
|
+ <Image source={{ uri: API_HOST + item.flag1 }} style={styles.flagSmall} />
|
|
|
+ {item.flag2 && item.flag2 !== item.flag1 && (
|
|
|
+ <Image
|
|
|
+ source={{ uri: API_HOST + item.flag2 }}
|
|
|
+ style={[
|
|
|
+ styles.flagSmall,
|
|
|
+ {
|
|
|
+ marginLeft: -6
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
</View>
|
|
|
- </View>
|
|
|
- </TouchableOpacity>
|
|
|
- );
|
|
|
- };
|
|
|
+ </TouchableOpacity>
|
|
|
+ ) : (
|
|
|
+ <TouchableOpacity
|
|
|
+ style={{ paddingVertical: 12 }}
|
|
|
+ onPress={() => {
|
|
|
+ handleCloseModal();
|
|
|
+ if (index === 1) {
|
|
|
+ setShouldOpenModal({ id: item.id, type: 'regions' });
|
|
|
+ } else {
|
|
|
+ setShouldOpenModal({ id: item.id, type: 'places' });
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <View style={styles.container}>
|
|
|
+ {item.flag1 && <Image source={{ uri: API_HOST + item.flag1 }} style={styles.img} />}
|
|
|
+ {item.flag2 && (
|
|
|
+ <Image
|
|
|
+ source={{ uri: API_HOST + item.flag2 }}
|
|
|
+ style={[
|
|
|
+ styles.img,
|
|
|
+ {
|
|
|
+ marginLeft: -20
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ <View style={styles.textContainer}>
|
|
|
+ <Text style={styles.title}>{name}</Text>
|
|
|
+ <Text style={styles.subTitle}>{subname}</Text>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </TouchableOpacity>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ [index]
|
|
|
+ );
|
|
|
|
|
|
const renderScene = ({ route }: { route: any }) => {
|
|
|
return (
|
|
@@ -167,50 +201,54 @@ const SearchModal = ({
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
- <ReactModal
|
|
|
- isVisible={searchVisible}
|
|
|
- onBackdropPress={handleCloseModal}
|
|
|
- onBackButtonPress={handleCloseModal}
|
|
|
- style={styles.modal}
|
|
|
- statusBarTranslucent={true}
|
|
|
- presentationStyle="overFullScreen"
|
|
|
- onModalHide={() => {
|
|
|
+ <ActionSheet
|
|
|
+ ref={actionSheetRef}
|
|
|
+ onClose={() => {
|
|
|
+ handleCloseModal();
|
|
|
if (shouldOpenModal) {
|
|
|
handleFindRegion(shouldOpenModal.id, shouldOpenModal.type);
|
|
|
setShouldOpenModal(null);
|
|
|
}
|
|
|
}}
|
|
|
+ containerStyle={styles.modal}
|
|
|
+ gestureEnabled={false}
|
|
|
+ defaultOverlayOpacity={0.5}
|
|
|
>
|
|
|
- <View style={styles.modalContainer}>
|
|
|
- <TabView
|
|
|
- navigationState={{ index, routes }}
|
|
|
- renderScene={renderScene}
|
|
|
- onIndexChange={setIndex}
|
|
|
- lazy={true}
|
|
|
- renderTabBar={(props) => (
|
|
|
- <TabBar
|
|
|
- {...props}
|
|
|
- indicatorStyle={{ backgroundColor: Colors.DARK_BLUE }}
|
|
|
- style={styles.tabBar}
|
|
|
- tabStyle={styles.tabStyle}
|
|
|
- pressColor={'transparent'}
|
|
|
- renderLabel={({ route, focused }) => (
|
|
|
- <Text
|
|
|
- style={[styles.tabLabel, { color: Colors.DARK_BLUE, opacity: focused ? 1 : 0.4 }]}
|
|
|
- >
|
|
|
- {route.title}
|
|
|
- </Text>
|
|
|
- )}
|
|
|
- renderBadge={({ route }) =>
|
|
|
- searchData?.[route.key] && searchData?.[route.key].length > 0 ? (
|
|
|
- <MessagesDot messagesCount={searchData?.[route.key].length} top={4} />
|
|
|
- ) : null
|
|
|
- }
|
|
|
- />
|
|
|
- )}
|
|
|
- />
|
|
|
+ <View style={[styles.modalContainer, { height: modalHeight }]}>
|
|
|
+ <TabViewDelayed>
|
|
|
+ <TabView
|
|
|
+ navigationState={{ index, routes }}
|
|
|
+ renderScene={renderScene}
|
|
|
+ onIndexChange={setIndex}
|
|
|
+ lazy={true}
|
|
|
+ renderTabBar={(props) => (
|
|
|
+ <TabBar
|
|
|
+ {...props}
|
|
|
+ indicatorStyle={{ backgroundColor: Colors.DARK_BLUE }}
|
|
|
+ style={styles.tabBar}
|
|
|
+ tabStyle={styles.tabStyle}
|
|
|
+ pressColor={'transparent'}
|
|
|
+ renderLabel={({ route, focused }) => (
|
|
|
+ <Text
|
|
|
+ style={[
|
|
|
+ styles.tabLabel,
|
|
|
+ { color: Colors.DARK_BLUE, opacity: focused ? 1 : 0.4 }
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ {route.title}
|
|
|
+ </Text>
|
|
|
+ )}
|
|
|
+ renderBadge={({ route }) =>
|
|
|
+ searchData?.[route.key] && searchData?.[route.key].length > 0 ? (
|
|
|
+ <MessagesDot messagesCount={searchData?.[route.key].length} top={4} />
|
|
|
+ ) : null
|
|
|
+ }
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ </TabViewDelayed>
|
|
|
</View>
|
|
|
- </ReactModal>
|
|
|
+ </ActionSheet>
|
|
|
);
|
|
|
};
|
|
|
|