forked from vergnet/application-amicale
Improved project structure
This commit is contained in:
parent
fac9d8208e
commit
7e90b80ca2
30 changed files with 672 additions and 698 deletions
12
App.js
12
App.js
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Platform, StatusBar} from 'react-native';
|
import {Platform, StatusBar} from 'react-native';
|
||||||
import LocaleManager from './utils/LocaleManager';
|
import LocaleManager from './managers/LocaleManager';
|
||||||
import AsyncStorageManager from "./utils/AsyncStorageManager";
|
import AsyncStorageManager from "./managers/AsyncStorageManager";
|
||||||
import CustomIntroSlider from "./components/CustomIntroSlider";
|
import CustomIntroSlider from "./components/CustomIntroSlider";
|
||||||
import {SplashScreen} from 'expo';
|
import {SplashScreen} from 'expo';
|
||||||
import ThemeManager from './utils/ThemeManager';
|
import ThemeManager from './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 './navigation/DrawerNavigator';
|
import DrawerNavigator from './navigation/DrawerNavigator';
|
||||||
import NotificationsManager from "./utils/NotificationsManager";
|
import {initExpoToken} from "./utils/Notifications";
|
||||||
import {Provider as PaperProvider} from 'react-native-paper';
|
import {Provider as PaperProvider} from 'react-native-paper';
|
||||||
import AprilFoolsManager from "./utils/AprilFoolsManager";
|
import AprilFoolsManager from "./managers/AprilFoolsManager";
|
||||||
import Update from "./constants/Update";
|
import Update from "./constants/Update";
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
@ -90,7 +90,7 @@ export default class App extends React.Component<Props, State> {
|
||||||
// Wait for custom fonts to be loaded before showing the app
|
// Wait for custom fonts to be loaded before showing the app
|
||||||
await AsyncStorageManager.getInstance().loadPreferences();
|
await AsyncStorageManager.getInstance().loadPreferences();
|
||||||
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
|
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
|
||||||
await NotificationsManager.initExpoToken();
|
await initExpoToken();
|
||||||
this.onLoadFinished();
|
this.onLoadFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
210
__tests__/utils/PlanningEventManager.test.js
Normal file
210
__tests__/utils/PlanningEventManager.test.js
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
import React from 'react';
|
||||||
|
import * as Planning from "../../utils/Planning";
|
||||||
|
|
||||||
|
test('isDescriptionEmpty', () => {
|
||||||
|
expect(Planning.isDescriptionEmpty("")).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty(" ")).toBeTrue();
|
||||||
|
// noinspection CheckTagEmptyBody
|
||||||
|
expect(Planning.isDescriptionEmpty("<p></p>")).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty("<p> </p>")).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty("<p><br></p>")).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty("<p><br></p><p><br></p>")).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty("<p><br><br><br></p>")).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty("<p><br>")).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty(null)).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty(undefined)).toBeTrue();
|
||||||
|
expect(Planning.isDescriptionEmpty("coucou")).toBeFalse();
|
||||||
|
expect(Planning.isDescriptionEmpty("<p>coucou</p>")).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isEventDateStringFormatValid', () => {
|
||||||
|
expect(Planning.isEventDateStringFormatValid("2020-03-21 09:00")).toBeTrue();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("3214-64-12 01:16")).toBeTrue();
|
||||||
|
|
||||||
|
expect(Planning.isEventDateStringFormatValid("3214-64-12 01:16:00")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("3214-64-12 1:16")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("3214-f4-12 01:16")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("sqdd 09:00")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("2020-03-21")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("2020-03-21 truc")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("3214-64-12 1:16:65")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("garbage")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid("")).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid(undefined)).toBeFalse();
|
||||||
|
expect(Planning.isEventDateStringFormatValid(null)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('stringToDate', () => {
|
||||||
|
let testDate = new Date();
|
||||||
|
expect(Planning.stringToDate(undefined)).toBeNull();
|
||||||
|
expect(Planning.stringToDate("")).toBeNull();
|
||||||
|
expect(Planning.stringToDate("garbage")).toBeNull();
|
||||||
|
expect(Planning.stringToDate("2020-03-21")).toBeNull();
|
||||||
|
expect(Planning.stringToDate("09:00:00")).toBeNull();
|
||||||
|
expect(Planning.stringToDate("2020-03-21 09:g0")).toBeNull();
|
||||||
|
expect(Planning.stringToDate("2020-03-21 09:g0:")).toBeNull();
|
||||||
|
testDate.setFullYear(2020, 2, 21);
|
||||||
|
testDate.setHours(9, 0, 0, 0);
|
||||||
|
expect(Planning.stringToDate("2020-03-21 09:00")).toEqual(testDate);
|
||||||
|
testDate.setFullYear(2020, 0, 31);
|
||||||
|
testDate.setHours(18, 30, 0, 0);
|
||||||
|
expect(Planning.stringToDate("2020-01-31 18:30")).toEqual(testDate);
|
||||||
|
testDate.setFullYear(2020, 50, 50);
|
||||||
|
testDate.setHours(65, 65, 0, 0);
|
||||||
|
expect(Planning.stringToDate("2020-51-50 65:65")).toEqual(testDate);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getFormattedEventTime', () => {
|
||||||
|
expect(Planning.getFormattedEventTime(null, null))
|
||||||
|
.toBe('/ - /');
|
||||||
|
expect(Planning.getFormattedEventTime(undefined, undefined))
|
||||||
|
.toBe('/ - /');
|
||||||
|
expect(Planning.getFormattedEventTime("20:30", "23:00"))
|
||||||
|
.toBe('/ - /');
|
||||||
|
expect(Planning.getFormattedEventTime("2020-03-30", "2020-03-31"))
|
||||||
|
.toBe('/ - /');
|
||||||
|
|
||||||
|
|
||||||
|
expect(Planning.getFormattedEventTime("2020-03-21 09:00", "2020-03-21 09:00"))
|
||||||
|
.toBe('09:00');
|
||||||
|
expect(Planning.getFormattedEventTime("2020-03-21 09:00", "2020-03-22 17:00"))
|
||||||
|
.toBe('09:00 - 23:59');
|
||||||
|
expect(Planning.getFormattedEventTime("2020-03-30 20:30", "2020-03-30 23:00"))
|
||||||
|
.toBe('20:30 - 23:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getDateOnlyString', () => {
|
||||||
|
expect(Planning.getDateOnlyString("2020-03-21 09:00")).toBe("2020-03-21");
|
||||||
|
expect(Planning.getDateOnlyString("2021-12-15 09:00")).toBe("2021-12-15");
|
||||||
|
expect(Planning.getDateOnlyString("2021-12-o5 09:00")).toBeNull();
|
||||||
|
expect(Planning.getDateOnlyString("2021-12-15 09:")).toBeNull();
|
||||||
|
expect(Planning.getDateOnlyString("2021-12-15")).toBeNull();
|
||||||
|
expect(Planning.getDateOnlyString("garbage")).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isEventBefore', () => {
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 09:00", "2020-03-21 10:00")).toBeTrue();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 10:00", "2020-03-21 10:15")).toBeTrue();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 10:15", "2021-03-21 10:15")).toBeTrue();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 10:15", "2020-05-21 10:15")).toBeTrue();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 10:15", "2020-03-30 10:15")).toBeTrue();
|
||||||
|
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 10:00", "2020-03-21 10:00")).toBeFalse();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 10:00", "2020-03-21 09:00")).toBeFalse();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-21 10:15", "2020-03-21 10:00")).toBeFalse();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2021-03-21 10:15", "2020-03-21 10:15")).toBeFalse();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-05-21 10:15", "2020-03-21 10:15")).toBeFalse();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"2020-03-30 10:15", "2020-03-21 10:15")).toBeFalse();
|
||||||
|
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
"garbage", "2020-03-21 10:15")).toBeFalse();
|
||||||
|
expect(Planning.isEventBefore(
|
||||||
|
undefined, undefined)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('dateToString', () => {
|
||||||
|
let testDate = new Date();
|
||||||
|
testDate.setFullYear(2020, 2, 21);
|
||||||
|
testDate.setHours(9, 0, 0, 0);
|
||||||
|
expect(Planning.dateToString(testDate)).toBe("2020-03-21 09:00");
|
||||||
|
testDate.setFullYear(2021, 0, 12);
|
||||||
|
testDate.setHours(9, 10, 0, 0);
|
||||||
|
expect(Planning.dateToString(testDate)).toBe("2021-01-12 09:10");
|
||||||
|
testDate.setFullYear(2022, 11, 31);
|
||||||
|
testDate.setHours(9, 10, 15, 0);
|
||||||
|
expect(Planning.dateToString(testDate)).toBe("2022-12-31 09:10");
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateEmptyCalendar', () => {
|
||||||
|
jest.spyOn(Date, 'now')
|
||||||
|
.mockImplementation(() =>
|
||||||
|
new Date('2020-01-14T00:00:00.000Z').getTime()
|
||||||
|
);
|
||||||
|
let calendar = Planning.generateEmptyCalendar(1);
|
||||||
|
expect(calendar).toHaveProperty("2020-01-14");
|
||||||
|
expect(calendar).toHaveProperty("2020-01-20");
|
||||||
|
expect(calendar).toHaveProperty("2020-02-10");
|
||||||
|
expect(Object.keys(calendar).length).toBe(32);
|
||||||
|
calendar = Planning.generateEmptyCalendar(3);
|
||||||
|
expect(calendar).toHaveProperty("2020-01-14");
|
||||||
|
expect(calendar).toHaveProperty("2020-01-20");
|
||||||
|
expect(calendar).toHaveProperty("2020-02-10");
|
||||||
|
expect(calendar).toHaveProperty("2020-02-14");
|
||||||
|
expect(calendar).toHaveProperty("2020-03-20");
|
||||||
|
expect(calendar).toHaveProperty("2020-04-12");
|
||||||
|
expect(Object.keys(calendar).length).toBe(92);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('pushEventInOrder', () => {
|
||||||
|
let eventArray = [];
|
||||||
|
let event1 = {date_begin: "2020-01-14 09:15"};
|
||||||
|
Planning.pushEventInOrder(eventArray, event1);
|
||||||
|
expect(eventArray.length).toBe(1);
|
||||||
|
expect(eventArray[0]).toBe(event1);
|
||||||
|
|
||||||
|
let event2 = {date_begin: "2020-01-14 10:15"};
|
||||||
|
Planning.pushEventInOrder(eventArray, event2);
|
||||||
|
expect(eventArray.length).toBe(2);
|
||||||
|
expect(eventArray[0]).toBe(event1);
|
||||||
|
expect(eventArray[1]).toBe(event2);
|
||||||
|
|
||||||
|
let event3 = {date_begin: "2020-01-14 10:15", title: "garbage"};
|
||||||
|
Planning.pushEventInOrder(eventArray, event3);
|
||||||
|
expect(eventArray.length).toBe(3);
|
||||||
|
expect(eventArray[0]).toBe(event1);
|
||||||
|
expect(eventArray[1]).toBe(event2);
|
||||||
|
expect(eventArray[2]).toBe(event3);
|
||||||
|
|
||||||
|
let event4 = {date_begin: "2020-01-13 09:00"};
|
||||||
|
Planning.pushEventInOrder(eventArray, event4);
|
||||||
|
expect(eventArray.length).toBe(4);
|
||||||
|
expect(eventArray[0]).toBe(event4);
|
||||||
|
expect(eventArray[1]).toBe(event1);
|
||||||
|
expect(eventArray[2]).toBe(event2);
|
||||||
|
expect(eventArray[3]).toBe(event3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateEventAgenda', () => {
|
||||||
|
jest.spyOn(Date, 'now')
|
||||||
|
.mockImplementation(() =>
|
||||||
|
new Date('2020-01-14T00:00:00.000Z').getTime()
|
||||||
|
);
|
||||||
|
let eventList = [
|
||||||
|
{date_begin: "2020-01-14 09:15"},
|
||||||
|
{date_begin: "2020-02-01 09:15"},
|
||||||
|
{date_begin: "2020-01-15 09:15"},
|
||||||
|
{date_begin: "2020-02-01 09:30"},
|
||||||
|
{date_begin: "2020-02-01 08:30"},
|
||||||
|
];
|
||||||
|
const calendar = Planning.generateEventAgenda(eventList, 2);
|
||||||
|
expect(calendar["2020-01-14"].length).toBe(1);
|
||||||
|
expect(calendar["2020-01-14"][0]).toBe(eventList[0]);
|
||||||
|
expect(calendar["2020-01-15"].length).toBe(1);
|
||||||
|
expect(calendar["2020-01-15"][0]).toBe(eventList[2]);
|
||||||
|
expect(calendar["2020-02-01"].length).toBe(3);
|
||||||
|
expect(calendar["2020-02-01"][0]).toBe(eventList[4]);
|
||||||
|
expect(calendar["2020-02-01"][1]).toBe(eventList[1]);
|
||||||
|
expect(calendar["2020-02-01"][2]).toBe(eventList[3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getCurrentDateString', () => {
|
||||||
|
jest.spyOn(Date, 'now')
|
||||||
|
.mockImplementation(() => {
|
||||||
|
let date = new Date();
|
||||||
|
date.setFullYear(2020, 0, 14);
|
||||||
|
date.setHours(15, 30, 54, 65);
|
||||||
|
return date.getTime();
|
||||||
|
});
|
||||||
|
expect(Planning.getCurrentDateString()).toBe('2020-01-14 15:30');
|
||||||
|
});
|
|
@ -5,7 +5,7 @@ import {StyleSheet, View} from "react-native";
|
||||||
import HTML from "react-native-render-html";
|
import HTML from "react-native-render-html";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import {Avatar, Button, Card, withTheme} from 'react-native-paper';
|
import {Avatar, Button, Card, withTheme} from 'react-native-paper';
|
||||||
import PlanningEventManager from "../utils/PlanningEventManager";
|
import {getFormattedEventTime, isDescriptionEmpty} from "../utils/Planning";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component used to display an event preview if an event is available
|
* Component used to display an event preview if an event is available
|
||||||
|
@ -17,7 +17,7 @@ function PreviewEventDashboardItem(props) {
|
||||||
const {colors} = props.theme;
|
const {colors} = props.theme;
|
||||||
const isEmpty = props.event === undefined
|
const isEmpty = props.event === undefined
|
||||||
? true
|
? true
|
||||||
: PlanningEventManager.isDescriptionEmpty(props.event['description']);
|
: isDescriptionEmpty(props.event['description']);
|
||||||
|
|
||||||
if (props.event !== undefined && props.event !== null) {
|
if (props.event !== undefined && props.event !== null) {
|
||||||
const hasImage = props.event['logo'] !== '' && props.event['logo'] !== null;
|
const hasImage = props.event['logo'] !== '' && props.event['logo'] !== null;
|
||||||
|
@ -34,12 +34,12 @@ function PreviewEventDashboardItem(props) {
|
||||||
{hasImage ?
|
{hasImage ?
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={props.event['title']}
|
title={props.event['title']}
|
||||||
subtitle={PlanningEventManager.getFormattedEventTime(props.event['date_begin'], props.event['date_end'])}
|
subtitle={getFormattedEventTime(props.event['date_begin'], props.event['date_end'])}
|
||||||
left={getImage}
|
left={getImage}
|
||||||
/> :
|
/> :
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={props.event['title']}
|
title={props.event['title']}
|
||||||
subtitle={PlanningEventManager.getFormattedEventTime(props.event['date_begin'], props.event['date_end'])}
|
subtitle={getFormattedEventTime(props.event['date_begin'], props.event['date_end'])}
|
||||||
/>}
|
/>}
|
||||||
{!isEmpty ?
|
{!isEmpty ?
|
||||||
<Card.Content style={styles.content}>
|
<Card.Content style={styles.content}>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import WebDataManager from "../utils/WebDataManager";
|
import {readData} from "../utils/WebData";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import {Snackbar} from 'react-native-paper';
|
import {Snackbar} from 'react-native-paper';
|
||||||
import {RefreshControl, SectionList, View} from "react-native";
|
import {RefreshControl, SectionList, View} from "react-native";
|
||||||
|
@ -42,8 +42,6 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
updateData: 0,
|
updateData: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
webDataManager: WebDataManager;
|
|
||||||
|
|
||||||
refreshInterval: IntervalID;
|
refreshInterval: IntervalID;
|
||||||
lastRefresh: Date;
|
lastRefresh: Date;
|
||||||
|
|
||||||
|
@ -79,7 +77,6 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
* Allows to detect when the screen is focused
|
* Allows to detect when the screen is focused
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.webDataManager = new WebDataManager(this.props.fetchUrl);
|
|
||||||
const onScreenFocus = this.onScreenFocus.bind(this);
|
const onScreenFocus = this.onScreenFocus.bind(this);
|
||||||
const onScreenBlur = this.onScreenBlur.bind(this);
|
const onScreenBlur = this.onScreenBlur.bind(this);
|
||||||
this.props.navigation.addListener('focus', onScreenFocus);
|
this.props.navigation.addListener('focus', onScreenFocus);
|
||||||
|
@ -144,7 +141,7 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
canRefresh = true;
|
canRefresh = true;
|
||||||
if (canRefresh) {
|
if (canRefresh) {
|
||||||
this.setState({refreshing: true});
|
this.setState({refreshing: true});
|
||||||
this.webDataManager.readData()
|
readData(this.props.fetchUrl)
|
||||||
.then(this.onFetchSuccess)
|
.then(this.onFetchSuccess)
|
||||||
.catch(this.onFetchError);
|
.catch(this.onFetchError);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<coverage generated="1584889501493" clover="3.2.0">
|
<coverage generated="1584889501493" clover="3.2.0">
|
||||||
<project timestamp="1584889501493" name="All files">
|
<project timestamp="1584889501493" name="All files">
|
||||||
<metrics statements="65" coveredstatements="65" conditionals="39" coveredconditionals="36" methods="11" coveredmethods="11" elements="115" coveredelements="112" complexity="0" loc="65" ncloc="65" packages="1" files="1" classes="1"/>
|
<metrics statements="65" coveredstatements="65" conditionals="39" coveredconditionals="36" methods="11" coveredmethods="11" elements="115" coveredelements="112" complexity="0" loc="65" ncloc="65" packages="1" files="1" classes="1"/>
|
||||||
<file name="PlanningEventManager.js" path="/home/keplyx/expo-projects/application-amicale/utils/PlanningEventManager.js">
|
<file name="Planning.js" path="/home/keplyx/expo-projects/application-amicale/utils/Planning.js">
|
||||||
<metrics statements="65" coveredstatements="65" conditionals="39" coveredconditionals="36" methods="11" coveredmethods="11"/>
|
<metrics statements="65" coveredstatements="65" conditionals="39" coveredconditionals="36" methods="11" coveredmethods="11"/>
|
||||||
<line num="18" count="1" type="stmt"/>
|
<line num="18" count="1" type="stmt"/>
|
||||||
<line num="27" count="1" type="stmt"/>
|
<line num="27" count="1" type="stmt"/>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Code coverage report for PlanningEventManager.js</title>
|
<title>Code coverage report for Planning.js</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" href="prettify.css" />
|
<link rel="stylesheet" href="prettify.css" />
|
||||||
<link rel="stylesheet" href="base.css" />
|
<link rel="stylesheet" href="base.css" />
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div class='wrapper'>
|
<div class='wrapper'>
|
||||||
<div class='pad1'>
|
<div class='pad1'>
|
||||||
<h1><a href="index.html">All files</a> PlanningEventManager.js</h1>
|
<h1><a href="index.html">All files</a> Planning.js</h1>
|
||||||
<div class='clearfix'>
|
<div class='clearfix'>
|
||||||
|
|
||||||
<div class='fl pad1y space-right2'>
|
<div class='fl pad1y space-right2'>
|
||||||
|
@ -806,4 +806,3 @@ export default class PlanningEventManager {
|
||||||
<script src="block-navigation.js"></script>
|
<script src="block-navigation.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
<td class="file high" data-value="PlanningEventManager.js"><a href="PlanningEventManager.js.html">PlanningEventManager.js</a></td>
|
<td class="file high" data-value="Planning.js"><a href="PlanningEventManager.js.html">Planning.js</a></td>
|
||||||
<td data-value="100" class="pic high">
|
<td data-value="100" class="pic high">
|
||||||
<div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
|
<div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -108,4 +108,3 @@
|
||||||
<script src="block-navigation.js"></script>
|
<script src="block-navigation.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TN:
|
TN:
|
||||||
SF:utils/PlanningEventManager.js
|
SF:utils/Planning.js
|
||||||
FN:26,(anonymous_0)
|
FN:26,(anonymous_0)
|
||||||
FN:37,(anonymous_1)
|
FN:37,(anonymous_1)
|
||||||
FN:53,(anonymous_2)
|
FN:53,(anonymous_2)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import ProximoListScreen from "../screens/Proximo/ProximoListScreen";
|
||||||
import ProximoAboutScreen from "../screens/Proximo/ProximoAboutScreen";
|
import ProximoAboutScreen from "../screens/Proximo/ProximoAboutScreen";
|
||||||
import PlanexScreen from '../screens/Websites/PlanexScreen';
|
import PlanexScreen from '../screens/Websites/PlanexScreen';
|
||||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||||
import AsyncStorageManager from "../utils/AsyncStorageManager";
|
import AsyncStorageManager from "../managers/AsyncStorageManager";
|
||||||
import HeaderButton from "../components/HeaderButton";
|
import HeaderButton from "../components/HeaderButton";
|
||||||
import {withTheme} from 'react-native-paper';
|
import {withTheme} from 'react-native-paper';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from 'react';
|
||||||
import {FlatList, Linking, Platform, View} from 'react-native';
|
import {FlatList, Linking, Platform, View} from 'react-native';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import appJson from '../../app';
|
import appJson from '../../app';
|
||||||
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
import AsyncStorageManager from "../../managers/AsyncStorageManager";
|
||||||
import CustomModal from "../../components/CustomModal";
|
import CustomModal from "../../components/CustomModal";
|
||||||
import {Avatar, Button, Card, List, Text, Title, withTheme} from 'react-native-paper';
|
import {Avatar, Button, Card, List, Text, Title, withTheme} from 'react-native-paper';
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {ScrollView, View} from "react-native";
|
import {ScrollView, View} from "react-native";
|
||||||
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
import AsyncStorageManager from "../../managers/AsyncStorageManager";
|
||||||
import CustomModal from "../../components/CustomModal";
|
import CustomModal from "../../components/CustomModal";
|
||||||
import {Button, Card, List, Subheading, TextInput, Title, withTheme} from 'react-native-paper';
|
import {Button, Card, List, Subheading, TextInput, Title, withTheme} from 'react-native-paper';
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {Text, withTheme} from 'react-native-paper';
|
||||||
import FeedItem from "../components/FeedItem";
|
import FeedItem from "../components/FeedItem";
|
||||||
import SquareDashboardItem from "../components/SquareDashboardItem";
|
import SquareDashboardItem from "../components/SquareDashboardItem";
|
||||||
import PreviewEventDashboardItem from "../components/PreviewEventDashboardItem";
|
import PreviewEventDashboardItem from "../components/PreviewEventDashboardItem";
|
||||||
import PlanningEventManager from "../utils/PlanningEventManager";
|
import {stringToDate} from "../utils/Planning";
|
||||||
// import DATA from "../dashboard_data.json";
|
// import DATA from "../dashboard_data.json";
|
||||||
|
|
||||||
|
|
||||||
|
@ -201,8 +201,8 @@ class HomeScreen extends React.Component<Props> {
|
||||||
* @return {number} The number of milliseconds
|
* @return {number} The number of milliseconds
|
||||||
*/
|
*/
|
||||||
getEventDuration(event: Object): number {
|
getEventDuration(event: Object): number {
|
||||||
let start = PlanningEventManager.stringToDate(event['date_begin']);
|
let start = stringToDate(event['date_begin']);
|
||||||
let end = PlanningEventManager.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 !== undefined && start !== null && end !== undefined && end !== null)
|
||||||
duration = end - start;
|
duration = end - start;
|
||||||
|
@ -219,7 +219,7 @@ class HomeScreen extends React.Component<Props> {
|
||||||
getEventsAfterLimit(events: Object, limit: Date): Array<Object> {
|
getEventsAfterLimit(events: Object, limit: Date): Array<Object> {
|
||||||
let validEvents = [];
|
let validEvents = [];
|
||||||
for (let event of events) {
|
for (let event of events) {
|
||||||
let startDate = PlanningEventManager.stringToDate(event['date_begin']);
|
let startDate = stringToDate(event['date_begin']);
|
||||||
if (startDate !== undefined && startDate !== null && startDate >= limit) {
|
if (startDate !== undefined && startDate !== null && startDate >= limit) {
|
||||||
validEvents.push(event);
|
validEvents.push(event);
|
||||||
}
|
}
|
||||||
|
@ -255,8 +255,8 @@ class HomeScreen extends React.Component<Props> {
|
||||||
let validEvents = [];
|
let validEvents = [];
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
for (let event of events) {
|
for (let event of events) {
|
||||||
let startDate = PlanningEventManager.stringToDate(event['date_begin']);
|
let startDate = stringToDate(event['date_begin']);
|
||||||
let endDate = PlanningEventManager.stringToDate(event['date_end']);
|
let endDate = stringToDate(event['date_end']);
|
||||||
if (startDate !== undefined && startDate !== null) {
|
if (startDate !== undefined && startDate !== null) {
|
||||||
if (startDate > now)
|
if (startDate > now)
|
||||||
validEvents.push(event);
|
validEvents.push(event);
|
||||||
|
|
|
@ -4,9 +4,9 @@ import * as React from 'react';
|
||||||
import {Image, ScrollView, View} from 'react-native';
|
import {Image, ScrollView, View} from 'react-native';
|
||||||
import HTML from "react-native-render-html";
|
import HTML from "react-native-render-html";
|
||||||
import {Linking} from "expo";
|
import {Linking} from "expo";
|
||||||
import PlanningEventManager from '../../utils/PlanningEventManager';
|
import {getDateOnlyString, getFormattedEventTime} from '../../utils/Planning';
|
||||||
import {Card, withTheme} from 'react-native-paper';
|
import {Card, withTheme} from 'react-native-paper';
|
||||||
import DateManager from "../../utils/DateManager";
|
import DateManager from "../../managers/DateManager";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigation: Object,
|
navigation: Object,
|
||||||
|
@ -33,9 +33,9 @@ class PlanningDisplayScreen extends React.Component<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// console.log("rendering planningDisplayScreen");
|
// console.log("rendering planningDisplayScreen");
|
||||||
let subtitle = PlanningEventManager.getFormattedEventTime(
|
let subtitle = getFormattedEventTime(
|
||||||
this.displayData["date_begin"], this.displayData["date_end"]);
|
this.displayData["date_begin"], this.displayData["date_end"]);
|
||||||
let dateString = PlanningEventManager.getDateOnlyString(this.displayData["date_begin"]);
|
let dateString = getDateOnlyString(this.displayData["date_begin"]);
|
||||||
if (dateString !== null)
|
if (dateString !== null)
|
||||||
subtitle += ' | ' + DateManager.getInstance().getTranslatedDate(dateString);
|
subtitle += ' | ' + DateManager.getInstance().getTranslatedDate(dateString);
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -4,9 +4,14 @@ import * as React from 'react';
|
||||||
import {BackHandler, View} from 'react-native';
|
import {BackHandler, View} from 'react-native';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import {LocaleConfig} from 'react-native-calendars';
|
import {LocaleConfig} from 'react-native-calendars';
|
||||||
import WebDataManager from "../../utils/WebDataManager";
|
import {readData} from "../../utils/WebData";
|
||||||
import type {eventObject} from "../../utils/PlanningEventManager";
|
import type {eventObject} from "../../utils/Planning";
|
||||||
import PlanningEventManager from '../../utils/PlanningEventManager';
|
import {
|
||||||
|
generateEventAgenda,
|
||||||
|
getCurrentDateString,
|
||||||
|
getDateOnlyString,
|
||||||
|
getFormattedEventTime,
|
||||||
|
} from '../../utils/Planning';
|
||||||
import {Avatar, Divider, List} from 'react-native-paper';
|
import {Avatar, Divider, List} from 'react-native-paper';
|
||||||
import CustomAgenda from "../../components/CustomAgenda";
|
import CustomAgenda from "../../components/CustomAgenda";
|
||||||
|
|
||||||
|
@ -38,7 +43,6 @@ const AGENDA_MONTH_SPAN = 3;
|
||||||
export default class PlanningScreen extends React.Component<Props, State> {
|
export default class PlanningScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
agendaRef: Object;
|
agendaRef: Object;
|
||||||
webDataManager: WebDataManager;
|
|
||||||
|
|
||||||
lastRefresh: Date;
|
lastRefresh: Date;
|
||||||
minTimeBetweenRefresh = 60;
|
minTimeBetweenRefresh = 60;
|
||||||
|
@ -59,11 +63,10 @@ export default class PlanningScreen extends React.Component<Props, State> {
|
||||||
onAgendaRef: Function;
|
onAgendaRef: Function;
|
||||||
onCalendarToggled: Function;
|
onCalendarToggled: Function;
|
||||||
onBackButtonPressAndroid: Function;
|
onBackButtonPressAndroid: Function;
|
||||||
currentDate = PlanningEventManager.getDateOnlyString(PlanningEventManager.getCurrentDateString());
|
currentDate = getDateOnlyString(getCurrentDateString());
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
this.webDataManager = new WebDataManager(FETCH_URL);
|
|
||||||
if (i18n.currentLocale().startsWith("fr")) {
|
if (i18n.currentLocale().startsWith("fr")) {
|
||||||
LocaleConfig.defaultLocale = 'fr';
|
LocaleConfig.defaultLocale = 'fr';
|
||||||
}
|
}
|
||||||
|
@ -141,11 +144,11 @@ export default class PlanningScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
if (canRefresh) {
|
if (canRefresh) {
|
||||||
this.setState({refreshing: true});
|
this.setState({refreshing: true});
|
||||||
this.webDataManager.readData()
|
readData(FETCH_URL)
|
||||||
.then((fetchedData) => {
|
.then((fetchedData) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
agendaItems: PlanningEventManager.generateEventAgenda(fetchedData, AGENDA_MONTH_SPAN)
|
agendaItems: generateEventAgenda(fetchedData, AGENDA_MONTH_SPAN)
|
||||||
});
|
});
|
||||||
this.lastRefresh = new Date();
|
this.lastRefresh = new Date();
|
||||||
})
|
})
|
||||||
|
@ -189,7 +192,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<List.Item
|
<List.Item
|
||||||
title={item.title}
|
title={item.title}
|
||||||
description={PlanningEventManager.getFormattedEventTime(item["date_begin"], item["date_end"])}
|
description={getFormattedEventTime(item["date_begin"], item["date_end"])}
|
||||||
left={() => <Avatar.Image
|
left={() => <Avatar.Image
|
||||||
source={{uri: item.logo}}
|
source={{uri: item.logo}}
|
||||||
style={{backgroundColor: 'transparent'}}
|
style={{backgroundColor: 'transparent'}}
|
||||||
|
@ -204,7 +207,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<List.Item
|
<List.Item
|
||||||
title={item.title}
|
title={item.title}
|
||||||
description={PlanningEventManager.getFormattedEventTime(item["date_begin"], item["date_end"])}
|
description={getFormattedEventTime(item["date_begin"], item["date_end"])}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -4,15 +4,15 @@ import * as React from 'react';
|
||||||
import {Alert, Platform, View} from 'react-native';
|
import {Alert, Platform, View} from 'react-native';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import WebSectionList from "../../components/WebSectionList";
|
import WebSectionList from "../../components/WebSectionList";
|
||||||
import NotificationsManager from "../../utils/NotificationsManager";
|
import * as Notifications from "../../utils/Notifications";
|
||||||
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
import AsyncStorageManager from "../../managers/AsyncStorageManager";
|
||||||
import * as Expo from "expo";
|
import * as Expo from "expo";
|
||||||
import {Avatar, Banner, Button, Card, Text, withTheme} from 'react-native-paper';
|
import {Avatar, Banner, Button, Card, Text, withTheme} from 'react-native-paper';
|
||||||
import HeaderButton from "../../components/HeaderButton";
|
import HeaderButton from "../../components/HeaderButton";
|
||||||
import ProxiwashListItem from "../../components/ProxiwashListItem";
|
import ProxiwashListItem from "../../components/ProxiwashListItem";
|
||||||
import ProxiwashConstants from "../../constants/ProxiwashConstants";
|
import ProxiwashConstants from "../../constants/ProxiwashConstants";
|
||||||
import CustomModal from "../../components/CustomModal";
|
import CustomModal from "../../components/CustomModal";
|
||||||
import AprilFoolsManager from "../../utils/AprilFoolsManager";
|
import AprilFoolsManager from "../../managers/AprilFoolsManager";
|
||||||
|
|
||||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
|
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
|
||||||
|
|
||||||
|
@ -118,12 +118,12 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
});
|
});
|
||||||
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
||||||
// Get latest watchlist from server
|
// Get latest watchlist from server
|
||||||
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
|
Notifications.getMachineNotificationWatchlist((fetchedList) => {
|
||||||
this.setState({machinesWatched: fetchedList})
|
this.setState({machinesWatched: fetchedList})
|
||||||
});
|
});
|
||||||
// Get updated watchlist after received notification
|
// Get updated watchlist after received notification
|
||||||
Expo.Notifications.addListener(() => {
|
Expo.Notifications.addListener(() => {
|
||||||
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
|
Notifications.getMachineNotificationWatchlist((fetchedList) => {
|
||||||
this.setState({machinesWatched: fetchedList})
|
this.setState({machinesWatched: fetchedList})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -175,7 +175,7 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
setupNotifications(machineId: string) {
|
setupNotifications(machineId: string) {
|
||||||
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
||||||
if (!this.isMachineWatched(machineId)) {
|
if (!this.isMachineWatched(machineId)) {
|
||||||
NotificationsManager.setupMachineNotification(machineId, true);
|
Notifications.setupMachineNotification(machineId, true);
|
||||||
this.saveNotificationToState(machineId);
|
this.saveNotificationToState(machineId);
|
||||||
} else
|
} else
|
||||||
this.disableNotification(machineId);
|
this.disableNotification(machineId);
|
||||||
|
@ -205,7 +205,7 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
let arrayIndex = data.indexOf(machineId);
|
let arrayIndex = data.indexOf(machineId);
|
||||||
if (arrayIndex !== -1) {
|
if (arrayIndex !== -1) {
|
||||||
NotificationsManager.setupMachineNotification(machineId, false);
|
Notifications.setupMachineNotification(machineId, false);
|
||||||
this.removeNotificationFroState(arrayIndex);
|
this.removeNotificationFroState(arrayIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
import DateManager from "../utils/DateManager";
|
import DateManager from "../managers/DateManager";
|
||||||
import WebSectionList from "../components/WebSectionList";
|
import WebSectionList from "../components/WebSectionList";
|
||||||
import {Card, Text, withTheme} from 'react-native-paper';
|
import {Card, Text, withTheme} from 'react-native-paper';
|
||||||
import AprilFoolsManager from "../utils/AprilFoolsManager";
|
import AprilFoolsManager from "../managers/AprilFoolsManager";
|
||||||
|
|
||||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
|
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {ScrollView} from "react-native";
|
import {ScrollView} from "react-native";
|
||||||
import ThemeManager from '../utils/ThemeManager';
|
import ThemeManager from '../managers/ThemeManager';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import AsyncStorageManager from "../utils/AsyncStorageManager";
|
import AsyncStorageManager from "../managers/AsyncStorageManager";
|
||||||
import NotificationsManager from "../utils/NotificationsManager";
|
import {setMachineReminderNotificationTime} from "../utils/Notifications";
|
||||||
import {Card, List, Switch, ToggleButton} from 'react-native-paper';
|
import {Card, List, Switch, ToggleButton} from 'react-native-paper';
|
||||||
import {Appearance} from "react-native-appearance";
|
import {Appearance} from "react-native-appearance";
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
||||||
let intVal = 0;
|
let intVal = 0;
|
||||||
if (value !== 'never')
|
if (value !== 'never')
|
||||||
intVal = parseInt(value);
|
intVal = parseInt(value);
|
||||||
NotificationsManager.setMachineReminderNotificationTime(intVal);
|
setMachineReminderNotificationTime(intVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import ThemeManager from "../../utils/ThemeManager";
|
import ThemeManager from "../../managers/ThemeManager";
|
||||||
import WebViewScreen from "../../components/WebViewScreen";
|
import WebViewScreen from "../../components/WebViewScreen";
|
||||||
import {Avatar, Banner} from "react-native-paper";
|
import {Avatar, Banner} from "react-native-paper";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import {View} from "react-native";
|
import {View} from "react-native";
|
||||||
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
import AsyncStorageManager from "../../managers/AsyncStorageManager";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigation: Object,
|
navigation: Object,
|
||||||
|
|
125
utils/Notifications.js
Normal file
125
utils/Notifications.js
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as Permissions from 'expo-permissions';
|
||||||
|
import {Notifications} from 'expo';
|
||||||
|
import AsyncStorageManager from "../managers/AsyncStorageManager";
|
||||||
|
import LocaleManager from "../managers/LocaleManager";
|
||||||
|
import passwords from "../passwords";
|
||||||
|
|
||||||
|
const EXPO_TOKEN_SERVER = 'https://etud.insa-toulouse.fr/~amicale_app/expo_notifications/save_token.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async function asking permission to send notifications to the user
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export async function askPermissions() {
|
||||||
|
const {status: existingStatus} = await Permissions.getAsync(Permissions.NOTIFICATIONS);
|
||||||
|
let finalStatus = existingStatus;
|
||||||
|
if (existingStatus !== 'granted') {
|
||||||
|
const {status} = await Permissions.askAsync(Permissions.NOTIFICATIONS);
|
||||||
|
finalStatus = status;
|
||||||
|
}
|
||||||
|
return finalStatus === 'granted';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save expo token to allow sending notifications to this device.
|
||||||
|
* This token is unique for each device and won't change.
|
||||||
|
* It only needs to be fetched once, then it will be saved in storage.
|
||||||
|
*
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function initExpoToken() {
|
||||||
|
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
||||||
|
if (token === '') {
|
||||||
|
try {
|
||||||
|
await askPermissions();
|
||||||
|
let expoToken = await Notifications.getExpoPushTokenAsync();
|
||||||
|
// Save token for instant use later on
|
||||||
|
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.expoToken.key, expoToken);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the machines watched from the server
|
||||||
|
*
|
||||||
|
* @param callback Function to execute with the fetched data
|
||||||
|
*/
|
||||||
|
export function getMachineNotificationWatchlist(callback: Function) {
|
||||||
|
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
||||||
|
if (token !== '') {
|
||||||
|
let data = {
|
||||||
|
function: 'get_machine_watchlist',
|
||||||
|
password: passwords.expoNotifications,
|
||||||
|
token: token,
|
||||||
|
};
|
||||||
|
fetch(EXPO_TOKEN_SERVER, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: new Headers({
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}),
|
||||||
|
body: JSON.stringify(data) // <-- Post parameters
|
||||||
|
}).then((response) => response.json())
|
||||||
|
.then((responseJson) => {
|
||||||
|
callback(responseJson);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the server to enable/disable notifications for the specified machine
|
||||||
|
*
|
||||||
|
* @param machineID The machine ID
|
||||||
|
* @param isEnabled True to enable notifications, false to disable
|
||||||
|
*/
|
||||||
|
export function setupMachineNotification(machineID: string, isEnabled: boolean) {
|
||||||
|
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
||||||
|
if (token !== '') {
|
||||||
|
let data = {
|
||||||
|
function: 'setup_machine_notification',
|
||||||
|
password: passwords.expoNotifications,
|
||||||
|
locale: LocaleManager.getCurrentLocale(),
|
||||||
|
token: token,
|
||||||
|
machine_id: machineID,
|
||||||
|
enabled: isEnabled
|
||||||
|
};
|
||||||
|
fetch(EXPO_TOKEN_SERVER, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: new Headers({
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}),
|
||||||
|
body: JSON.stringify(data) // <-- Post parameters
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the selected reminder time for notifications to the server
|
||||||
|
*
|
||||||
|
* @param time The reminder time to use
|
||||||
|
*/
|
||||||
|
export function setMachineReminderNotificationTime(time: number) {
|
||||||
|
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
||||||
|
if (token !== '') {
|
||||||
|
let data = {
|
||||||
|
function: 'set_machine_reminder',
|
||||||
|
password: passwords.expoNotifications,
|
||||||
|
token: token,
|
||||||
|
time: time,
|
||||||
|
};
|
||||||
|
fetch(EXPO_TOKEN_SERVER, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: new Headers({
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}),
|
||||||
|
body: JSON.stringify(data) // <-- Post parameters
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,131 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import * as Permissions from 'expo-permissions';
|
|
||||||
import {Notifications} from 'expo';
|
|
||||||
import AsyncStorageManager from "./AsyncStorageManager";
|
|
||||||
import LocaleManager from "./LocaleManager";
|
|
||||||
import passwords from "../passwords";
|
|
||||||
|
|
||||||
const EXPO_TOKEN_SERVER = 'https://etud.insa-toulouse.fr/~amicale_app/expo_notifications/save_token.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static class used to manage notifications sent to the user
|
|
||||||
*/
|
|
||||||
export default class NotificationsManager {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async function asking permission to send notifications to the user
|
|
||||||
*
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
static async askPermissions() {
|
|
||||||
const {status: existingStatus} = await Permissions.getAsync(Permissions.NOTIFICATIONS);
|
|
||||||
let finalStatus = existingStatus;
|
|
||||||
if (existingStatus !== 'granted') {
|
|
||||||
const {status} = await Permissions.askAsync(Permissions.NOTIFICATIONS);
|
|
||||||
finalStatus = status;
|
|
||||||
}
|
|
||||||
return finalStatus === 'granted';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save expo token to allow sending notifications to this device.
|
|
||||||
* This token is unique for each device and won't change.
|
|
||||||
* It only needs to be fetched once, then it will be saved in storage.
|
|
||||||
*
|
|
||||||
* @return {Promise<void>}
|
|
||||||
*/
|
|
||||||
static async initExpoToken() {
|
|
||||||
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
|
||||||
if (token === '') {
|
|
||||||
try {
|
|
||||||
await NotificationsManager.askPermissions();
|
|
||||||
let expoToken = await Notifications.getExpoPushTokenAsync();
|
|
||||||
// Save token for instant use later on
|
|
||||||
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.expoToken.key, expoToken);
|
|
||||||
} catch(e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the machines watched from the server
|
|
||||||
*
|
|
||||||
* @param callback Function to execute with the fetched data
|
|
||||||
*/
|
|
||||||
static getMachineNotificationWatchlist(callback: Function) {
|
|
||||||
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
|
||||||
if (token !== '') {
|
|
||||||
let data = {
|
|
||||||
function: 'get_machine_watchlist',
|
|
||||||
password: passwords.expoNotifications,
|
|
||||||
token: token,
|
|
||||||
};
|
|
||||||
fetch(EXPO_TOKEN_SERVER, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: new Headers({
|
|
||||||
Accept: 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}),
|
|
||||||
body: JSON.stringify(data) // <-- Post parameters
|
|
||||||
}).then((response) => response.json())
|
|
||||||
.then((responseJson) => {
|
|
||||||
callback(responseJson);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the server to enable/disable notifications for the specified machine
|
|
||||||
*
|
|
||||||
* @param machineID The machine ID
|
|
||||||
* @param isEnabled True to enable notifications, false to disable
|
|
||||||
*/
|
|
||||||
static setupMachineNotification(machineID: string, isEnabled: boolean) {
|
|
||||||
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
|
||||||
if (token !== '') {
|
|
||||||
let data = {
|
|
||||||
function: 'setup_machine_notification',
|
|
||||||
password: passwords.expoNotifications,
|
|
||||||
locale: LocaleManager.getCurrentLocale(),
|
|
||||||
token: token,
|
|
||||||
machine_id: machineID,
|
|
||||||
enabled: isEnabled
|
|
||||||
};
|
|
||||||
fetch(EXPO_TOKEN_SERVER, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: new Headers({
|
|
||||||
Accept: 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}),
|
|
||||||
body: JSON.stringify(data) // <-- Post parameters
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the selected reminder time for notifications to the server
|
|
||||||
*
|
|
||||||
* @param time The reminder time to use
|
|
||||||
*/
|
|
||||||
static setMachineReminderNotificationTime(time: number) {
|
|
||||||
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
|
||||||
if (token !== '') {
|
|
||||||
let data = {
|
|
||||||
function: 'set_machine_reminder',
|
|
||||||
password: passwords.expoNotifications,
|
|
||||||
token: token,
|
|
||||||
time: time,
|
|
||||||
};
|
|
||||||
fetch(EXPO_TOKEN_SERVER, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: new Headers({
|
|
||||||
Accept: 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}),
|
|
||||||
body: JSON.stringify(data) // <-- Post parameters
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
240
utils/Planning.js
Normal file
240
utils/Planning.js
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
// @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,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given date string is in the format
|
||||||
|
* YYYY-MM-DD HH:MM
|
||||||
|
*
|
||||||
|
* @param dateString The string to check
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export function isEventDateStringFormatValid(dateString: ?string): boolean {
|
||||||
|
return dateString !== undefined
|
||||||
|
&& dateString !== null
|
||||||
|
&& dateRegExp.test(dateString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given date string to a date object.<br>
|
||||||
|
* Accepted format: YYYY-MM-DD HH:MM
|
||||||
|
*
|
||||||
|
* @param dateString The string to convert
|
||||||
|
* @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;
|
||||||
|
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a date object to a string in the format
|
||||||
|
* YYYY-MM-DD HH-MM-SS
|
||||||
|
*
|
||||||
|
* @param date The date object to convert
|
||||||
|
* @return {string} The converted string
|
||||||
|
*/
|
||||||
|
export function dateToString(date: Date): 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 hours = String(date.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
|
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string corresponding to the event start and end times in the following format:
|
||||||
|
*
|
||||||
|
* HH:MM - HH:MM
|
||||||
|
*
|
||||||
|
* If the end date is not specified or is equal to start time, only start time will be shown.
|
||||||
|
*
|
||||||
|
* If the end date is not on the same day, 23:59 will be shown as end time
|
||||||
|
*
|
||||||
|
* @param start Start time in YYYY-MM-DD HH:MM:SS format
|
||||||
|
* @param end End time in YYYY-MM-DD HH:MM:SS format
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given description can be considered empty.
|
||||||
|
* <br>
|
||||||
|
* An empty description is composed only of whitespace, <b>br</b> or <b>p</b> tags
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param description The text to check
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export function isDescriptionEmpty(description: ?string): boolean {
|
||||||
|
if (description !== undefined && description !== null) {
|
||||||
|
return description
|
||||||
|
.split('<p>').join('') // Equivalent to a replace all
|
||||||
|
.split('</p>').join('')
|
||||||
|
.split('<br>').join('').trim() === '';
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an object with an empty array for each key.
|
||||||
|
* Each key is a date string in the format
|
||||||
|
* YYYY-MM-DD
|
||||||
|
*
|
||||||
|
* @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)));
|
||||||
|
if (dateString !== null)
|
||||||
|
daysOfYear[dateString] = []
|
||||||
|
}
|
||||||
|
return daysOfYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an object with an array of eventObject at each key.
|
||||||
|
* Each key is a date string in the format
|
||||||
|
* YYYY-MM-DD.
|
||||||
|
*
|
||||||
|
* If no event is available at the given key, the array will be empty
|
||||||
|
*
|
||||||
|
* @param eventList The list of events to map to the agenda
|
||||||
|
* @param numberOfMonths The number of months to create the agenda for
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
export function generateEventAgenda(eventList: Array<eventObject>, 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)
|
||||||
|
this.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<eventObject>, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,243 +0,0 @@
|
||||||
// @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 default class PlanningEventManager {
|
|
||||||
|
|
||||||
// Regex used to check date string validity
|
|
||||||
static 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
|
|
||||||
*/
|
|
||||||
static getCurrentDateString(): string {
|
|
||||||
return PlanningEventManager.dateToString(new Date(Date.now()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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}
|
|
||||||
*/
|
|
||||||
static isEventBefore(event1Date: string, event2Date: string): boolean {
|
|
||||||
let date1 = PlanningEventManager.stringToDate(event1Date);
|
|
||||||
let date2 = PlanningEventManager.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
|
|
||||||
*/
|
|
||||||
static getDateOnlyString(dateString: string): string | null {
|
|
||||||
if (PlanningEventManager.isEventDateStringFormatValid(dateString))
|
|
||||||
return dateString.split(" ")[0];
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given date string is in the format
|
|
||||||
* YYYY-MM-DD HH:MM
|
|
||||||
*
|
|
||||||
* @param dateString The string to check
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
static isEventDateStringFormatValid(dateString: ?string): boolean {
|
|
||||||
return dateString !== undefined
|
|
||||||
&& dateString !== null
|
|
||||||
&& PlanningEventManager.dateRegExp.test(dateString);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the given date string to a date object.<br>
|
|
||||||
* Accepted format: YYYY-MM-DD HH:MM
|
|
||||||
*
|
|
||||||
* @param dateString The string to convert
|
|
||||||
* @return {Date|null} The date object or null if the given string is invalid
|
|
||||||
*/
|
|
||||||
static stringToDate(dateString: string): Date | null {
|
|
||||||
let date = new Date();
|
|
||||||
if (PlanningEventManager.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;
|
|
||||||
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a date object to a string in the format
|
|
||||||
* YYYY-MM-DD HH-MM-SS
|
|
||||||
*
|
|
||||||
* @param date The date object to convert
|
|
||||||
* @return {string} The converted string
|
|
||||||
*/
|
|
||||||
static dateToString(date: Date): 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 hours = String(date.getHours()).padStart(2, '0');
|
|
||||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
||||||
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string corresponding to the event start and end times in the following format:
|
|
||||||
*
|
|
||||||
* HH:MM - HH:MM
|
|
||||||
*
|
|
||||||
* If the end date is not specified or is equal to start time, only start time will be shown.
|
|
||||||
*
|
|
||||||
* If the end date is not on the same day, 23:59 will be shown as end time
|
|
||||||
*
|
|
||||||
* @param start Start time in YYYY-MM-DD HH:MM:SS format
|
|
||||||
* @param end End time in YYYY-MM-DD HH:MM:SS format
|
|
||||||
* @return {string} Formatted string or "/ - /" on error
|
|
||||||
*/
|
|
||||||
static getFormattedEventTime(start: string, end: string): string {
|
|
||||||
let formattedStr = '/ - /';
|
|
||||||
let startDate = PlanningEventManager.stringToDate(start);
|
|
||||||
let endDate = PlanningEventManager.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');
|
|
||||||
|
|
||||||
return formattedStr
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given description can be considered empty.
|
|
||||||
* <br>
|
|
||||||
* An empty description is composed only of whitespace, <b>br</b> or <b>p</b> tags
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param description The text to check
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
static isDescriptionEmpty(description: ?string): boolean {
|
|
||||||
if (description !== undefined && description !== null) {
|
|
||||||
return description
|
|
||||||
.split('<p>').join('') // Equivalent to a replace all
|
|
||||||
.split('</p>').join('')
|
|
||||||
.split('<br>').join('').trim() === '';
|
|
||||||
} else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an object with an empty array for each key.
|
|
||||||
* Each key is a date string in the format
|
|
||||||
* YYYY-MM-DD
|
|
||||||
*
|
|
||||||
* @param numberOfMonths The number of months to create, starting from the current date
|
|
||||||
* @return {Object}
|
|
||||||
*/
|
|
||||||
static 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 = PlanningEventManager.getDateOnlyString(
|
|
||||||
PlanningEventManager.dateToString(new Date(d)));
|
|
||||||
if (dateString !== null)
|
|
||||||
daysOfYear[dateString] = []
|
|
||||||
}
|
|
||||||
return daysOfYear;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an object with an array of eventObject at each key.
|
|
||||||
* Each key is a date string in the format
|
|
||||||
* YYYY-MM-DD.
|
|
||||||
*
|
|
||||||
* If no event is available at the given key, the array will be empty
|
|
||||||
*
|
|
||||||
* @param eventList The list of events to map to the agenda
|
|
||||||
* @param numberOfMonths The number of months to create the agenda for
|
|
||||||
* @return {Object}
|
|
||||||
*/
|
|
||||||
static generateEventAgenda(eventList: Array<eventObject>, numberOfMonths: number): Object {
|
|
||||||
let agendaItems = PlanningEventManager.generateEmptyCalendar(numberOfMonths);
|
|
||||||
for (let i = 0; i < eventList.length; i++) {
|
|
||||||
const dateString = PlanningEventManager.getDateOnlyString(eventList[i].date_begin);
|
|
||||||
if (dateString !== null) {
|
|
||||||
const eventArray = agendaItems[dateString];
|
|
||||||
if (eventArray !== undefined)
|
|
||||||
this.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
|
|
||||||
*/
|
|
||||||
static pushEventInOrder(eventArray: Array<eventObject>, event: eventObject): Object {
|
|
||||||
if (eventArray.length === 0)
|
|
||||||
eventArray.push(event);
|
|
||||||
else {
|
|
||||||
for (let i = 0; i < eventArray.length; i++) {
|
|
||||||
if (PlanningEventManager.isEventBefore(event.date_begin, eventArray[i].date_begin)) {
|
|
||||||
eventArray.splice(i, 0, event);
|
|
||||||
break;
|
|
||||||
} else if (i === eventArray.length - 1) {
|
|
||||||
eventArray.push(event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
19
utils/WebData.js
Normal file
19
utils/WebData.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data from FETCH_URL and return it.
|
||||||
|
* If no data was found, returns an empty object
|
||||||
|
*
|
||||||
|
* @param url The urls to fetch data from
|
||||||
|
* @return {Promise<Object>}
|
||||||
|
*/
|
||||||
|
export async function readData(url: string) {
|
||||||
|
let fetchedData: Object = {};
|
||||||
|
try {
|
||||||
|
let response = await fetch(url);
|
||||||
|
fetchedData = await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('Could not read FetchedData from server');
|
||||||
|
}
|
||||||
|
return fetchedData;
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class used to get json data from the web
|
|
||||||
*/
|
|
||||||
export default class WebDataManager {
|
|
||||||
|
|
||||||
FETCH_URL: string;
|
|
||||||
lastDataFetched: Object = {};
|
|
||||||
|
|
||||||
|
|
||||||
constructor(url: string) {
|
|
||||||
this.FETCH_URL = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read data from FETCH_URL and return it.
|
|
||||||
* If no data was found, returns an empty object
|
|
||||||
*
|
|
||||||
* @return {Promise<Object>}
|
|
||||||
*/
|
|
||||||
async readData() {
|
|
||||||
let fetchedData: Object = {};
|
|
||||||
try {
|
|
||||||
let response = await fetch(this.FETCH_URL);
|
|
||||||
fetchedData = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error('Could not read FetchedData from server');
|
|
||||||
}
|
|
||||||
this.lastDataFetched = fetchedData;
|
|
||||||
return fetchedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,210 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PlanningEventManager from "../PlanningEventManager";
|
|
||||||
|
|
||||||
test('isDescriptionEmpty', () => {
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty(" ")).toBeTrue();
|
|
||||||
// noinspection CheckTagEmptyBody
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("<p></p>")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("<p> </p>")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("<p><br></p>")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("<p><br></p><p><br></p>")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("<p><br><br><br></p>")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("<p><br>")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty(null)).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty(undefined)).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("coucou")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isDescriptionEmpty("<p>coucou</p>")).toBeFalse();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('isEventDateStringFormatValid', () => {
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("2020-03-21 09:00")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("3214-64-12 01:16")).toBeTrue();
|
|
||||||
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("3214-64-12 01:16:00")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("3214-64-12 1:16")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("3214-f4-12 01:16")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("sqdd 09:00")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("2020-03-21")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("2020-03-21 truc")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("3214-64-12 1:16:65")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("garbage")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid("")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid(undefined)).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventDateStringFormatValid(null)).toBeFalse();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('stringToDate', () => {
|
|
||||||
let testDate = new Date();
|
|
||||||
expect(PlanningEventManager.stringToDate(undefined)).toBeNull();
|
|
||||||
expect(PlanningEventManager.stringToDate("")).toBeNull();
|
|
||||||
expect(PlanningEventManager.stringToDate("garbage")).toBeNull();
|
|
||||||
expect(PlanningEventManager.stringToDate("2020-03-21")).toBeNull();
|
|
||||||
expect(PlanningEventManager.stringToDate("09:00:00")).toBeNull();
|
|
||||||
expect(PlanningEventManager.stringToDate("2020-03-21 09:g0")).toBeNull();
|
|
||||||
expect(PlanningEventManager.stringToDate("2020-03-21 09:g0:")).toBeNull();
|
|
||||||
testDate.setFullYear(2020, 2, 21);
|
|
||||||
testDate.setHours(9, 0, 0, 0);
|
|
||||||
expect(PlanningEventManager.stringToDate("2020-03-21 09:00")).toEqual(testDate);
|
|
||||||
testDate.setFullYear(2020, 0, 31);
|
|
||||||
testDate.setHours(18, 30, 0, 0);
|
|
||||||
expect(PlanningEventManager.stringToDate("2020-01-31 18:30")).toEqual(testDate);
|
|
||||||
testDate.setFullYear(2020, 50, 50);
|
|
||||||
testDate.setHours(65, 65, 0, 0);
|
|
||||||
expect(PlanningEventManager.stringToDate("2020-51-50 65:65")).toEqual(testDate);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getFormattedEventTime', () => {
|
|
||||||
expect(PlanningEventManager.getFormattedEventTime(null, null))
|
|
||||||
.toBe('/ - /');
|
|
||||||
expect(PlanningEventManager.getFormattedEventTime(undefined, undefined))
|
|
||||||
.toBe('/ - /');
|
|
||||||
expect(PlanningEventManager.getFormattedEventTime("20:30", "23:00"))
|
|
||||||
.toBe('/ - /');
|
|
||||||
expect(PlanningEventManager.getFormattedEventTime("2020-03-30", "2020-03-31"))
|
|
||||||
.toBe('/ - /');
|
|
||||||
|
|
||||||
|
|
||||||
expect(PlanningEventManager.getFormattedEventTime("2020-03-21 09:00", "2020-03-21 09:00"))
|
|
||||||
.toBe('09:00');
|
|
||||||
expect(PlanningEventManager.getFormattedEventTime("2020-03-21 09:00", "2020-03-22 17:00"))
|
|
||||||
.toBe('09:00 - 23:59');
|
|
||||||
expect(PlanningEventManager.getFormattedEventTime("2020-03-30 20:30", "2020-03-30 23:00"))
|
|
||||||
.toBe('20:30 - 23:00');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getDateOnlyString', () => {
|
|
||||||
expect(PlanningEventManager.getDateOnlyString("2020-03-21 09:00")).toBe("2020-03-21");
|
|
||||||
expect(PlanningEventManager.getDateOnlyString("2021-12-15 09:00")).toBe("2021-12-15");
|
|
||||||
expect(PlanningEventManager.getDateOnlyString("2021-12-o5 09:00")).toBeNull();
|
|
||||||
expect(PlanningEventManager.getDateOnlyString("2021-12-15 09:")).toBeNull();
|
|
||||||
expect(PlanningEventManager.getDateOnlyString("2021-12-15")).toBeNull();
|
|
||||||
expect(PlanningEventManager.getDateOnlyString("garbage")).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('isEventBefore', () => {
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 09:00", "2020-03-21 10:00")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 10:00", "2020-03-21 10:15")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 10:15", "2021-03-21 10:15")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 10:15", "2020-05-21 10:15")).toBeTrue();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 10:15", "2020-03-30 10:15")).toBeTrue();
|
|
||||||
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 10:00", "2020-03-21 10:00")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 10:00", "2020-03-21 09:00")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-21 10:15", "2020-03-21 10:00")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2021-03-21 10:15", "2020-03-21 10:15")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-05-21 10:15", "2020-03-21 10:15")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"2020-03-30 10:15", "2020-03-21 10:15")).toBeFalse();
|
|
||||||
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
"garbage", "2020-03-21 10:15")).toBeFalse();
|
|
||||||
expect(PlanningEventManager.isEventBefore(
|
|
||||||
undefined, undefined)).toBeFalse();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('dateToString', () => {
|
|
||||||
let testDate = new Date();
|
|
||||||
testDate.setFullYear(2020, 2, 21);
|
|
||||||
testDate.setHours(9, 0, 0, 0);
|
|
||||||
expect(PlanningEventManager.dateToString(testDate)).toBe("2020-03-21 09:00");
|
|
||||||
testDate.setFullYear(2021, 0, 12);
|
|
||||||
testDate.setHours(9, 10, 0, 0);
|
|
||||||
expect(PlanningEventManager.dateToString(testDate)).toBe("2021-01-12 09:10");
|
|
||||||
testDate.setFullYear(2022, 11, 31);
|
|
||||||
testDate.setHours(9, 10, 15, 0);
|
|
||||||
expect(PlanningEventManager.dateToString(testDate)).toBe("2022-12-31 09:10");
|
|
||||||
});
|
|
||||||
|
|
||||||
test('generateEmptyCalendar', () => {
|
|
||||||
jest.spyOn(Date, 'now')
|
|
||||||
.mockImplementation(() =>
|
|
||||||
new Date('2020-01-14T00:00:00.000Z').getTime()
|
|
||||||
);
|
|
||||||
let calendar = PlanningEventManager.generateEmptyCalendar(1);
|
|
||||||
expect(calendar).toHaveProperty("2020-01-14");
|
|
||||||
expect(calendar).toHaveProperty("2020-01-20");
|
|
||||||
expect(calendar).toHaveProperty("2020-02-10");
|
|
||||||
expect(Object.keys(calendar).length).toBe(32);
|
|
||||||
calendar = PlanningEventManager.generateEmptyCalendar(3);
|
|
||||||
expect(calendar).toHaveProperty("2020-01-14");
|
|
||||||
expect(calendar).toHaveProperty("2020-01-20");
|
|
||||||
expect(calendar).toHaveProperty("2020-02-10");
|
|
||||||
expect(calendar).toHaveProperty("2020-02-14");
|
|
||||||
expect(calendar).toHaveProperty("2020-03-20");
|
|
||||||
expect(calendar).toHaveProperty("2020-04-12");
|
|
||||||
expect(Object.keys(calendar).length).toBe(92);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('pushEventInOrder', () => {
|
|
||||||
let eventArray = [];
|
|
||||||
let event1 = {date_begin: "2020-01-14 09:15"};
|
|
||||||
PlanningEventManager.pushEventInOrder(eventArray, event1);
|
|
||||||
expect(eventArray.length).toBe(1);
|
|
||||||
expect(eventArray[0]).toBe(event1);
|
|
||||||
|
|
||||||
let event2 = {date_begin: "2020-01-14 10:15"};
|
|
||||||
PlanningEventManager.pushEventInOrder(eventArray, event2);
|
|
||||||
expect(eventArray.length).toBe(2);
|
|
||||||
expect(eventArray[0]).toBe(event1);
|
|
||||||
expect(eventArray[1]).toBe(event2);
|
|
||||||
|
|
||||||
let event3 = {date_begin: "2020-01-14 10:15", title: "garbage"};
|
|
||||||
PlanningEventManager.pushEventInOrder(eventArray, event3);
|
|
||||||
expect(eventArray.length).toBe(3);
|
|
||||||
expect(eventArray[0]).toBe(event1);
|
|
||||||
expect(eventArray[1]).toBe(event2);
|
|
||||||
expect(eventArray[2]).toBe(event3);
|
|
||||||
|
|
||||||
let event4 = {date_begin: "2020-01-13 09:00"};
|
|
||||||
PlanningEventManager.pushEventInOrder(eventArray, event4);
|
|
||||||
expect(eventArray.length).toBe(4);
|
|
||||||
expect(eventArray[0]).toBe(event4);
|
|
||||||
expect(eventArray[1]).toBe(event1);
|
|
||||||
expect(eventArray[2]).toBe(event2);
|
|
||||||
expect(eventArray[3]).toBe(event3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('generateEventAgenda', () => {
|
|
||||||
jest.spyOn(Date, 'now')
|
|
||||||
.mockImplementation(() =>
|
|
||||||
new Date('2020-01-14T00:00:00.000Z').getTime()
|
|
||||||
);
|
|
||||||
let eventList = [
|
|
||||||
{date_begin: "2020-01-14 09:15"},
|
|
||||||
{date_begin: "2020-02-01 09:15"},
|
|
||||||
{date_begin: "2020-01-15 09:15"},
|
|
||||||
{date_begin: "2020-02-01 09:30"},
|
|
||||||
{date_begin: "2020-02-01 08:30"},
|
|
||||||
];
|
|
||||||
const calendar = PlanningEventManager.generateEventAgenda(eventList, 2);
|
|
||||||
expect(calendar["2020-01-14"].length).toBe(1);
|
|
||||||
expect(calendar["2020-01-14"][0]).toBe(eventList[0]);
|
|
||||||
expect(calendar["2020-01-15"].length).toBe(1);
|
|
||||||
expect(calendar["2020-01-15"][0]).toBe(eventList[2]);
|
|
||||||
expect(calendar["2020-02-01"].length).toBe(3);
|
|
||||||
expect(calendar["2020-02-01"][0]).toBe(eventList[4]);
|
|
||||||
expect(calendar["2020-02-01"][1]).toBe(eventList[1]);
|
|
||||||
expect(calendar["2020-02-01"][2]).toBe(eventList[3]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getCurrentDateString', () => {
|
|
||||||
jest.spyOn(Date, 'now')
|
|
||||||
.mockImplementation(() => {
|
|
||||||
let date = new Date();
|
|
||||||
date.setFullYear(2020, 0, 14);
|
|
||||||
date.setHours(15, 30, 54, 65);
|
|
||||||
return date.getTime();
|
|
||||||
});
|
|
||||||
expect(PlanningEventManager.getCurrentDateString()).toBe('2020-01-14 15:30');
|
|
||||||
});
|
|
Loading…
Reference in a new issue