Improve request error handling
This commit is contained in:
parent
a1cfb0385a
commit
d55c692bd3
8 changed files with 100 additions and 78 deletions
|
@ -1,10 +1,17 @@
|
|||
import React, { useEffect, useRef } from 'react';
|
||||
import ErrorView from './ErrorView';
|
||||
import { useRequestLogic } from '../../utils/customHooks';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
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 ConnectionManager from '../../managers/ConnectionManager';
|
||||
|
||||
export type RequestScreenProps<T> = {
|
||||
request: () => Promise<T>;
|
||||
|
@ -37,6 +44,8 @@ type Props<T> = RequestScreenProps<T>;
|
|||
const MIN_REFRESH_TIME = 5 * 1000;
|
||||
|
||||
export default function RequestScreen<T>(props: Props<T>) {
|
||||
const navigation = useNavigation<StackNavigationProp<any>>();
|
||||
const route = useRoute();
|
||||
const refreshInterval = useRef<number>();
|
||||
const [
|
||||
loading,
|
||||
|
@ -89,22 +98,42 @@ export default function RequestScreen<T>(props: Props<T>) {
|
|||
}, [props.cache, props.refreshOnFocus])
|
||||
);
|
||||
|
||||
const isErrorCritical = (e: API_REQUEST_CODES | undefined) => {
|
||||
return e === API_REQUEST_CODES.BAD_TOKEN;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isErrorCritical(code)) {
|
||||
ConnectionManager.getInstance()
|
||||
.disconnect()
|
||||
.then(() => {
|
||||
navigation.replace(MainRoutes.Login, { nextScreen: route.name });
|
||||
});
|
||||
}
|
||||
}, [code, navigation, route]);
|
||||
|
||||
if (data === undefined && loading && props.showLoading !== false) {
|
||||
return <BasicLoadingScreen />;
|
||||
} else if (
|
||||
data === undefined &&
|
||||
status !== REQUEST_STATUS.SUCCESS &&
|
||||
(status !== REQUEST_STATUS.SUCCESS ||
|
||||
(status === REQUEST_STATUS.SUCCESS && code !== undefined)) &&
|
||||
props.showError !== false
|
||||
) {
|
||||
return (
|
||||
<ErrorView
|
||||
status={status}
|
||||
code={code}
|
||||
loading={loading}
|
||||
button={{
|
||||
button={
|
||||
isErrorCritical(code)
|
||||
? undefined
|
||||
: {
|
||||
icon: 'refresh',
|
||||
text: i18n.t('general.retry'),
|
||||
onPress: () => refreshData(),
|
||||
}}
|
||||
}
|
||||
}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -156,7 +156,7 @@ class ClubListScreen extends React.Component<PropsType, StateType> {
|
|||
this.categories = data?.categories;
|
||||
return [{ title: '', data: data.clubs }];
|
||||
} else {
|
||||
return [{ title: '', data: [] }];
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> {
|
|||
}
|
||||
return [{ title: '', data: data.devices }];
|
||||
} else {
|
||||
return [{ title: '', data: [] }];
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -110,10 +110,9 @@ class LoginScreen extends React.Component<Props, StateType> {
|
|||
this.onInputChange(false, value);
|
||||
};
|
||||
props.navigation.addListener('focus', this.onScreenFocus);
|
||||
// TODO remove
|
||||
this.state = {
|
||||
email: 'vergnet@etud.insa-toulouse.fr',
|
||||
password: 'IGtt25ùj',
|
||||
email: '',
|
||||
password: '',
|
||||
isEmailValidated: false,
|
||||
isPasswordValidated: false,
|
||||
loading: false,
|
||||
|
@ -373,7 +372,7 @@ class LoginScreen extends React.Component<Props, StateType> {
|
|||
* Saves the screen to navigate to after a successful login if one was provided in navigation parameters
|
||||
*/
|
||||
handleNavigationParams() {
|
||||
this.nextScreen = this.props.route.params.nextScreen;
|
||||
this.nextScreen = this.props.route.params?.nextScreen;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -121,12 +121,16 @@ function GroupSelectionScreen() {
|
|||
}
|
||||
| undefined
|
||||
): Array<{ title: string; data: Array<PlanexGroupCategoryType> }> => {
|
||||
if (fetchedData) {
|
||||
return [
|
||||
{
|
||||
title: '',
|
||||
data: generateData(fetchedData),
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -181,14 +185,11 @@ function GroupSelectionScreen() {
|
|||
* @returns {[]}
|
||||
*/
|
||||
const generateData = (
|
||||
fetchedData: PlanexGroupsType | undefined
|
||||
fetchedData: PlanexGroupsType
|
||||
): Array<PlanexGroupCategoryType> => {
|
||||
const data: Array<PlanexGroupCategoryType> = [];
|
||||
|
||||
if (fetchedData) {
|
||||
// Convert the object into an array
|
||||
Object.values(fetchedData).forEach(
|
||||
(category: PlanexGroupCategoryType) => {
|
||||
Object.values(fetchedData).forEach((category: PlanexGroupCategoryType) => {
|
||||
const content: Array<PlanexGroupType> = [];
|
||||
// Filter groups matching the search query
|
||||
category.content.forEach((g: PlanexGroupType) => {
|
||||
|
@ -204,8 +205,7 @@ function GroupSelectionScreen() {
|
|||
content: content,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
data.sort(sortName);
|
||||
// Add the favorites at the top
|
||||
data.unshift({
|
||||
|
@ -213,7 +213,6 @@ function GroupSelectionScreen() {
|
|||
id: 0,
|
||||
content: favoriteGroups,
|
||||
});
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
|
|
|
@ -349,13 +349,7 @@ function ProximoListScreen(props: Props) {
|
|||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
title: '',
|
||||
data: [],
|
||||
keyExtractor: keyExtractor,
|
||||
},
|
||||
];
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -239,13 +239,7 @@ function ProximoMainScreen() {
|
|||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
title: '',
|
||||
data: [],
|
||||
keyExtractor: getKeyExtractor,
|
||||
},
|
||||
];
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import WebSectionList from '../../components/Screens/WebSectionList';
|
|||
import type { SectionListDataType } from '../../components/Screens/WebSectionList';
|
||||
import Urls from '../../constants/Urls';
|
||||
import { readData } from '../../utils/WebData';
|
||||
import { REQUEST_STATUS } from '../../utils/Requests';
|
||||
|
||||
type PropsType = {
|
||||
navigation: StackNavigationProp<any>;
|
||||
|
@ -109,9 +110,14 @@ class SelfMenuScreen extends React.Component<PropsType> {
|
|||
* @return {[]}
|
||||
*/
|
||||
createDataset = (
|
||||
fetchedData: Array<RawRuMenuType> | undefined
|
||||
fetchedData: Array<RawRuMenuType> | undefined,
|
||||
_loading: boolean,
|
||||
_lastRefreshDate: Date | undefined,
|
||||
_refreshData: (newRequest?: () => Promise<Array<RawRuMenuType>>) => void,
|
||||
status: REQUEST_STATUS
|
||||
): SectionListDataType<RuFoodCategoryType> => {
|
||||
let result: SectionListDataType<RuFoodCategoryType> = [];
|
||||
if (status === REQUEST_STATUS.SUCCESS) {
|
||||
if (fetchedData == null || fetchedData.length === 0) {
|
||||
result = [
|
||||
{
|
||||
|
@ -129,6 +135,7 @@ class SelfMenuScreen extends React.Component<PropsType> {
|
|||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue