Improved flow typing of home screen and associated components

This commit is contained in:
Arnaud Vergnet 2020-04-19 20:21:39 +02:00
parent b64b68dc8a
commit 581ea516ae
11 changed files with 281 additions and 168 deletions

5
App.js
View file

@ -6,12 +6,13 @@ import LocaleManager from './src/managers/LocaleManager';
import AsyncStorageManager from "./src/managers/AsyncStorageManager"; import AsyncStorageManager from "./src/managers/AsyncStorageManager";
import CustomIntroSlider from "./src/components/Overrides/CustomIntroSlider"; import CustomIntroSlider from "./src/components/Overrides/CustomIntroSlider";
import {SplashScreen} from 'expo'; import {SplashScreen} from 'expo';
import type {CustomTheme} from "./src/managers/ThemeManager";
import ThemeManager from './src/managers/ThemeManager'; import ThemeManager from './src/managers/ThemeManager';
import {NavigationContainer} from '@react-navigation/native'; import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack'; import {createStackNavigator} from '@react-navigation/stack';
import DrawerNavigator from './src/navigation/DrawerNavigator'; import DrawerNavigator from './src/navigation/DrawerNavigator';
import {initExpoToken} from "./src/utils/Notifications"; import {initExpoToken} from "./src/utils/Notifications";
import {Provider as PaperProvider, Theme} from 'react-native-paper'; import {Provider as PaperProvider} from 'react-native-paper';
import AprilFoolsManager from "./src/managers/AprilFoolsManager"; import AprilFoolsManager from "./src/managers/AprilFoolsManager";
import Update from "./src/constants/Update"; import Update from "./src/constants/Update";
import ConnectionManager from "./src/managers/ConnectionManager"; import ConnectionManager from "./src/managers/ConnectionManager";
@ -30,7 +31,7 @@ type State = {
showIntro: boolean, showIntro: boolean,
showUpdate: boolean, showUpdate: boolean,
showAprilFools: boolean, showAprilFools: boolean,
currentTheme: Theme | null, currentTheme: CustomTheme | null,
}; };
const Stack = createStackNavigator(); const Stack = createStackNavigator();

View file

@ -1,16 +1,17 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {Avatar, Card, List, ProgressBar, Subheading, Theme, withTheme} from "react-native-paper"; import {Avatar, Card, List, ProgressBar, Subheading, withTheme} from "react-native-paper";
import {FlatList, StyleSheet} from "react-native"; import {FlatList, StyleSheet} from "react-native";
import i18n from 'i18n-js'; import i18n from 'i18n-js';
import type {team} from "../../../screens/Amicale/VoteScreen"; import type {team} from "../../../screens/Amicale/VoteScreen";
import type {CustomTheme} from "../../../managers/ThemeManager";
type Props = { type Props = {
teams: Array<team>, teams: Array<team>,
dateEnd: string, dateEnd: string,
theme: Theme, theme: CustomTheme,
} }
class VoteResults extends React.Component<Props> { class VoteResults extends React.Component<Props> {
@ -38,9 +39,9 @@ class VoteResults extends React.Component<Props> {
} }
} }
getWinnerIds(teams: Array<team>){ getWinnerIds(teams: Array<team>) {
let max = teams[0].votes; let max = teams[0].votes;
this.winnerIds= []; this.winnerIds = [];
for (let i = 0; i < teams.length; i++) { for (let i = 0; i < teams.length; i++) {
if (teams[i].votes === max) if (teams[i].votes === max)
this.winnerIds.push(teams[i].id); this.winnerIds.push(teams[i].id);
@ -51,7 +52,7 @@ class VoteResults extends React.Component<Props> {
voteKeyExtractor = (item: team) => item.id.toString(); voteKeyExtractor = (item: team) => item.id.toString();
resultRenderItem = ({item}: {item: team}) => { resultRenderItem = ({item}: { item: team }) => {
const isWinner = this.winnerIds.indexOf(item.id) !== -1; const isWinner = this.winnerIds.indexOf(item.id) !== -1;
const isDraw = this.winnerIds.length > 1; const isDraw = this.winnerIds.length > 1;
const colors = this.props.theme.colors; const colors = this.props.theme.colors;
@ -90,7 +91,7 @@ class VoteResults extends React.Component<Props> {
/>} />}
/> />
<Card.Content> <Card.Content>
<Subheading>{i18n.t('voteScreen.results.totalVotes') + ' ' +this.totalVotes}</Subheading> <Subheading>{i18n.t('voteScreen.results.totalVotes') + ' ' + this.totalVotes}</Subheading>
{/*$FlowFixMe*/} {/*$FlowFixMe*/}
<FlatList <FlatList
data={this.props.teams} data={this.props.teams}

View file

@ -1,16 +1,17 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {ActivityIndicator, Card, Paragraph, Theme, withTheme} from "react-native-paper"; import {ActivityIndicator, Card, Paragraph, withTheme} from "react-native-paper";
import {StyleSheet} from "react-native"; import {StyleSheet} from "react-native";
import i18n from 'i18n-js'; import i18n from 'i18n-js';
import type {CustomTheme} from "../../../managers/ThemeManager";
type Props = { type Props = {
startDate: string | null, startDate: string | null,
justVoted: boolean, justVoted: boolean,
hasVoted: boolean, hasVoted: boolean,
isVoteRunning: boolean, isVoteRunning: boolean,
theme: Theme, theme: CustomTheme,
} }
class VoteWait extends React.Component<Props> { class VoteWait extends React.Component<Props> {

View file

@ -2,17 +2,18 @@
import * as React from 'react'; import * as React from 'react';
import {StyleSheet, View} from "react-native"; import {StyleSheet, View} from "react-native";
import {FAB, IconButton, Surface, Theme, withTheme} from "react-native-paper"; import {FAB, IconButton, Surface, withTheme} from "react-native-paper";
import AutoHideHandler from "../../utils/AutoHideHandler"; import AutoHideHandler from "../../utils/AutoHideHandler";
import * as Animatable from 'react-native-animatable'; import * as Animatable from 'react-native-animatable';
import CustomTabBar from "../Tabbar/CustomTabBar"; import CustomTabBar from "../Tabbar/CustomTabBar";
import {StackNavigationProp} from "@react-navigation/stack"; import {StackNavigationProp} from "@react-navigation/stack";
import type {CustomTheme} from "../../managers/ThemeManager";
const AnimatedFAB = Animatable.createAnimatableComponent(FAB); const AnimatedFAB = Animatable.createAnimatableComponent(FAB);
type Props = { type Props = {
navigation: StackNavigationProp, navigation: StackNavigationProp,
theme: Theme, theme: CustomTheme,
onPress: (action: string, data: any) => void, onPress: (action: string, data: any) => void,
seekAttention: boolean, seekAttention: boolean,
} }

View file

@ -4,10 +4,12 @@ import * as React from 'react';
import {Button, Card, withTheme} from 'react-native-paper'; import {Button, Card, withTheme} from 'react-native-paper';
import {Platform, StyleSheet} from "react-native"; import {Platform, StyleSheet} from "react-native";
import i18n from 'i18n-js'; import i18n from 'i18n-js';
import {DrawerNavigationProp} from "@react-navigation/drawer";
import type {CustomTheme} from "../../managers/ThemeManager";
type Props = { type Props = {
navigation: Object, navigation: DrawerNavigationProp,
theme: Object, theme: CustomTheme,
} }
class ActionsDashBoardItem extends React.Component<Props> { class ActionsDashBoardItem extends React.Component<Props> {

View file

@ -4,11 +4,13 @@ import * as React from 'react';
import {Avatar, Card, Text, withTheme} from 'react-native-paper'; import {Avatar, Card, Text, withTheme} from 'react-native-paper';
import {StyleSheet} from "react-native"; import {StyleSheet} from "react-native";
import i18n from "i18n-js"; import i18n from "i18n-js";
import type {CustomTheme} from "../../managers/ThemeManager";
type Props = { type Props = {
eventNumber: number; eventNumber: number;
clickAction: Function, clickAction: () => void,
theme: Object, theme: CustomTheme,
children?: React.Node
} }
/** /**

View file

@ -1,15 +1,21 @@
// @flow
import * as React from 'react'; import * as React from 'react';
import {Avatar, Button, Card, Text} from 'react-native-paper'; import {Avatar, Button, Card, Text} from 'react-native-paper';
import {View} from "react-native"; import {View} from "react-native";
import Autolink from "react-native-autolink"; import Autolink from "react-native-autolink";
import i18n from "i18n-js"; import i18n from "i18n-js";
import ImageModal from 'react-native-image-modal'; import ImageModal from 'react-native-image-modal';
import {StackNavigationProp} from "@react-navigation/stack";
import type {CustomTheme} from "../../managers/ThemeManager";
import type {feedItem} from "../../screens/Home/HomeScreen";
const ICON_AMICALE = require('../../../assets/amicale.png'); const ICON_AMICALE = require('../../../assets/amicale.png');
type Props = { type Props = {
navigation: Object, navigation: StackNavigationProp,
theme: Object, theme: CustomTheme,
item: feedItem,
title: string, title: string,
subtitle: string, subtitle: string,
height: number, height: number,
@ -32,17 +38,19 @@ class FeedItem extends React.Component<Props> {
*/ */
getAvatar() { getAvatar() {
return ( return (
<Avatar.Image size={48} source={ICON_AMICALE} <Avatar.Image
style={{backgroundColor: 'transparent'}}/> size={48} source={ICON_AMICALE}
style={{backgroundColor: 'transparent'}}/>
); );
} }
onPress = () => { onPress = () => {
this.props.navigation.navigate('feed-information', this.props.navigation.navigate(
'feed-information',
{ {
data: this.props.item, data: this.props.item,
date: this.props.subtitle date: this.props.subtitle
}) });
}; };
render() { render() {

View file

@ -6,10 +6,13 @@ import i18n from "i18n-js";
import {Avatar, Button, Card} from 'react-native-paper'; import {Avatar, Button, Card} from 'react-native-paper';
import {getFormattedEventTime, isDescriptionEmpty} from "../../utils/Planning"; import {getFormattedEventTime, isDescriptionEmpty} from "../../utils/Planning";
import CustomHTML from "../Overrides/CustomHTML"; import CustomHTML from "../Overrides/CustomHTML";
import type {CustomTheme} from "../../managers/ThemeManager";
import type {event} from "../../screens/Home/HomeScreen";
type Props = { type Props = {
event: Object, event?: event,
clickAction: Function, clickAction: () => void,
theme?: CustomTheme,
} }
/** /**
@ -19,14 +22,15 @@ class PreviewEventDashboardItem extends React.Component<Props> {
render() { render() {
const props = this.props; const props = this.props;
const isEmpty = props.event === undefined const isEmpty = props.event == null
? true ? true
: isDescriptionEmpty(props.event['description']); : isDescriptionEmpty(props.event.description);
if (props.event !== undefined && props.event !== null) { if (props.event != null) {
const hasImage = props.event['logo'] !== '' && props.event['logo'] !== null; const event = props.event;
const hasImage = event.logo !== '' && event.logo != null;
const getImage = () => <Avatar.Image const getImage = () => <Avatar.Image
source={{uri: props.event['logo']}} source={{uri: event.logo}}
size={50} size={50}
style={styles.avatar}/>; style={styles.avatar}/>;
return ( return (
@ -37,17 +41,17 @@ class PreviewEventDashboardItem extends React.Component<Props> {
> >
{hasImage ? {hasImage ?
<Card.Title <Card.Title
title={props.event['title']} title={event.title}
subtitle={getFormattedEventTime(props.event['date_begin'], props.event['date_end'])} subtitle={getFormattedEventTime(event.date_begin, event.date_end)}
left={getImage} left={getImage}
/> : /> :
<Card.Title <Card.Title
title={props.event['title']} title={event.title}
subtitle={getFormattedEventTime(props.event['date_begin'], props.event['date_end'])} subtitle={getFormattedEventTime(event.date_begin, event.date_end)}
/>} />}
{!isEmpty ? {!isEmpty ?
<Card.Content style={styles.content}> <Card.Content style={styles.content}>
<CustomHTML html={props.event['description']}/> <CustomHTML html={event.description}/>
</Card.Content> : null} </Card.Content> : null}
<Card.Actions style={styles.actions}> <Card.Actions style={styles.actions}>

View file

@ -3,15 +3,16 @@
import * as React from 'react'; import * as React from 'react';
import {Badge, IconButton, withTheme} from 'react-native-paper'; import {Badge, IconButton, withTheme} from 'react-native-paper';
import {View} from "react-native"; import {View} from "react-native";
import type {CustomTheme} from "../../managers/ThemeManager";
type Props = { type Props = {
color: string, color: string,
icon: string, icon: string,
clickAction: Function, clickAction: () => void,
isAvailable: boolean, isAvailable: boolean,
badgeNumber: number, badgeNumber: number,
theme: Object, theme: CustomTheme,
}; };
/** /**

View file

@ -1,12 +1,61 @@
// @flow // @flow
import AsyncStorageManager from "./AsyncStorageManager"; import AsyncStorageManager from "./AsyncStorageManager";
import {DarkTheme, DefaultTheme} from 'react-native-paper'; import {DarkTheme, DefaultTheme, Theme} from 'react-native-paper';
import AprilFoolsManager from "./AprilFoolsManager"; import AprilFoolsManager from "./AprilFoolsManager";
import {Appearance} from 'react-native-appearance'; import {Appearance} from 'react-native-appearance';
const colorScheme = Appearance.getColorScheme(); const colorScheme = Appearance.getColorScheme();
export type CustomTheme = {
...Theme,
colors: {
primary: string,
accent: string,
tabIcon: string,
card: string,
dividerBackground: string,
ripple: string,
textDisabled: string,
icon: string,
subtitle: string,
success: string,
warning: string,
danger: string,
// Calendar/Agenda
agendaBackgroundColor: string,
agendaDayTextColor: string,
// PROXIWASH
proxiwashFinishedColor: string,
proxiwashReadyColor: string,
proxiwashRunningColor: string,
proxiwashRunningBgColor: string,
proxiwashBrokenColor: string,
proxiwashErrorColor: string,
// Screens
planningColor: string,
proximoColor: string,
proxiwashColor: string,
menuColor: string,
tutorinsaColor: string,
// Tetris
tetrisBackground: string,
tetrisBorder:string,
tetrisScore:string,
tetrisI : string,
tetrisO : string,
tetrisT : string,
tetrisS : string,
tetrisZ : string,
tetrisJ : string,
tetrisL : string,
},
}
/** /**
* Singleton class used to manage themes * Singleton class used to manage themes
*/ */
@ -22,9 +71,9 @@ export default class ThemeManager {
/** /**
* Gets the light theme * Gets the light theme
* *
* @return {Object} Object containing theme variables * @return {CustomTheme} Object containing theme variables
* */ * */
static getWhiteTheme(): Object { static getWhiteTheme(): CustomTheme {
return { return {
...DefaultTheme, ...DefaultTheme,
colors: { colors: {
@ -41,6 +90,7 @@ export default class ThemeManager {
success: "#5cb85c", success: "#5cb85c",
warning: "#f0ad4e", warning: "#f0ad4e",
danger: "#d9534f", danger: "#d9534f",
cc: 'dst',
// Calendar/Agenda // Calendar/Agenda
agendaBackgroundColor: '#f3f3f4', agendaBackgroundColor: '#f3f3f4',
@ -79,9 +129,9 @@ export default class ThemeManager {
/** /**
* Gets the dark theme * Gets the dark theme
* *
* @return {Object} Object containing theme variables * @return {CustomTheme} Object containing theme variables
* */ * */
static getDarkTheme(): Object { static getDarkTheme(): CustomTheme {
return { return {
...DarkTheme, ...DarkTheme,
colors: { colors: {
@ -162,9 +212,9 @@ export default class ThemeManager {
/** /**
* Get the current theme based on night mode and events * Get the current theme based on night mode and events
* *
* @returns {Object} The current theme * @returns {CustomTheme} The current theme
*/ */
static getCurrentTheme(): Object { static getCurrentTheme(): CustomTheme {
if (AprilFoolsManager.getInstance().isAprilFoolsEnabled()) if (AprilFoolsManager.getInstance().isAprilFoolsEnabled())
return AprilFoolsManager.getAprilFoolsTheme(ThemeManager.getWhiteTheme()); return AprilFoolsManager.getAprilFoolsTheme(ThemeManager.getWhiteTheme());
else else
@ -174,9 +224,9 @@ export default class ThemeManager {
/** /**
* Get the theme based on night mode * Get the theme based on night mode
* *
* @return {Object} The theme * @return {CustomTheme} The theme
*/ */
static getBaseTheme() { static getBaseTheme(): CustomTheme {
if (ThemeManager.getNightMode()) if (ThemeManager.getNightMode())
return ThemeManager.getDarkTheme(); return ThemeManager.getDarkTheme();
else else
@ -188,7 +238,7 @@ export default class ThemeManager {
* *
* @param callback Function to call after theme change * @param callback Function to call after theme change
*/ */
setUpdateThemeCallback(callback: ?Function) { setUpdateThemeCallback(callback: () => void) {
this.updateThemeCallback = callback; this.updateThemeCallback = callback;
} }
@ -200,7 +250,7 @@ export default class ThemeManager {
setNightMode(isNightMode: boolean) { setNightMode(isNightMode: boolean) {
let nightModeKey = AsyncStorageManager.getInstance().preferences.nightMode.key; let nightModeKey = AsyncStorageManager.getInstance().preferences.nightMode.key;
AsyncStorageManager.getInstance().savePref(nightModeKey, isNightMode ? '1' : '0'); AsyncStorageManager.getInstance().savePref(nightModeKey, isNightMode ? '1' : '0');
if (this.updateThemeCallback !== null) if (this.updateThemeCallback != null)
this.updateThemeCallback(); this.updateThemeCallback();
} }

View file

@ -1,7 +1,7 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {Animated, FlatList} from 'react-native'; import {FlatList} from 'react-native';
import i18n from "i18n-js"; import i18n from "i18n-js";
import DashboardItem from "../../components/Home/EventDashboardItem"; import DashboardItem from "../../components/Home/EventDashboardItem";
import WebSectionList from "../../components/Screens/WebSectionList"; import WebSectionList from "../../components/Screens/WebSectionList";
@ -14,9 +14,10 @@ import ActionsDashBoardItem from "../../components/Home/ActionsDashboardItem";
import ConnectionManager from "../../managers/ConnectionManager"; import ConnectionManager from "../../managers/ConnectionManager";
import {CommonActions} from '@react-navigation/native'; import {CommonActions} from '@react-navigation/native';
import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton"; import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
import {AnimatedValue} from "react-native-reanimated";
import AnimatedFAB from "../../components/Animations/AnimatedFAB"; import AnimatedFAB from "../../components/Animations/AnimatedFAB";
import AnimatedFocusView from "../../components/Animations/AnimatedFocusView"; import AnimatedFocusView from "../../components/Animations/AnimatedFocusView";
import {StackNavigationProp} from "@react-navigation/stack";
import type {CustomTheme} from "../../managers/ThemeManager";
// import DATA from "../dashboard_data.json"; // import DATA from "../dashboard_data.json";
@ -31,30 +32,80 @@ const SECTIONS_ID = [
const REFRESH_TIME = 1000 * 20; // Refresh every 20 seconds const REFRESH_TIME = 1000 * 20; // Refresh every 20 seconds
type Props = { type rawDashboard = {
navigation: Object, news_feed: {
route: Object, data: Array<feedItem>,
theme: Object, },
dashboard: fullDashboard,
} }
type State = { export type feedItem = {
fabPosition: AnimatedValue full_picture: string,
message: string,
permalink_url: string,
created_time: number,
id: string,
};
type fullDashboard = {
today_menu: Array<{ [key: string]: any }>,
proximo_articles: number,
available_machines: {
dryers: number,
washers: number,
},
today_events: Array<{ [key: string]: any }>,
available_tutorials: number,
}
type dashboardItem = {
id: string,
content: Array<{ [key: string]: any }>
};
type dashboardSmallItem = {
id: string,
data: number,
icon: string,
color: string,
onPress: () => void,
isAvailable: boolean
};
export type event = {
id: number,
title: string,
logo: string | null,
date_begin: string,
date_end: string,
description: string,
club: string,
category_id: number,
url: string,
}
type listSection = {
title: string,
data: Array<dashboardItem> | Array<feedItem>,
id: string
};
type Props = {
navigation: StackNavigationProp,
route: { params: any, ... },
theme: CustomTheme,
} }
/** /**
* Class defining the app's home screen * Class defining the app's home screen
*/ */
class HomeScreen extends React.Component<Props, State> { class HomeScreen extends React.Component<Props> {
colors: Object; colors: Object;
isLoggedIn: boolean | null; isLoggedIn: boolean | null;
fabRef: Object; fabRef: { current: null | AnimatedFAB };
state = {
fabPosition: new Animated.Value(0),
};
constructor(props) { constructor(props) {
super(props); super(props);
@ -69,8 +120,8 @@ class HomeScreen extends React.Component<Props, State> {
* @param dateString {string} The Unix Timestamp representation of a date * @param dateString {string} The Unix Timestamp representation of a date
* @return {string} The formatted output date * @return {string} The formatted output date
*/ */
static getFormattedDate(dateString: string) { static getFormattedDate(dateString: number) {
let date = new Date(Number.parseInt(dateString) * 1000); let date = new Date(dateString * 1000);
return date.toLocaleString(); return date.toLocaleString();
} }
@ -92,8 +143,8 @@ class HomeScreen extends React.Component<Props, State> {
}; };
handleNavigationParams = () => { handleNavigationParams = () => {
if (this.props.route.params !== undefined) { if (this.props.route.params != null) {
if (this.props.route.params.nextScreen !== undefined && this.props.route.params.nextScreen !== null) { if (this.props.route.params.nextScreen != null) {
this.props.navigation.navigate(this.props.route.params.nextScreen, this.props.route.params.data); this.props.navigation.navigate(this.props.route.params.nextScreen, this.props.route.params.data);
// reset params to prevent infinite loop // reset params to prevent infinite loop
this.props.navigation.dispatch(CommonActions.setParams({nextScreen: null})); this.props.navigation.dispatch(CommonActions.setParams({nextScreen: null}));
@ -138,14 +189,14 @@ class HomeScreen extends React.Component<Props, State> {
* @param fetchedData * @param fetchedData
* @return {*} * @return {*}
*/ */
createDataset = (fetchedData: Object) => { createDataset = (fetchedData: rawDashboard) => {
// fetchedData = DATA; // fetchedData = DATA;
let newsData = []; let newsData = [];
let dashboardData = []; let dashboardData = [];
if (fetchedData['news_feed'] !== undefined) if (fetchedData.news_feed != null)
newsData = fetchedData['news_feed']['data']; newsData = fetchedData.news_feed.data;
if (fetchedData['dashboard'] !== undefined) if (fetchedData.dashboard != null)
dashboardData = this.generateDashboardDataset(fetchedData['dashboard']); dashboardData = this.generateDashboardDataset(fetchedData.dashboard);
return [ return [
{ {
title: '', title: '',
@ -164,79 +215,61 @@ class HomeScreen extends React.Component<Props, State> {
* Generates the dataset associated to the dashboard to be displayed in the FlatList as a section * Generates the dataset associated to the dashboard to be displayed in the FlatList as a section
* *
* @param dashboardData * @param dashboardData
* @return {*} * @return {Array<dashboardItem>}
*/ */
generateDashboardDataset(dashboardData: Object) { generateDashboardDataset(dashboardData: fullDashboard): Array<dashboardItem> {
let dataset = [ return [
{ {
id: 'top', id: 'top',
content: [] content: [
}, {
{
id: 'actions',
content: undefined
},
{
id: 'event',
content: undefined
},
];
for (let [key, value: number | Object | Array<string>] of Object.entries(dashboardData)) {
switch (key) {
case 'available_machines':
dataset[0]['content'][0] = {
id: 'washers', id: 'washers',
data: value.washers, data: dashboardData.available_machines.washers,
icon: 'washing-machine', icon: 'washing-machine',
color: this.colors.proxiwashColor, color: this.colors.proxiwashColor,
onPress: this.onProxiwashClick, onPress: this.onProxiwashClick,
isAvailable: value.washers > 0 isAvailable: dashboardData.available_machines.washers > 0
}; },
dataset[0]['content'][1] = { {
...dataset[0]['content'][0],
id: 'dryers', id: 'dryers',
data: value.dryers, data: dashboardData.available_machines.dryers,
icon: 'tumble-dryer', icon: 'tumble-dryer',
isAvailable: value.dryers > 0 color: this.colors.proxiwashColor,
}; onPress: this.onProxiwashClick,
break; isAvailable: dashboardData.available_machines.dryers > 0
case 'available_tutorials': },
dataset[0]['content'][2] = { {
id: key, id: 'available_tutorials',
data: value, data: dashboardData.available_tutorials,
icon: 'school', icon: 'school',
color: this.colors.tutorinsaColor, color: this.colors.tutorinsaColor,
onPress: this.onTutorInsaClick, onPress: this.onTutorInsaClick,
isAvailable: parseInt(value) > 0 isAvailable: dashboardData.available_tutorials > 0
}; },
break; {
case 'proximo_articles': id: 'proximo_articles',
dataset[0]['content'][3] = { data: dashboardData.proximo_articles,
id: key,
data: value,
icon: 'shopping', icon: 'shopping',
color: this.colors.proximoColor, color: this.colors.proximoColor,
onPress: this.onProximoClick, onPress: this.onProximoClick,
isAvailable: parseInt(value) > 0 isAvailable: dashboardData.proximo_articles > 0
}; },
break; {
case 'today_menu': id: 'silverware-fork-knife',
dataset[0]['content'][4] = { data: dashboardData.today_menu,
id: key, icon: 'shopping',
data: 0,
icon: 'silverware-fork-knife',
color: this.colors.menuColor, color: this.colors.menuColor,
onPress: this.onMenuClick, onPress: this.onMenuClick,
isAvailable: value.length > 0 isAvailable: dashboardData.today_menu.length > 0
}; },
break; ]
case 'today_events': },
dataset[2]['content'] = value; {id: 'actions', content: []},
break; {
} id: 'event',
} content: dashboardData.today_events
return dataset },
];
} }
/** /**
@ -245,11 +278,11 @@ class HomeScreen extends React.Component<Props, State> {
* @param item The item to display * @param item The item to display
* @return {*} * @return {*}
*/ */
getDashboardItem(item: Object) { getDashboardItem(item: dashboardItem) {
let content = item['content']; let content = item.content;
if (item['id'] === 'event') if (item.id === 'event')
return this.getDashboardEvent(content); return this.getDashboardEvent(content);
else if (item['id'] === 'top') else if (item.id === 'top')
return this.getDashboardRow(content); return this.getDashboardRow(content);
else else
return this.getDashboardActions(); return this.getDashboardActions();
@ -278,14 +311,14 @@ class HomeScreen extends React.Component<Props, State> {
/** /**
* Gets the duration (in milliseconds) of an event * Gets the duration (in milliseconds) of an event
* *
* @param event {Object} * @param event {event}
* @return {number} The number of milliseconds * @return {number} The number of milliseconds
*/ */
getEventDuration(event: Object): number { getEventDuration(event: event): number {
let start = stringToDate(event['date_begin']); let start = stringToDate(event.date_begin);
let end = stringToDate(event['date_end']); let end = stringToDate(event.date_end);
let duration = 0; let duration = 0;
if (start !== undefined && start !== null && end !== undefined && end !== null) if (start != null && end != null)
duration = end - start; duration = end - start;
return duration; return duration;
} }
@ -297,11 +330,11 @@ class HomeScreen extends React.Component<Props, State> {
* @param limit * @param limit
* @return {Array<Object>} * @return {Array<Object>}
*/ */
getEventsAfterLimit(events: Object, limit: Date): Array<Object> { getEventsAfterLimit(events: Array<event>, limit: Date): Array<event> {
let validEvents = []; let validEvents = [];
for (let event of events) { for (let event of events) {
let startDate = stringToDate(event['date_begin']); let startDate = stringToDate(event.date_begin);
if (startDate !== undefined && startDate !== null && startDate >= limit) { if (startDate != null && startDate >= limit) {
validEvents.push(event); validEvents.push(event);
} }
} }
@ -314,7 +347,7 @@ class HomeScreen extends React.Component<Props, State> {
* *
* @param events * @param events
*/ */
getLongestEvent(events: Array<Object>): Object { getLongestEvent(events: Array<event>): event {
let longestEvent = events[0]; let longestEvent = events[0];
let longestTime = 0; let longestTime = 0;
for (let event of events) { for (let event of events) {
@ -332,16 +365,16 @@ class HomeScreen extends React.Component<Props, State> {
* *
* @param events * @param events
*/ */
getFutureEvents(events: Array<Object>): Array<Object> { getFutureEvents(events: Array<event>): Array<event> {
let validEvents = []; let validEvents = [];
let now = new Date(); let now = new Date();
for (let event of events) { for (let event of events) {
let startDate = stringToDate(event['date_begin']); let startDate = stringToDate(event.date_begin);
let endDate = stringToDate(event['date_end']); let endDate = stringToDate(event.date_end);
if (startDate !== undefined && startDate !== null) { if (startDate != null) {
if (startDate > now) if (startDate > now)
validEvents.push(event); validEvents.push(event);
else if (endDate !== undefined && endDate !== null) { else if (endDate != null) {
if (endDate > now || endDate < startDate) // Display event if it ends the following day if (endDate > now || endDate < startDate) // Display event if it ends the following day
validEvents.push(event); validEvents.push(event);
} }
@ -356,8 +389,8 @@ class HomeScreen extends React.Component<Props, State> {
* @param events * @param events
* @return {Object} * @return {Object}
*/ */
getDisplayEvent(events: Array<Object>): Object { getDisplayEvent(events: Array<event>): event | null {
let displayEvent = undefined; let displayEvent = null;
if (events.length > 1) { if (events.length > 1) {
let eventsAfterLimit = this.getEventsAfterLimit(events, this.getTodayEventTimeLimit()); let eventsAfterLimit = this.getEventsAfterLimit(events, this.getTodayEventTimeLimit());
if (eventsAfterLimit.length > 0) { if (eventsAfterLimit.length > 0) {
@ -383,7 +416,7 @@ class HomeScreen extends React.Component<Props, State> {
* @param content * @param content
* @return {*} * @return {*}
*/ */
getDashboardEvent(content: Array<Object>) { getDashboardEvent(content: Array<event>) {
let futureEvents = this.getFutureEvents(content); let futureEvents = this.getFutureEvents(content);
let displayEvent = this.getDisplayEvent(futureEvents); let displayEvent = this.getDisplayEvent(futureEvents);
const clickPreviewAction = () => const clickPreviewAction = () =>
@ -394,14 +427,14 @@ class HomeScreen extends React.Component<Props, State> {
clickAction={this.onEventContainerClick} clickAction={this.onEventContainerClick}
> >
<PreviewEventDashboardItem <PreviewEventDashboardItem
event={displayEvent} event={displayEvent != null ? displayEvent : undefined}
clickAction={clickPreviewAction} clickAction={clickPreviewAction}
/> />
</DashboardItem> </DashboardItem>
); );
} }
dashboardRowRenderItem = ({item}: Object) => { dashboardRowRenderItem = ({item}: { item: dashboardSmallItem }) => {
return ( return (
<SquareDashboardItem <SquareDashboardItem
color={item.color} color={item.color}
@ -419,16 +452,18 @@ class HomeScreen extends React.Component<Props, State> {
* @param content * @param content
* @return {*} * @return {*}
*/ */
getDashboardRow(content: Array<Object>) { getDashboardRow(content: Array<dashboardSmallItem>) {
return <FlatList return (
data={content} //$FlowFixMe
renderItem={this.dashboardRowRenderItem} <FlatList
horizontal={true} data={content}
contentContainerStyle={{ renderItem={this.dashboardRowRenderItem}
marginLeft: 'auto', horizontal={true}
marginRight: 'auto', contentContainerStyle={{
}} marginLeft: 'auto',
/>; marginRight: 'auto',
}}
/>);
} }
/** /**
@ -437,7 +472,7 @@ class HomeScreen extends React.Component<Props, State> {
* @param item The feed item to display * @param item The feed item to display
* @return {*} * @return {*}
*/ */
getFeedItem(item: Object) { getFeedItem(item: feedItem) {
return ( return (
<FeedItem <FeedItem
{...this.props} {...this.props}
@ -456,27 +491,34 @@ class HomeScreen extends React.Component<Props, State> {
* @param section The current section * @param section The current section
* @return {*} * @return {*}
*/ */
getRenderItem = ({item, section}: Object) => { getRenderItem = ({item, section}: {
return (section['id'] === SECTIONS_ID[0] item: { [key: string]: any },
? this.getDashboardItem(item) section: listSection
: this.getFeedItem(item)); }) => {
if (section.id === SECTIONS_ID[0]) {
const data: dashboardItem = item;
return this.getDashboardItem(data);
} else {
const data: feedItem = item;
return this.getFeedItem(data);
}
}; };
openScanner = () => this.props.navigation.navigate("scanner"); openScanner = () => this.props.navigation.navigate("scanner");
onScroll = (event: Object) => { onScroll = (event: SyntheticEvent<EventTarget>) => {
this.fabRef.current.onScroll(event); if (this.fabRef.current != null)
this.fabRef.current.onScroll(event);
}; };
render() { render() {
const nav = this.props.navigation;
return ( return (
<AnimatedFocusView <AnimatedFocusView
{...this.props} {...this.props}
> >
<WebSectionList <WebSectionList
{...this.props}
createDataset={this.createDataset} createDataset={this.createDataset}
navigation={nav}
autoRefreshTime={REFRESH_TIME} autoRefreshTime={REFRESH_TIME}
refreshOnFocus={true} refreshOnFocus={true}
fetchUrl={DATA_URL} fetchUrl={DATA_URL}