Browse Source

feat: Travellers Screens

Oleksandr Honcharov 1 year ago
parent
commit
780bc052e9

+ 28 - 1
Route.tsx

@@ -21,6 +21,11 @@ import TravellersScreen from './src/screens/InAppScreens/TravellersScreen';
 import { EditPersonalInfo } from './src/screens/InAppScreens/ProfileScreen/Profile/edit-personal-info';
 import Settings from './src/screens/InAppScreens/ProfileScreen/Settings/';
 
+import MasterRankingScreen from './src/screens/InAppScreens/TravellersScreen/MasterRankingScreen';
+import LPIRanking from './src/screens/InAppScreens/TravellersScreen/LPIRankingScreen';
+import InMemoriamScreen from './src/screens/InAppScreens/TravellersScreen/InMemoriamScreen';
+import InHistoryScreen from './src/screens/InAppScreens/TravellersScreen/InHistoryScreen';
+
 import { NAVIGATION_PAGES } from './src/types';
 import { storage, StoreType } from './src/storage';
 import { openDatabases } from './src/db';
@@ -105,7 +110,29 @@ const Route = () => {
         {() => (
           <BottomTab.Navigator screenOptions={screenOptions}>
             <BottomTab.Screen name={NAVIGATION_PAGES.MAP_TAB} component={MapScreen} />
-            <BottomTab.Screen name={NAVIGATION_PAGES.TRAVELLERS_TAB} component={TravellersScreen} />
+            <BottomTab.Screen name={NAVIGATION_PAGES.IN_APP_TRAVELLERS_TAB}>
+              {() => (
+                <ScreenStack.Navigator screenOptions={screenOptions}>
+                  <ScreenStack.Screen
+                    name={NAVIGATION_PAGES.TRAVELLERS_TAB}
+                    component={TravellersScreen}
+                  />
+                  <ScreenStack.Screen
+                    name={NAVIGATION_PAGES.MASTER_RANKING}
+                    component={MasterRankingScreen}
+                  />
+                  <ScreenStack.Screen name={NAVIGATION_PAGES.LPI_RANKING} component={LPIRanking} />
+                  <ScreenStack.Screen
+                    name={NAVIGATION_PAGES.IN_MEMORIAM}
+                    component={InMemoriamScreen}
+                  />
+                  <ScreenStack.Screen
+                    name={NAVIGATION_PAGES.IN_HISTORY}
+                    component={InHistoryScreen}
+                  />
+                </ScreenStack.Navigator>
+              )}
+            </BottomTab.Screen>
             <BottomTab.Screen name={NAVIGATION_PAGES.TRAVELS_TAB} component={TravelsScreen} />
             <BottomTab.Screen name={NAVIGATION_PAGES.IN_APP_PROFILE}>
               {() => (

File diff suppressed because it is too large
+ 2 - 0
assets/icons/nm_icon.svg


File diff suppressed because it is too large
+ 2 - 0
assets/icons/tick.svg


File diff suppressed because it is too large
+ 2 - 0
assets/icons/un_icon.svg


+ 1 - 1
src/components/TabBarButton/index.tsx

@@ -15,7 +15,7 @@ const getTabIcon = (routeName: string) => {
   switch (routeName) {
     case NAVIGATION_PAGES.MAP_TAB:
       return MapIcon;
-    case NAVIGATION_PAGES.TRAVELLERS_TAB:
+    case NAVIGATION_PAGES.IN_APP_TRAVELLERS_TAB:
       return TravellersIcon;
     case NAVIGATION_PAGES.TRAVELS_TAB:
       return GlobeIcon;

+ 130 - 0
src/screens/InAppScreens/TravellersScreen/Components/Profile.tsx

@@ -0,0 +1,130 @@
+import React, { FC } from 'react';
+import { Text, View } from 'react-native';
+import { Image } from 'expo-image';
+
+import { API_HOST } from '../../../../constants';
+import { styles } from './styles';
+import { getFontSize } from '../../../../utils';
+import { Colors } from '../../../../theme';
+
+import TickIcon from '../../../../../assets/icons/tick.svg';
+import UNIcon from '../../../../../assets/icons/un_icon.svg';
+import NMIcon from '../../../../../assets/icons/nm_icon.svg';
+
+type Props = {
+  avatar: string;
+  first_name: string;
+  last_name: string;
+  date_of_birth: number;
+  homebase_flag: string;
+  homebase2_flag: string;
+  index: number;
+  score: any[];
+  tbt_score: number;
+};
+
+//TODO: Profile
+export const Profile: FC<Props> = ({
+  avatar,
+  first_name,
+  last_name,
+  date_of_birth,
+  homebase_flag,
+  homebase2_flag,
+  index,
+  score,
+  tbt_score
+}) => {
+  const scoreNames = ['NM1301', 'DARE', 'UN', 'UN+', 'TCC', 'YES', 'SLOW', 'WHS', 'KYE'];
+
+  return (
+    <>
+      <View style={{ alignItems: 'center', flexDirection: 'row', gap: 10, marginBottom: 5 }}>
+        <View>
+          <Text style={styles.rankText}>{index + 1}</Text>
+        </View>
+        <View>
+          <Image
+            style={{ borderRadius: 24, width: 48, height: 48 }}
+            source={{ uri: API_HOST + '/img/avatars/' + avatar }}
+          />
+        </View>
+        <View style={{ gap: 5, width: '75%' }}>
+          <Text style={[styles.headerText, { fontSize: getFontSize(14), flex: 0 }]}>
+            {first_name} {last_name}
+          </Text>
+          <View style={{ display: 'flex', justifyContent: 'space-between', flexDirection: 'row' }}>
+            <View
+              style={{
+                display: 'flex',
+                flexDirection: 'row',
+                gap: 10,
+                alignItems: 'center'
+              }}
+            >
+              <Text
+                style={{ color: Colors.DARK_BLUE, fontWeight: '600', fontSize: getFontSize(12) }}
+              >
+                Age: {date_of_birth}
+              </Text>
+              <Image
+                source={{ uri: API_HOST + '/img/flags_new/' + homebase_flag }}
+                style={styles.countryFlag}
+              />
+              {homebase2_flag ? (
+                <Image
+                  source={{ uri: API_HOST + '/img/flags_new/' + homebase2_flag }}
+                  style={[styles.countryFlag, { marginLeft: -15 }]}
+                />
+              ) : null}
+              <View style={{ display: 'flex', flexDirection: 'row', gap: 10 }}>
+                <TickIcon />
+                <UNIcon />
+                <NMIcon />
+              </View>
+            </View>
+          </View>
+        </View>
+      </View>
+
+      <View
+        style={{
+          display: 'flex',
+          flexDirection: 'row',
+          justifyContent: 'space-evenly',
+          marginBottom: 15
+        }}
+      >
+        {/*TBT Score*/}
+        {/*<View*/}
+        {/*  style={{*/}
+        {/*    display: 'flex',*/}
+        {/*    marginTop: 10*/}
+        {/*  }}*/}
+        {/*>*/}
+        {/*  <View style={{ display: 'flex', alignItems: 'center' }}>*/}
+        {/*    <Text style={[styles.headerText, { flex: 0 }]}>Icon</Text>*/}
+        {/*    <Text style={[styles.titleText, { flex: 0 }]}>TBT #{tbt_score}</Text>*/}
+        {/*  </View>*/}
+        {/*</View>*/}
+
+        {score.map((number, index) => {
+          if (!number) return;
+          return (
+            <View
+              style={{
+                display: 'flex',
+                marginTop: 10
+              }}
+            >
+              <View style={{ display: 'flex', alignItems: 'center' }}>
+                <Text style={[styles.headerText, { flex: 0 }]}>{number}</Text>
+                <Text style={[styles.titleText, { flex: 0 }]}>{scoreNames[index]}</Text>
+              </View>
+            </View>
+          );
+        })}
+      </View>
+    </>
+  );
+};

+ 30 - 0
src/screens/InAppScreens/TravellersScreen/Components/styles.ts

@@ -0,0 +1,30 @@
+import { Colors } from '../../../../theme';
+import { StyleSheet } from 'react-native';
+import { getFontSize } from '../../../../utils';
+
+export const styles = StyleSheet.create({
+  rankText: {
+    fontSize: 18,
+    color: Colors.DARK_BLUE,
+    fontWeight: '700'
+  },
+  countryFlag: {
+    width: 20,
+    height: 20,
+    borderRadius: 20 / 2,
+    borderWidth: 0.5,
+    borderColor: 'gray'
+  },
+  headerText: {
+    flex: 1,
+    fontFamily: 'redhat-700',
+    color: Colors.DARK_BLUE,
+    fontSize: getFontSize(12)
+  },
+  titleText: {
+    flex: 1,
+    color: Colors.DARK_BLUE,
+    fontWeight: '600',
+    fontSize: getFontSize(11)
+  }
+});

+ 67 - 0
src/screens/InAppScreens/TravellersScreen/InHistoryScreen/index.tsx

@@ -0,0 +1,67 @@
+import React, { useEffect, useState } from 'react';
+import { Header, PageWrapper } from '../../../../components';
+import { storage, StoreType } from '../../../../storage';
+
+import { Profile } from '../Components/Profile';
+
+import { Ranking } from '../Ranking';
+import { FlatList } from 'react-native';
+import { fetchFullRanking } from '@api/ranking';
+
+const InHistoryScreen = () => {
+  const [historyRanking, setHistoryRanking] = useState<Ranking[]>([]);
+  const { mutateAsync } = fetchFullRanking();
+
+  const inHistory: string = storage.get('inHistoryRanking', StoreType.STRING) as string;
+
+  useEffect(() => {
+    setHistoryRanking(
+      JSON.parse(inHistory).sort((a: Ranking, b: Ranking) => b.score_nm - a.score_nm)
+    );
+  }, []);
+
+  const getFullRanking = async () => {
+    await mutateAsync(undefined, {
+      onSuccess: (data) => {
+        setHistoryRanking(data.data);
+      }
+    });
+  };
+
+  return (
+    <PageWrapper>
+      <Header label="In History" />
+      <FlatList
+        data={historyRanking}
+        keyExtractor={(item) => item.user_id.toString()}
+        renderItem={({ item, index }) => (
+          <Profile
+            index={index}
+            first_name={item.first_name}
+            last_name={item.last_name}
+            avatar={item.avatar}
+            date_of_birth={item.age}
+            homebase_flag={item.flag1}
+            homebase2_flag={item.flag2}
+            tbt_score={item.score_tbt}
+            score={[
+              item.score_nm,
+              item.score_dare,
+              item.score_un,
+              item.score_unp,
+              item.score_tcc,
+              item.score_yes,
+              item.score_slow,
+              item.score_whs,
+              item.score_kye
+            ]}
+          />
+        )}
+        onEndReached={() => getFullRanking()}
+        onEndReachedThreshold={0.1}
+      />
+    </PageWrapper>
+  );
+};
+
+export default InHistoryScreen;

+ 67 - 0
src/screens/InAppScreens/TravellersScreen/InMemoriamScreen/index.tsx

@@ -0,0 +1,67 @@
+import React, { useEffect, useState } from 'react';
+import { Header, PageWrapper } from '../../../../components';
+import { storage, StoreType } from '../../../../storage';
+
+import { Profile } from '../Components/Profile';
+
+import { Ranking } from '../Ranking';
+import { FlatList } from 'react-native';
+import { fetchFullRanking } from '@api/ranking';
+
+const InMemoriamScreen = () => {
+  const [memoriamRanking, setMemoriamRanking] = useState<Ranking[]>([]);
+  const { mutateAsync } = fetchFullRanking();
+
+  const inMemoriam: string = storage.get('inMemoriamRanking', StoreType.STRING) as string;
+
+  useEffect(() => {
+    setMemoriamRanking(
+      JSON.parse(inMemoriam).sort((a: Ranking, b: Ranking) => b.score_nm - a.score_nm)
+    );
+  }, []);
+
+  const getFullRanking = async () => {
+    await mutateAsync(undefined, {
+      onSuccess: (data) => {
+        setMemoriamRanking(data.data);
+      }
+    });
+  };
+
+  return (
+    <PageWrapper>
+      <Header label="In Memoriam" />
+      <FlatList
+        data={memoriamRanking}
+        keyExtractor={(item) => item.user_id.toString()}
+        renderItem={({ item, index }) => (
+          <Profile
+            index={index}
+            first_name={item.first_name}
+            last_name={item.last_name}
+            avatar={item.avatar}
+            date_of_birth={item.age}
+            homebase_flag={item.flag1}
+            homebase2_flag={item.flag2}
+            score={[
+              item.score_nm,
+              item.score_dare,
+              item.score_un,
+              item.score_unp,
+              item.score_tcc,
+              item.score_yes,
+              item.score_slow,
+              item.score_whs,
+              item.score_kye
+            ]}
+            tbt_score={item.score_tbt}
+          />
+        )}
+        onEndReached={() => getFullRanking()}
+        onEndReachedThreshold={0.1}
+      />
+    </PageWrapper>
+  );
+};
+
+export default InMemoriamScreen;

+ 65 - 0
src/screens/InAppScreens/TravellersScreen/LPIRankingScreen/index.tsx

@@ -0,0 +1,65 @@
+import React, { useEffect, useState } from 'react';
+import { Header, PageWrapper } from '../../../../components';
+import { storage, StoreType } from '../../../../storage';
+
+import { Profile } from '../Components/Profile';
+
+import { Ranking } from '../Ranking';
+import { FlatList } from 'react-native';
+import { fetchFullRanking } from '@api/ranking';
+
+const LPIRankingScreen = () => {
+  const [LPIRanking, setLPIRanking] = useState<Ranking[]>([]);
+  const { mutateAsync } = fetchFullRanking();
+
+  const lpi: string = storage.get('lpiRanking', StoreType.STRING) as string;
+
+  useEffect(() => {
+    setLPIRanking(JSON.parse(lpi).sort((a: Ranking, b: Ranking) => b.score_nm - a.score_nm));
+  }, []);
+
+  const getFullRanking = async () => {
+    await mutateAsync(undefined, {
+      onSuccess: (data) => {
+        setLPIRanking(data.data);
+      }
+    });
+  };
+
+  return (
+    <PageWrapper>
+      <Header label="LPI Ranking" />
+      <FlatList
+        data={LPIRanking}
+        keyExtractor={(item) => item.user_id.toString()}
+        renderItem={({ item, index }) => (
+          <Profile
+            index={index}
+            first_name={item.first_name}
+            last_name={item.last_name}
+            avatar={item.avatar}
+            date_of_birth={item.age}
+            homebase_flag={item.flag1}
+            homebase2_flag={item.flag2}
+            score={[
+              item.score_nm,
+              item.score_dare,
+              item.score_un,
+              item.score_unp,
+              item.score_tcc,
+              item.score_yes,
+              item.score_slow,
+              item.score_whs,
+              item.score_kye
+            ]}
+            tbt_score={item.score_tbt}
+          />
+        )}
+        onEndReached={() => getFullRanking()}
+        onEndReachedThreshold={0.1}
+      />
+    </PageWrapper>
+  );
+};
+
+export default LPIRankingScreen;

+ 65 - 0
src/screens/InAppScreens/TravellersScreen/MasterRankingScreen/index.tsx

@@ -0,0 +1,65 @@
+import React, { useEffect, useState } from 'react';
+import { Header, PageWrapper } from '../../../../components';
+import { storage, StoreType } from '../../../../storage';
+
+import { Profile } from '../Components/Profile';
+
+import { Ranking } from '../Ranking';
+import { FlatList } from 'react-native';
+import { fetchFullRanking } from '@api/ranking';
+
+const MasterRankingScreen = () => {
+  const [masterRanking, setMasterRanking] = useState<Ranking[]>([]);
+  const { mutateAsync } = fetchFullRanking();
+
+  const ranking = storage.get('masterRanking', StoreType.STRING) as string;
+
+  useEffect(() => {
+    setMasterRanking(JSON.parse(ranking).sort((a: Ranking, b: Ranking) => b.score_nm - a.score_nm));
+  }, []);
+
+  const getFullRanking = async () => {
+    await mutateAsync(undefined, {
+      onSuccess: (data) => {
+        setMasterRanking(data.data);
+      }
+    });
+  };
+
+  return (
+    <PageWrapper>
+      <Header label="Master Ranking" />
+      <FlatList
+        data={masterRanking}
+        keyExtractor={(item) => item.user_id.toString()}
+        renderItem={({ item, index }) => (
+          <Profile
+            index={index}
+            first_name={item.first_name}
+            last_name={item.last_name}
+            avatar={item.avatar}
+            date_of_birth={item.age}
+            homebase_flag={item.flag1}
+            homebase2_flag={item.flag2}
+            score={[
+              item.score_nm,
+              item.score_dare,
+              item.score_un,
+              item.score_unp,
+              item.score_tcc,
+              item.score_yes,
+              item.score_slow,
+              item.score_whs,
+              item.score_kye
+            ]}
+            tbt_score={item.score_tbt}
+          />
+        )}
+        onEndReached={() => getFullRanking()}
+        onEndReachedThreshold={0.8}
+      />
+    </PageWrapper>
+  );
+};
+
+export default MasterRankingScreen;

+ 19 - 5
src/screens/InAppScreens/TravellersScreen/index.tsx

@@ -14,10 +14,15 @@ import MemoriamIcon from '../../../../assets/icons/monument.svg';
 import ScrollIcon from '../../../../assets/icons/scroll.svg';
 import TrophyIcon from '../../../../assets/icons/trophy.svg';
 
+import { NAVIGATION_PAGES } from '../../../types';
+
 const buttons: MenuButtonType[] = [
   {
     label: 'Master Ranking',
-    icon: <UserGroupIcon fill={Colors.DARK_BLUE} width={20} height={20} />
+    icon: <UserGroupIcon fill={Colors.DARK_BLUE} width={20} height={20} />,
+    buttonFn: (navigation) => {
+      navigation.navigate(NAVIGATION_PAGES.MASTER_RANKING);
+    }
   },
   {
     label: 'UN Masters',
@@ -25,7 +30,10 @@ const buttons: MenuButtonType[] = [
   },
   {
     label: 'LPI Ranking',
-    icon: <IDCardIcon fill={Colors.DARK_BLUE} width={20} height={20} />
+    icon: <IDCardIcon fill={Colors.DARK_BLUE} width={20} height={20} />,
+    buttonFn: (navigation) => {
+      navigation.navigate(NAVIGATION_PAGES.LPI_RANKING);
+    }
   },
   {
     label: 'Series Ranking',
@@ -37,11 +45,17 @@ const buttons: MenuButtonType[] = [
   },
   {
     label: 'In Memoriam',
-    icon: <MemoriamIcon fill={Colors.DARK_BLUE} width={20} height={20} />
+    icon: <MemoriamIcon fill={Colors.DARK_BLUE} width={20} height={20} />,
+    buttonFn: (navigation) => {
+      navigation.navigate(NAVIGATION_PAGES.IN_MEMORIAM);
+    }
   },
   {
     label: 'In History',
-    icon: <ScrollIcon fill={Colors.DARK_BLUE} width={20} height={20} />
+    icon: <ScrollIcon fill={Colors.DARK_BLUE} width={20} height={20} />,
+    buttonFn: (navigation) => {
+      navigation.navigate(NAVIGATION_PAGES.IN_HISTORY);
+    }
   },
   {
     label: 'Triumphs',
@@ -53,7 +67,7 @@ const TravellersScreen = () => {
   return (
     <PageWrapper>
       {buttons.map((button) => (
-        <MenuButton label={button.label} icon={button.icon} />
+        <MenuButton label={button.label} icon={button.icon} buttonFn={button.buttonFn} />
       ))}
     </PageWrapper>
   );

+ 6 - 1
src/types/navigation.ts

@@ -8,7 +8,12 @@ export enum NAVIGATION_PAGES {
   IN_APP = 'inAppStack',
   MAP_TAB = 'Map',
   TRAVELS_TAB = 'Travels',
-  TRAVELLERS_TAB = 'Travellers',
+  IN_APP_TRAVELLERS_TAB = 'Travellers',
+  TRAVELLERS_TAB = 'inAppTravellers',
+  MASTER_RANKING = 'inAppMasterRanking',
+  LPI_RANKING = 'inAppLpiRanking',
+  IN_MEMORIAM = 'inAppInMemoriam',
+  IN_HISTORY = 'inAppInHistory',
   IN_APP_PROFILE = 'Profile',
   PROFILE_TAB = 'inAppProfile',
   EDIT_PERSONAL_INFO = 'editPersonalInfo',

Some files were not shown because too many files changed in this diff