Jelajahi Sumber

added ranking sync

Viktoriia 1 tahun lalu
induk
melakukan
72457777cb

+ 2 - 3
App.tsx

@@ -1,12 +1,11 @@
 import 'react-native-gesture-handler';
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { QueryClientProvider } from '@tanstack/react-query';
 import { NavigationContainer } from '@react-navigation/native';
+import { queryClient } from 'src/utils/queryClient';
 
 import Route from './Route';
 
 export default function App() {
-  const queryClient = new QueryClient();
-
   return (
     <QueryClientProvider client={queryClient}>
       <NavigationContainer>

+ 2 - 0
Route.tsx

@@ -27,6 +27,7 @@ import { openDatabases } from './src/db';
 
 import TabBarButton from './src/components/TabBarButton';
 import { ParamListBase, RouteProp } from '@react-navigation/native';
+import setupDatabaseAndSync from 'src/database';
 
 const ScreenStack = createStackNavigator();
 const BottomTab = createBottomTabNavigator();
@@ -47,6 +48,7 @@ const Route = () => {
     const prepareApp = async () => {
       await openDatabases();
       setDbLoaded(true);
+      await setupDatabaseAndSync();
     };
 
     prepareApp();

+ 73 - 0
src/database/index.ts

@@ -0,0 +1,73 @@
+import * as SQLite from 'expo-sqlite';
+import NetInfo, { NetInfoState } from '@react-native-community/netinfo';
+import { storage } from 'src/storage';
+import { fetchLimitedRanking, fetchLpi, fetchInHistory } from '@api/ranking';
+
+const db = SQLite.openDatabase('nomadManiaDb.db');
+
+export const initializeDatabase = (): Promise<void> => {
+  return new Promise<void>((resolve, reject) => {
+    db.transaction(tx => {
+      createSyncTriggers('tableName');
+
+      resolve();
+    }, error => {
+      console.error('DB initialization error: ', error);
+      reject(error);
+    });
+  });
+};
+
+const createSyncTriggers = (tableName: string): void => {
+};
+
+export const checkInternetConnection = async (): Promise<NetInfoState> => {
+  const state = await NetInfo.fetch();
+  return state;
+};
+
+export const syncDataWithServer = async (): Promise<void> => {
+  const { isConnected, isInternetReachable } = await checkInternetConnection();
+  if (isConnected && isInternetReachable) {
+    processSyncQueue();
+    await updateAvatars();
+    await updateMasterRanking();
+  }
+};
+
+const processSyncQueue = (): void => {
+};
+
+export const updateAvatars = async (): Promise<void> => {
+};
+
+export const updateStaticGeoJSON = async (): Promise<void> => {
+};
+
+export const setupDatabaseAndSync = async (): Promise<void> => {
+  await initializeDatabase();
+  await syncDataWithServer();
+  await updateStaticGeoJSON();
+};
+
+const updateMasterRanking = async () => {
+  const dataLimitedRanking = await fetchLimitedRanking();
+
+  if (dataLimitedRanking && dataLimitedRanking.data) {
+    storage.set('masterRanking', JSON.stringify(dataLimitedRanking.data));
+  }
+
+  const dataLpi = await fetchLpi();
+
+  if (dataLpi && dataLpi.data) {
+    storage.set('lpiRanking', JSON.stringify(dataLpi.data));
+  }
+
+  const dataInHistory = await fetchInHistory();
+
+  if (dataInHistory && dataInHistory.data) {
+    storage.set('inHistoryRanking', JSON.stringify(dataInHistory.data));
+  }
+};
+
+export default setupDatabaseAndSync;

+ 3 - 0
src/modules/api/ranking/index.ts

@@ -0,0 +1,3 @@
+export * from './queries';
+export * from './ranking-api';
+export * from './ranking-query-keys';

+ 4 - 0
src/modules/api/ranking/queries/index.ts

@@ -0,0 +1,4 @@
+export * from './use-post-get-limited-ranking';
+export * from './use-post-get-full-ranking';
+export * from './use-post-get-lpi';
+export * from './use-post-get-in-history';

+ 17 - 0
src/modules/api/ranking/queries/use-post-get-full-ranking.tsx

@@ -0,0 +1,17 @@
+import { useMutation } from '@tanstack/react-query';
+
+import { rankingQueryKeys } from '../ranking-query-keys';
+import { type PostGetRanking, rankingApi } from '../ranking-api';
+
+import type { BaseAxiosError } from '../../../../types';
+
+export const fetchFullRanking = () => {
+  return useMutation<PostGetRanking, BaseAxiosError, void>({
+    mutationKey: rankingQueryKeys.getFullRanking(),
+    mutationFn: async () => {
+      const response = await rankingApi.getFullRanking();
+      
+      return response.data;
+    }
+  });
+};

+ 18 - 0
src/modules/api/ranking/queries/use-post-get-in-history.tsx

@@ -0,0 +1,18 @@
+import { rankingQueryKeys } from '../ranking-query-keys';
+import { type PostGetRanking, rankingApi } from '../ranking-api';
+import { queryClient } from 'src/utils/queryClient';
+
+export const fetchInHistory = async () => {
+  try {
+    const data: PostGetRanking = await queryClient.fetchQuery({
+      queryKey: rankingQueryKeys.getInHistory(),
+      queryFn: () => rankingApi.getInHistory().then((res) => res.data),
+      gcTime: 0,
+      staleTime: 0
+    });
+    
+    return data;
+  } catch (error) {
+    console.error('Failed to fetch in-history data:', error);
+  }
+};

+ 18 - 0
src/modules/api/ranking/queries/use-post-get-limited-ranking.tsx

@@ -0,0 +1,18 @@
+import { rankingQueryKeys } from '../ranking-query-keys';
+import { type PostGetRanking, rankingApi } from '../ranking-api';
+import { queryClient } from 'src/utils/queryClient';
+
+export const fetchLimitedRanking = async () => {
+  try {
+    const data: PostGetRanking = await queryClient.fetchQuery({
+      queryKey: rankingQueryKeys.getLimitedRanking(),
+      queryFn: () => rankingApi.getLimitedRanking().then((res) => res.data),
+      gcTime: 0,
+      staleTime: 0
+    });
+
+    return data;
+  } catch (error) {
+    console.error('Failed to fetch master ranking data:', error);
+  }
+};

+ 18 - 0
src/modules/api/ranking/queries/use-post-get-lpi.tsx

@@ -0,0 +1,18 @@
+import { rankingQueryKeys } from '../ranking-query-keys';
+import { type PostGetRanking, rankingApi } from '../ranking-api';
+import { queryClient } from 'src/utils/queryClient';
+
+export const fetchLpi = async () => {
+  try {
+    const data: PostGetRanking = await queryClient.fetchQuery({
+      queryKey: rankingQueryKeys.getLpi(),
+      queryFn: () => rankingApi.getLpi().then((res) => res.data),
+      gcTime: 0,
+      staleTime: 0
+    });
+    
+    return data;
+  } catch (error) {
+    console.error('Failed to fetch lpi data:', error);
+  }
+};

+ 57 - 0
src/modules/api/ranking/ranking-api.tsx

@@ -0,0 +1,57 @@
+import { request } from '../../../utils';
+import { API } from '../../../types';
+import { ResponseType } from '../response-type';
+
+export interface PostGetRanking extends ResponseType {
+  data: {
+    user_id: number,
+    score_dare: number,
+    score_nm: number,
+    score_un: number,
+    score_unp: number,
+    score_tcc: number,
+    score_deep: number,
+    score_whs: number,
+    score_kye: number,
+    score_tbt: number,
+    score_yes: number,
+    score_slow: number,
+    rank_tbt: number,
+    avatar: string,
+    first_name: string,
+    last_name: string,
+    age: number,
+    flag1: string,
+    flag2: string,
+    badge_1281: number,
+    badge_un: number,
+    badge_supreme: number,
+    badge_tbt: number,
+    badge_offline: number,
+    patreon: number,
+    country: string,
+    auth: number,
+    rank: number,
+    country_rank: number,
+    dod: number,
+    ukr: number,
+    badges: number,
+    arrow_nm: number,
+    arrow_un: number,
+    arrow_unp: number,
+    arrow_dare: number,
+    arrow_yes: number,
+    arrow_whs: number,
+    arrow_tcc: number,
+    arrow_tbt: number,
+    arrow_slow: number,
+    arrow_kye: number,
+  }[];
+};
+
+export const rankingApi = {
+  getLimitedRanking: () => request.postForm<PostGetRanking>(API.GET_LIMITED_RANKING),
+  getFullRanking: () => request.postForm<PostGetRanking>(API.GET_FULL_RANKING),
+  getLpi: () => request.postForm<PostGetRanking>(API.GET_LPI),
+  getInHistory: () => request.postForm<PostGetRanking>(API.GET_IN_HISTORY)
+};

+ 6 - 0
src/modules/api/ranking/ranking-query-keys.tsx

@@ -0,0 +1,6 @@
+export const rankingQueryKeys = {
+  getLimitedRanking: () => ['getLimitedRanking'] as const,
+  getFullRanking: () => ['getFullRanking'] as const,
+  getLpi: () => ['getLpi'] as const,
+  getInHistory: () => ['getInHistory'] as const
+};

+ 89 - 0
src/screens/InAppScreens/TravellersScreen/Ranking/index.tsx

@@ -0,0 +1,89 @@
+import React, { useEffect, useState } from 'react';
+import { View, Text, FlatList } from 'react-native';
+import { StoreType, storage } from 'src/storage';
+import { fetchFullRanking } from '@api/ranking';
+
+export interface Ranking {
+  user_id: number,
+  score_dare: number,
+  score_nm: number,
+  score_un: number,
+  score_unp: number,
+  score_tcc: number,
+  score_deep: number,
+  score_whs: number,
+  score_kye: number,
+  score_tbt: number,
+  score_yes: number,
+  score_slow: number,
+  rank_tbt: number,
+  avatar: string,
+  first_name: string,
+  last_name: string,
+  age: number,
+  flag1: string,
+  flag2: string,
+  badge_1281: number,
+  badge_un: number,
+  badge_supreme: number,
+  badge_tbt: number,
+  badge_offline: number,
+  patreon: number,
+  country: string,
+  auth: number,
+  rank: number,
+  country_rank: number,
+  dod: number,
+  ukr: number,
+  badges: number,
+  arrow_nm: number,
+  arrow_un: number,
+  arrow_unp: number,
+  arrow_dare: number,
+  arrow_yes: number,
+  arrow_whs: number,
+  arrow_tcc: number,
+  arrow_tbt: number,
+  arrow_slow: number,
+  arrow_kye: number,
+}
+
+const RankingScreen = () => {
+  const [masterRanking, setMasterRanking] = useState<Ranking[]>([]);
+  const { mutateAsync } = fetchFullRanking();
+
+  const ranking: string = storage.get('masterRanking', StoreType.STRING) as string;
+  const lpi: string = storage.get('lpiRanking', StoreType.STRING) as string;
+  const inHistory: string = storage.get('inHistoryRanking', StoreType.STRING) as string;
+
+  useEffect(() => {
+    setMasterRanking(
+      JSON.parse(ranking).sort((a: Ranking, b: Ranking) => b.score_nm - a.score_nm)
+    );
+  }, [ranking]);
+
+  const getFullRanking = async () => {
+    await mutateAsync(undefined, {
+      onSuccess: (data) => {
+        setMasterRanking(data.data);
+      }
+    });
+  }
+
+  return (
+    <FlatList
+      data={masterRanking}
+      keyExtractor={(item) => item.user_id.toString()}
+      renderItem={({ item }) => (
+        <View style={{ display: 'flex', flexDirection: 'row' }}>
+          <Text>{item.score_nm}</Text>
+          <Text>{item.last_name}</Text>
+        </View>
+      )}
+      onEndReached={() => getFullRanking()}
+      onEndReachedThreshold={0.1}
+    />
+  );
+};
+
+export default RankingScreen;

+ 12 - 3
src/types/api.ts

@@ -3,7 +3,8 @@ import { AxiosError } from 'axios';
 export enum API_ROUTE {
   USER = 'user',
   REGIONS = 'regions',
-  SERIES = 'series'
+  SERIES = 'series',
+  RANKING = 'ranking'
 }
 
 export enum API_ENDPOINT {
@@ -16,7 +17,11 @@ export enum API_ENDPOINT {
   GET_SETTINGS_APP = 'get-settings-app',
   SET_SETTINGS_APP = 'set-settings-app',
   SERIES = 'get-for-regions',
-  PROFILE_INFO = 'profile-info'
+  PROFILE_INFO = 'profile-info',
+  GET_LIMITED_RANKING = 'get-app-limited',
+  GET_FULL_RANKING = 'get-app-full',
+  GET_LPI = 'get-app-lpi',
+  GET_IN_HISTORY = 'get-app-in-history'
 }
 
 export enum API {
@@ -28,7 +33,11 @@ export enum API {
   GET_USER_SETTINGS_DATA = `${API_ROUTE.USER}/${API_ENDPOINT.GET_SETTINGS_APP}`,
   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 = `${API_ROUTE.USER}/${API_ENDPOINT.PROFILE_INFO}`,
+  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}`,
+  GET_IN_HISTORY = `${API_ROUTE.RANKING}/${API_ENDPOINT.GET_IN_HISTORY}`
 }
 
 export type BaseAxiosError = AxiosError;

+ 3 - 0
src/utils/queryClient.ts

@@ -0,0 +1,3 @@
+import { QueryClient } from '@tanstack/react-query';
+
+export const queryClient = new QueryClient();