Update dialogs to use TypeScript

This commit is contained in:
Arnaud Vergnet 2020-09-22 11:49:31 +02:00
parent f95635136e
commit 98518c46b6
5 changed files with 149 additions and 166 deletions

View file

@ -17,36 +17,31 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {Button, Dialog, Paragraph, Portal} from 'react-native-paper'; import {Button, Dialog, Paragraph, Portal} from 'react-native-paper';
import i18n from 'i18n-js'; import i18n from 'i18n-js';
type PropsType = { type PropsType = {
visible: boolean, visible: boolean;
onDismiss: () => void, onDismiss: () => void;
title: string | React.Node, title: string | React.ReactNode;
message: string | React.Node, message: string | React.ReactNode;
}; };
class AlertDialog extends React.PureComponent<PropsType> { function AlertDialog(props: PropsType) {
render(): React.Node { return (
const {props} = this; <Portal>
return ( <Dialog visible={props.visible} onDismiss={props.onDismiss}>
<Portal> <Dialog.Title>{props.title}</Dialog.Title>
<Dialog visible={props.visible} onDismiss={props.onDismiss}> <Dialog.Content>
<Dialog.Title>{props.title}</Dialog.Title> <Paragraph>{props.message}</Paragraph>
<Dialog.Content> </Dialog.Content>
<Paragraph>{props.message}</Paragraph> <Dialog.Actions>
</Dialog.Content> <Button onPress={props.onDismiss}>{i18n.t('dialog.ok')}</Button>
<Dialog.Actions> </Dialog.Actions>
<Button onPress={props.onDismiss}>{i18n.t('dialog.ok')}</Button> </Dialog>
</Dialog.Actions> </Portal>
</Dialog> );
</Portal>
);
}
} }
export default AlertDialog; export default AlertDialog;

View file

