diff --git a/src/components/Amicale/AuthenticatedScreen.js b/src/components/Amicale/AuthenticatedScreen.tsx similarity index 80% rename from src/components/Amicale/AuthenticatedScreen.js rename to src/components/Amicale/AuthenticatedScreen.tsx index 97ff4eb..68aa704 100644 --- a/src/components/Amicale/AuthenticatedScreen.js +++ b/src/components/Amicale/AuthenticatedScreen.tsx @@ -17,37 +17,34 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {StackNavigationProp} from '@react-navigation/stack'; import ConnectionManager from '../../managers/ConnectionManager'; -import type {ApiGenericDataType} from '../../utils/WebData'; import {ERROR_TYPE} from '../../utils/WebData'; import ErrorView from '../Screens/ErrorView'; import BasicLoadingScreen from '../Screens/BasicLoadingScreen'; -type PropsType = { - navigation: StackNavigationProp, +type PropsType = { + navigation: StackNavigationProp; requests: Array<{ - link: string, - params: {...}, - mandatory: boolean, - }>, - renderFunction: (Array) => React.Node, + link: string; + params: object; + mandatory: boolean; + }>; + renderFunction: (data: Array) => React.ReactNode; errorViewOverride?: Array<{ - errorCode: number, - message: string, - icon: string, - showRetryButton: boolean, - }> | null, + errorCode: number; + message: string; + icon: string; + showRetryButton: boolean; + }> | null; }; type StateType = { - loading: boolean, + loading: boolean; }; -class AuthenticatedScreen extends React.Component { +class AuthenticatedScreen extends React.Component, StateType> { static defaultProps = { errorViewOverride: null, }; @@ -58,13 +55,14 @@ class AuthenticatedScreen extends React.Component { errors: Array; - fetchedData: Array; + fetchedData: Array; - constructor(props: PropsType) { + constructor(props: PropsType) { super(props); this.state = { loading: true, }; + this.currentUserToken = null; this.connectionManager = ConnectionManager.getInstance(); props.navigation.addListener('focus', this.onScreenFocus); this.fetchedData = new Array(props.requests.length); @@ -91,20 +89,20 @@ class AuthenticatedScreen extends React.Component { * @param index The index for the data * @param error The error code received */ - onRequestFinished( - data: ApiGenericDataType | null, - index: number, - error?: number, - ) { + onRequestFinished(data: T | null, index: number, error?: number) { const {props} = this; if (index >= 0 && index < props.requests.length) { this.fetchedData[index] = data; this.errors[index] = error != null ? error : ERROR_TYPE.SUCCESS; } // Token expired, logout user - if (error === ERROR_TYPE.BAD_TOKEN) this.connectionManager.disconnect(); + if (error === ERROR_TYPE.BAD_TOKEN) { + this.connectionManager.disconnect(); + } - if (this.allRequestsFinished()) this.setState({loading: false}); + if (this.allRequestsFinished()) { + this.setState({loading: false}); + } } /** @@ -132,7 +130,7 @@ class AuthenticatedScreen extends React.Component { * * @return {*} */ - getErrorRender(): React.Node { + getErrorRender() { const {props} = this; const errorCode = this.getError(); let shouldOverride = false; @@ -169,18 +167,18 @@ class AuthenticatedScreen extends React.Component { */ fetchData = () => { const {state, props} = this; - if (!state.loading) this.setState({loading: true}); + if (!state.loading) { + this.setState({loading: true}); + } if (this.connectionManager.isLoggedIn()) { for (let i = 0; i < props.requests.length; i += 1) { this.connectionManager - .authenticatedRequest( + .authenticatedRequest( props.requests[i].link, props.requests[i].params, ) - .then((response: ApiGenericDataType): void => - this.onRequestFinished(response, i), - ) + .then((response: T): void => this.onRequestFinished(response, i)) .catch((error: number): void => this.onRequestFinished(null, i, error), ); @@ -200,7 +198,9 @@ class AuthenticatedScreen extends React.Component { allRequestsFinished(): boolean { let finished = true; this.errors.forEach((error: number | null) => { - if (error == null) finished = false; + if (error == null) { + finished = false; + } }); return finished; } @@ -212,11 +212,14 @@ class AuthenticatedScreen extends React.Component { this.fetchData(); } - render(): React.Node { + render() { const {state, props} = this; - if (state.loading) return ; - if (this.getError() === ERROR_TYPE.SUCCESS) + if (state.loading) { + return ; + } + if (this.getError() === ERROR_TYPE.SUCCESS) { return props.renderFunction(this.fetchedData); + } return this.getErrorRender(); } } diff --git a/src/components/Amicale/LogoutDialog.js b/src/components/Amicale/LogoutDialog.tsx similarity index 64% rename from src/components/Amicale/LogoutDialog.js rename to src/components/Amicale/LogoutDialog.tsx index d380539..98205d3 100644 --- a/src/components/Amicale/LogoutDialog.js +++ b/src/components/Amicale/LogoutDialog.tsx @@ -17,28 +17,25 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import i18n from 'i18n-js'; -import {StackNavigationProp} from '@react-navigation/stack'; import LoadingConfirmDialog from '../Dialogs/LoadingConfirmDialog'; import ConnectionManager from '../../managers/ConnectionManager'; +import {useNavigation} from '@react-navigation/native'; type PropsType = { - navigation: StackNavigationProp, - visible: boolean, - onDismiss: () => void, + visible: boolean; + onDismiss: () => void; }; -class LogoutDialog extends React.PureComponent { - onClickAccept = async (): Promise => { - const {props} = this; +function LogoutDialog(props: PropsType) { + const navigation = useNavigation(); + const onClickAccept = async (): Promise => { return new Promise((resolve: () => void) => { ConnectionManager.getInstance() .disconnect() .then(() => { - props.navigation.reset({ + navigation.reset({ index: 0, routes: [{name: 'main'}], }); @@ -48,19 +45,16 @@ class LogoutDialog extends React.PureComponent { }); }; - render(): React.Node { - const {props} = this; - return ( - - ); - } + return ( + + ); } export default LogoutDialog; diff --git a/src/components/Amicale/Vote/VoteNotAvailable.js b/src/components/Amicale/Vote/VoteNotAvailable.tsx similarity index 52% rename from src/components/Amicale/Vote/VoteNotAvailable.js rename to src/components/Amicale/Vote/VoteNotAvailable.tsx index 3262a8a..f4d60ac 100644 --- a/src/components/Amicale/Vote/VoteNotAvailable.js +++ b/src/components/Amicale/Vote/VoteNotAvailable.tsx @@ -17,42 +17,29 @@ * along with Campus INSAT. If not, see . */ -// @flow - -import * as React from 'react'; +import React from 'react'; import {View} from 'react-native'; -import {Headline, withTheme} from 'react-native-paper'; +import {Headline, useTheme} from 'react-native-paper'; import i18n from 'i18n-js'; -import type {CustomThemeType} from '../../../managers/ThemeManager'; -type PropsType = { - theme: CustomThemeType, -}; - -class VoteNotAvailable extends React.Component { - shouldComponentUpdate(): boolean { - return false; - } - - render(): React.Node { - const {props} = this; - return ( - + - - {i18n.t('screens.vote.noVote')} - - - ); - } + {i18n.t('screens.vote.noVote')} + + + ); } -export default withTheme(VoteNotAvailable); +export default VoteNotAvailable; diff --git a/src/components/Amicale/Vote/VoteResults.js b/src/components/Amicale/Vote/VoteResults.tsx similarity index 79% rename from src/components/Amicale/Vote/VoteResults.js rename to src/components/Amicale/Vote/VoteResults.tsx index cd9acd2..f0e9396 100644 --- a/src/components/Amicale/Vote/VoteResults.js +++ b/src/components/Amicale/Vote/VoteResults.tsx @@ -17,8 +17,6 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import { Avatar, @@ -31,16 +29,11 @@ import { import {FlatList, StyleSheet} from 'react-native'; import i18n from 'i18n-js'; import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen'; -import type {CustomThemeType} from '../../../managers/ThemeManager'; -import type { - CardTitleIconPropsType, - ListIconPropsType, -} from '../../../constants/PaperStyles'; type PropsType = { - teams: Array, - dateEnd: string, - theme: CustomThemeType, + teams: Array; + dateEnd: string; + theme: ReactNativePaper.Theme; }; const styles = StyleSheet.create({ @@ -58,10 +51,10 @@ class VoteResults extends React.Component { winnerIds: Array; constructor(props: PropsType) { - super(); + super(props); props.teams.sort(this.sortByVotes); - this.getTotalVotes(props.teams); - this.getWinnerIds(props.teams); + this.totalVotes = this.getTotalVotes(props.teams); + this.winnerIds = this.getWinnerIds(props.teams); } shouldComponentUpdate(): boolean { @@ -69,26 +62,31 @@ class VoteResults extends React.Component { } getTotalVotes(teams: Array) { - this.totalVotes = 0; + let totalVotes = 0; for (let i = 0; i < teams.length; i += 1) { - this.totalVotes += teams[i].votes; + totalVotes += teams[i].votes; } + return totalVotes; } getWinnerIds(teams: Array) { const max = teams[0].votes; - this.winnerIds = []; + let winnerIds = []; for (let i = 0; i < teams.length; i += 1) { - if (teams[i].votes === max) this.winnerIds.push(teams[i].id); - else break; + if (teams[i].votes === max) { + winnerIds.push(teams[i].id); + } else { + break; + } } + return winnerIds; } sortByVotes = (a: VoteTeamType, b: VoteTeamType): number => b.votes - a.votes; voteKeyExtractor = (item: VoteTeamType): string => item.id.toString(); - resultRenderItem = ({item}: {item: VoteTeamType}): React.Node => { + resultRenderItem = ({item}: {item: VoteTeamType}) => { const isWinner = this.winnerIds.indexOf(item.id) !== -1; const isDraw = this.winnerIds.length > 1; const {props} = this; @@ -101,7 +99,7 @@ class VoteResults extends React.Component { + left={(iconProps) => isWinner ? ( { ); }; - render(): React.Node { + render() { const {props} = this; return ( @@ -134,15 +132,14 @@ class VoteResults extends React.Component { subtitle={`${i18n.t('screens.vote.results.subtitle')} ${ props.dateEnd }`} - left={(iconProps: CardTitleIconPropsType): React.Node => ( + left={(iconProps) => ( )} /> - {`${i18n.t('screens.vote.results.totalVotes')} ${ - this.totalVotes - }`} - {/* $FlowFixMe */} + + {`${i18n.t('screens.vote.results.totalVotes')} ${this.totalVotes}`} + . */ -// @flow - import * as React from 'react'; import {Avatar, Button, Card, RadioButton} from 'react-native-paper'; import {FlatList, StyleSheet, View} from 'react-native'; @@ -27,19 +25,18 @@ import ConnectionManager from '../../../managers/ConnectionManager'; import LoadingConfirmDialog from '../../Dialogs/LoadingConfirmDialog'; import ErrorDialog from '../../Dialogs/ErrorDialog'; import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen'; -import type {CardTitleIconPropsType} from '../../../constants/PaperStyles'; type PropsType = { - teams: Array, - onVoteSuccess: () => void, - onVoteError: () => void, + teams: Array; + onVoteSuccess: () => void; + onVoteError: () => void; }; type StateType = { - selectedTeam: string, - voteDialogVisible: boolean, - errorDialogVisible: boolean, - currentError: number, + selectedTeam: string; + voteDialogVisible: boolean; + errorDialogVisible: boolean; + currentError: number; }; const styles = StyleSheet.create({ @@ -53,10 +50,10 @@ const styles = StyleSheet.create({ export default class VoteSelect extends React.PureComponent< PropsType, - StateType, + StateType > { - constructor() { - super(); + constructor(props: PropsType) { + super(props); this.state = { selectedTeam: 'none', voteDialogVisible: false, @@ -70,7 +67,7 @@ export default class VoteSelect extends React.PureComponent< voteKeyExtractor = (item: VoteTeamType): string => item.id.toString(); - voteRenderItem = ({item}: {item: VoteTeamType}): React.Node => ( + voteRenderItem = ({item}: {item: VoteTeamType}) => ( ); @@ -111,7 +108,7 @@ export default class VoteSelect extends React.PureComponent< props.onVoteError(); }; - render(): React.Node { + render() { const {state, props} = this; return ( @@ -119,7 +116,7 @@ export default class VoteSelect extends React.PureComponent< ( + left={(iconProps) => ( )} /> @@ -127,7 +124,6 @@ export default class VoteSelect extends React.PureComponent< - {/* $FlowFixMe */} . */ -// @flow - import * as React from 'react'; import {Avatar, Card, Paragraph} from 'react-native-paper'; import {StyleSheet} from 'react-native'; import i18n from 'i18n-js'; -import type {CardTitleIconPropsType} from '../../../constants/PaperStyles'; type PropsType = { - startDate: string, + startDate: string; }; const styles = StyleSheet.create({ @@ -38,28 +35,19 @@ const styles = StyleSheet.create({ }, }); -export default class VoteTease extends React.Component { - shouldComponentUpdate(): boolean { - return false; - } - - render(): React.Node { - const {props} = this; - return ( - - ( - - )} - /> - - - {`${i18n.t('screens.vote.tease.message')} ${props.startDate}`} - - - - ); - } +export default function VoteTease(props: PropsType) { + return ( + + } + /> + + + {`${i18n.t('screens.vote.tease.message')} ${props.startDate}`} + + + + ); } diff --git a/src/components/Amicale/Vote/VoteWait.js b/src/components/Amicale/Vote/VoteWait.js deleted file mode 100644 index c711a97..0000000 --- a/src/components/Amicale/Vote/VoteWait.js +++ /dev/null @@ -1,93 +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 . - */ - -// @flow - -import * as React from 'react'; -import {Avatar, Card, Paragraph, withTheme} from 'react-native-paper'; -import {StyleSheet} from 'react-native'; -import i18n from 'i18n-js'; -import type {CustomThemeType} from '../../../managers/ThemeManager'; -import type {CardTitleIconPropsType} from '../../../constants/PaperStyles'; - -type PropsType = { - startDate: string | null, - justVoted: boolean, - hasVoted: boolean, - isVoteRunning: boolean, - theme: CustomThemeType, -}; - -const styles = StyleSheet.create({ - card: { - margin: 10, - }, - icon: { - backgroundColor: 'transparent', - }, -}); - -class VoteWait extends React.Component { - shouldComponentUpdate(): boolean { - return false; - } - - render(): React.Node { - const {props} = this; - const {startDate} = props; - return ( - - ( - - )} - /> - - {props.justVoted ? ( - - {i18n.t('screens.vote.wait.messageSubmitted')} - - ) : null} - {props.hasVoted ? ( - - {i18n.t('screens.vote.wait.messageVoted')} - - ) : null} - {startDate != null ? ( - - {`${i18n.t('screens.vote.wait.messageDate')} ${startDate}`} - - ) : ( - - {i18n.t('screens.vote.wait.messageDateUndefined')} - - )} - - - ); - } -} - -export default withTheme(VoteWait); diff --git a/src/components/Amicale/Vote/VoteWait.tsx b/src/components/Amicale/Vote/VoteWait.tsx new file mode 100644 index 0000000..b961fc2 --- /dev/null +++ b/src/components/Amicale/Vote/VoteWait.tsx @@ -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 . + */ + +import * as React from 'react'; +import {Avatar, Card, Paragraph, useTheme} from 'react-native-paper'; +import {StyleSheet} from 'react-native'; +import i18n from 'i18n-js'; + +type PropsType = { + startDate: string | null; + justVoted: boolean; + hasVoted: boolean; + isVoteRunning: boolean; +}; + +const styles = StyleSheet.create({ + card: { + margin: 10, + }, + icon: { + backgroundColor: 'transparent', + }, +}); + +export default function VoteWait(props: PropsType) { + const theme = useTheme(); + const {startDate} = props; + return ( + + ( + + )} + /> + + {props.justVoted ? ( + + {i18n.t('screens.vote.wait.messageSubmitted')} + + ) : null} + {props.hasVoted ? ( + + {i18n.t('screens.vote.wait.messageVoted')} + + ) : null} + {startDate != null ? ( + + {`${i18n.t('screens.vote.wait.messageDate')} ${startDate}`} + + ) : ( + + {i18n.t('screens.vote.wait.messageDateUndefined')} + + )} + + + ); +} diff --git a/src/components/Collapsible/CollapsibleComponent.js b/src/components/Collapsible/CollapsibleComponent.js deleted file mode 100644 index 583ca49..0000000 --- a/src/components/Collapsible/CollapsibleComponent.js +++ /dev/null @@ -1,78 +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 . - */ - -// @flow - -import * as React from 'react'; -import {Collapsible} from 'react-navigation-collapsible'; -import withCollapsible from '../../utils/withCollapsible'; -import CustomTabBar from '../Tabbar/CustomTabBar'; - -export type CollapsibleComponentPropsType = { - children?: React.Node, - hasTab?: boolean, - onScroll?: (event: SyntheticEvent) => void, -}; - -type PropsType = { - ...CollapsibleComponentPropsType, - collapsibleStack: Collapsible, - // eslint-disable-next-line flowtype/no-weak-types - component: any, -}; - -class CollapsibleComponent extends React.Component { - static defaultProps = { - children: null, - hasTab: false, - onScroll: null, - }; - - onScroll = (event: SyntheticEvent) => { - const {props} = this; - if (props.onScroll) props.onScroll(event); - }; - - render(): React.Node { - const {props} = this; - const Comp = props.component; - const { - containerPaddingTop, - scrollIndicatorInsetTop, - onScrollWithListener, - } = props.collapsibleStack; - - return ( - - {props.children} - - ); - } -} - -export default withCollapsible(CollapsibleComponent); diff --git a/src/components/Collapsible/CollapsibleComponent.tsx b/src/components/Collapsible/CollapsibleComponent.tsx new file mode 100644 index 0000000..2039854 --- /dev/null +++ b/src/components/Collapsible/CollapsibleComponent.tsx @@ -0,0 +1,63 @@ +/* + * 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 . + */ + +import * as React from 'react'; +import {useCollapsibleStack} from 'react-navigation-collapsible'; +import CustomTabBar from '../Tabbar/CustomTabBar'; +import {NativeScrollEvent, NativeSyntheticEvent} from 'react-native'; + +export interface CollapsibleComponentPropsType { + children?: React.ReactNode; + hasTab?: boolean; + onScroll?: (event: NativeSyntheticEvent) => void; +} + +interface PropsType extends CollapsibleComponentPropsType { + component: React.ComponentType; +} + +function CollapsibleComponent(props: PropsType) { + const onScroll = (event: NativeSyntheticEvent) => { + if (props.onScroll) { + props.onScroll(event); + } + }; + const Comp = props.component; + const { + containerPaddingTop, + scrollIndicatorInsetTop, + onScrollWithListener, + } = useCollapsibleStack(); + + return ( + + {props.children} + + ); +} + +export default CollapsibleComponent; diff --git a/src/components/Collapsible/CollapsibleFlatList.js b/src/components/Collapsible/CollapsibleFlatList.tsx similarity index 65% rename from src/components/Collapsible/CollapsibleFlatList.js rename to src/components/Collapsible/CollapsibleFlatList.tsx index 3b12374..e8c1ce6 100644 --- a/src/components/Collapsible/CollapsibleFlatList.js +++ b/src/components/Collapsible/CollapsibleFlatList.tsx @@ -17,29 +17,19 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; -import {Animated} from 'react-native'; +import {Animated, FlatListProps} from 'react-native'; import type {CollapsibleComponentPropsType} from './CollapsibleComponent'; import CollapsibleComponent from './CollapsibleComponent'; -type PropsType = { - ...CollapsibleComponentPropsType, -}; +type Props = FlatListProps & CollapsibleComponentPropsType; -// eslint-disable-next-line react/prefer-stateless-function -class CollapsibleFlatList extends React.Component { - render(): React.Node { - const {props} = this; - return ( - - {props.children} - - ); - } +function CollapsibleFlatList(props: Props) { + return ( + + {props.children} + + ); } export default CollapsibleFlatList; diff --git a/src/components/Collapsible/CollapsibleScrollView.js b/src/components/Collapsible/CollapsibleScrollView.tsx similarity index 65% rename from src/components/Collapsible/CollapsibleScrollView.js rename to src/components/Collapsible/CollapsibleScrollView.tsx index 28d9eab..3d8cdd7 100644 --- a/src/components/Collapsible/CollapsibleScrollView.js +++ b/src/components/Collapsible/CollapsibleScrollView.tsx @@ -17,29 +17,19 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; -import {Animated} from 'react-native'; +import {Animated, ScrollViewProps} from 'react-native'; import type {CollapsibleComponentPropsType} from './CollapsibleComponent'; import CollapsibleComponent from './CollapsibleComponent'; -type PropsType = { - ...CollapsibleComponentPropsType, -}; +type Props = ScrollViewProps & CollapsibleComponentPropsType; -// eslint-disable-next-line react/prefer-stateless-function -class CollapsibleScrollView extends React.Component { - render(): React.Node { - const {props} = this; - return ( - - {props.children} - - ); - } +function CollapsibleScrollView(props: Props) { + return ( + + {props.children} + + ); } export default CollapsibleScrollView; diff --git a/src/components/Collapsible/CollapsibleSectionList.js b/src/components/Collapsible/CollapsibleSectionList.tsx similarity index 65% rename from src/components/Collapsible/CollapsibleSectionList.js rename to src/components/Collapsible/CollapsibleSectionList.tsx index f722e06..ed0a337 100644 --- a/src/components/Collapsible/CollapsibleSectionList.js +++ b/src/components/Collapsible/CollapsibleSectionList.tsx @@ -17,29 +17,19 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; -import {Animated} from 'react-native'; +import {Animated, SectionListProps} from 'react-native'; import type {CollapsibleComponentPropsType} from './CollapsibleComponent'; import CollapsibleComponent from './CollapsibleComponent'; -type PropsType = { - ...CollapsibleComponentPropsType, -}; +type Props = SectionListProps & CollapsibleComponentPropsType; -// eslint-disable-next-line react/prefer-stateless-function -class CollapsibleSectionList extends React.Component { - render(): React.Node { - const {props} = this; - return ( - - {props.children} - - ); - } +function CollapsibleSectionList(props: Props) { + return ( + + {props.children} + + ); } export default CollapsibleSectionList; diff --git a/src/components/Screens/BasicLoadingScreen.js b/src/components/Screens/BasicLoadingScreen.tsx similarity index 66% rename from src/components/Screens/BasicLoadingScreen.js rename to src/components/Screens/BasicLoadingScreen.tsx index 9cef1ad..95d55d6 100644 --- a/src/components/Screens/BasicLoadingScreen.js +++ b/src/components/Screens/BasicLoadingScreen.tsx @@ -21,8 +21,11 @@ import * as React from 'react'; import {View} from 'react-native'; -import {ActivityIndicator, withTheme} from 'react-native-paper'; -import type {CustomThemeType} from '../../managers/ThemeManager'; +import {ActivityIndicator, useTheme} from 'react-native-paper'; + +type Props = { + isAbsolute?: boolean; +}; /** * Component used to display a header button @@ -30,29 +33,21 @@ import type {CustomThemeType} from '../../managers/ThemeManager'; * @param props Props to pass to the component * @return {*} */ -function BasicLoadingScreen(props: { - theme: CustomThemeType, - isAbsolute: boolean, -}): React.Node { - const {theme, isAbsolute} = props; - const {colors} = theme; - let position; - if (isAbsolute != null && isAbsolute) position = 'absolute'; - +export default function BasicLoadingScreen(props: Props) { + const theme = useTheme(); + const {isAbsolute} = props; return ( - + ); } - -export default withTheme(BasicLoadingScreen); diff --git a/src/components/Screens/ErrorView.js b/src/components/Screens/ErrorView.tsx similarity index 87% rename from src/components/Screens/ErrorView.js rename to src/components/Screens/ErrorView.tsx index d63c27c..2e57a8e 100644 --- a/src/components/Screens/ErrorView.js +++ b/src/components/Screens/ErrorView.tsx @@ -17,8 +17,6 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {Button, Subheading, withTheme} from 'react-native-paper'; import {StyleSheet, View} from 'react-native'; @@ -27,17 +25,16 @@ import i18n from 'i18n-js'; import * as Animatable from 'react-native-animatable'; import {StackNavigationProp} from '@react-navigation/stack'; import {ERROR_TYPE} from '../../utils/WebData'; -import type {CustomThemeType} from '../../managers/ThemeManager'; type PropsType = { - navigation: StackNavigationProp, - theme: CustomThemeType, - route: {name: string}, - onRefresh?: () => void, - errorCode?: number, - icon?: string, - message?: string, - showRetryButton?: boolean, + navigation?: StackNavigationProp; + theme: ReactNativePaper.Theme; + route?: {name: string}; + onRefresh?: () => void; + errorCode?: number; + icon?: string; + message?: string; + showRetryButton?: boolean; }; const styles = StyleSheet.create({ @@ -82,9 +79,11 @@ class ErrorView extends React.PureComponent { constructor(props: PropsType) { super(props); this.icon = ''; + this.showLoginButton = false; + this.message = ''; } - getRetryButton(): React.Node { + getRetryButton() { const {props} = this; return ( ); + } return this.getContent(); }; - getScreen = (data: Array): React.Node => { + getScreen = (data: Array) => { const {state} = this; // data[0] = FAKE_TEAMS2; // data[1] = FAKE_DATE; this.lastRefresh = new Date(); - const teams: TeamResponseType | null = data[0]; - const dateStrings: VoteDatesStringType | null = data[1]; + const teams = data[0] as TeamResponseType | null; + const dateStrings = data[1] as VoteDatesStringType | null; - if (dateStrings != null && dateStrings.date_begin == null) + if (dateStrings != null && dateStrings.date_begin == null) { this.datesString = null; - else this.datesString = dateStrings; + } else { + this.datesString = dateStrings; + } if (teams != null) { this.teams = teams.teams; @@ -225,13 +228,20 @@ export default class VoteScreen extends React.Component { ); }; - getContent(): React.Node { + getContent() { const {state} = this; - if (!this.isVoteStarted()) return this.getTeaseVoteCard(); - if (this.isVoteRunning() && !this.hasVoted && !state.hasVoted) + if (!this.isVoteStarted()) { + return this.getTeaseVoteCard(); + } + if (this.isVoteRunning() && !this.hasVoted && !state.hasVoted) { return this.getVoteCard(); - if (!this.isResultStarted()) return this.getWaitVoteCard(); - if (this.isResultRunning()) return this.getVoteResultCard(); + } + if (!this.isResultStarted()) { + return this.getWaitVoteCard(); + } + if (this.isResultRunning()) { + return this.getVoteResultCard(); + } return ; } @@ -240,7 +250,7 @@ export default class VoteScreen extends React.Component { /** * The user has not voted yet, and the votes are open */ - getVoteCard(): React.Node { + getVoteCard() { return ( { /** * Votes have ended, results can be displayed */ - getVoteResultCard(): React.Node { - if (this.dates != null && this.datesString != null) + getVoteResultCard() { + if (this.dates != null && this.datesString != null) { return ( { )} /> ); + } return ; } /** * Vote will open shortly */ - getTeaseVoteCard(): React.Node { - if (this.dates != null && this.datesString != null) + getTeaseVoteCard() { + if (this.dates != null && this.datesString != null) { return ( { )} /> ); + } return ; } /** * Votes have ended, or user has voted waiting for results */ - getWaitVoteCard(): React.Node { + getWaitVoteCard() { const {state} = this; let startDate = null; if ( this.dates != null && this.datesString != null && this.dates.date_result_begin != null - ) + ) { startDate = this.getDateString( this.dates.date_result_begin, this.datesString.date_result_begin, ); + } return ( { reloadData = () => { let canRefresh; const {lastRefresh} = this; - if (lastRefresh != null) + if (lastRefresh != null) { canRefresh = new Date().getTime() - lastRefresh.getTime() > MIN_REFRESH_TIME; - else canRefresh = true; - if (canRefresh && this.authRef.current != null) + } else { + canRefresh = true; + } + if (canRefresh && this.authRef.current != null) { this.authRef.current.reload(); + } }; showMascotDialog = () => { @@ -380,8 +396,12 @@ export default class VoteScreen extends React.Component { date_result_begin: dateResultBegin, date_result_end: dateResultEnd, }; - } else this.dates = null; - } else this.dates = null; + } else { + this.dates = null; + } + } else { + this.dates = null; + } } /** @@ -391,11 +411,11 @@ export default class VoteScreen extends React.Component { * * @returns {*} */ - render(): React.Node { + render() { const {props, state} = this; return ( - navigation={props.navigation} ref={this.authRef} requests={[ @@ -418,7 +438,6 @@ export default class VoteScreen extends React.Component { message={i18n.t('screens.vote.mascotDialog.message')} icon="vote" buttons={{ - action: null, cancel: { message: i18n.t('screens.vote.mascotDialog.button'), icon: 'check', diff --git a/src/utils/WebData.ts b/src/utils/WebData.ts index 44e68d7..f27e6d8 100644 --- a/src/utils/WebData.ts +++ b/src/utils/WebData.ts @@ -35,8 +35,6 @@ export type ApiDataLoginType = { token: string; }; -export type ApiGenericDataType = {[key: string]: any}; - type ApiResponseType = { error: number; data: T; @@ -70,7 +68,7 @@ export function isApiResponseValid(response: ApiResponseType): boolean { * @param path The API path from the API endpoint * @param method The HTTP method to use (GET or POST) * @param params The params to use for this request - * @returns {Promise} + * @returns {Promise} */ export async function apiRequest( path: string,