Переглянути джерело

Merge branch 'dev' of https://git.nomadmania.travel/Viktoriia/nomadmania-app into notifications-test

Viktoriia 9 місяців тому
батько
коміт
0116f1fd8d

+ 2 - 0
Route.tsx

@@ -83,6 +83,7 @@ import CountryViewScreen from 'src/screens/InAppScreens/MapScreen/CountryViewScr
 import { userApi } from '@api/user';
 import axios from 'axios';
 import { useNotification } from 'src/contexts/NotificationContext';
+import PreviewScreen from 'src/screens/InAppScreens/ProfileScreen/ShareScreen';
 
 enableScreens();
 
@@ -275,6 +276,7 @@ const Route = () => {
             />
             <ScreenStack.Screen name={NAVIGATION_PAGES.SETTINGS} component={Settings} />
             <ScreenStack.Screen name={NAVIGATION_PAGES.MY_FRIENDS} component={MyFriendsScreen} />
+            <ScreenStack.Screen name={NAVIGATION_PAGES.SHARE_PROFILE} component={PreviewScreen} />
           </ScreenStack.Navigator>
         )}
       </BottomTab.Screen>

+ 10 - 0
assets/icons/share.svg

@@ -0,0 +1,10 @@
+<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_3959_35958)">
+<path d="M9.88281 0.366211C9.39453 -0.12207 8.60156 -0.12207 8.11328 0.366211L3.11328 5.36621C2.625 5.85449 2.625 6.64746 3.11328 7.13574C3.60156 7.62402 4.39453 7.62402 4.88281 7.13574L7.75 4.26855V12.499C7.75 13.1904 8.30859 13.749 9 13.749C9.69141 13.749 10.25 13.1904 10.25 12.499V4.26855L13.1172 7.13574C13.6055 7.62402 14.3984 7.62402 14.8867 7.13574C15.375 6.64746 15.375 5.85449 14.8867 5.36621L9.88672 0.366211H9.88281ZM2.75 13.749C2.75 13.0576 2.19141 12.499 1.5 12.499C0.808594 12.499 0.25 13.0576 0.25 13.749V16.249C0.25 18.3193 1.92969 19.999 4 19.999H14C16.0703 19.999 17.75 18.3193 17.75 16.249V13.749C17.75 13.0576 17.1914 12.499 16.5 12.499C15.8086 12.499 15.25 13.0576 15.25 13.749V16.249C15.25 16.9404 14.6914 17.499 14 17.499H4C3.30859 17.499 2.75 16.9404 2.75 16.249V13.749Z" fill="#0F3F4F"/>
+</g>
+<defs>
+<clipPath id="clip0_3959_35958">
+<rect width="17.5" height="20" fill="white" transform="translate(0.25)"/>
+</clipPath>
+</defs>
+</svg>

+ 2 - 0
package.json

@@ -67,8 +67,10 @@
     "react-native-safe-area-context": "4.6.3",
     "react-native-screens": "~3.22.0",
     "react-native-searchable-dropdown-kj": "^1.9.1",
+    "react-native-share": "^10.2.1",
     "react-native-svg": "13.9.0",
     "react-native-tab-view": "^3.5.2",
+    "react-native-view-shot": "^3.7.0",
     "react-native-walkthrough-tooltip": "^1.6.0",
     "yup": "^1.3.3",
     "zustand": "^4.4.7"

+ 140 - 0
src/screens/InAppScreens/ProfileScreen/ShareScreen/index.tsx

@@ -0,0 +1,140 @@
+import React, { useRef } from 'react';
+import { View, Text, Image, TouchableOpacity } from 'react-native';
+import ViewShot from 'react-native-view-shot';
+import Share from 'react-native-share';
+
+import { API_HOST } from 'src/constants';
+import { AvatarWithInitials, Header, PageWrapper } from 'src/components';
+import { adaptiveStyle, Colors } from 'src/theme';
+import { ProfileStyles } from '../../TravellersScreen/Components/styles';
+
+import Logo from 'assets/images/logo.svg';
+import TickIcon from 'assets/icons/tick.svg';
+import UNIcon from 'assets/icons/un_icon.svg';
+import NMIcon from 'assets/icons/nm_icon.svg';
+import { styles } from './styles';
+
+const PreviewScreen = ({ route }: { route: any }) => {
+  const data = route.params.data;
+  const viewShotRef = useRef<ViewShot>(null);
+
+  const handleCaptureAndShare = async () => {
+    if (viewShotRef.current && viewShotRef.current.capture) {
+      try {
+        const uri = await viewShotRef.current.capture();
+        if (uri) {
+          await Share.open({ url: uri });
+        }
+      } catch (error) {
+        console.error('Error capturing or sharing the view:', error);
+      }
+    }
+  };
+
+  return (
+    <PageWrapper>
+      <Header label={'Preview'} />
+
+      <View style={styles.container}>
+        <ViewShot ref={viewShotRef} style={styles.viewShot}>
+          <View style={styles.imageContainer}>
+            <View style={styles.imageWrapper}>
+              <Image
+                style={styles.usersMap}
+                source={{
+                  uri: `${API_HOST}/img/single_maps/${data.id}.png`
+                }}
+                resizeMode="cover"
+              />
+            </View>
+
+            <View style={styles.pageWrapper}>
+              <View style={styles.avatarWrapper}>
+                {data.avatar ? (
+                  <Image
+                    style={styles.avatar}
+                    source={{ uri: API_HOST + '/img/avatars/' + data.avatar }}
+                  />
+                ) : (
+                  <AvatarWithInitials
+                    text={`${data.first_name[0] ?? ''}${data.last_name[0] ?? ''}`}
+                    flag={API_HOST + '/img/flags_new/' + data.flag1}
+                    size={64}
+                    borderColor={Colors.WHITE}
+                  />
+                )}
+              </View>
+              <View style={styles.userInfoSection}>
+                <View style={styles.userNameSpacer} />
+                <View style={styles.nameRow}>
+                  <Text style={styles.headerText}>
+                    {data.first_name} {data.last_name}
+                  </Text>
+                </View>
+
+                <View style={styles.userInfo}>
+                  <View style={styles.flagsContainer}>
+                    <Image
+                      source={{ uri: API_HOST + '/img/flags_new/' + data.flag1 }}
+                      style={styles.countryFlag}
+                    />
+                    {data.flag2 && data.flag2 !== data.flag1 ? (
+                      <Image
+                        source={{ uri: API_HOST + '/img/flags_new/' + data.flag2 }}
+                        style={styles.additionalFlag}
+                      />
+                    ) : null}
+                    <View
+                      style={[adaptiveStyle(ProfileStyles.badgesWrapper, {}), { marginLeft: 12 }]}
+                    >
+                      {data.auth ? <TickIcon /> : null}
+                      {data.badge_un ? <UNIcon /> : null}
+                      {data.badge_nm ? <NMIcon /> : null}
+                    </View>
+                  </View>
+                </View>
+              </View>
+            </View>
+
+            <View style={styles.scoreContainer}>
+              <View style={styles.rankingItem}>
+                <View style={styles.rankingItemRow}>
+                  <Logo width={20} height={20} />
+                  <Text style={styles.rankingScore}>{data.scores?.rank_nm}</Text>
+                </View>
+
+                <View style={styles.rankingItemRow}>
+                  <Image
+                    source={{ uri: API_HOST + '/img/flags_new/' + data.flag1 }}
+                    style={styles.flagImage}
+                  />
+                  <Text style={styles.rankingScore}>{data.scores?.rank_country}</Text>
+                </View>
+              </View>
+
+              <View style={styles.rankingItem}>
+                <Text style={styles.rankingScore}>{data.scores.score_nm}</Text>
+                <Text style={styles.titleText}>NM</Text>
+              </View>
+
+              <View style={styles.rankingItem}>
+                <Text style={styles.rankingScore}>{data.scores.score_un}</Text>
+                <Text style={styles.titleText}>UN</Text>
+              </View>
+            </View>
+
+            <View style={styles.nomadManiaContainer}>
+              <Text style={styles.nomadManiaText}>NomadMania.com</Text>
+            </View>
+          </View>
+        </ViewShot>
+      </View>
+
+      <TouchableOpacity style={styles.shareButton} onPress={handleCaptureAndShare}>
+        <Text style={styles.shareButtonText}>Share</Text>
+      </TouchableOpacity>
+    </PageWrapper>
+  );
+};
+
+export default PreviewScreen;