@ -1,90 +0,0 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import i18n from 'i18n-js';
import {ERROR_TYPE} from '../../utils/WebData';
import AlertDialog from './AlertDialog';
type PropsType = {
visible: boolean,
onDismiss: () => void,
errorCode: number,
};
class ErrorDialog extends React.PureComponent<PropsType> {
title: string;
message: string;
generateMessage() {
const {props} = this;
this.title = i18n.t('errors.title');
switch (props.errorCode) {
case ERROR_TYPE.BAD_CREDENTIALS:
this.message = i18n.t('errors.badCredentials');
break;
case ERROR_TYPE.BAD_TOKEN:
this.message = i18n.t('errors.badToken');
break;
case ERROR_TYPE.NO_CONSENT:
this.message = i18n.t('errors.noConsent');
break;
case ERROR_TYPE.TOKEN_SAVE:
this.message = i18n.t('errors.tokenSave');
break;
case ERROR_TYPE.TOKEN_RETRIEVE:
this.message = i18n.t('errors.unknown');
break;
case ERROR_TYPE.BAD_INPUT:
this.message = i18n.t('errors.badInput');
break;
case ERROR_TYPE.FORBIDDEN:
this.message = i18n.t('errors.forbidden');
break;
case ERROR_TYPE.CONNECTION_ERROR:
this.message = i18n.t('errors.connectionError');
break;
case ERROR_TYPE.SERVER_ERROR:
this.message = i18n.t('errors.serverError');
break;
default:
this.message = i18n.t('errors.unknown');
break;
}
this.message += `\n\nCode ${props.errorCode}`;
}
render(): React.Node {
this.generateMessage();
const {props} = this;
return (
<AlertDialog
visible={props.visible}
onDismiss={props.onDismiss}
title={this.title}
message={this.message}
/>
);
}
}
export default ErrorDialog;

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
import * as React from 'react';
import i18n from 'i18n-js';
import {ERROR_TYPE} from '../../utils/WebData';
import AlertDialog from './AlertDialog';
type PropsType = {
visible: boolean;
onDismiss: () => void;
errorCode: number;
};
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 (
<AlertDialog
visible={props.visible}
onDismiss={props.onDismiss}
title={title}
message={message}
/>
);
}
export default ErrorDialog;

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import { import {
ActivityIndicator, ActivityIndicator,
@ -30,20 +28,23 @@ import {
import i18n from 'i18n-js'; import i18n from 'i18n-js';
type PropsType = { type PropsType = {
visible: boolean, visible: boolean;
onDismiss?: () => void, onDismiss?: () => void;
onAccept?: () => Promise<void>, // async function to be executed onAccept?: () => Promise<void>; // async function to be executed
title?: string, title?: string;
titleLoading?: string, titleLoading?: string;
message?: string, message?: string;
startLoading?: boolean, startLoading?: boolean;
}; };
type StateType = { type StateType = {
loading: boolean, loading: boolean;
}; };
class LoadingConfirmDialog extends React.PureComponent<PropsType, StateType> { export default class LoadingConfirmDialog extends React.PureComponent<
PropsType,
StateType
> {
static defaultProps = { static defaultProps = {
onDismiss: () => {}, onDismiss: () => {},
onAccept: (): Promise<void> => { onAccept: (): Promise<void> => {
@ -71,14 +72,16 @@ class LoadingConfirmDialog extends React.PureComponent<PropsType, StateType> {
onClickAccept = () => { onClickAccept = () => {
const {props} = this; const {props} = this;
this.setState({loading: true}); this.setState({loading: true});
if (props.onAccept != null) props.onAccept().then(this.hideLoading); if (props.onAccept != null) {
props.onAccept().then(this.hideLoading);
}
}; };
/** /**
* Waits for fade out animations to finish before hiding loading * Waits for fade out animations to finish before hiding loading
* @returns {TimeoutID} * @returns {NodeJS.Timeout}
*/ */
hideLoading = (): TimeoutID => hideLoading = (): NodeJS.Timeout =>
setTimeout(() => { setTimeout(() => {
this.setState({loading: false}); this.setState({loading: false});
}, 200); }, 200);
@ -88,10 +91,12 @@ class LoadingConfirmDialog extends React.PureComponent<PropsType, StateType> {
*/ */
onDismiss = () => { onDismiss = () => {
const {state, props} = this; const {state, props} = this;
if (!state.loading && props.onDismiss != null) props.onDismiss(); if (!state.loading && props.onDismiss != null) {
props.onDismiss();
}
}; };
render(): React.Node { render() {
const {state, props} = this; const {state, props} = this;
return ( return (
<Portal> <Portal>
@ -121,5 +126,3 @@ class LoadingConfirmDialog extends React.PureComponent<PropsType, StateType> {
); );
} }
} }
export default LoadingConfirmDialog;

View file

@ -17,28 +17,26 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {Button, Dialog, Paragraph, Portal} from 'react-native-paper'; import {Button, Dialog, Paragraph, Portal} from 'react-native-paper';
import {FlatList} from 'react-native'; import {FlatList} from 'react-native';
export type OptionsDialogButtonType = { export type OptionsDialogButtonType = {
title: string, title: string;
icon?: string, icon?: string;
onPress: () => void, onPress: () => void;
}; };
type PropsType = { type PropsType = {
visible: boolean, visible: boolean;
title: string, title: string;
message: string, message: string;
buttons: Array<OptionsDialogButtonType>, buttons: Array<OptionsDialogButtonType>;
onDismiss: () => void, onDismiss: () => void;
}; };
class OptionsDialog extends React.PureComponent<PropsType> { function OptionsDialog(props: PropsType) {
getButtonRender = ({item}: {item: OptionsDialogButtonType}): React.Node => { const getButtonRender = ({item}: {item: OptionsDialogButtonType}) => {
return ( return (
<Button onPress={item.onPress} icon={item.icon}> <Button onPress={item.onPress} icon={item.icon}>
{item.title} {item.title}
@ -46,35 +44,32 @@ class OptionsDialog extends React.PureComponent<PropsType> {
); );
}; };
keyExtractor = (item: OptionsDialogButtonType): string => { const keyExtractor = (item: OptionsDialogButtonType): string => {
if (item.icon != null) { if (item.icon != null) {
return item.title + item.icon; return item.title + item.icon;
} }
return item.title; return item.title;
}; };
render(): React.Node { return (
const {props} = this; <Portal>
return ( <Dialog visible={props.visible} onDismiss={props.onDismiss}>
<Portal> <Dialog.Title>{props.title}</Dialog.Title>
<Dialog visible={props.visible} onDismiss={props.onDismiss}> <Dialog.Content>
<Dialog.Title>{props.title}</Dialog.Title> <Paragraph>{props.message}</Paragraph>
<Dialog.Content> </Dialog.Content>
<Paragraph>{props.message}</Paragraph> <Dialog.Actions>
</Dialog.Content> <FlatList
<Dialog.Actions> data={props.buttons}
<FlatList renderItem={getButtonRender}
data={props.buttons} keyExtractor={keyExtractor}
renderItem={this.getButtonRender} horizontal
keyExtractor={this.keyExtractor} inverted
horizontal />
inverted </Dialog.Actions>
/> </Dialog>
</Dialog.Actions> </Portal>
</Dialog> );
</Portal>
);
}
} }
export default OptionsDialog; export default OptionsDialog;