application-amicale/screens/PlanningScreen.js

339 lines
13 KiB
JavaScript
Raw Normal View History

// @flow
import * as React from 'react';
import {BackHandler, Image} from 'react-native';
import {H3, Text, View} from 'native-base';
2019-06-25 22:20:24 +02:00
import i18n from "i18n-js";
2019-08-05 16:08:39 +02:00
import ThemeManager from "../utils/ThemeManager";
2019-08-24 19:17:21 +02:00
import {Linking} from "expo";
import BaseContainer from "../components/BaseContainer";
2019-11-14 15:23:25 +01:00
import {Agenda, LocaleConfig} from 'react-native-calendars';
2019-09-15 15:12:26 +02:00
import Touchable from 'react-native-platform-touchable';
import WebDataManager from "../utils/WebDataManager";
import PlanningEventManager from '../utils/PlanningEventManager';
2019-09-15 15:12:26 +02:00
LocaleConfig.locales['fr'] = {
2019-11-14 15:23:25 +01:00
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'
};
2019-06-25 22:20:24 +02:00
type Props = {
navigation: Object,
}
2019-09-15 15:12:26 +02:00
type State = {
refreshing: boolean,
agendaItems: Object,
calendarShowing: boolean,
2019-09-15 15:12:26 +02:00
};
const FETCH_URL = "https://amicale-insat.fr/event/json/list";
const AGENDA_MONTH_SPAN = 6;
2019-08-05 16:08:39 +02:00
/**
* Opens a link in the device's browser
* @param link The link to open
*/
function openWebLink(link) {
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
}
2019-06-29 15:43:57 +02:00
/**
* Class defining the app's planning screen
*/
2019-09-15 15:12:26 +02:00
export default class PlanningScreen extends React.Component<Props, State> {
2019-11-14 15:23:25 +01:00
agendaRef: Agenda;
2019-09-15 15:12:26 +02:00
webDataManager: WebDataManager;
lastRefresh: Date;
minTimeBetweenRefresh = 60;
2019-11-14 15:23:25 +01:00
didFocusSubscription: Function;
willBlurSubscription: Function;
2020-02-11 01:05:24 +01:00
2020-01-31 16:51:43 +01:00
state = {
refreshing: false,
agendaItems: {},
calendarShowing: false,
};
2019-09-15 15:12:26 +02:00
constructor(props: any) {
super(props);
this.webDataManager = new WebDataManager(FETCH_URL);
2019-11-14 15:23:25 +01:00
this.didFocusSubscription = props.navigation.addListener(
'didFocus',
2020-01-31 16:51:43 +01:00
() =>
BackHandler.addEventListener(
'hardwareBackPress',
this.onBackButtonPressAndroid
)
);
if (i18n.currentLocale().startsWith("fr")) {
LocaleConfig.defaultLocale = 'fr';
}
2020-02-11 01:05:24 +01:00
// Create references for functions required in the render function
this._onRefresh = this._onRefresh.bind(this);
this.onCalendarToggled = this.onCalendarToggled.bind(this);
this.getRenderItem = this.getRenderItem.bind(this);
this.getRenderEmptyDate = this.getRenderEmptyDate.bind(this);
this.setAgendaRef = this.setAgendaRef.bind(this);
this.onCalendarToggled = this.onCalendarToggled.bind(this);
this.onCalendarToggled = this.onCalendarToggled.bind(this);
this.onBackButtonPressAndroid = this.onBackButtonPressAndroid.bind(this);
}
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
return nextState.refreshing === false && this.state.refreshing === true ||
nextState.agendaItems !== this.state.agendaItems ||
nextState.calendarShowing !== this.state.calendarShowing;
2019-09-15 15:12:26 +02:00
}
componentDidMount() {
this._onRefresh();
2019-11-14 15:23:25 +01:00
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
2020-01-31 16:51:43 +01:00
() =>
BackHandler.removeEventListener(
'hardwareBackPress',
this.onBackButtonPressAndroid
)
);
}
2020-02-11 01:05:24 +01:00
onBackButtonPressAndroid() {
if (this.state.calendarShowing) {
2019-11-14 15:23:25 +01:00
this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
return true;
} else {
return false;
}
};
componentWillUnmount() {
2019-11-14 15:23:25 +01:00
this.didFocusSubscription && this.didFocusSubscription.remove();
this.willBlurSubscription && this.willBlurSubscription.remove();
2019-09-15 15:12:26 +02:00
}
getCurrentDate() {
let today = new Date();
return this.getFormattedDate(today);
}
getFormattedDate(date: Date) {
let dd = String(date.getDate()).padStart(2, '0');
let mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
let yyyy = date.getFullYear();
return yyyy + '-' + mm + '-' + dd;
}
generateEmptyCalendar() {
let end = new Date(new Date().setMonth(new Date().getMonth() + AGENDA_MONTH_SPAN + 1));
let daysOfYear = {};
for (let d = new Date(2019, 8, 1); d <= end; d.setDate(d.getDate() + 1)) {
daysOfYear[this.getFormattedDate(new Date(d))] = []
}
return daysOfYear;
}
getRenderItem(item: Object) {
return (
<Touchable
style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
borderRadius: 10,
marginRight: 10,
marginTop: 17,
}}
2020-02-11 01:05:24 +01:00
onPress={() => this.props.navigation.navigate('PlanningDisplayScreen', {data: item})}>
2019-09-15 15:12:26 +02:00
<View style={{
padding: 10,
flex: 1,
flexDirection: 'row'
}}>
<View style={{
width: item.logo !== null ? '70%' : '100%',
}}>
2019-09-15 15:12:26 +02:00
<Text style={{
color: ThemeManager.getCurrentThemeVariables().listNoteColor,
marginTop: 5,
marginBottom: 10
}}>
{PlanningEventManager.getFormattedTime(item)}
2019-09-15 15:12:26 +02:00
</Text>
<H3 style={{marginBottom: 10}}>{item.title}</H3>
</View>
<View style={{
width: item.logo !== null ? '30%' : 0,
2019-09-15 15:12:26 +02:00
height: 80
}}>
{item.logo !== null ?
<Image source={{uri: item.logo}}
style={{
flex: 1,
resizeMode: "contain"
}}/>
: <View/>}
</View>
2019-08-05 16:08:39 +02:00
</View>
2019-09-15 15:12:26 +02:00
</Touchable>
);
}
getRenderEmptyDate() {
return (
<View style={{
padding: 10,
flex: 1,
}}>
<View style={{
width: '100%',
height: 1,
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaEmptyLine,
marginTop: 'auto',
marginBottom: 'auto',
}}/>
</View>
);
}
rowHasChanged(r1: Object, r2: Object) {
if (r1 !== undefined && r2 !== undefined)
return r1.title !== r2.title;
else return !(r1 === undefined && r2 === undefined);
}
/**
* Refresh data and show a toast if any error occurred
* @private
*/
_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});
this.webDataManager.readData()
.then((fetchedData) => {
this.setState({
refreshing: false,
});
this.generateEventAgenda(fetchedData);
this.lastRefresh = new Date();
})
.catch((err) => {
this.setState({
refreshing: false,
});
console.log(err);
2019-09-15 15:12:26 +02:00
});
}
2019-09-15 15:12:26 +02:00
};
generateEventAgenda(eventList: Array<Object>) {
let agendaItems = this.generateEmptyCalendar();
for (let i = 0; i < eventList.length; i++) {
if (agendaItems[PlanningEventManager.getEventStartDate(eventList[i])] !== undefined) {
this.pushEventInOrder(agendaItems, eventList[i], PlanningEventManager.getEventStartDate(eventList[i]));
}
2019-09-15 15:12:26 +02:00
}
this.setState({agendaItems: agendaItems})
}
pushEventInOrder(agendaItems: Object, event: Object, startDate: string) {
if (agendaItems[startDate].length === 0)
agendaItems[startDate].push(event);
else {
for (let i = 0; i < agendaItems[startDate].length; i++) {
if (PlanningEventManager.isEventBefore(event, agendaItems[startDate][i])) {
agendaItems[startDate].splice(i, 0, event);
break;
} else if (i === agendaItems[startDate].length - 1) {
agendaItems[startDate].push(event);
break;
}
}
}
}
2020-02-11 01:05:24 +01:00
setAgendaRef(ref) {
this.agendaRef = ref;
}
onCalendarToggled(calendarOpened) {
this.setState({calendarShowing: calendarOpened});
}
currentDate = this.getCurrentDate();
2019-09-15 15:12:26 +02:00
render() {
2020-02-11 01:05:24 +01:00
// console.log("rendering PlanningScreen");
2019-09-15 15:12:26 +02:00
return (
2020-02-11 01:05:24 +01:00
<BaseContainer navigation={this.props.navigation} headerTitle={i18n.t('screens.planning')}>
2019-09-15 15:12:26 +02:00
<Agenda
// the list of items that have to be displayed in agenda. If you want to render item as empty date
// the value of date key kas to be an empty array []. If there exists no value for date key it is
// considered that the date in question is not yet loaded
items={this.state.agendaItems}
// initially selected day
2020-02-11 01:05:24 +01:00
selected={this.currentDate}
2019-09-15 15:12:26 +02:00
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
2020-02-11 01:05:24 +01:00
minDate={this.currentDate}
2019-09-15 15:12:26 +02:00
// Max amount of months allowed to scroll to the past. Default = 50
pastScrollRange={1}
// Max amount of months allowed to scroll to the future. Default = 50
futureScrollRange={AGENDA_MONTH_SPAN}
// If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
2020-02-11 01:05:24 +01:00
onRefresh={this._onRefresh}
// callback that fires when the calendar is opened or closed
2020-02-11 01:05:24 +01:00
onCalendarToggled={this.onCalendarToggled}
2019-09-15 15:12:26 +02:00
// Set this true while waiting for new data from a refresh
refreshing={this.state.refreshing}
2020-02-11 01:05:24 +01:00
renderItem={this.getRenderItem}
renderEmptyDate={this.getRenderEmptyDate}
rowHasChanged={this.rowHasChanged}
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay={1}
// ref to this agenda in order to handle back button event
2020-02-11 01:05:24 +01:00
ref={this.setAgendaRef}
2019-09-15 15:12:26 +02:00
// agenda theme
theme={{
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor,
calendarBackground: ThemeManager.getCurrentThemeVariables().containerBgColor,
textSectionTitleColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
selectedDayBackgroundColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
selectedDayTextColor: '#ffffff',
todayTextColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
dayTextColor: ThemeManager.getCurrentThemeVariables().textColor,
textDisabledColor: ThemeManager.getCurrentThemeVariables().textDisabledColor,
dotColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
indicatorColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
agendaDayNumColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
agendaTodayColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
agendaKnobColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
}}
/>
</BaseContainer>
2019-06-25 22:20:24 +02:00
);
}
}