+ 168 - 0
src/screens/InAppScreens/ProfileScreen/ShareScreen/styles.tsx

@@ -0,0 +1,168 @@
+import { Dimensions, StyleSheet } from 'react-native';
+import { Colors } from 'src/theme';
+import { getFontSize } from 'src/utils';
+
+const screenWidth = Dimensions.get('window').width;
+const IMAGE_HEIGHT = screenWidth * 0.75;
+
+export const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    justifyContent: 'center',
+    alignItems: 'center'
+  },
+  viewShot: {
+    backgroundColor: 'transparent',
+    height: IMAGE_HEIGHT,
+    width: screenWidth,
+    alignItems: 'center'
+  },
+  imageContainer: {
+    width: screenWidth,
+    alignItems: 'center',
+    backgroundColor: Colors.WHITE,
+    borderWidth: 2,
+    borderColor: Colors.FILL_LIGHT,
+    borderRadius: 16,
+    height: IMAGE_HEIGHT
+  },
+  imageWrapper: {
+    height: IMAGE_HEIGHT * 0.44,
+    width: screenWidth - 4,
+    overflow: 'hidden',
+    backgroundColor: '#EBF2F5',
+    borderTopLeftRadius: 14,
+    borderTopRightRadius: 14,
+    alignItems: 'flex-start'
+  },
+  usersMap: {
+    width: '100%',
+    height: '120%'
+  },
+  pageWrapper: {
+    flexDirection: 'row',
+    gap: 12,
+    marginTop: -34
+  },
+  avatarWrapper: {
+    gap: 8
+  },
+  avatar: {
+    borderRadius: 64 / 2,
+    width: 64,
+    height: 64,
+    borderWidth: 2,
+    borderColor: Colors.WHITE
+  },
+  userInfoSection: {
+    gap: 5,
+    flex: 1
+  },
+  userNameSpacer: {
+    height: 34
+  },
+  nameRow: {
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    alignItems: 'center'
+  },
+  headerText: {
+    flex: 1,
+    fontFamily: 'redhat-700',
+    color: Colors.DARK_BLUE,
+    fontSize: screenWidth > 330 ? getFontSize(18) : getFontSize(16)
+  },
+  userInfo: {
+    flexDirection: 'row',
+    gap: 10,
+    alignItems: 'center',
+    justifyContent: 'space-between'
+  },
+  flagsContainer: {
+    flexDirection: 'row'
+  },
+  countryFlag: {
+    width: 20,
+    height: 20,
+    borderRadius: 10,
+    borderWidth: 0.5,
+    borderColor: Colors.BORDER_LIGHT
+  },
+  additionalFlag: {
+    marginLeft: -7,
+    width: 20,
+    height: 20,
+    borderRadius: 10,
+    borderWidth: 0.5,
+    borderColor: Colors.BORDER_LIGHT
+  },
+  scoreContainer: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    marginTop: 12,
+    justifyContent: 'space-around',
+    width: '100%'
+  },
+  rankingItem: {
+    width: '31%',
+    flexDirection: 'column',
+    alignItems: 'center',
+    justifyContent: 'center',
+    backgroundColor: Colors.FILL_LIGHT,
+    borderRadius: 10,
+    padding: 4,
+    gap: 4,
+    height: IMAGE_HEIGHT / 5.5
+  },
+  rankingItemRow: {
+    flexDirection: 'row',
+    gap: 4,
+    alignItems: 'center'
+  },
+  rankingScore: {
+    fontFamily: 'montserrat-700',
+    color: Colors.DARK_BLUE,
+    fontSize: getFontSize(16)
+  },
+  flagImage: {
+    borderRadius: 0,
+    height: 15,
+    width: 20,
+    borderWidth: 0.5,
+    borderColor: Colors.BORDER_LIGHT
+  },
+  titleText: {
+    color: Colors.DARK_BLUE,
+    fontWeight: '600',
+    fontSize: getFontSize(16)
+  },
+  nomadManiaContainer: {
+    flex: 1,
+    justifyContent: 'center',
+    alignItems: 'center'
+  },
+  nomadManiaText: {
+    color: Colors.ORANGE,
+    fontWeight: '700',
+    fontSize: 16,
+    textAlign: 'center'
+  },
+  shareButton: {
+    paddingVertical: 12,
+    borderRadius: 4,
+    alignItems: 'center',
+    justifyContent: 'center',
+    paddingHorizontal: 16,
+    gap: 4,
+    borderWidth: 1,
+    backgroundColor: Colors.ORANGE,
+    borderColor: Colors.ORANGE,
+    marginVertical: 8
+  },
+  shareButtonText: {
+    fontSize: getFontSize(14),
+    fontWeight: 'bold',
+    fontFamily: 'redhat-700',
+    color: Colors.WHITE
+  }
+});

+ 41 - 11
src/screens/InAppScreens/ProfileScreen/index.tsx

@@ -31,6 +31,7 @@ import TickIcon from '../../../../assets/icons/tick.svg';
 import UNIcon from '../../../../assets/icons/un_icon.svg';
 import NMIcon from '../../../../assets/icons/nm_icon.svg';
 import ChevronIcon from '../../../../assets/icons/chevron-left.svg';
+import ShareIcon from '../../../../assets/icons/share.svg';
 
 import { ProfileStyles, ScoreStyles, TBTStyles } from '../TravellersScreen/Components/styles';
 import UnauthenticatedProfileScreen from './UnauthenticatedProfileScreen';
@@ -258,17 +259,46 @@ const ProfileScreen: FC<Props> = ({ navigation, route }) => {
               </View>
 
               {data.own_profile === 1 ? (
-                <TouchableOpacity
-                  style={styles.settings}
-                  onPress={() => navigation.navigate(NAVIGATION_PAGES.EDIT_PERSONAL_INFO)}
-                >
-                  <GearIcon
-                    width={20}
-                    height={20}
-                    fill={Colors.DARK_BLUE}
-                    style={{ alignSelf: 'center' }}
-                  />
-                </TouchableOpacity>
+                <>
+                  <TouchableOpacity
+                    style={[styles.settings, { right: 25 }]}
+                    onPress={() =>
+                      navigation.navigate(NAVIGATION_PAGES.SHARE_PROFILE, {
+                        data: {
+                          avatar: data.user_data.avatar,
+                          first_name: data.user_data.first_name,
+                          last_name: data.user_data.last_name,
+                          flag1: data.user_data.flag1,
+                          flag2: data.user_data.flag2,
+                          id: +currentUserId,
+                          auth: data.user_data.auth,
+                          badge_un: data.user_data.badge_un,
+                          badge_nm: data.user_data.badge_nm,
+                          scores: data.scores
+                        }
+                      })
+                    }
+                  >
+                    <ShareIcon
+                      width={20}
+                      height={20}
+                      fill={Colors.DARK_BLUE}
+                      style={{ alignSelf: 'center' }}
+                    />
+                  </TouchableOpacity>
+                  
+                  <TouchableOpacity
+                    style={styles.settings}
+                    onPress={() => navigation.navigate(NAVIGATION_PAGES.EDIT_PERSONAL_INFO)}
+                  >
+                    <GearIcon
+                      width={20}
+                      height={20}
+                      fill={Colors.DARK_BLUE}
+                      style={{ alignSelf: 'center' }}
+                    />
+                  </TouchableOpacity>
+                </>
               ) : null}
             </View>
 

+ 2 - 1
src/types/navigation.ts

@@ -60,5 +60,6 @@ export enum NAVIGATION_PAGES {
   MENU_DRAWER = 'Menu',
   FIXERS = 'inAppFixers',
   ADD_FIXER = 'inAppAddFixer',
-  FIXERS_COMMENTS = 'inAppFixersComments'
+  FIXERS_COMMENTS = 'inAppFixersComments',
+  SHARE_PROFILE = 'inAppShareProfile',
 }