From c198a40148aea0a7886517f08db749062c700b1c Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Tue, 22 Sep 2020 22:52:35 +0200 Subject: [PATCH] Update home screens to use TypeScript --- src/components/Home/SmallDashboardItem.tsx | 8 +- .../{FeedItemScreen.js => FeedItemScreen.tsx} | 30 ++-- .../Home/{HomeScreen.js => HomeScreen.tsx} | 143 ++++++++---------- .../{ScannerScreen.js => ScannerScreen.tsx} | 49 +++--- 4 files changed, 102 insertions(+), 128 deletions(-) rename src/screens/Home/{FeedItemScreen.js => FeedItemScreen.tsx} (83%) rename src/screens/Home/{HomeScreen.js => HomeScreen.tsx} (83%) rename src/screens/Home/{ScannerScreen.js => ScannerScreen.tsx} (87%) diff --git a/src/components/Home/SmallDashboardItem.tsx b/src/components/Home/SmallDashboardItem.tsx index 7052b1a..6a5a8ad 100644 --- a/src/components/Home/SmallDashboardItem.tsx +++ b/src/components/Home/SmallDashboardItem.tsx @@ -23,9 +23,9 @@ import {Dimensions, Image, View} from 'react-native'; import * as Animatable from 'react-native-animatable'; type PropsType = { - image: string | null; - onPress: () => void | null; - badgeCount: number | null; + image?: string | number; + onPress?: () => void; + badgeCount?: number; }; /** @@ -50,7 +50,7 @@ function SmallDashboardItem(props: PropsType) { }}> {image ? ( . */ -// @flow - import * as React from 'react'; import {Linking, Image} from 'react-native'; -import {Card, Text, withTheme} from 'react-native-paper'; +import {Card, Text} from 'react-native-paper'; import Autolink from 'react-native-autolink'; import {StackNavigationProp} from '@react-navigation/stack'; import MaterialHeaderButtons, { @@ -31,12 +29,14 @@ import CustomTabBar from '../../components/Tabbar/CustomTabBar'; import type {FeedItemType} from './HomeScreen'; import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView'; import ImageGalleryButton from '../../components/Media/ImageGalleryButton'; -import NewsSourcesConstants from '../../constants/NewsSourcesConstants'; +import NewsSourcesConstants, { + AvailablePages, +} from '../../constants/NewsSourcesConstants'; import type {NewsSourceType} from '../../constants/NewsSourcesConstants'; type PropsType = { - navigation: StackNavigationProp, - route: {params: {data: FeedItemType, date: string}}, + navigation: StackNavigationProp; + route: {params: {data: FeedItemType; date: string}}; }; /** @@ -72,7 +72,7 @@ class FeedItemScreen extends React.Component { * * @returns {*} */ - getHeaderButton = (): React.Node => { + getHeaderButton = () => { return ( { ); }; - render(): React.Node { - const {navigation} = this.props; - const hasImage = - this.displayData.image !== '' && this.displayData.image != null; + render() { const pageSource: NewsSourceType = - NewsSourcesConstants[this.displayData.page_id]; + NewsSourcesConstants[this.displayData.page_id as AvailablePages]; return ( ( + left={() => ( { /> )} /> - {hasImage ? ( + {this.displayData.image ? ( { ) : null} @@ -133,4 +129,4 @@ class FeedItemScreen extends React.Component { } } -export default withTheme(FeedItemScreen); +export default FeedItemScreen; diff --git a/src/screens/Home/HomeScreen.js b/src/screens/Home/HomeScreen.tsx similarity index 83% rename from src/screens/Home/HomeScreen.js rename to src/screens/Home/HomeScreen.tsx index d39dedb..9051a79 100644 --- a/src/screens/Home/HomeScreen.js +++ b/src/screens/Home/HomeScreen.tsx @@ -17,10 +17,8 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; -import {FlatList} from 'react-native'; +import {FlatList, NativeScrollEvent, NativeSyntheticEvent} from 'react-native'; import i18n from 'i18n-js'; import {ActivityIndicator, Headline, withTheme} from 'react-native-paper'; import {CommonActions} from '@react-navigation/native'; @@ -38,7 +36,6 @@ import MaterialHeaderButtons, { Item, } from '../../components/Overrides/CustomHeaderButton'; import AnimatedFAB from '../../components/Animations/AnimatedFAB'; -import type {CustomThemeType} from '../../managers/ThemeManager'; import ConnectionManager from '../../managers/ConnectionManager'; import LogoutDialog from '../../components/Amicale/LogoutDialog'; import AsyncStorageManager from '../../managers/AsyncStorageManager'; @@ -59,40 +56,40 @@ const SECTIONS_ID = ['dashboard', 'news_feed']; const REFRESH_TIME = 1000 * 20; // Refresh every 20 seconds export type FeedItemType = { - id: string, - message: string, - url: string, - image: string | null, - video: string | null, - link: string | null, - time: number, - page_id: string, + id: string; + message: string; + url: string; + image: string | null; + video: string | null; + link: string | null; + time: number; + page_id: string; }; export type FullDashboardType = { - today_menu: Array<{[key: string]: {...}}>, - proximo_articles: number, - available_dryers: number, - available_washers: number, - today_events: Array, - available_tutorials: number, + today_menu: Array<{[key: string]: object}>; + proximo_articles: number; + available_dryers: number; + available_washers: number; + today_events: Array; + available_tutorials: number; }; type RawNewsFeedType = {[key: string]: Array}; type RawDashboardType = { - news_feed: RawNewsFeedType, - dashboard: FullDashboardType, + news_feed: RawNewsFeedType; + dashboard: FullDashboardType; }; type PropsType = { - navigation: StackNavigationProp, - route: {params: {nextScreen: string, data: {...}}}, - theme: CustomThemeType, + navigation: StackNavigationProp; + route: {params: {nextScreen: string; data: object}}; + theme: ReactNativePaper.Theme; }; type StateType = { - dialogVisible: boolean, + dialogVisible: boolean; }; /** @@ -103,10 +100,12 @@ class HomeScreen extends React.Component { b.time - a.time; static generateNewsFeed(rawFeed: RawNewsFeedType): Array { - const finalFeed = []; + const finalFeed: Array = []; Object.keys(rawFeed).forEach((key: string) => { const category: Array | null = rawFeed[key]; - if (category != null && category.length > 0) finalFeed.push(...category); + if (category != null && category.length > 0) { + finalFeed.push(...category); + } }); finalFeed.sort(HomeScreen.sortFeedTime); return finalFeed; @@ -164,7 +163,7 @@ class HomeScreen extends React.Component { * * @returns {*} */ - getHeaderButton = (): React.Node => { + getHeaderButton = () => { const {props} = this; let onPressLog = (): void => props.navigation.navigate('login', {nextScreen: 'profile'}); @@ -201,7 +200,7 @@ class HomeScreen extends React.Component { * @param content * @return {*} */ - getDashboardEvent(content: Array): React.Node { + getDashboardEvent(content: Array) { const futureEvents = getFutureEvents(content); const displayEvent = getDisplayEvent(futureEvents); // const clickPreviewAction = () => @@ -221,30 +220,14 @@ class HomeScreen extends React.Component { ); } - /** - * Gets a dashboard item with action buttons - * - * @returns {*} - */ - getDashboardActions(): React.Node { - const {props} = this; - return ( - - ); - } - /** * Gets a dashboard item with a row of shortcut buttons. * * @param content * @return {*} */ - getDashboardRow(content: Array): React.Node { + getDashboardRow(content: Array) { return ( - // $FlowFixMe { * @param item * @returns {*} */ - getDashboardRowRenderItem = ({ - item, - }: { - item: ServiceItemType | null, - }): React.Node => { - if (item != null) + getDashboardRowRenderItem = ({item}: {item: ServiceItemType | null}) => { + if (item != null) { return ( { badgeCount={ this.currentDashboard != null && item.badgeFunction != null ? item.badgeFunction(this.currentDashboard) - : null + : undefined } /> ); - return ; + } + return ; }; /** @@ -291,15 +271,8 @@ class HomeScreen extends React.Component { * @param item The feed item to display * @return {*} */ - getFeedItem(item: FeedItemType): React.Node { - const {props} = this; - return ( - - ); + getFeedItem(item: FeedItemType) { + return ; } /** @@ -309,20 +282,19 @@ class HomeScreen extends React.Component { * @param section The current section * @return {*} */ - getRenderItem = ({item}: {item: FeedItemType}): React.Node => - this.getFeedItem(item); + getRenderItem = ({item}: {item: FeedItemType}) => this.getFeedItem(item); getRenderSectionHeader = ( data: { section: { - data: Array<{...}>, - title: string, - }, + data: Array; + title: string; + }; }, isLoading: boolean, - ): React.Node => { + ) => { const {props} = this; - if (data.section.data.length > 0) + if (data.section.data.length > 0) { return ( { {data.section.title} ); + } return ( { ); }; - getListHeader = (fetchedData: RawDashboardType): React.Node => { + getListHeader = (fetchedData: RawDashboardType) => { let dashboard = null; - if (fetchedData != null) dashboard = fetchedData.dashboard; + if (fetchedData != null) { + dashboard = fetchedData.dashboard; + } return ( - {this.getDashboardActions()} + {this.getDashboardRow(this.dashboardManager.getCurrentDashboard())} {this.getDashboardEvent( dashboard == null ? [] : dashboard.today_events, @@ -418,20 +393,22 @@ class HomeScreen extends React.Component { fetchedData: RawDashboardType | null, isLoading: boolean, ): Array<{ - title: string, - data: [] | Array, - id: string, + title: string; + data: [] | Array; + id: string; }> => { // fetchedData = DATA; if (fetchedData != null) { - if (fetchedData.news_feed != null) + if (fetchedData.news_feed != null) { this.currentNewFeed = HomeScreen.generateNewsFeed( fetchedData.news_feed, ); - if (fetchedData.dashboard != null) + } + if (fetchedData.dashboard != null) { this.currentDashboard = fetchedData.dashboard; + } } - if (this.currentNewFeed.length > 0) + if (this.currentNewFeed.length > 0) { return [ { title: i18n.t('screens.home.feedTitle'), @@ -439,6 +416,7 @@ class HomeScreen extends React.Component { id: SECTIONS_ID[1], }, ]; + } return [ { title: isLoading @@ -455,8 +433,10 @@ class HomeScreen extends React.Component { props.navigation.navigate('planning'); }; - onScroll = (event: SyntheticEvent) => { - if (this.fabRef.current != null) this.fabRef.current.onScroll(event); + onScroll = (event: NativeSyntheticEvent) => { + if (this.fabRef.current) { + this.fabRef.current.onScroll(event); + } }; /** @@ -470,7 +450,7 @@ class HomeScreen extends React.Component { }); }; - render(): React.Node { + render() { const {props, state} = this; return ( @@ -521,7 +501,6 @@ class HomeScreen extends React.Component { onPress={this.openScanner} /> diff --git a/src/screens/Home/ScannerScreen.js b/src/screens/Home/ScannerScreen.tsx similarity index 87% rename from src/screens/Home/ScannerScreen.js rename to src/screens/Home/ScannerScreen.tsx index 0856fa3..9e948dd 100644 --- a/src/screens/Home/ScannerScreen.js +++ b/src/screens/Home/ScannerScreen.tsx @@ -17,11 +17,9 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {Linking, Platform, StyleSheet, View} from 'react-native'; -import {Button, Text, withTheme} from 'react-native-paper'; +import {Button, Text} from 'react-native-paper'; import {RNCamera} from 'react-native-camera'; import {BarcodeMask} from '@nartc/react-native-barcode-mask'; import i18n from 'i18n-js'; @@ -34,11 +32,11 @@ import {MASCOT_STYLE} from '../../components/Mascot/Mascot'; import MascotPopup from '../../components/Mascot/MascotPopup'; type StateType = { - hasPermission: boolean, - scanned: boolean, - dialogVisible: boolean, - mascotDialogVisible: boolean, - loading: boolean, + hasPermission: boolean; + scanned: boolean; + dialogVisible: boolean; + mascotDialogVisible: boolean; + loading: boolean; }; const styles = StyleSheet.create({ @@ -54,9 +52,11 @@ const styles = StyleSheet.create({ }, }); -class ScannerScreen extends React.Component { +type PermissionResults = 'unavailable' | 'denied' | 'blocked' | 'granted'; + +class ScannerScreen extends React.Component<{}, StateType> { constructor() { - super(); + super({}); this.state = { hasPermission: false, scanned: false, @@ -75,7 +75,7 @@ class ScannerScreen extends React.Component { * * @returns {*} */ - getPermissionScreen(): React.Node { + getPermissionScreen() { return ( {i18n.t('screens.scanner.permissions.error')} @@ -101,15 +101,13 @@ class ScannerScreen extends React.Component { * * @returns {*} */ - getScanner(): React.Node { + getScanner() { const {state} = this; return ( { * Requests permission to use the camera */ requestPermissions = () => { - if (Platform.OS === 'android') + if (Platform.OS === 'android') { request(PERMISSIONS.ANDROID.CAMERA).then(this.updatePermissionStatus); - else request(PERMISSIONS.IOS.CAMERA).then(this.updatePermissionStatus); + } else { + request(PERMISSIONS.IOS.CAMERA).then(this.updatePermissionStatus); + } }; /** @@ -138,7 +138,7 @@ class ScannerScreen extends React.Component { * * @param result */ - updatePermissionStatus = (result: RESULTS) => { + updatePermissionStatus = (result: PermissionResults) => { this.setState({ hasPermission: result === RESULTS.GRANTED, }); @@ -147,7 +147,6 @@ class ScannerScreen extends React.Component { /** * Shows a dialog indicating the user the scanned code was invalid */ - // eslint-disable-next-line react/sort-comp showErrorDialog() { this.setState({ dialogVisible: true, @@ -199,14 +198,15 @@ class ScannerScreen extends React.Component { * @param data The scanned value */ onCodeScanned = ({data}: {data: string}) => { - if (!URLHandler.isUrlValid(data)) this.showErrorDialog(); - else { + if (!URLHandler.isUrlValid(data)) { + this.showErrorDialog(); + } else { this.showOpeningDialog(); Linking.openURL(data); } }; - render(): React.Node { + render() { const {state} = this; return ( { message={i18n.t('screens.scanner.mascotDialog.message')} icon="camera-iris" buttons={{ - action: null, cancel: { message: i18n.t('screens.scanner.mascotDialog.button'), icon: 'check', @@ -253,4 +252,4 @@ class ScannerScreen extends React.Component { } } -export default withTheme(ScannerScreen); +export default ScannerScreen;