diff --git a/src/screens/Planning/PlanningDisplayScreen.js b/src/screens/Planning/PlanningDisplayScreen.js index 503194d..d72322f 100644 --- a/src/screens/Planning/PlanningDisplayScreen.js +++ b/src/screens/Planning/PlanningDisplayScreen.js @@ -2,166 +2,183 @@ import * as React from 'react'; import {View} from 'react-native'; -import {getDateOnlyString, getFormattedEventTime} from '../../utils/Planning'; import {Card, withTheme} from 'react-native-paper'; -import DateManager from "../../managers/DateManager"; import ImageModal from 'react-native-image-modal'; -import BasicLoadingScreen from "../../components/Screens/BasicLoadingScreen"; -import {apiRequest, ERROR_TYPE} from "../../utils/WebData"; -import ErrorView from "../../components/Screens/ErrorView"; -import CustomHTML from "../../components/Overrides/CustomHTML"; -import CustomTabBar from "../../components/Tabbar/CustomTabBar"; import i18n from 'i18n-js'; -import {StackNavigationProp} from "@react-navigation/stack"; -import type {CustomTheme} from "../../managers/ThemeManager"; -import CollapsibleScrollView from "../../components/Collapsible/CollapsibleScrollView"; +import {StackNavigationProp} from '@react-navigation/stack'; +import {getDateOnlyString, getFormattedEventTime} from '../../utils/Planning'; +import DateManager from '../../managers/DateManager'; +import BasicLoadingScreen from '../../components/Screens/BasicLoadingScreen'; +import {apiRequest, ERROR_TYPE} from '../../utils/WebData'; +import ErrorView from '../../components/Screens/ErrorView'; +import CustomHTML from '../../components/Overrides/CustomHTML'; +import CustomTabBar from '../../components/Tabbar/CustomTabBar'; +import type {CustomThemeType} from '../../managers/ThemeManager'; +import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView'; +import type {PlanningEventType} from '../../utils/Planning'; -type Props = { - navigation: StackNavigationProp, - route: { params: { data: Object, id: number, eventId: number } }, - theme: CustomTheme +type PropsType = { + navigation: StackNavigationProp, + route: {params: {data: PlanningEventType, id: number, eventId: number}}, + theme: CustomThemeType, }; -type State = { - loading: boolean +type StateType = { + loading: boolean, }; -const CLUB_INFO_PATH = "event/info"; +const EVENT_INFO_URL = 'event/info'; /** * Class defining a planning event information page. */ -class PlanningDisplayScreen extends React.Component { +class PlanningDisplayScreen extends React.Component { + displayData: null | PlanningEventType; - displayData: Object; - shouldFetchData: boolean; - eventId: number; - errorCode: number; + shouldFetchData: boolean; - /** - * Generates data depending on whether the screen was opened from the planning or from a link - * - * @param props - */ - constructor(props) { - super(props); + eventId: number; - if (this.props.route.params.data != null) { - this.displayData = this.props.route.params.data; - this.eventId = this.displayData.id; - this.shouldFetchData = false; - this.errorCode = 0; - this.state = { - loading: false, - }; - } else { - this.displayData = null; - this.eventId = this.props.route.params.eventId; - this.shouldFetchData = true; - this.errorCode = 0; - this.state = { - loading: true, - }; - this.fetchData(); + errorCode: number; - } + /** + * Generates data depending on whether the screen was opened from the planning or from a link + * + * @param props + */ + constructor(props: PropsType) { + super(props); + + if (props.route.params.data != null) { + this.displayData = props.route.params.data; + this.eventId = this.displayData.id; + this.shouldFetchData = false; + this.errorCode = 0; + this.state = { + loading: false, + }; + } else { + this.displayData = null; + this.eventId = props.route.params.eventId; + this.shouldFetchData = true; + this.errorCode = 0; + this.state = { + loading: true, + }; + this.fetchData(); } + } - /** - * Fetches data for the current event id from the API - */ - fetchData = () => { - this.setState({loading: true}); - apiRequest(CLUB_INFO_PATH, 'POST', {id: this.eventId}) - .then(this.onFetchSuccess) - .catch(this.onFetchError); - }; + /** + * Hides loading and saves fetched data + * + * @param data Received data + */ + onFetchSuccess = (data: PlanningEventType) => { + this.displayData = data; + this.setState({loading: false}); + }; - /** - * Hides loading and saves fetched data - * - * @param data Received data - */ - onFetchSuccess = (data: Object) => { - this.displayData = data; - this.setState({loading: false}); - }; + /** + * Hides loading and saves the error code + * + * @param error + */ + onFetchError = (error: number) => { + this.errorCode = error; + this.setState({loading: false}); + }; - /** - * Hides loading and saves the error code - * - * @param error - */ - onFetchError = (error: number) => { - this.errorCode = error; - this.setState({loading: false}); - }; + /** + * Gets content to display + * + * @returns {*} + */ + getContent(): React.Node { + const {theme} = this.props; + const {displayData} = this; + if (displayData == null) return null; + let subtitle = getFormattedEventTime( + displayData.date_begin, + displayData.date_end, + ); + const dateString = getDateOnlyString(displayData.date_begin); + if (dateString !== null) + subtitle += ` | ${DateManager.getInstance().getTranslatedDate( + dateString, + )}`; + return ( + + + {displayData.logo !== null ? ( + + + + ) : null} - /** - * Gets content to display - * - * @returns {*} - */ - getContent() { - let subtitle = getFormattedEventTime( - this.displayData["date_begin"], this.displayData["date_end"]); - let dateString = getDateOnlyString(this.displayData["date_begin"]); - if (dateString !== null) - subtitle += ' | ' + DateManager.getInstance().getTranslatedDate(dateString); - return ( - - - {this.displayData.logo !== null ? - - - : } + {displayData.description !== null ? ( + + + + ) : ( + + )} + + ); + } - {this.displayData.description !== null ? - - - - : } - - ); - } + /** + * Shows an error view and use a custom message if the event does not exist + * + * @returns {*} + */ + getErrorView(): React.Node { + const {navigation} = this.props; + if (this.errorCode === ERROR_TYPE.BAD_INPUT) + return ( + + ); + return ( + + ); + } - /** - * Shows an error view and use a custom message if the event does not exist - * - * @returns {*} - */ - getErrorView() { - if (this.errorCode === ERROR_TYPE.BAD_INPUT) - return ; - else - return ; - } + /** + * Fetches data for the current event id from the API + */ + fetchData = () => { + this.setState({loading: true}); + apiRequest(EVENT_INFO_URL, 'POST', {id: this.eventId}) + .then(this.onFetchSuccess) + .catch(this.onFetchError); + }; - render() { - if (this.state.loading) - return ; - else if (this.errorCode === 0) - return this.getContent(); - else - return this.getErrorView(); - } + render(): React.Node { + const {loading} = this.state; + if (loading) return ; + if (this.errorCode === 0) return this.getContent(); + return this.getErrorView(); + } } export default withTheme(PlanningDisplayScreen); diff --git a/src/screens/Planning/PlanningScreen.js b/src/screens/Planning/PlanningScreen.js index 67dd40e..dded013 100644 --- a/src/screens/Planning/PlanningScreen.js +++ b/src/screens/Planning/PlanningScreen.js @@ -2,259 +2,282 @@ import * as React from 'react'; import {BackHandler, View} from 'react-native'; -import i18n from "i18n-js"; -import {LocaleConfig} from 'react-native-calendars'; -import {readData} from "../../utils/WebData"; -import type {eventObject} from "../../utils/Planning"; -import { - generateEventAgenda, - getCurrentDateString, - getDateOnlyString, - getFormattedEventTime, -} from '../../utils/Planning'; +import i18n from 'i18n-js'; +import {Agenda, LocaleConfig} from 'react-native-calendars'; import {Avatar, Divider, List} from 'react-native-paper'; -import CustomAgenda from "../../components/Overrides/CustomAgenda"; -import {StackNavigationProp} from "@react-navigation/stack"; -import {MASCOT_STYLE} from "../../components/Mascot/Mascot"; -import MascotPopup from "../../components/Mascot/MascotPopup"; -import AsyncStorageManager from "../../managers/AsyncStorageManager"; +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' +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 Props = { - navigation: StackNavigationProp, -} - -type State = { - refreshing: boolean, - agendaItems: Object, - calendarShowing: boolean, +type PropsType = { + navigation: StackNavigationProp, }; -const FETCH_URL = "https://www.amicale-insat.fr/api/event/list"; +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 { +class PlanningScreen extends React.Component { + agendaRef: null | Agenda; - agendaRef: Object; + lastRefresh: Date; - lastRefresh: Date; - minTimeBetweenRefresh = 60; + minTimeBetweenRefresh = 60; - state = { - refreshing: false, - agendaItems: {}, - calendarShowing: false, + currentDate = getDateOnlyString(getCurrentDateString()); + + constructor(props: PropsType) { + super(props); + if (i18n.currentLocale().startsWith('fr')) { + LocaleConfig.defaultLocale = 'fr'; + } + this.state = { + refreshing: false, + agendaItems: {}, + calendarShowing: false, }; + } - currentDate = getDateOnlyString(getCurrentDateString()); + /** + * 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, + ); + }); + } - constructor(props: any) { - super(props); - if (i18n.currentLocale().startsWith("fr")) { - LocaleConfig.defaultLocale = 'fr'; - } + /** + * 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; + }; - /** - * Captures focus and blur events to hook on android back button - */ - componentDidMount() { - this.onRefresh(); - this.props.navigation.addListener( - 'focus', - () => - BackHandler.addEventListener( - 'hardwareBackPress', - this.onBackButtonPressAndroid - ) - ); - this.props.navigation.addListener( - 'blur', - () => - BackHandler.removeEventListener( - 'hardwareBackPress', - this.onBackButtonPressAndroid - ) - ); + /** + * 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, + }); + }); } + }; - /** - * Overrides default android back button behaviour to close the calendar if it was open. - * - * @return {boolean} - */ - onBackButtonPressAndroid = () => { - if (this.state.calendarShowing) { - this.agendaRef.chooseDay(this.agendaRef.state.selectedDay); - return true; - } else { - return 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, + }); }; - - /** - * Function used to check if a row has changed - * - * @param r1 - * @param r2 - * @return {boolean} - */ - rowHasChanged(r1: Object, r2: Object) { - return false; - // if (r1 !== undefined && r2 !== undefined) - // return r1.title !== r2.title; - // else return !(r1 === undefined && r2 === undefined); + if (item.logo !== null) { + return ( + + + ( + + )} + onPress={onPress} + /> + + ); } + return ( + + + + + ); + }; - /** - * 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; + /** + * Gets an empty render item for an empty date + * + * @return {*} + */ + getRenderEmptyDate = (): React.Node => ; - if (canRefresh) { - this.setState({refreshing: true}); - readData(FETCH_URL) - .then((fetchedData) => { - 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: Object) => { - 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: eventObject) => { - const onPress = this.props.navigation.navigate.bind(this, 'planning-information', {data: item}); - if (item.logo !== null) { - return ( - - - } - onPress={onPress} - /> - - ); - } else { - return ( - - - - - ); - } - } - - /** - * Gets an empty render item for an empty date - * - * @return {*} - */ - getRenderEmptyDate = () => ; - - render() { - return ( - - - - - ); - } + render(): React.Node { + const {state, props} = this; + return ( + + + + + ); + } } export default PlanningScreen; diff --git a/src/utils/Planning.js b/src/utils/Planning.js index c4f59e3..39f616d 100644 --- a/src/utils/Planning.js +++ b/src/utils/Planning.js @@ -1,74 +1,20 @@ // @flow -export type eventObject = { - id: number, - title: string, - logo: string, - date_begin: string, - date_end: string, - description: string, - club: string, - category_id: number, - url: string, +export type PlanningEventType = { + id: number, + title: string, + logo: string, + date_begin: string, + date_end: string, + description: string, + club: string, + category_id: number, + url: string, }; // Regex used to check date string validity const dateRegExp = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/; -/** - * Gets the current day string representation in the format - * YYYY-MM-DD - * - * @return {string} The string representation - */ -export function getCurrentDateString(): string { - return dateToString(new Date(Date.now()), false); -} - -/** - * Checks if the given date is before the other. - * - * @param event1Date Event 1 date in format YYYY-MM-DD HH:MM - * @param event2Date Event 2 date in format YYYY-MM-DD HH:MM - * @return {boolean} - */ -export function isEventBefore(event1Date: string, event2Date: string): boolean { - let date1 = stringToDate(event1Date); - let date2 = stringToDate(event2Date); - if (date1 !== null && date2 !== null) - return date1 < date2; - else - return false; -} - -/** - * Gets only the date part of the given event date string in the format - * YYYY-MM-DD HH:MM - * - * @param dateString The string to get the date from - * @return {string|null} Date in format YYYY:MM:DD or null if given string is invalid - */ -export function getDateOnlyString(dateString: string): string | null { - if (isEventDateStringFormatValid(dateString)) - return dateString.split(" ")[0]; - else - return null; -} - -/** - * Gets only the time part of the given event date string in the format - * YYYY-MM-DD HH:MM - * - * @param dateString The string to get the date from - * @return {string|null} Time in format HH:MM or null if given string is invalid - */ -export function getTimeOnlyString(dateString: string): string | null { - if (isEventDateStringFormatValid(dateString)) - return dateString.split(" ")[1]; - else - return null; -} - /** * Checks if the given date string is in the format * YYYY-MM-DD HH:MM @@ -77,9 +23,11 @@ export function getTimeOnlyString(dateString: string): string | null { * @return {boolean} */ export function isEventDateStringFormatValid(dateString: ?string): boolean { - return dateString !== undefined - && dateString !== null - && dateRegExp.test(dateString); + return ( + dateString !== undefined && + dateString !== null && + dateRegExp.test(dateString) + ); } /** @@ -90,26 +38,20 @@ export function isEventDateStringFormatValid(dateString: ?string): boolean { * @return {Date|null} The date object or null if the given string is invalid */ export function stringToDate(dateString: string): Date | null { - let date = new Date(); - if (isEventDateStringFormatValid(dateString)) { - let stringArray = dateString.split(' '); - let dateArray = stringArray[0].split('-'); - let timeArray = stringArray[1].split(':'); - date.setFullYear( - parseInt(dateArray[0]), - parseInt(dateArray[1]) - 1, // Month range from 0 to 11 - parseInt(dateArray[2]) - ); - date.setHours( - parseInt(timeArray[0]), - parseInt(timeArray[1]), - 0, - 0, - ); - } else - date = null; + let date = new Date(); + if (isEventDateStringFormatValid(dateString)) { + const stringArray = dateString.split(' '); + const dateArray = stringArray[0].split('-'); + const timeArray = stringArray[1].split(':'); + date.setFullYear( + parseInt(dateArray[0], 10), + parseInt(dateArray[1], 10) - 1, // Month range from 0 to 11 + parseInt(dateArray[2], 10), + ); + date.setHours(parseInt(timeArray[0], 10), parseInt(timeArray[1], 10), 0, 0); + } else date = null; - return date; + return date; } /** @@ -121,13 +63,61 @@ export function stringToDate(dateString: string): Date | null { * @return {string} The converted string */ export function dateToString(date: Date, isUTC: boolean): string { - const day = String(date.getDate()).padStart(2, '0'); - const month = String(date.getMonth() + 1).padStart(2, '0'); //January is 0! - const year = date.getFullYear(); - const h = isUTC ? date.getUTCHours() : date.getHours(); - const hours = String(h).padStart(2, '0'); - const minutes = String(date.getMinutes()).padStart(2, '0'); - return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes; + const day = String(date.getDate()).padStart(2, '0'); + const month = String(date.getMonth() + 1).padStart(2, '0'); // January is 0! + const year = date.getFullYear(); + const h = isUTC ? date.getUTCHours() : date.getHours(); + const hours = String(h).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + return `${year}-${month}-${day} ${hours}:${minutes}`; +} + +/** + * Gets the current day string representation in the format + * YYYY-MM-DD + * + * @return {string} The string representation + */ +export function getCurrentDateString(): string { + return dateToString(new Date(Date.now()), false); +} + +/** + * Checks if the given date is before the other. + * + * @param event1Date Event 1 date in format YYYY-MM-DD HH:MM + * @param event2Date Event 2 date in format YYYY-MM-DD HH:MM + * @return {boolean} + */ +export function isEventBefore(event1Date: string, event2Date: string): boolean { + const date1 = stringToDate(event1Date); + const date2 = stringToDate(event2Date); + if (date1 !== null && date2 !== null) return date1 < date2; + return false; +} + +/** + * Gets only the date part of the given event date string in the format + * YYYY-MM-DD HH:MM + * + * @param dateString The string to get the date from + * @return {string|null} Date in format YYYY:MM:DD or null if given string is invalid + */ +export function getDateOnlyString(dateString: string): string | null { + if (isEventDateStringFormatValid(dateString)) return dateString.split(' ')[0]; + return null; +} + +/** + * Gets only the time part of the given event date string in the format + * YYYY-MM-DD HH:MM + * + * @param dateString The string to get the date from + * @return {string|null} Time in format HH:MM or null if given string is invalid + */ +export function getTimeOnlyString(dateString: string): string | null { + if (isEventDateStringFormatValid(dateString)) return dateString.split(' ')[1]; + return null; } /** @@ -144,26 +134,34 @@ export function dateToString(date: Date, isUTC: boolean): string { * @return {string} Formatted string or "/ - /" on error */ export function getFormattedEventTime(start: string, end: string): string { - let formattedStr = '/ - /'; - let startDate = stringToDate(start); - let endDate = stringToDate(end); + let formattedStr = '/ - /'; + const startDate = stringToDate(start); + const endDate = stringToDate(end); - if (startDate !== null && endDate !== null && startDate.getTime() !== endDate.getTime()) { - formattedStr = String(startDate.getHours()).padStart(2, '0') + ':' - + String(startDate.getMinutes()).padStart(2, '0') + ' - '; - if (endDate.getFullYear() > startDate.getFullYear() - || endDate.getMonth() > startDate.getMonth() - || endDate.getDate() > startDate.getDate()) - formattedStr += '23:59'; - else - formattedStr += String(endDate.getHours()).padStart(2, '0') + ':' - + String(endDate.getMinutes()).padStart(2, '0'); - } else if (startDate !== null) - formattedStr = - String(startDate.getHours()).padStart(2, '0') + ':' - + String(startDate.getMinutes()).padStart(2, '0'); + if ( + startDate !== null && + endDate !== null && + startDate.getTime() !== endDate.getTime() + ) { + formattedStr = `${String(startDate.getHours()).padStart(2, '0')}:${String( + startDate.getMinutes(), + ).padStart(2, '0')} - `; + if ( + endDate.getFullYear() > startDate.getFullYear() || + endDate.getMonth() > startDate.getMonth() || + endDate.getDate() > startDate.getDate() + ) + formattedStr += '23:59'; + else + formattedStr += `${String(endDate.getHours()).padStart(2, '0')}:${String( + endDate.getMinutes(), + ).padStart(2, '0')}`; + } else if (startDate !== null) + formattedStr = `${String(startDate.getHours()).padStart(2, '0')}:${String( + startDate.getMinutes(), + ).padStart(2, '0')}`; - return formattedStr + return formattedStr; } /** @@ -176,13 +174,19 @@ export function getFormattedEventTime(start: string, end: string): string { * @return {boolean} */ export function isDescriptionEmpty(description: ?string): boolean { - if (description !== undefined && description !== null) { - return description - .split('

').join('') // Equivalent to a replace all - .split('

').join('') - .split('
').join('').trim() === ''; - } else - return true; + if (description !== undefined && description !== null) { + return ( + description + .split('

') + .join('') // Equivalent to a replace all + .split('

') + .join('') + .split('
') + .join('') + .trim() === '' + ); + } + return true; } /** @@ -193,17 +197,43 @@ export function isDescriptionEmpty(description: ?string): boolean { * @param numberOfMonths The number of months to create, starting from the current date * @return {Object} */ -export function generateEmptyCalendar(numberOfMonths: number): Object { - let end = new Date(Date.now()); - end.setMonth(end.getMonth() + numberOfMonths); - let daysOfYear = {}; - for (let d = new Date(Date.now()); d <= end; d.setDate(d.getDate() + 1)) { - const dateString = getDateOnlyString( - dateToString(new Date(d), false)); - if (dateString !== null) - daysOfYear[dateString] = [] +export function generateEmptyCalendar( + numberOfMonths: number, +): {[key: string]: Array} { + const end = new Date(Date.now()); + end.setMonth(end.getMonth() + numberOfMonths); + const daysOfYear = {}; + for (let d = new Date(Date.now()); d <= end; d.setDate(d.getDate() + 1)) { + const dateString = getDateOnlyString(dateToString(new Date(d), false)); + if (dateString !== null) daysOfYear[dateString] = []; + } + return daysOfYear; +} + +/** + * Adds events to the given array depending on their starting date. + * + * Events starting before are added at the front. + * + * @param eventArray The array to hold sorted events + * @param event The event to add to the array + */ +export function pushEventInOrder( + eventArray: Array, + event: PlanningEventType, +) { + if (eventArray.length === 0) eventArray.push(event); + else { + for (let i = 0; i < eventArray.length; i += 1) { + if (isEventBefore(event.date_begin, eventArray[i].date_begin)) { + eventArray.splice(i, 0, event); + break; + } else if (i === eventArray.length - 1) { + eventArray.push(event); + break; + } } - return daysOfYear; + } } /** @@ -217,40 +247,17 @@ export function generateEmptyCalendar(numberOfMonths: number): Object { * @param numberOfMonths The number of months to create the agenda for * @return {Object} */ -export function generateEventAgenda(eventList: Array, numberOfMonths: number): Object { - let agendaItems = generateEmptyCalendar(numberOfMonths); - for (let i = 0; i < eventList.length; i++) { - const dateString = getDateOnlyString(eventList[i].date_begin); - if (dateString !== null) { - const eventArray = agendaItems[dateString]; - if (eventArray !== undefined) - pushEventInOrder(eventArray, eventList[i]); - } - - } - return agendaItems; -} - -/** - * Adds events to the given array depending on their starting date. - * - * Events starting before are added at the front. - * - * @param eventArray The array to hold sorted events - * @param event The event to add to the array - */ -export function pushEventInOrder(eventArray: Array, event: eventObject): Object { - if (eventArray.length === 0) - eventArray.push(event); - else { - for (let i = 0; i < eventArray.length; i++) { - if (isEventBefore(event.date_begin, eventArray[i].date_begin)) { - eventArray.splice(i, 0, event); - break; - } else if (i === eventArray.length - 1) { - eventArray.push(event); - break; - } - } +export function generateEventAgenda( + eventList: Array, + numberOfMonths: number, +): {[key: string]: Array} { + const agendaItems = generateEmptyCalendar(numberOfMonths); + for (let i = 0; i < eventList.length; i += 1) { + const dateString = getDateOnlyString(eventList[i].date_begin); + if (dateString != null) { + const eventArray = agendaItems[dateString]; + if (eventArray != null) pushEventInOrder(eventArray, eventList[i]); } + } + return agendaItems; } diff --git a/src/utils/WebData.js b/src/utils/WebData.js index 2c9b6ee..738c196 100644 --- a/src/utils/WebData.js +++ b/src/utils/WebData.js @@ -100,15 +100,17 @@ export async function apiRequest( * If no data was found, returns an empty object * * @param url The urls to fetch data from - * @return Promise<{...}> + * @return Promise */ -export async function readData(url: string): Promise<{...}> { - return new Promise( - (resolve: (response: {...}) => void, reject: () => void) => { - fetch(url) - .then(async (response: Response): Promise<{...}> => response.json()) - .then((data: {...}): void => resolve(data)) - .catch((): void => reject()); - }, - ); +// eslint-disable-next-line flowtype/no-weak-types +export async function readData(url: string): Promise { + // eslint-disable-next-line flowtype/no-weak-types + return new Promise((resolve: (response: any) => void, reject: () => void) => { + fetch(url) + // eslint-disable-next-line flowtype/no-weak-types + .then(async (response: Response): Promise => response.json()) + // eslint-disable-next-line flowtype/no-weak-types + .then((data: any): void => resolve(data)) + .catch((): void => reject()); + }); }