Ver Fonte

feat: v1 sorting | needs refactor

Oleksandr Honcharov há 1 ano atrás
pai
commit
c0201e881f

Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
assets/icons/filter.svg


+ 2 - 0
package.json

@@ -44,11 +44,13 @@
     "react-native-keyboard-aware-scroll-view": "^0.9.5",
     "react-native-maps": "1.7.1",
     "react-native-mmkv": "^2.11.0",
+    "react-native-modal": "^13.0.1",
     "react-native-pager-view": "6.2.0",
     "react-native-reanimated": "~3.3.0",
     "react-native-render-html": "^6.3.4",
     "react-native-safe-area-context": "4.6.3",
     "react-native-screens": "~3.22.0",
+    "react-native-searchable-dropdown-kj": "^1.9.1",
     "react-native-svg": "13.9.0",
     "react-native-tab-view": "^3.5.2",
     "yup": "^1.3.3",

+ 37 - 10
src/components/Button/index.tsx

@@ -1,4 +1,4 @@
-import React, { FC, ReactNode } from 'react';
+import React, { CSSProperties, FC, ReactNode } from 'react';
 import { Text, TouchableOpacity } from 'react-native';
 
 import { styles } from './styles';
@@ -8,15 +8,27 @@ type Props = {
   children?: ReactNode;
   variant?: ButtonVariants;
   onPress?: () => void;
+  containerStyles?: CSSProperties;
+  textStyles?: CSSProperties;
 };
 
-export const Button: FC<Props> = ({ children, variant, onPress }) => {
+export const Button: FC<Props> = ({ children, variant, onPress, containerStyles, textStyles }) => {
   return (
     <>
       {variant === ButtonVariants.OPACITY ? (
-        <OpacityButton onPress={onPress} children={children} />
+        <OpacityButton
+          onPress={onPress}
+          children={children}
+          containerStyles={containerStyles}
+          textStyles={textStyles}
+        />
       ) : variant === ButtonVariants.FILL ? (
-        <FillButton onPress={onPress} children={children} />
+        <FillButton
+          onPress={onPress}
+          children={children}
+          containerStyles={containerStyles}
+          textStyles={textStyles}
+        />
       ) : variant == ButtonVariants.TEXT ? (
         <TextButton children={children} onPress={onPress} />
       ) : (
@@ -29,17 +41,32 @@ export const Button: FC<Props> = ({ children, variant, onPress }) => {
 type VariantProps = {
   children?: ReactNode;
   onPress?: () => void;
+  containerStyles?: CSSProperties | {};
+  textStyles?: CSSProperties | {};
 };
 
-const OpacityButton: FC<VariantProps> = ({ onPress, children }) => (
-  <TouchableOpacity style={[styles.button, styles.opacityButton]} onPress={onPress}>
-    <Text style={[styles.text, styles.opacityText]}>{children}</Text>
+const OpacityButton: FC<VariantProps> = ({
+  onPress,
+  children,
+  containerStyles = {},
+  textStyles = {}
+}) => (
+  <TouchableOpacity
+    style={[styles.button, styles.opacityButton, containerStyles]}
+    onPress={onPress}
+  >
+    <Text style={[styles.text, styles.opacityText, textStyles]}>{children}</Text>
   </TouchableOpacity>
 );
 
-const FillButton: FC<VariantProps> = ({ onPress, children }) => (
-  <TouchableOpacity style={[styles.button, styles.fillButton]} onPress={onPress}>
-    <Text style={[styles.text, styles.fillText]}>{children}</Text>
+const FillButton: FC<VariantProps> = ({
+  onPress,
+  children,
+  containerStyles = {},
+  textStyles = {}
+}) => (
+  <TouchableOpacity style={[styles.button, styles.fillButton, containerStyles]} onPress={onPress}>
+    <Text style={[styles.text, styles.fillText, textStyles]}>{children}</Text>
   </TouchableOpacity>
 );
 

+ 4 - 5
src/components/Header/index.tsx

@@ -1,4 +1,4 @@
-import React, { FC } from 'react';
+import React, { FC, ReactNode } from 'react';
 import { Text, TouchableOpacity, View } from 'react-native';
 import { useNavigation } from '@react-navigation/native';
 
@@ -8,9 +8,10 @@ import ChevronLeft from '../../../assets/icons/chevron-left.svg';
 
 type Props = {
   label: string;
+  rightElement?: ReactNode;
 };
 
-export const Header: FC<Props> = ({ label }) => {
+export const Header: FC<Props> = ({ label, rightElement }) => {
   const navigation = useNavigation();
 
   // navigation.setOptions() TODO
@@ -23,9 +24,7 @@ export const Header: FC<Props> = ({ label }) => {
         </View>
       </TouchableOpacity>
       <Text style={styles.label}>{label}</Text>
-      <View>
-        <Text>Text</Text>
-      </View>
+      <View>{rightElement ? rightElement : <Text>Text</Text>}</View>
     </View>
   );
 };

+ 1 - 0
src/modules/api/user/queries/index.ts

@@ -1,3 +1,4 @@
 export * from './use-post-get-profile';
 export * from './use-post-set-profile';
 export * from './use-post-get-profile-info';
+export * from './use-post-get-profile-info-public';

+ 17 - 0
src/modules/api/user/queries/use-post-get-profile-info-public.tsx

@@ -0,0 +1,17 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { userQueryKeys } from '../user-query-keys';
+import { type PostGetProfileInfoReturn, userApi } from '../user-api';
+
+import type { BaseAxiosError } from '../../../../types';
+
+export const usePostGetProfileInfoPublicQuery = (userId: number, enabled: boolean) => {
+  return useQuery<Exclude<PostGetProfileInfoReturn, { email: null }>, BaseAxiosError>({
+    queryKey: userQueryKeys.getProfileInfoPublic(),
+    queryFn: async () => {
+      const response = await userApi.getProfileInfoPublic(userId);
+      return response.data;
+    },
+    enabled
+  });
+};

+ 6 - 1
src/modules/api/user/user-api.tsx

@@ -111,5 +111,10 @@ export const userApi = {
 
     return request.postForm<PostSetProfileDataReturn>(API.SET_USER_SETTINGS_DATA, formData);
   },
-  getProfileInfo: (token: string) => request.postForm<PostGetProfileInfoReturn>(API.PROFILE_INFO)
+  getProfileInfo: (token: string) =>
+    request.postForm<PostGetProfileInfoReturn>(API.PROFILE_INFO, { token }),
+  getProfileInfoPublic: (uid: number) =>
+    request.postForm<Exclude<PostGetProfileInfoReturn, { email: null }>>(API.PROFILE_INFO_PUBLIC, {
+      uid
+    })
 };

+ 2 - 1
src/modules/api/user/user-query-keys.tsx

@@ -1,5 +1,6 @@
 export const userQueryKeys = {
   getProfileData: () => ['getProfileData'] as const,
   setProfileData: () => ['setProfileData'] as const,
-  getProfileInfo: () => ['getProfileInfo'] as const
+  getProfileInfo: () => ['getProfileInfo'] as const,
+  getProfileInfoPublic: () => ['getProfileInfoPublic'] as const
 };

+ 48 - 38
src/screens/InAppScreens/TravellersScreen/Components/Profile.tsx

@@ -1,5 +1,5 @@
 import React, { FC } from 'react';
-import { Text, View } from 'react-native';
+import { Text, TouchableOpacity, View } from 'react-native';
 import { Image } from 'expo-image';
 
 import { API_HOST } from '../../../../constants';
@@ -14,6 +14,8 @@ import TBTIcon from '../../../../../assets/icons/tbt.svg';
 import { getOnlineStatus } from 'src/storage';
 import * as FileSystem from 'expo-file-system';
 import { AvatarWithInitials } from 'src/components';
+import { useNavigation } from '@react-navigation/native';
+import { NAVIGATION_PAGES } from '../../../../types';
 
 type Props = {
   avatar: string;
@@ -30,6 +32,7 @@ type Props = {
   badge_1281: number;
   badge_un: number;
   auth: number;
+  userId: number;
 };
 
 //TODO: Profile
@@ -47,9 +50,12 @@ export const Profile: FC<Props> = ({
   badge_tbt,
   badge_1281,
   badge_un,
-  auth
+  auth,
+  userId
 }) => {
-  const scoreNames = ['NM1301', 'DARE', 'UN', 'UN+', 'TCC', 'YES', 'SLOW', 'WHS', 'KYE'];
+  const navigation = useNavigation();
+
+  const scoreNames = ['DARE', 'UN', 'UN+', 'TCC', 'YES', 'SLOW', 'WHS', 'KYE'];
   const isOnline = getOnlineStatus();
   const avatarBaseUri = isOnline
     ? `${API_HOST}/img/avatars/`
@@ -69,7 +75,7 @@ export const Profile: FC<Props> = ({
 
     const Rank = ({ color }: { color: string }) => (
       <View style={[styles.badge, { backgroundColor: color }]}>
-        {badge_tbt ? <TBTIcon /> : <Text style={{ fontSize: getFontSize(12) }}>{tbt_score}</Text>}
+        <TBTIcon />
       </View>
     );
 
@@ -81,7 +87,7 @@ export const Profile: FC<Props> = ({
         }}
       >
         <View style={{ display: 'flex', alignItems: 'center' }}>
-          <Rank color={colors[tbt_rank - 1]} />
+          {badge_tbt ? <Rank color={colors[tbt_rank - 1]} /> : null}
           <Text style={[styles.titleText, { flex: 0 }]}>TBT # {tbt_rank}</Text>
         </View>
       </View>
@@ -89,12 +95,12 @@ export const Profile: FC<Props> = ({
   };
 
   return (
-    <>
+    <TouchableOpacity onPress={() => navigation.navigate(NAVIGATION_PAGES.PROFILE_TAB, { userId })}>
       <View style={{ alignItems: 'center', flexDirection: 'row', gap: 10, marginBottom: 5 }}>
-        <View>
-          <Text style={styles.rankText}>{index + 1}</Text>
-        </View>
-        <View>
+        <View style={{ paddingLeft: 20 }}>
+          <View>
+            <Text style={styles.rankText}>{index + 1}</Text>
+          </View>
           {avatar ? (
             <Image
               style={{ borderRadius: 24, width: 48, height: 48 }}
@@ -133,7 +139,7 @@ export const Profile: FC<Props> = ({
                   style={[styles.countryFlag, { marginLeft: -15 }]}
                 />
               ) : null}
-              <View style={{ display: 'flex', flexDirection: 'row', gap: 10 }}>
+              <View style={{ display: 'flex', flexDirection: 'row', gap: 3, marginLeft: 10 }}>
                 {auth ? <TickIcon /> : null}
                 {badge_un ? <UNIcon /> : null}
                 {badge_1281 ? <NMIcon /> : null}
@@ -143,35 +149,39 @@ export const Profile: FC<Props> = ({
         </View>
       </View>
 
-      <View
-        style={{
-          display: 'flex',
-          flexDirection: 'row',
-          justifyContent: 'space-evenly',
-          marginBottom: 15
-        }}
-      >
-        <TBRanking />
+      <View style={styles.rankingWrapper}>
+        <View style={styles.nmWrapper}>
+          <Text style={{ fontSize: 20, color: Colors.DARK_BLUE, fontWeight: '700' }}>
+            {score[0]}
+          </Text>
+          <Text style={{ fontSize: 14, color: Colors.DARK_BLUE, fontWeight: '500' }}>NM</Text>
+        </View>
 
-        {score.map((number, index) => {
-          if (!number) return;
-          if (scoreNames[index] === 'YES' && number >= 10000) return;
-          if (scoreNames[index] === 'SLOW' && number >= 4500) 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 style={styles.seriesWrapper}>
+          {score.slice(1).map((number, index) => {
+            if (!number) return;
+            if (scoreNames[index] === 'YES' && number >= 10000) return;
+            if (scoreNames[index] === 'SLOW' && number >= 4500) 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>
-          );
-        })}
+            );
+          })}
+        </View>
+
+        <View style={{ marginRight: 15, marginLeft: 15 }}>
+          <TBRanking />
+        </View>
       </View>
-    </>
+    </TouchableOpacity>
   );
 };

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

@@ -6,7 +6,10 @@ export const styles = StyleSheet.create({
   rankText: {
     fontSize: 18,
     color: Colors.DARK_BLUE,
-    fontWeight: '700'
+    fontWeight: '700',
+    position: 'absolute',
+    left: -20,
+    top: 10
   },
   countryFlag: {
     width: 20,
@@ -34,6 +37,32 @@ export const styles = StyleSheet.create({
     display: 'flex',
     justifyContent: 'center',
     alignItems: 'center'
+  },
+  seriesWrapper: {
+    display: 'flex',
+    flexDirection: 'row',
+    justifyContent: 'center',
+    alignItems: 'center',
+    flexWrap: 'wrap',
+    columnGap: 20,
+    flex: 1
+  },
+  nmWrapper: {
+    paddingTop: 17,
+    paddingBottom: 17,
+    display: 'flex',
+    justifyContent: 'center',
+    alignItems: 'center',
+    marginLeft: 25,
+    marginRight: 10
+  },
+  rankingWrapper: {
+    display: 'flex',
+    flexDirection: 'row',
+    justifyContent: 'center',
+    alignItems: 'center',
+    marginBottom: 15,
+    flex: 1
   }
 });
 

+ 185 - 3
src/screens/InAppScreens/TravellersScreen/MasterRankingScreen/index.tsx

@@ -1,19 +1,40 @@
 import React, { useCallback, useState } from 'react';
 import { useFocusEffect } from '@react-navigation/native';
-import { FlatList } from 'react-native';
+import { FlatList, Text, TouchableOpacity, View } from 'react-native';
+import { Dropdown } from 'react-native-searchable-dropdown-kj';
+import Modal from 'react-native-modal';
+
 import { fetchFullRanking } from '@api/ranking';
 
-import { Header, Loading, PageWrapper } from '../../../../components';
+import { styles } from './styles';
+import { Colors } from '../../../../theme';
+
+import { dataAge, dataRanking } from './values';
+
+import { Button, Header, Loading, PageWrapper } from '../../../../components';
 import { getOnlineStatus, storage, StoreType } from '../../../../storage';
 
 import { Profile } from '../Components/Profile';
 
+import { ButtonVariants } from '../../../../types/components';
+
+import FilterIcon from '../../../../../assets/icons/filter.svg';
+import CloseIcon from '../../../../../assets/icons/close.svg';
+
 import type { Ranking } from '..';
 
 const MasterRankingScreen = () => {
   const [masterRanking, setMasterRanking] = useState<Ranking[]>([]);
   const { mutateAsync } = fetchFullRanking();
   const [isLoading, setIsLoading] = useState(true);
+  const [isModalVisible, setModalVisible] = useState(false);
+
+  const [valueAge, setValueAge] = useState<{ value: string; label: string } | null>();
+  const [valueRanking, setValueRanking] = useState<{ value: string; label: string } | null>({
+    value: '1',
+    label: '1301'
+  });
+  const [valueCountry, setValueCountry] = useState(null);
 
   useFocusEffect(
     useCallback(() => {
@@ -41,15 +62,176 @@ const MasterRankingScreen = () => {
     }
   };
 
+  const applySort = () => {
+    switch (valueRanking?.label) {
+      case '1301':
+        setMasterRanking(masterRanking.sort((a: Ranking, b: Ranking) => b.score_nm - a.score_nm));
+        break;
+      case 'DARE':
+        setMasterRanking(
+          masterRanking.sort((a: Ranking, b: Ranking) => b.score_dare - a.score_dare)
+        );
+        break;
+      case 'UN':
+        setMasterRanking(masterRanking.sort((a: Ranking, b: Ranking) => b.score_un - a.score_un));
+        break;
+      case 'UN+':
+        setMasterRanking(masterRanking.sort((a: Ranking, b: Ranking) => b.score_unp - a.score_unp));
+        break;
+      case 'TCC':
+        setMasterRanking(masterRanking.sort((a: Ranking, b: Ranking) => b.score_tcc - a.score_tcc));
+        break;
+      case 'DEEP':
+        setMasterRanking(
+          masterRanking.sort((a: Ranking, b: Ranking) => b.score_deep - a.score_deep)
+        );
+        break;
+      case 'YES':
+        const validUsers = masterRanking.filter((user) => user.score_yes !== 10000);
+        setMasterRanking(validUsers.sort((a: Ranking, b: Ranking) => a.score_yes - b.score_yes));
+        break;
+      case 'SLOW':
+        const valiidUsers = masterRanking.filter(
+          (user) => user.score_slow < 4500 && user.score_slow > 0
+        );
+        setMasterRanking(valiidUsers.sort((a: Ranking, b: Ranking) => b.score_slow - a.score_slow));
+        break;
+      case 'WHS':
+        setMasterRanking(masterRanking.sort((a: Ranking, b: Ranking) => b.score_whs - a.score_whs));
+        break;
+      case 'KYE':
+        setMasterRanking(masterRanking.sort((a: Ranking, b: Ranking) => b.score_kye - a.score_kye));
+        break;
+      case 'TBT':
+        setMasterRanking(masterRanking.sort((a: Ranking, b: Ranking) => b.score_tbt - a.score_tbt));
+        break;
+    }
+  };
+
+  const ModalComponent = () => {
+    return (
+      <>
+        <Modal isVisible={isModalVisible}>
+          <View style={{ height: 270, backgroundColor: 'white', borderRadius: 15 }}>
+            <View style={{ marginLeft: '5%', marginRight: '5%', marginTop: '5%' }}>
+              <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>
+                <View style={styles.ageAndRankingWrapper}>
+                  <Dropdown
+                    style={styles.dropdown}
+                    placeholderStyle={styles.placeholderStyle}
+                    selectedTextStyle={styles.selectedTextStyle}
+                    data={dataAge}
+                    maxHeight={300}
+                    labelField="label"
+                    valueField="value"
+                    placeholder="Select age"
+                    searchPlaceholder="Search..."
+                    value={valueAge?.value}
+                    onChange={(item) => {
+                      setValueAge(item);
+                    }}
+                  />
+                  <Dropdown
+                    style={styles.dropdown}
+                    placeholderStyle={styles.placeholderStyle}
+                    selectedTextStyle={styles.selectedTextStyle}
+                    data={dataRanking}
+                    maxHeight={300}
+                    labelField="label"
+                    valueField="value"
+                    placeholder="Select ranking"
+                    searchPlaceholder="Search..."
+                    value={valueRanking?.value}
+                    onChange={(item) => {
+                      setValueRanking(item);
+                    }}
+                  />
+                </View>
+                <Dropdown
+                  style={styles.dropdown}
+                  placeholderStyle={styles.placeholderStyle}
+                  selectedTextStyle={styles.selectedTextStyle}
+                  data={[]}
+                  maxHeight={300}
+                  labelField="label"
+                  valueField="value"
+                  placeholder="Select country"
+                  searchPlaceholder="Search..."
+                  value={valueRanking?.value}
+                  onChange={(item) => {
+                    //todo: Country
+                  }}
+                />
+                <View style={styles.buttonsWrapper}>
+                  <Button
+                    variant={ButtonVariants.OPACITY}
+                    containerStyles={{
+                      borderColor: Colors.DARK_BLUE,
+                      backgroundColor: 'white',
+                      width: '45%'
+                    }}
+                    textStyles={{
+                      color: Colors.DARK_BLUE
+                    }}
+                    onPress={() => {
+                      setValueAge(null);
+                      setValueRanking(null);
+                    }}
+                    children={'Clear'}
+                  />
+                  <Button
+                    variant={ButtonVariants.FILL}
+                    containerStyles={{
+                      borderColor: Colors.DARK_BLUE,
+                      backgroundColor: Colors.DARK_BLUE,
+                      width: '45%'
+                    }}
+                    textStyles={{
+                      color: Colors.WHITE
+                    }}
+                    onPress={() => {
+                      setModalVisible(!isModalVisible);
+                      applySort();
+                    }}
+                    children={'Filter'}
+                  />
+                </View>
+              </View>
+            </View>
+          </View>
+        </Modal>
+      </>
+    );
+  };
+
   return (
     <PageWrapper>
+      <ModalComponent />
       <FlatList
         showsVerticalScrollIndicator={false}
         data={masterRanking}
-        ListHeaderComponent={<Header label="Master Ranking" />}
+        ListHeaderComponent={
+          <Header
+            label="Master Ranking"
+            rightElement={
+              <TouchableOpacity onPress={() => setModalVisible(!isModalVisible)}>
+                <FilterIcon />
+              </TouchableOpacity>
+            }
+          />
+        }
         keyExtractor={(item) => item.user_id.toString()}
         renderItem={({ item, index }) => (
           <Profile
+            userId={item.user_id}
             key={index}
             index={index}
             first_name={item.first_name}

+ 35 - 0
src/screens/InAppScreens/TravellersScreen/MasterRankingScreen/styles.ts

@@ -0,0 +1,35 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from '../../../../theme';
+
+export const styles = StyleSheet.create({
+  dropdown: {
+    width: 150,
+    height: 40,
+    backgroundColor: '#F4F4F4',
+    borderRadius: 4,
+    paddingHorizontal: 8
+  },
+  placeholderStyle: {
+    fontSize: 16,
+    color: Colors.DARK_BLUE
+  },
+  selectedTextStyle: {
+    fontSize: 16,
+    color: Colors.DARK_BLUE
+  },
+  ageAndRankingWrapper: {
+    width: '100%',
+    display: 'flex',
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-between',
+    marginTop: 20
+  },
+  buttonsWrapper: {
+    width: '100%',
+    display: 'flex',
+    justifyContent: 'space-between',
+    flexDirection: 'row',
+    marginTop: 15
+  }
+});

+ 23 - 0
src/screens/InAppScreens/TravellersScreen/MasterRankingScreen/values.ts

@@ -0,0 +1,23 @@
+export const dataAge = [
+  { label: 'until 19', value: '1' },
+  { label: '20 - 29', value: '2' },
+  { label: '30 - 39', value: '3' },
+  { label: '40 - 49', value: '4' },
+  { label: '50 - 59', value: '5' },
+  { label: '60 - 69', value: '6' },
+  { label: '70+', value: '7' }
+];
+
+export const dataRanking = [
+  { label: '1301', value: '1' },
+  { label: 'DARE', value: '2' },
+  { label: 'UN', value: '3' },
+  { label: 'UN+', value: '4' },
+  { label: 'TCC', value: '5' },
+  { label: 'DEEP', value: '6' },
+  { label: 'YES', value: '7' },
+  { label: 'SLOW', value: '8' },
+  { label: 'WHS', value: '9' },
+  { label: 'KYE', value: '10' },
+  { label: 'TBT', value: '11' }
+];

+ 5 - 3
src/types/api.ts

@@ -7,7 +7,7 @@ export enum API_ROUTE {
   RANKING = 'ranking',
   UN_MASTERS = 'un-masters',
   AVATARS = 'avatars',
-  STATISTICS = 'statistics',
+  STATISTICS = 'statistics'
 }
 
 export enum API_ENDPOINT {
@@ -21,6 +21,7 @@ export enum API_ENDPOINT {
   SET_SETTINGS_APP = 'set-settings-app',
   SERIES = 'get-for-regions',
   PROFILE_INFO = 'profile-info',
+  PROFILE_INFO_PUBLIC = 'profile-info-public',
   GET_LIMITED_RANKING = 'get-app-limited',
   GET_FULL_RANKING = 'get-app-full',
   GET_LPI = 'get-app-lpi',
@@ -30,7 +31,7 @@ export enum API_ENDPOINT {
   GET_UN_MASTERS_TYPE = 'get-type',
   GET_UPDATED_AVATARS = 'get-updates',
   GET_LIST = 'get-list',
-  GET_STATISTIC = 'get-stat',
+  GET_STATISTIC = 'get-stat'
 }
 
 export enum API {
@@ -43,6 +44,7 @@ export enum API {
   SET_USER_SETTINGS_DATA = `${API_ROUTE.USER}/${API_ENDPOINT.SET_SETTINGS_APP}`,
   SERIES = `${API_ROUTE.SERIES}/${API_ENDPOINT.SERIES}`,
   PROFILE_INFO = `${API_ROUTE.USER}/${API_ENDPOINT.PROFILE_INFO}`,
+  PROFILE_INFO_PUBLIC = `${API_ROUTE.USER}/${API_ENDPOINT.PROFILE_INFO_PUBLIC}`,
   GET_LIMITED_RANKING = `${API_ROUTE.RANKING}/${API_ENDPOINT.GET_LIMITED_RANKING}`,
   GET_FULL_RANKING = `${API_ROUTE.RANKING}/${API_ENDPOINT.GET_FULL_RANKING}`,
   GET_LPI = `${API_ROUTE.RANKING}/${API_ENDPOINT.GET_LPI}`,
@@ -52,7 +54,7 @@ export enum API {
   GET_UN_MASTERS_TYPE = `${API_ROUTE.UN_MASTERS}/${API_ENDPOINT.GET_UN_MASTERS_TYPE}`,
   GET_UPDATED_AVATARS = `${API_ROUTE.AVATARS}/${API_ENDPOINT.GET_UPDATED_AVATARS}`,
   GET_LIST = `${API_ROUTE.STATISTICS}/${API_ENDPOINT.GET_LIST}`,
-  GET_STATISTIC = `${API_ROUTE.STATISTICS}/${API_ENDPOINT.GET_STATISTIC}`,
+  GET_STATISTIC = `${API_ROUTE.STATISTICS}/${API_ENDPOINT.GET_STATISTIC}`
 }
 
 export type BaseAxiosError = AxiosError;

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff