forked from vergnet/application-amicale
Update api error codes
This commit is contained in:
parent
50c62dd676
commit
9b4caade00
12 changed files with 217 additions and 204 deletions
|
@ -25,6 +25,8 @@ import ConnectionManager from '../../../managers/ConnectionManager';
|
||||||
import LoadingConfirmDialog from '../../Dialogs/LoadingConfirmDialog';
|
import LoadingConfirmDialog from '../../Dialogs/LoadingConfirmDialog';
|
||||||
import ErrorDialog from '../../Dialogs/ErrorDialog';
|
import ErrorDialog from '../../Dialogs/ErrorDialog';
|
||||||
import type { VoteTeamType } from '../../../screens/Amicale/VoteScreen';
|
import type { VoteTeamType } from '../../../screens/Amicale/VoteScreen';
|
||||||
|
import { ApiRejectType } from '../../../utils/WebData';
|
||||||
|
import { REQUEST_STATUS } from '../../../utils/Requests';
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
teams: Array<VoteTeamType>;
|
teams: Array<VoteTeamType>;
|
||||||
|
@ -36,7 +38,7 @@ type StateType = {
|
||||||
selectedTeam: string;
|
selectedTeam: string;
|
||||||
voteDialogVisible: boolean;
|
voteDialogVisible: boolean;
|
||||||
errorDialogVisible: boolean;
|
errorDialogVisible: boolean;
|
||||||
currentError: number;
|
currentError: ApiRejectType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -58,7 +60,7 @@ export default class VoteSelect extends React.PureComponent<
|
||||||
selectedTeam: 'none',
|
selectedTeam: 'none',
|
||||||
voteDialogVisible: false,
|
voteDialogVisible: false,
|
||||||
errorDialogVisible: false,
|
errorDialogVisible: false,
|
||||||
currentError: 0,
|
currentError: { status: REQUEST_STATUS.SUCCESS },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ export default class VoteSelect extends React.PureComponent<
|
||||||
props.onVoteSuccess();
|
props.onVoteSuccess();
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch((error: number) => {
|
.catch((error: ApiRejectType) => {
|
||||||
this.onVoteDialogDismiss();
|
this.onVoteDialogDismiss();
|
||||||
this.showErrorDialog(error);
|
this.showErrorDialog(error);
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -96,7 +98,7 @@ export default class VoteSelect extends React.PureComponent<
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
showErrorDialog = (error: number): void =>
|
showErrorDialog = (error: ApiRejectType): void =>
|
||||||
this.setState({
|
this.setState({
|
||||||
errorDialogVisible: true,
|
errorDialogVisible: true,
|
||||||
currentError: error,
|
currentError: error,
|
||||||
|
@ -156,7 +158,8 @@ export default class VoteSelect extends React.PureComponent<
|
||||||
<ErrorDialog
|
<ErrorDialog
|
||||||
visible={state.errorDialogVisible}
|
visible={state.errorDialogVisible}
|
||||||
onDismiss={this.onErrorDialogDismiss}
|
onDismiss={this.onErrorDialogDismiss}
|
||||||
errorCode={state.currentError}
|
status={state.currentError.status}
|
||||||
|
code={state.currentError.code}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
@ -19,60 +19,27 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import { ERROR_TYPE } from '../../utils/WebData';
|
|
||||||
import AlertDialog from './AlertDialog';
|
import AlertDialog from './AlertDialog';
|
||||||
|
import {
|
||||||
|
API_REQUEST_CODES,
|
||||||
|
getErrorMessage,
|
||||||
|
REQUEST_STATUS,
|
||||||
|
} from '../../utils/Requests';
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onDismiss: () => void;
|
onDismiss: () => void;
|
||||||
errorCode: number;
|
status?: REQUEST_STATUS;
|
||||||
|
code?: API_REQUEST_CODES;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ErrorDialog(props: PropsType) {
|
function ErrorDialog(props: PropsType) {
|
||||||
let title: string;
|
|
||||||
let message: string;
|
|
||||||
|
|
||||||
title = i18n.t('errors.title');
|
|
||||||
switch (props.errorCode) {
|
|
||||||
case ERROR_TYPE.BAD_CREDENTIALS:
|
|
||||||
message = i18n.t('errors.badCredentials');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.BAD_TOKEN:
|
|
||||||
message = i18n.t('errors.badToken');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.NO_CONSENT:
|
|
||||||
message = i18n.t('errors.noConsent');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.TOKEN_SAVE:
|
|
||||||
message = i18n.t('errors.tokenSave');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.TOKEN_RETRIEVE:
|
|
||||||
message = i18n.t('errors.unknown');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.BAD_INPUT:
|
|
||||||
message = i18n.t('errors.badInput');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.FORBIDDEN:
|
|
||||||
message = i18n.t('errors.forbidden');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.CONNECTION_ERROR:
|
|
||||||
message = i18n.t('errors.connectionError');
|
|
||||||
break;
|
|
||||||
case ERROR_TYPE.SERVER_ERROR:
|
|
||||||
message = i18n.t('errors.serverError');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
message = i18n.t('errors.unknown');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
message += `\n\nCode ${props.errorCode}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AlertDialog
|
<AlertDialog
|
||||||
visible={props.visible}
|
visible={props.visible}
|
||||||
onDismiss={props.onDismiss}
|
onDismiss={props.onDismiss}
|
||||||
title={title}
|
title={i18n.t('errors.title')}
|
||||||
message={message}
|
message={getErrorMessage(props)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,16 @@ import * as React from 'react';
|
||||||
import { Button, Subheading, useTheme } from 'react-native-paper';
|
import { Button, Subheading, useTheme } from 'react-native-paper';
|
||||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import i18n from 'i18n-js';
|
|
||||||
import * as Animatable from 'react-native-animatable';
|
import * as Animatable from 'react-native-animatable';
|
||||||
import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
|
import {
|
||||||
|
API_REQUEST_CODES,
|
||||||
|
getErrorMessage,
|
||||||
|
REQUEST_STATUS,
|
||||||
|
} from '../../utils/Requests';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
status?: REQUEST_STATUS;
|
status?: REQUEST_STATUS;
|
||||||
code?: REQUEST_CODES;
|
code?: API_REQUEST_CODES;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
message?: string;
|
message?: string;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
|
@ -63,92 +66,9 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function getMessage(props: Props) {
|
|
||||||
let fullMessage = {
|
|
||||||
message: '',
|
|
||||||
icon: '',
|
|
||||||
};
|
|
||||||
if (props.code === undefined) {
|
|
||||||
switch (props.status) {
|
|
||||||
case REQUEST_STATUS.BAD_INPUT:
|
|
||||||
fullMessage.message = i18n.t('errors.badInput');
|
|
||||||
fullMessage.icon = 'alert-circle-outline';
|
|
||||||
break;
|
|
||||||
case REQUEST_STATUS.FORBIDDEN:
|
|
||||||
fullMessage.message = i18n.t('errors.forbidden');
|
|
||||||
fullMessage.icon = 'lock';
|
|
||||||
break;
|
|
||||||
case REQUEST_STATUS.CONNECTION_ERROR:
|
|
||||||
fullMessage.message = i18n.t('errors.connectionError');
|
|
||||||
fullMessage.icon = 'access-point-network-off';
|
|
||||||
break;
|
|
||||||
case REQUEST_STATUS.SERVER_ERROR:
|
|
||||||
fullMessage.message = i18n.t('errors.serverError');
|
|
||||||
fullMessage.icon = 'server-network-off';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fullMessage.message = i18n.t('errors.unknown');
|
|
||||||
fullMessage.icon = 'alert-circle-outline';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (props.code) {
|
|
||||||
case REQUEST_CODES.BAD_CREDENTIALS:
|
|
||||||
fullMessage.message = i18n.t('errors.badCredentials');
|
|
||||||
fullMessage.icon = 'account-alert-outline';
|
|
||||||
break;
|
|
||||||
case REQUEST_CODES.BAD_TOKEN:
|
|
||||||
fullMessage.message = i18n.t('errors.badToken');
|
|
||||||
fullMessage.icon = 'account-alert-outline';
|
|
||||||
break;
|
|
||||||
case REQUEST_CODES.NO_CONSENT:
|
|
||||||
fullMessage.message = i18n.t('errors.noConsent');
|
|
||||||
fullMessage.icon = 'account-remove-outline';
|
|
||||||
break;
|
|
||||||
case REQUEST_CODES.TOKEN_SAVE:
|
|
||||||
fullMessage.message = i18n.t('errors.tokenSave');
|
|
||||||
fullMessage.icon = 'alert-circle-outline';
|
|
||||||
break;
|
|
||||||
case REQUEST_CODES.BAD_INPUT:
|
|
||||||
fullMessage.message = i18n.t('errors.badInput');
|
|
||||||
fullMessage.icon = 'alert-circle-outline';
|
|
||||||
break;
|
|
||||||
case REQUEST_CODES.FORBIDDEN:
|
|
||||||
fullMessage.message = i18n.t('errors.forbidden');
|
|
||||||
fullMessage.icon = 'lock';
|
|
||||||
break;
|
|
||||||
case REQUEST_CODES.CONNECTION_ERROR:
|
|
||||||
fullMessage.message = i18n.t('errors.connectionError');
|
|
||||||
fullMessage.icon = 'access-point-network-off';
|
|
||||||
break;
|
|
||||||
case REQUEST_CODES.SERVER_ERROR:
|
|
||||||
fullMessage.message = i18n.t('errors.serverError');
|
|
||||||
fullMessage.icon = 'server-network-off';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fullMessage.message = i18n.t('errors.unknown');
|
|
||||||
fullMessage.icon = 'alert-circle-outline';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.code !== undefined) {
|
|
||||||
fullMessage.message += `\n\nCode {${props.status}:${props.code}}`;
|
|
||||||
} else {
|
|
||||||
fullMessage.message += `\n\nCode {${props.status}}`;
|
|
||||||
}
|
|
||||||
if (props.message != null) {
|
|
||||||
fullMessage.message = props.message;
|
|
||||||
}
|
|
||||||
if (props.icon != null) {
|
|
||||||
fullMessage.icon = props.icon;
|
|
||||||
}
|
|
||||||
return fullMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ErrorView(props: Props) {
|
function ErrorView(props: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const fullMessage = getMessage(props);
|
const fullMessage = getErrorMessage(props, props.message, props.icon);
|
||||||
const { button } = props;
|
const { button } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useRequestLogic } from '../../utils/customHooks';
|
||||||
import { useFocusEffect } from '@react-navigation/native';
|
import { useFocusEffect } from '@react-navigation/native';
|
||||||
import BasicLoadingScreen from './BasicLoadingScreen';
|
import BasicLoadingScreen from './BasicLoadingScreen';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
|
import { API_REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
|
||||||
|
|
||||||
export type RequestScreenProps<T> = {
|
export type RequestScreenProps<T> = {
|
||||||
request: () => Promise<T>;
|
request: () => Promise<T>;
|
||||||
|
@ -14,7 +14,7 @@ export type RequestScreenProps<T> = {
|
||||||
lastRefreshDate: Date | undefined,
|
lastRefreshDate: Date | undefined,
|
||||||
refreshData: (newRequest?: () => Promise<T>) => void,
|
refreshData: (newRequest?: () => Promise<T>) => void,
|
||||||
status: REQUEST_STATUS,
|
status: REQUEST_STATUS,
|
||||||
code?: REQUEST_CODES
|
code?: API_REQUEST_CODES
|
||||||
) => React.ReactElement;
|
) => React.ReactElement;
|
||||||
cache?: T;
|
cache?: T;
|
||||||
onCacheUpdate?: (newCache: T) => void;
|
onCacheUpdate?: (newCache: T) => void;
|
||||||
|
|
|
@ -29,7 +29,7 @@ import ErrorView from './ErrorView';
|
||||||
import CollapsibleSectionList from '../Collapsible/CollapsibleSectionList';
|
import CollapsibleSectionList from '../Collapsible/CollapsibleSectionList';
|
||||||
import RequestScreen, { RequestScreenProps } from './RequestScreen';
|
import RequestScreen, { RequestScreenProps } from './RequestScreen';
|
||||||
import { CollapsibleComponentPropsType } from '../Collapsible/CollapsibleComponent';
|
import { CollapsibleComponentPropsType } from '../Collapsible/CollapsibleComponent';
|
||||||
import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
|
import { API_REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
|
||||||
|
|
||||||
export type SectionListDataType<ItemT> = Array<{
|
export type SectionListDataType<ItemT> = Array<{
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -61,7 +61,7 @@ type Props<ItemT, RawData> = Omit<
|
||||||
lastRefreshDate: Date | undefined,
|
lastRefreshDate: Date | undefined,
|
||||||
refreshData: (newRequest?: () => Promise<RawData>) => void,
|
refreshData: (newRequest?: () => Promise<RawData>) => void,
|
||||||
status: REQUEST_STATUS,
|
status: REQUEST_STATUS,
|
||||||
code?: REQUEST_CODES
|
code?: API_REQUEST_CODES
|
||||||
) => SectionListDataType<ItemT>;
|
) => SectionListDataType<ItemT>;
|
||||||
renderListHeaderComponent?: (
|
renderListHeaderComponent?: (
|
||||||
data: RawData | undefined,
|
data: RawData | undefined,
|
||||||
|
@ -69,7 +69,7 @@ type Props<ItemT, RawData> = Omit<
|
||||||
lastRefreshDate: Date | undefined,
|
lastRefreshDate: Date | undefined,
|
||||||
refreshData: (newRequest?: () => Promise<RawData>) => void,
|
refreshData: (newRequest?: () => Promise<RawData>) => void,
|
||||||
status: REQUEST_STATUS,
|
status: REQUEST_STATUS,
|
||||||
code?: REQUEST_CODES
|
code?: API_REQUEST_CODES
|
||||||
) => React.ComponentType<any> | React.ReactElement | null;
|
) => React.ComponentType<any> | React.ReactElement | null;
|
||||||
itemHeight?: number | null;
|
itemHeight?: number | null;
|
||||||
};
|
};
|
||||||
|
@ -103,7 +103,7 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
|
||||||
lastRefreshDate: Date | undefined,
|
lastRefreshDate: Date | undefined,
|
||||||
refreshData: (newRequest?: () => Promise<RawData>) => void,
|
refreshData: (newRequest?: () => Promise<RawData>) => void,
|
||||||
status: REQUEST_STATUS,
|
status: REQUEST_STATUS,
|
||||||
code?: REQUEST_CODES
|
code?: API_REQUEST_CODES
|
||||||
) => {
|
) => {
|
||||||
const { itemHeight } = props;
|
const { itemHeight } = props;
|
||||||
const dataset = props.createDataset(
|
const dataset = props.createDataset(
|
||||||
|
|
|
@ -43,11 +43,11 @@ import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityI
|
||||||
import { useTheme } from 'react-native-paper';
|
import { useTheme } from 'react-native-paper';
|
||||||
import { useCollapsibleHeader } from 'react-navigation-collapsible';
|
import { useCollapsibleHeader } from 'react-navigation-collapsible';
|
||||||
import MaterialHeaderButtons, { Item } from '../Overrides/CustomHeaderButton';
|
import MaterialHeaderButtons, { Item } from '../Overrides/CustomHeaderButton';
|
||||||
import { ERROR_TYPE } from '../../utils/WebData';
|
|
||||||
import ErrorView from './ErrorView';
|
import ErrorView from './ErrorView';
|
||||||
import BasicLoadingScreen from './BasicLoadingScreen';
|
import BasicLoadingScreen from './BasicLoadingScreen';
|
||||||
import { useFocusEffect, useNavigation } from '@react-navigation/core';
|
import { useFocusEffect, useNavigation } from '@react-navigation/core';
|
||||||
import { useCollapsible } from '../../utils/CollapsibleContext';
|
import { useCollapsible } from '../../utils/CollapsibleContext';
|
||||||
|
import { REQUEST_STATUS } from '../../utils/Requests';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -259,7 +259,7 @@ function WebViewScreen(props: Props) {
|
||||||
renderLoading={getRenderLoading}
|
renderLoading={getRenderLoading}
|
||||||
renderError={() => (
|
renderError={() => (
|
||||||
<ErrorView
|
<ErrorView
|
||||||
status={ERROR_TYPE.CONNECTION_ERROR}
|
status={REQUEST_STATUS.CONNECTION_ERROR}
|
||||||
button={{
|
button={{
|
||||||
icon: 'refresh',
|
icon: 'refresh',
|
||||||
text: i18n.t('general.retry'),
|
text: i18n.t('general.retry'),
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as Keychain from 'react-native-keychain';
|
import * as Keychain from 'react-native-keychain';
|
||||||
import type { ApiDataLoginType } from '../utils/WebData';
|
import { REQUEST_STATUS } from '../utils/Requests';
|
||||||
import { apiRequest, ERROR_TYPE } from '../utils/WebData';
|
import type { ApiDataLoginType, ApiRejectType } from '../utils/WebData';
|
||||||
|
import { apiRequest } from '../utils/WebData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* champ: error
|
* champ: error
|
||||||
|
@ -141,7 +142,7 @@ export default class ConnectionManager {
|
||||||
*/
|
*/
|
||||||
async connect(email: string, password: string): Promise<void> {
|
async connect(email: string, password: string): Promise<void> {
|
||||||
return new Promise(
|
return new Promise(
|
||||||
(resolve: () => void, reject: (error: number) => void) => {
|
(resolve: () => void, reject: (error: ApiRejectType) => void) => {
|
||||||
const data = {
|
const data = {
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
|
@ -150,13 +151,19 @@ export default class ConnectionManager {
|
||||||
.then((response: ApiDataLoginType) => {
|
.then((response: ApiDataLoginType) => {
|
||||||
if (response.token != null) {
|
if (response.token != null) {
|
||||||
this.saveLogin(email, response.token)
|
this.saveLogin(email, response.token)
|
||||||
.then((): void => resolve())
|
.then(() => resolve())
|
||||||
.catch((): void => reject(ERROR_TYPE.TOKEN_SAVE));
|
.catch(() =>
|
||||||
|
reject({
|
||||||
|
status: REQUEST_STATUS.TOKEN_SAVE,
|
||||||
|
})
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
reject(ERROR_TYPE.SERVER_ERROR);
|
reject({
|
||||||
|
status: REQUEST_STATUS.SERVER_ERROR,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error: number): void => reject(error));
|
.catch(reject);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -173,17 +180,22 @@ export default class ConnectionManager {
|
||||||
params: { [key: string]: any }
|
params: { [key: string]: any }
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
return new Promise(
|
return new Promise(
|
||||||
(resolve: (response: T) => void, reject: (error: number) => void) => {
|
(
|
||||||
|
resolve: (response: T) => void,
|
||||||
|
reject: (error: ApiRejectType) => void
|
||||||
|
) => {
|
||||||
if (this.getToken() !== null) {
|
if (this.getToken() !== null) {
|
||||||
const data = {
|
const data = {
|
||||||
...params,
|
...params,
|
||||||
token: this.getToken(),
|
token: this.getToken(),
|
||||||
};
|
};
|
||||||
apiRequest<T>(path, 'POST', data)
|
apiRequest<T>(path, 'POST', data)
|
||||||
.then((response: T): void => resolve(response))
|
.then((response: T) => resolve(response))
|
||||||
.catch((error: number): void => reject(error));
|
.catch(reject);
|
||||||
} else {
|
} else {
|
||||||
reject(ERROR_TYPE.TOKEN_RETRIEVE);
|
reject({
|
||||||
|
status: REQUEST_STATUS.TOKEN_RETRIEVE,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -46,6 +46,8 @@ import ConnectionManager from '../../../managers/ConnectionManager';
|
||||||
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
||||||
import { MainStackParamsList } from '../../../navigation/MainNavigator';
|
import { MainStackParamsList } from '../../../navigation/MainNavigator';
|
||||||
import GENERAL_STYLES from '../../../constants/Styles';
|
import GENERAL_STYLES from '../../../constants/Styles';
|
||||||
|
import { ApiRejectType } from '../../../utils/WebData';
|
||||||
|
import { REQUEST_STATUS } from '../../../utils/Requests';
|
||||||
|
|
||||||
type EquipmentRentScreenNavigationProp = StackScreenProps<
|
type EquipmentRentScreenNavigationProp = StackScreenProps<
|
||||||
MainStackParamsList,
|
MainStackParamsList,
|
||||||
|
@ -65,7 +67,7 @@ type StateType = {
|
||||||
dialogVisible: boolean;
|
dialogVisible: boolean;
|
||||||
errorDialogVisible: boolean;
|
errorDialogVisible: boolean;
|
||||||
markedDates: MarkedDatesObjectType;
|
markedDates: MarkedDatesObjectType;
|
||||||
currentError: number;
|
currentError: ApiRejectType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -133,7 +135,7 @@ class EquipmentRentScreen extends React.Component<Props, StateType> {
|
||||||
dialogVisible: false,
|
dialogVisible: false,
|
||||||
errorDialogVisible: false,
|
errorDialogVisible: false,
|
||||||
markedDates: {},
|
markedDates: {},
|
||||||
currentError: 0,
|
currentError: { status: REQUEST_STATUS.SUCCESS },
|
||||||
};
|
};
|
||||||
this.resetSelection();
|
this.resetSelection();
|
||||||
this.bookRef = React.createRef();
|
this.bookRef = React.createRef();
|
||||||
|
@ -231,7 +233,7 @@ class EquipmentRentScreen extends React.Component<Props, StateType> {
|
||||||
});
|
});
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch((error: number) => {
|
.catch((error: ApiRejectType) => {
|
||||||
this.onDialogDismiss();
|
this.onDialogDismiss();
|
||||||
this.showErrorDialog(error);
|
this.showErrorDialog(error);
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -284,7 +286,7 @@ class EquipmentRentScreen extends React.Component<Props, StateType> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
showErrorDialog = (error: number) => {
|
showErrorDialog = (error: ApiRejectType) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
errorDialogVisible: true,
|
errorDialogVisible: true,
|
||||||
currentError: error,
|
currentError: error,
|
||||||
|
@ -460,7 +462,8 @@ class EquipmentRentScreen extends React.Component<Props, StateType> {
|
||||||
<ErrorDialog
|
<ErrorDialog
|
||||||
visible={state.errorDialogVisible}
|
visible={state.errorDialogVisible}
|
||||||
onDismiss={this.onErrorDialogDismiss}
|
onDismiss={this.onErrorDialogDismiss}
|
||||||
errorCode={state.currentError}
|
status={state.currentError.status}
|
||||||
|
code={state.currentError.code}
|
||||||
/>
|
/>
|
||||||
<Animatable.View
|
<Animatable.View
|
||||||
ref={this.bookRef}
|
ref={this.bookRef}
|
||||||
|
|
|
@ -38,6 +38,8 @@ import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrol
|
||||||
import { MainStackParamsList } from '../../navigation/MainNavigator';
|
import { MainStackParamsList } from '../../navigation/MainNavigator';
|
||||||
import GENERAL_STYLES from '../../constants/Styles';
|
import GENERAL_STYLES from '../../constants/Styles';
|
||||||
import Urls from '../../constants/Urls';
|
import Urls from '../../constants/Urls';
|
||||||
|
import { ApiRejectType } from '../../utils/WebData';
|
||||||
|
import { REQUEST_STATUS } from '../../utils/Requests';
|
||||||
|
|
||||||
type LoginScreenNavigationProp = StackScreenProps<MainStackParamsList, 'login'>;
|
type LoginScreenNavigationProp = StackScreenProps<MainStackParamsList, 'login'>;
|
||||||
|
|
||||||
|
@ -53,7 +55,7 @@ type StateType = {
|
||||||
isPasswordValidated: boolean;
|
isPasswordValidated: boolean;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
dialogVisible: boolean;
|
dialogVisible: boolean;
|
||||||
dialogError: number;
|
dialogError: REQUEST_STATUS;
|
||||||
mascotDialogVisible: boolean;
|
mascotDialogVisible: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,7 +117,7 @@ class LoginScreen extends React.Component<Props, StateType> {
|
||||||
isPasswordValidated: false,
|
isPasswordValidated: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
dialogVisible: false,
|
dialogVisible: false,
|
||||||
dialogError: 0,
|
dialogError: REQUEST_STATUS.SUCCESS,
|
||||||
mascotDialogVisible: AsyncStorageManager.getBool(
|
mascotDialogVisible: AsyncStorageManager.getBool(
|
||||||
AsyncStorageManager.PREFERENCES.loginShowMascot.key
|
AsyncStorageManager.PREFERENCES.loginShowMascot.key
|
||||||
),
|
),
|
||||||
|
@ -335,10 +337,10 @@ class LoginScreen extends React.Component<Props, StateType> {
|
||||||
*
|
*
|
||||||
* @param error The error given by the login request
|
* @param error The error given by the login request
|
||||||
*/
|
*/
|
||||||
showErrorDialog = (error: number) => {
|
showErrorDialog = (error: ApiRejectType) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
dialogVisible: true,
|
dialogVisible: true,
|
||||||
dialogError: error,
|
dialogError: error.status,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -433,10 +435,10 @@ class LoginScreen extends React.Component<Props, StateType> {
|
||||||
end={{ x: 0.1, y: 1 }}
|
end={{ x: 0.1, y: 1 }}
|
||||||
>
|
>
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
behavior="height"
|
behavior={'height'}
|
||||||
contentContainerStyle={GENERAL_STYLES.flex}
|
contentContainerStyle={GENERAL_STYLES.flex}
|
||||||
style={GENERAL_STYLES.flex}
|
style={GENERAL_STYLES.flex}
|
||||||
enabled
|
enabled={true}
|
||||||
keyboardVerticalOffset={100}
|
keyboardVerticalOffset={100}
|
||||||
>
|
>
|
||||||
<CollapsibleScrollView headerColors={'transparent'}>
|
<CollapsibleScrollView headerColors={'transparent'}>
|
||||||
|
@ -445,7 +447,7 @@ class LoginScreen extends React.Component<Props, StateType> {
|
||||||
visible={mascotDialogVisible}
|
visible={mascotDialogVisible}
|
||||||
title={i18n.t('screens.login.mascotDialog.title')}
|
title={i18n.t('screens.login.mascotDialog.title')}
|
||||||
message={i18n.t('screens.login.mascotDialog.message')}
|
message={i18n.t('screens.login.mascotDialog.message')}
|
||||||
icon="help"
|
icon={'help'}
|
||||||
buttons={{
|
buttons={{
|
||||||
cancel: {
|
cancel: {
|
||||||
message: i18n.t('screens.login.mascotDialog.button'),
|
message: i18n.t('screens.login.mascotDialog.button'),
|
||||||
|
@ -458,7 +460,7 @@ class LoginScreen extends React.Component<Props, StateType> {
|
||||||
<ErrorDialog
|
<ErrorDialog
|
||||||
visible={dialogVisible}
|
visible={dialogVisible}
|
||||||
onDismiss={this.hideErrorDialog}
|
onDismiss={this.hideErrorDialog}
|
||||||
errorCode={dialogError}
|
status={dialogError}
|
||||||
/>
|
/>
|
||||||
</CollapsibleScrollView>
|
</CollapsibleScrollView>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
|
import i18n from 'i18n-js';
|
||||||
|
import { ApiRejectType } from './WebData';
|
||||||
|
|
||||||
export enum REQUEST_STATUS {
|
export enum REQUEST_STATUS {
|
||||||
SUCCESS = 200,
|
SUCCESS = 200,
|
||||||
BAD_INPUT = 400,
|
|
||||||
FORBIDDEN = 403,
|
|
||||||
CONNECTION_ERROR = 404,
|
|
||||||
SERVER_ERROR = 500,
|
|
||||||
UNKNOWN = 999,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum REQUEST_CODES {
|
|
||||||
SUCCESS = 0,
|
|
||||||
BAD_CREDENTIALS = 1,
|
|
||||||
BAD_TOKEN = 2,
|
|
||||||
NO_CONSENT = 3,
|
|
||||||
TOKEN_SAVE = 4,
|
TOKEN_SAVE = 4,
|
||||||
TOKEN_RETRIEVE = 5,
|
TOKEN_RETRIEVE = 5,
|
||||||
BAD_INPUT = 400,
|
BAD_INPUT = 400,
|
||||||
|
@ -20,3 +11,92 @@ export enum REQUEST_CODES {
|
||||||
SERVER_ERROR = 500,
|
SERVER_ERROR = 500,
|
||||||
UNKNOWN = 999,
|
UNKNOWN = 999,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum API_REQUEST_CODES {
|
||||||
|
SUCCESS = 0,
|
||||||
|
BAD_CREDENTIALS = 1,
|
||||||
|
BAD_TOKEN = 2,
|
||||||
|
NO_CONSENT = 3,
|
||||||
|
BAD_INPUT = 400,
|
||||||
|
FORBIDDEN = 403,
|
||||||
|
UNKNOWN = 999,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getErrorMessage(
|
||||||
|
props: Partial<ApiRejectType>,
|
||||||
|
message?: string,
|
||||||
|
icon?: string
|
||||||
|
) {
|
||||||
|
let fullMessage = {
|
||||||
|
message: '',
|
||||||
|
icon: '',
|
||||||
|
};
|
||||||
|
if (props.code === undefined) {
|
||||||
|
switch (props.status) {
|
||||||
|
case REQUEST_STATUS.BAD_INPUT:
|
||||||
|
fullMessage.message = i18n.t('errors.badInput');
|
||||||
|
fullMessage.icon = 'alert-circle-outline';
|
||||||
|
break;
|
||||||
|
case REQUEST_STATUS.FORBIDDEN:
|
||||||
|
fullMessage.message = i18n.t('errors.forbidden');
|
||||||
|
fullMessage.icon = 'lock';
|
||||||
|
break;
|
||||||
|
case REQUEST_STATUS.CONNECTION_ERROR:
|
||||||
|
fullMessage.message = i18n.t('errors.connectionError');
|
||||||
|
fullMessage.icon = 'access-point-network-off';
|
||||||
|
break;
|
||||||
|
case REQUEST_STATUS.SERVER_ERROR:
|
||||||
|
fullMessage.message = i18n.t('errors.serverError');
|
||||||
|
fullMessage.icon = 'server-network-off';
|
||||||
|
break;
|
||||||
|
case REQUEST_STATUS.TOKEN_SAVE:
|
||||||
|
fullMessage.message = i18n.t('errors.tokenSave');
|
||||||
|
fullMessage.icon = 'alert-circle-outline';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fullMessage.message = i18n.t('errors.unknown');
|
||||||
|
fullMessage.icon = 'alert-circle-outline';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (props.code) {
|
||||||
|
case API_REQUEST_CODES.BAD_CREDENTIALS:
|
||||||
|
fullMessage.message = i18n.t('errors.badCredentials');
|
||||||
|
fullMessage.icon = 'account-alert-outline';
|
||||||
|
break;
|
||||||
|
case API_REQUEST_CODES.BAD_TOKEN:
|
||||||
|
fullMessage.message = i18n.t('errors.badToken');
|
||||||
|
fullMessage.icon = 'account-alert-outline';
|
||||||
|
break;
|
||||||
|
case API_REQUEST_CODES.NO_CONSENT:
|
||||||
|
fullMessage.message = i18n.t('errors.noConsent');
|
||||||
|
fullMessage.icon = 'account-remove-outline';
|
||||||
|
break;
|
||||||
|
case API_REQUEST_CODES.BAD_INPUT:
|
||||||
|
fullMessage.message = i18n.t('errors.badInput');
|
||||||
|
fullMessage.icon = 'alert-circle-outline';
|
||||||
|
break;
|
||||||
|
case API_REQUEST_CODES.FORBIDDEN:
|
||||||
|
fullMessage.message = i18n.t('errors.forbidden');
|
||||||
|
fullMessage.icon = 'lock';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fullMessage.message = i18n.t('errors.unknown');
|
||||||
|
fullMessage.icon = 'alert-circle-outline';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.code !== undefined) {
|
||||||
|
fullMessage.message += `\n\nCode {${props.status}:${props.code}}`;
|
||||||
|
} else {
|
||||||
|
fullMessage.message += `\n\nCode {${props.status}}`;
|
||||||
|
}
|
||||||
|
if (message) {
|
||||||
|
fullMessage.message = message;
|
||||||
|
}
|
||||||
|
if (icon) {
|
||||||
|
fullMessage.icon = icon;
|
||||||
|
}
|
||||||
|
return fullMessage;
|
||||||
|
}
|
||||||
|
|
|
@ -18,20 +18,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Urls from '../constants/Urls';
|
import Urls from '../constants/Urls';
|
||||||
|
import { API_REQUEST_CODES, REQUEST_STATUS } from './Requests';
|
||||||
|
|
||||||
export const ERROR_TYPE = {
|
// export const ERROR_TYPE = {
|
||||||
SUCCESS: 0,
|
// SUCCESS: 0,
|
||||||
BAD_CREDENTIALS: 1,
|
// BAD_CREDENTIALS: 1,
|
||||||
BAD_TOKEN: 2,
|
// BAD_TOKEN: 2,
|
||||||
NO_CONSENT: 3,
|
// NO_CONSENT: 3,
|
||||||
TOKEN_SAVE: 4,
|
// TOKEN_SAVE: 4,
|
||||||
TOKEN_RETRIEVE: 5,
|
// TOKEN_RETRIEVE: 5,
|
||||||
BAD_INPUT: 400,
|
// BAD_INPUT: 400,
|
||||||
FORBIDDEN: 403,
|
// FORBIDDEN: 403,
|
||||||
CONNECTION_ERROR: 404,
|
// CONNECTION_ERROR: 404,
|
||||||
SERVER_ERROR: 500,
|
// SERVER_ERROR: 500,
|
||||||
UNKNOWN: 999,
|
// UNKNOWN: 999,
|
||||||
};
|
// };
|
||||||
|
|
||||||
export type ApiDataLoginType = {
|
export type ApiDataLoginType = {
|
||||||
token: string;
|
token: string;
|
||||||
|
@ -42,6 +43,11 @@ type ApiResponseType<T> = {
|
||||||
data: T;
|
data: T;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiRejectType = {
|
||||||
|
status: REQUEST_STATUS;
|
||||||
|
code?: API_REQUEST_CODES;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given API response is valid.
|
* Checks if the given API response is valid.
|
||||||
*
|
*
|
||||||
|
@ -76,7 +82,7 @@ export async function apiRequest<T>(
|
||||||
params?: object
|
params?: object
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
return new Promise(
|
return new Promise(
|
||||||
(resolve: (data: T) => void, reject: (error: number) => void) => {
|
(resolve: (data: T) => void, reject: (error: ApiRejectType) => void) => {
|
||||||
let requestParams = {};
|
let requestParams = {};
|
||||||
if (params != null) {
|
if (params != null) {
|
||||||
requestParams = { ...params };
|
requestParams = { ...params };
|
||||||
|
@ -95,16 +101,25 @@ export async function apiRequest<T>(
|
||||||
)
|
)
|
||||||
.then((response: ApiResponseType<T>) => {
|
.then((response: ApiResponseType<T>) => {
|
||||||
if (isApiResponseValid(response)) {
|
if (isApiResponseValid(response)) {
|
||||||
if (response.error === ERROR_TYPE.SUCCESS) {
|
if (response.error === API_REQUEST_CODES.SUCCESS) {
|
||||||
resolve(response.data);
|
resolve(response.data);
|
||||||
} else {
|
} else {
|
||||||
reject(response.error);
|
reject({
|
||||||
|
status: REQUEST_STATUS.SUCCESS,
|
||||||
|
code: response.error,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reject(ERROR_TYPE.SERVER_ERROR);
|
reject({
|
||||||
|
status: REQUEST_STATUS.SERVER_ERROR,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((): void => reject(ERROR_TYPE.CONNECTION_ERROR));
|
.catch(() =>
|
||||||
|
reject({
|
||||||
|
status: REQUEST_STATUS.SERVER_ERROR,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
import { DependencyList, useEffect, useRef, useState } from 'react';
|
import { DependencyList, useEffect, useRef, useState } from 'react';
|
||||||
import { REQUEST_STATUS } from './Requests';
|
import { REQUEST_STATUS } from './Requests';
|
||||||
|
import { ApiRejectType } from './WebData';
|
||||||
|
|
||||||
export function useMountEffect(func: () => void) {
|
export function useMountEffect(func: () => void) {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
@ -97,14 +98,24 @@ export function useRequestLogic<T>(
|
||||||
onCacheUpdate(requestResponse);
|
onCacheUpdate(requestResponse);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((error: ApiRejectType | undefined) => {
|
||||||
setResponse((prevState) => ({
|
if (!error) {
|
||||||
loading: false,
|
setResponse((prevState) => ({
|
||||||
lastRefreshDate: prevState.lastRefreshDate,
|
loading: false,
|
||||||
status: REQUEST_STATUS.CONNECTION_ERROR,
|
lastRefreshDate: prevState.lastRefreshDate,
|
||||||
code: undefined,
|
status: REQUEST_STATUS.CONNECTION_ERROR,
|
||||||
data: prevState.data,
|
code: undefined,
|
||||||
}));
|
data: prevState.data,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
setResponse((prevState) => ({
|
||||||
|
loading: false,
|
||||||
|
lastRefreshDate: prevState.lastRefreshDate,
|
||||||
|
status: error.status,
|
||||||
|
code: error.code,
|
||||||
|
data: prevState.data,
|
||||||
|
}));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue