123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import React, { useEffect, useRef } from 'react';
- import ErrorView from './ErrorView';
- import { useRequestLogic } from '../../utils/customHooks';
- import {
- useFocusEffect,
- useNavigation,
- useRoute,
- } from '@react-navigation/native';
- import BasicLoadingScreen from './BasicLoadingScreen';
- import i18n from 'i18n-js';
- import { API_REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
- import { StackNavigationProp } from '@react-navigation/stack';
- import { MainRoutes } from '../../navigation/MainNavigator';
- import { useLogout } from '../../utils/logout';
-
- export type RequestScreenProps<T> = {
- request: () => Promise<T>;
- render: (
- data: T | undefined,
- loading: boolean,
- lastRefreshDate: Date | undefined,
- refreshData: (newRequest?: () => Promise<T>) => void,
- status: REQUEST_STATUS,
- code?: API_REQUEST_CODES
- ) => React.ReactElement;
- cache?: T;
- onCacheUpdate?: (newCache: T) => void;
- onMajorError?: (status: number, code?: number) => void;
- showLoading?: boolean;
- showError?: boolean;
- refreshOnFocus?: boolean;
- autoRefreshTime?: number;
- refresh?: boolean;
- onFinish?: () => void;
- };
-
- export type RequestProps = {
- refreshData: () => void;
- loading: boolean;
- };
-
- type Props<T> = RequestScreenProps<T>;
-
- const MIN_REFRESH_TIME = 3 * 1000;
-
- export default function RequestScreen<T>(props: Props<T>) {
- const onLogout = useLogout();
- const navigation = useNavigation<StackNavigationProp<any>>();
- const route = useRoute();
- const refreshInterval = useRef<number>();
- const [
- loading,
- lastRefreshDate,
- status,
- code,
- data,
- refreshData,
- ] = useRequestLogic<T>(
- props.request,
- props.cache,
- props.onCacheUpdate,
- props.refreshOnFocus,
- MIN_REFRESH_TIME
- );
- // Store last refresh prop value
- const lastRefresh = useRef<boolean>(false);
-
- useEffect(() => {
- // Refresh data if refresh prop changed and we are not loading
- if (props.refresh && !lastRefresh.current && !loading) {
- refreshData();
- // Call finish callback if refresh prop was set and we finished loading
- } else if (lastRefresh.current && !loading && props.onFinish) {
- props.onFinish();
- }
- // Update stored refresh prop value
- if (props.refresh !== lastRefresh.current) {
- lastRefresh.current = props.refresh === true;
- }
- }, [props, loading, refreshData]);
-
- useFocusEffect(
- React.useCallback(() => {
- if (!props.cache && props.refreshOnFocus !== false) {
- refreshData();
- }
- if (props.autoRefreshTime && props.autoRefreshTime > 0) {
- refreshInterval.current = setInterval(
- refreshData,
- props.autoRefreshTime
- );
- }
- return () => {
- if (refreshInterval.current) {
- clearInterval(refreshInterval.current);
- }
- };
- }, [props.cache, props.refreshOnFocus, props.autoRefreshTime, refreshData])
- );
-
- const isErrorCritical = (e: API_REQUEST_CODES | undefined) => {
- return e === API_REQUEST_CODES.BAD_TOKEN;
- };
-
- useEffect(() => {
- if (isErrorCritical(code)) {
- onLogout();
- navigation.replace(MainRoutes.Login, { nextScreen: route.name });
- }
- }, [code, navigation, route, onLogout]);
-
- if (data === undefined && loading && props.showLoading !== false) {
- return <BasicLoadingScreen />;
- } else if (
- data === undefined &&
- (status !== REQUEST_STATUS.SUCCESS ||
- (status === REQUEST_STATUS.SUCCESS && code !== undefined)) &&
- props.showError !== false
- ) {
- return (
- <ErrorView
- status={status}
- code={code}
- loading={loading}
- button={
- isErrorCritical(code)
- ? undefined
- : {
- icon: 'refresh',
- text: i18n.t('general.retry'),
- onPress: () => refreshData(),
- }
- }
- />
- );
- } else {
- return props.render(
- data,
- loading,
- lastRefreshDate,
- refreshData,
- status,
- code
- );
- }
- }
|