浏览代码

Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	src/screens/InAppScreens/TravellersScreen/Components/Profile.tsx
Oleksandr Honcharov 1 年之前
父节点
当前提交
54e853bb10

+ 97 - 0
src/components/WarningModal/index.tsx

@@ -0,0 +1,97 @@
+import React from 'react';
+import { Text, View, TouchableOpacity } from 'react-native';
+import Modal from 'react-native-modal';
+
+import { styles } from './styles';
+import CloseIcon from '../../../assets/icons/close.svg';
+import { Colors } from 'src/theme';
+
+import { useNavigation } from '@react-navigation/native';
+import { NAVIGATION_PAGES } from 'src/types';
+import { ButtonVariants } from 'src/types/components';
+import { Button } from '../Button';
+
+export const WarningModal = ({
+  isVisible,
+  onClose,
+  type
+}: {
+  isVisible: boolean;
+  onClose: () => void;
+  type: string;
+}) => {
+  const navigation = useNavigation();
+
+  const content = {
+    offline: {
+      message: 'Please check your Internet connection and try again.',
+      buttons: [{ text: 'OK', textColor: Colors.WHITE, color: Colors.DARK_BLUE, action: onClose }]
+    },
+    unauthorized: {
+      message: 'To use this feature you need to have an account with NomadMania.',
+      buttons: [
+        {
+          text: 'Login',
+          textColor: Colors.DARK_BLUE,
+          color: Colors.WHITE,
+          action: () => {
+            onClose();
+            navigation.navigate(NAVIGATION_PAGES.LOGIN as never);
+          }
+        },
+        {
+          text: 'Register',
+          textColor: Colors.WHITE,
+          color: Colors.DARK_BLUE,
+          action: () => {
+            onClose();
+            navigation.navigate(NAVIGATION_PAGES.REGISTER as never);
+          }
+        }
+      ]
+    }
+  };
+
+  const modalContent = content[type as keyof typeof content] || {};
+
+  return (
+    <Modal isVisible={isVisible}>
+      <View style={styles.centeredView}>
+        <View style={styles.modalView}>
+          <View style={{ alignSelf: 'flex-end' }}>
+            <TouchableOpacity onPress={onClose}>
+              <CloseIcon fill={Colors.LIGHT_GRAY} />
+            </TouchableOpacity>
+          </View>
+          <View style={styles.modalContent}>
+            <Text style={styles.modalTitle}>Oops!</Text>
+            <Text style={styles.modalText}>{modalContent.message}</Text>
+            <View style={styles.buttonContainer}>
+              {modalContent.buttons.map(
+                (
+                  button: { text: string; textColor: string; color: string; action: () => void },
+                  idx: number
+                ) => (
+                  <Button
+                    key={idx}
+                    variant={ButtonVariants.OPACITY}
+                    containerStyles={{
+                      borderColor: Colors.DARK_BLUE,
+                      backgroundColor: button.color,
+                      width: type === 'offline' ? '60%' : '45%'
+                    }}
+                    textStyles={{
+                      color: button.textColor
+                    }}
+                    onPress={button.action}
+                    children={button.text}
+                  />
+                )
+              )}
+            </View>
+          </View>
+        </View>
+      </View>
+    </Modal>
+  );
+};

+ 47 - 0
src/components/WarningModal/styles.tsx

@@ -0,0 +1,47 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'src/theme';
+
+export const styles = StyleSheet.create({
+  centeredView: {
+    backgroundColor: Colors.WHITE,
+    borderRadius: 15
+  },
+  modalView: {
+    marginLeft: '5%',
+    marginRight: '5%',
+    marginTop: '5%',
+    marginBottom: '5%',
+    shadowColor: 'rgba(0, 0, 0, 0.05)',
+    shadowOffset: {
+      width: 0,
+      height: 10
+    },
+    shadowOpacity: 0.05,
+    shadowRadius: 15,
+    elevation: 5
+  },
+  modalContent: {
+    display: 'flex',
+    alignItems: 'center'
+  },
+  modalTitle: {
+    marginBottom: 15,
+    textAlign: 'center',
+    fontWeight: 'bold',
+    fontSize: 18,
+    color: Colors.DARK_BLUE
+  },
+  modalText: {
+    marginBottom: 24,
+    textAlign: 'left',
+    color: Colors.DARK_BLUE,
+    fontWeight: '500',
+    fontSize: 14,
+    lineHeight: 20,
+  },
+  buttonContainer: {
+    flexDirection: 'row',
+    marginBottom: 20,
+    gap: 15
+  },
+});

+ 1 - 0
src/components/index.ts

@@ -13,3 +13,4 @@ export * from './Loading';
 export * from './MenuButton';
 export * from './AvatarWithInitials';
 export * from './Loading';
+export * from './WarningModal';

+ 14 - 2
src/screens/InAppScreens/MapScreen/index.tsx

@@ -17,7 +17,7 @@ import dareRegions from '../../../../assets/geojson/mqp.json';
 
 import NetInfo from '@react-native-community/netinfo';
 import { getFirstDatabase, getSecondDatabase } from '../../../db';
-import { LocationPopup, RegionPopup } from '../../../components';
+import { LocationPopup, RegionPopup, WarningModal } from '../../../components';
 
 import { styles } from './style';
 import {
@@ -77,6 +77,7 @@ const MapScreen: React.FC<MapScreenProps> = ({ navigation }) => {
   const [location, setLocation] = useState<Location.LocationObjectCoords | null>(null);
   const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
   const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
+  const [isWarningModalVisible, setIsWarningModalVisible] = useState<boolean>(false);
 
   const [markers, setMarkers] = useState<MarkerData[]>([]);
   const [clusters, setClusters] = useState<ClusterData | null>(null);
@@ -453,7 +454,13 @@ const MapScreen: React.FC<MapScreenProps> = ({ navigation }) => {
           <RegionPopup
             region={regionData}
             userAvatars={userAvatars}
-            onMarkVisited={() => console.log('Mark as visited')}
+            onMarkVisited={() => {
+              if (!token) {
+                setIsWarningModalVisible(true);
+              } else {
+                console.log('Mark as visited');
+              }
+            }}
           />
         </>
       ) : (
@@ -480,6 +487,11 @@ const MapScreen: React.FC<MapScreenProps> = ({ navigation }) => {
           </TouchableOpacity>
         </>
       )}
+      <WarningModal
+        type={'unauthorized'}
+        isVisible={isWarningModalVisible}
+        onClose={() => setIsWarningModalVisible(false)}
+      />
     </View>
   );
 };

+ 23 - 8
src/screens/InAppScreens/TravellersScreen/Components/Profile.tsx

@@ -1,4 +1,4 @@
-import React, { FC } from 'react';
+import React, { FC, useState } from 'react';
 import { Text, TouchableOpacity, View } from 'react-native';
 import { Image } from 'expo-image';
 import { useNavigation } from '@react-navigation/native';
@@ -6,8 +6,8 @@ import * as FileSystem from 'expo-file-system';
 
 import { ProfileStyles, ScoreStyles, TBTStyles } from './styles';
 
-import { getOnlineStatus } from 'src/storage';
-import { AvatarWithInitials } from 'src/components';
+import { getOnlineStatus, storage, StoreType } from 'src/storage';
+import { AvatarWithInitials, WarningModal } from 'src/components';
 
 import { API_HOST } from '../../../../constants';
 import { getFontSize } from '../../../../utils';
@@ -61,6 +61,18 @@ export const Profile: FC<Props> = ({
 
   const scoreNames = ['NM', 'DARE', 'UN', 'UN+', 'TCC', 'DEEP', 'YES', 'SLOW', 'WHS', 'KYE'];
   const isOnline = getOnlineStatus();
+  const token = storage.get('token', StoreType.STRING);
+  const [modalType, setModalType] = useState<string | null>(null);
+
+  const handlePress = () => {
+    if (!isOnline) {
+      setModalType('offline');
+    } else if (!token) {
+      setModalType('unauthorized');
+    } else {
+      navigation.navigate(...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId }] as never));
+    }
+  };
 
   const avatarBaseUri = isOnline
     ? `${API_HOST}/img/avatars/`
@@ -106,11 +118,7 @@ export const Profile: FC<Props> = ({
 
   return (
     <View>
-      <TouchableOpacity
-        onPress={() =>
-          navigation.navigate(...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId }] as never))
-        }
-      >
+      <TouchableOpacity onPress={() => handlePress()}>
         <View style={adaptiveStyle(ProfileStyles.profileRoot, {})}>
           <View style={{ paddingLeft: 20 }}>
             {index + 1 < 100 ? (
@@ -196,6 +204,13 @@ export const Profile: FC<Props> = ({
           })}
         </View>
       </View>
+      {modalType && (
+        <WarningModal
+          type={modalType}
+          isVisible={true}
+          onClose={() => setModalType(null)}
+        />
+      )}
     </View>
   );
 };