123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- // @flow
-
- import * as React from 'react';
- import {Content, H1, H2, H3, Text, Button} from 'native-base';
- import i18n from "i18n-js";
- import {View, Image} from "react-native";
- import ThemeManager from "../utils/ThemeManager";
- import {Linking} from "expo";
- import BaseContainer from "../components/BaseContainer";
- import {Agenda} from 'react-native-calendars';
- import HTML from 'react-native-render-html';
- import Touchable from 'react-native-platform-touchable';
- import Modalize from 'react-native-modalize';
- import WebDataManager from "../utils/WebDataManager";
- import CustomMaterialIcon from "../components/CustomMaterialIcon";
-
-
- type Props = {
- navigation: Object,
- }
-
- type State = {
- modalCurrentDisplayItem: Object,
- refreshing: boolean,
- agendaItems: Object,
- };
-
- const FETCH_URL = "https://amicale-insat.fr/event/json/list";
-
- const AGENDA_MONTH_SPAN = 6;
-
- /**
- * 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));
- }
-
- /**
- * Class defining the app's planning screen
- */
- export default class PlanningScreen extends React.Component<Props, State> {
-
- modalRef: { current: null | Modalize };
- webDataManager: WebDataManager;
-
- lastRefresh: Date;
- minTimeBetweenRefresh = 60;
-
- constructor(props: any) {
- super(props);
- this.modalRef = React.createRef();
- this.webDataManager = new WebDataManager(FETCH_URL);
- }
-
- componentDidMount() {
- this._onRefresh();
- }
-
- state = {
- modalCurrentDisplayItem: {},
- refreshing: false,
- agendaItems: {},
- };
-
- 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;
- }
-
- getModalHeader() {
- return (
- <View style={{marginBottom: 0}}>
- <Button
- onPress={() => this.modalRef.current.close()}
- style={{
- marginTop: 50,
- marginLeft: 'auto',
- }}
- transparent>
- <CustomMaterialIcon icon={'close'}/>
- </Button>
- </View>
- );
- }
-
- getModalContent() {
- return (
- <View style={{
- flex: 1,
- padding: 20
- }}>
- <H1>
- {this.state.modalCurrentDisplayItem.title}
- </H1>
- <H3 style={{
- marginTop: 10,
- color: ThemeManager.getCurrentThemeVariables().listNoteColor
- }}>
- {this.getFormattedTime(this.state.modalCurrentDisplayItem)}
- </H3>
- <Content>
- {this.state.modalCurrentDisplayItem.logo !== null ?
- <View style={{width: '100%', height: 200, marginTop: 20, marginBottom: 20}}>
- <Image style={{flex: 1, resizeMode: "contain"}}
- source={{uri: this.state.modalCurrentDisplayItem.logo}}/>
- </View>
- : <View/>}
-
- {this.state.modalCurrentDisplayItem.description !== null ?
- // Surround description with div to allow text styling if the description is not html
- <HTML html={"<div>" + this.state.modalCurrentDisplayItem.description + "</div>"}
- tagsStyles={{
- p: {
- color: ThemeManager.getCurrentThemeVariables().textColor,
- fontSize: ThemeManager.getCurrentThemeVariables().fontSizeBase
- },
- div: {color: ThemeManager.getCurrentThemeVariables().textColor}
- }}
- onLinkPress={(event, link) => openWebLink(link)}/>
- : <View/>}
- </Content>
- </View>
- );
- }
-
- showItemDetails(item: Object) {
- this.setState({
- modalCurrentDisplayItem: item,
- });
- if (this.modalRef.current) {
- this.modalRef.current.open();
- }
- }
-
- getRenderItem(item: Object) {
- return (
- <Touchable
- style={{
- backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
- borderRadius: 10,
- marginRight: 10,
- marginTop: 17,
- }}
- onPress={() => this.showItemDetails(item)}>
- <View style={{
- padding: 10,
- flex: 1,
- flexDirection: 'row'
- }}>
- <View style={{width: '70%'}}>
- <Text style={{
- color: ThemeManager.getCurrentThemeVariables().listNoteColor,
- marginTop: 5,
- marginBottom: 10
- }}>
- {this.getFormattedTime(item)}
- </Text>
- <H3 style={{marginBottom: 10}}>{item.title}</H3>
- </View>
- <View style={{
- width: '30%',
- height: 80
- }}>
- {item.logo !== null ?
- <Image source={{uri: item.logo}}
- style={{
- flex: 1,
- resizeMode: "contain"
- }}/>
- : <View/>}
- </View>
- </View>
- </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);
- });
- }
- };
-
- generateEventAgenda(eventList: Array<Object>) {
- let agendaItems = this.generateEmptyCalendar();
- for (let i = 0; i < eventList.length; i++) {
- if (agendaItems[this.getEventStartDate(eventList[i])] !== undefined) {
- this.pushEventInOrder(agendaItems, eventList[i], this.getEventStartDate(eventList[i]));
- }
- }
- 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 (this.isEventBefore(event, agendaItems[startDate][i])) {
- agendaItems[startDate].splice(i, 0, event);
- break;
- } else if (i === agendaItems[startDate].length - 1) {
- agendaItems[startDate].push(event);
- break;
- }
- }
- }
- }
-
- isEventBefore(event1: Object, event2: Object) {
- let date1 = new Date();
- let date2 = new Date();
- let timeArray = this.getEventStartTime(event1).split(":");
- date1.setHours(parseInt(timeArray[0]), parseInt(timeArray[1]));
- timeArray = this.getEventStartTime(event2).split(":");
- date2.setHours(parseInt(timeArray[0]), parseInt(timeArray[1]));
- return date1 < date2;
- }
-
- getEventStartDate(event: Object) {
- return event.date_begin.split(" ")[0];
- }
-
- getEventStartTime(event: Object) {
- if (event !== undefined && Object.keys(event).length > 0 && event.date_begin !== null)
- return this.formatTime(event.date_begin.split(" ")[1]);
- else
- return "";
- }
-
- getEventEndTime(event: Object) {
- if (event !== undefined && Object.keys(event).length > 0 && event.date_end !== null)
- return this.formatTime(event.date_end.split(" ")[1]);
- else
- return "";
- }
-
- getFormattedTime(event: Object) {
- if (this.getEventEndTime(event) !== "")
- return this.getEventStartTime(event) + " - " + this.getEventEndTime(event)
- else
- return this.getEventStartTime(event);
- }
-
- formatTime(time: string) {
- let array = time.split(':');
- return array[0] + ':' + array[1];
- }
-
- onModalClosed() {
- this.setState({
- modalCurrentDisplayItem: {},
- });
- }
-
- render() {
- const nav = this.props.navigation;
- return (
- <BaseContainer navigation={nav} headerTitle={i18n.t('screens.planning')}>
- <Modalize ref={this.modalRef}
- modalStyle={{
- backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
- }}
- // adjustToContentHeight // Breaks when displaying full screen, half, then full again
- HeaderComponent={() => this.getModalHeader()}
- onClosed={() => this.onModalClosed()}>
- {this.getModalContent()}
- </Modalize>
- <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
- selected={this.getCurrentDate()}
- // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
- minDate={this.getCurrentDate()}
- // 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.
- onRefresh={() => this._onRefresh()}
- // Set this true while waiting for new data from a refresh
- refreshing={this.state.refreshing}
- renderItem={(item) => this.getRenderItem(item)}
- renderEmptyDate={() => this.getRenderEmptyDate()}
- rowHasChanged={() => this.rowHasChanged()}
- // 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,
- // Fix for days hiding behind knob
- 'stylesheet.calendar.header': {
- week: {
- marginTop: 0,
- flexDirection: 'row',
- justifyContent: 'space-between'
- }
- }
- }}
- />
- </BaseContainer>
- );
- }
- }
|