// @flow import * as React from 'react'; import {BackHandler, View} from 'react-native'; import i18n from 'i18n-js'; import {Agenda, LocaleConfig} from 'react-native-calendars'; import {Avatar, Divider, List} from 'react-native-paper'; import {StackNavigationProp} from '@react-navigation/stack'; import {readData} from '../../utils/WebData'; import type {PlanningEventType} from '../../utils/Planning'; import { generateEventAgenda, getCurrentDateString, getDateOnlyString, getFormattedEventTime, } from '../../utils/Planning'; import CustomAgenda from '../../components/Overrides/CustomAgenda'; import {MASCOT_STYLE} from '../../components/Mascot/Mascot'; import MascotPopup from '../../components/Mascot/MascotPopup'; import AsyncStorageManager from '../../managers/AsyncStorageManager'; LocaleConfig.locales.fr = { monthNames: [ 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre', ], monthNamesShort: [ 'Janv.', 'Févr.', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil.', 'Août', 'Sept.', 'Oct.', 'Nov.', 'Déc.', ], dayNames: [ 'Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', ], dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'], today: "Aujourd'hui", }; type PropsType = { navigation: StackNavigationProp, }; type StateType = { refreshing: boolean, agendaItems: {[key: string]: Array}, calendarShowing: boolean, }; const FETCH_URL = 'https://www.amicale-insat.fr/api/event/list'; const AGENDA_MONTH_SPAN = 3; /** * Class defining the app's planning screen */ class PlanningScreen extends React.Component { agendaRef: null | Agenda; lastRefresh: Date; minTimeBetweenRefresh = 60; currentDate = getDateOnlyString(getCurrentDateString()); constructor(props: PropsType) { super(props); if (i18n.currentLocale().startsWith('fr')) { LocaleConfig.defaultLocale = 'fr'; } this.state = { refreshing: false, agendaItems: {}, calendarShowing: false, }; } /** * Captures focus and blur events to hook on android back button */ componentDidMount() { const {navigation} = this.props; this.onRefresh(); navigation.addListener('focus', () => { BackHandler.addEventListener( 'hardwareBackPress', this.onBackButtonPressAndroid, ); }); navigation.addListener('blur', () => { BackHandler.removeEventListener( 'hardwareBackPress', this.onBackButtonPressAndroid, ); }); } /** * Overrides default android back button behaviour to close the calendar if it was open. * * @return {boolean} */ onBackButtonPressAndroid = (): boolean => { const {calendarShowing} = this.state; if (calendarShowing && this.agendaRef != null) { this.agendaRef.chooseDay(this.agendaRef.state.selectedDay); return true; } return false; }; /** * Refreshes data and shows an animation while doing it */ onRefresh = () => { let canRefresh; if (this.lastRefresh !== undefined) canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh; else canRefresh = true; if (canRefresh) { this.setState({refreshing: true}); readData(FETCH_URL) .then((fetchedData: Array) => { this.setState({ refreshing: false, agendaItems: generateEventAgenda(fetchedData, AGENDA_MONTH_SPAN), }); this.lastRefresh = new Date(); }) .catch(() => { this.setState({ refreshing: false, }); }); } }; /** * Callback used when receiving the agenda ref * * @param ref */ onAgendaRef = (ref: Agenda) => { this.agendaRef = ref; }; /** * Callback used when a button is pressed to toggle the calendar * * @param isCalendarOpened True is the calendar is already open, false otherwise */ onCalendarToggled = (isCalendarOpened: boolean) => { this.setState({calendarShowing: isCalendarOpened}); }; /** * Gets an event render item * * @param item The current event to render * @return {*} */ getRenderItem = (item: PlanningEventType): React.Node => { const {navigation} = this.props; const onPress = () => { navigation.navigate('planning-information', { data: item, }); }; if (item.logo !== null) { return ( ( )} onPress={onPress} /> ); } return ( ); }; /** * Gets an empty render item for an empty date * * @return {*} */ getRenderEmptyDate = (): React.Node => ; render(): React.Node { const {state, props} = this; return ( ); } } export default PlanningScreen;