UNPKG

react-native-calendar-strip-slide-navigation

Version:

This is a fork of react-native-calendar-strip updated Slide navigation for selected dates

307 lines (274 loc) 11.8 kB
/** * Created by bogdanbegovic on 8/20/16. */ import React, {Component} from 'react'; import { Text, View, Image, Animated, Easing, TouchableOpacity } from 'react-native'; import CalendarDay from './CalendarDay'; import moment from 'moment'; import styles from './Calendar.style.js'; //Just a shallow array of 7 elements const arr = []; for (let i = 0; i < 7; i++) { arr.push(i); } /* * Class CalendarStrip that is representing the whole calendar strip and contains CalendarDay elements * */ export default class CalendarStrip extends Component { static propTypes = { style: React.PropTypes.any, calendarColor: React.PropTypes.string, highlightColor: React.PropTypes.string, borderHighlightColor: React.PropTypes.string, startingDate: React.PropTypes.any, selectedDate: React.PropTypes.any, onDateSelected: React.PropTypes.func, onWeekChanged: React.PropTypes.func, useIsoWeekday: React.PropTypes.bool, iconLeft: React.PropTypes.any, iconRight: React.PropTypes.any, iconStyle: React.PropTypes.any, iconLeftStyle: React.PropTypes.any, iconRightStyle: React.PropTypes.any, iconContainer: React.PropTypes.any, calendarHeaderStyle: React.PropTypes.any, calendarHeaderFormat: React.PropTypes.string, calendarAnimation: React.PropTypes.object, selection: React.PropTypes.string, selectionAnimation: React.PropTypes.object, dateNameStyle: React.PropTypes.any, dateNumberStyle: React.PropTypes.any, weekendDateNameStyle: React.PropTypes.any, weekendDateNumberStyle: React.PropTypes.any, highlightDateNameStyle: React.PropTypes.any, highlightDateNumberStyle: React.PropTypes.any, styleWeekend: React.PropTypes.bool, locale: React.PropTypes.object }; static defaultProps = { startingDate: moment(), useIsoWeekday: true, iconLeft: require('./img/left-arrow-black.png'), iconRight: require('./img/right-arrow-black.png'), calendarHeaderFormat: 'MMMM YYYY' }; constructor(props) { super(props); if(props.locale) { if(props.locale.name && props.locale.config) { moment.locale(props.locale.name, props.locale.config); } else { throw new Error('Locale prop is not in the correct format. \b Locale has to be in form of object, with params NAME and CONFIG!'); } } const startingDate = this.setLocale(moment(this.props.startingDate)); const selectedDate = this.setLocale(moment(this.props.selectedDate)); this.state = { startingDate, selectedDate }; this.resetAnimation(); this.componentDidMount = this.componentDidMount.bind(this); this.componentWillUpdate = this.componentWillUpdate.bind(this); this.getDatesForWeek = this.getDatesForWeek.bind(this); this.getPreviousWeek = this.getPreviousWeek.bind(this); this.getNextWeek = this.getNextWeek.bind(this); this.onDateSelected = this.onDateSelected.bind(this); this.isDateSelected = this.isDateSelected.bind(this); this.formatCalendarHeader = this.formatCalendarHeader.bind(this); this.animate = this.animate.bind(this); this.resetAnimation = this.resetAnimation.bind(this); } //Animate showing of CalendarDay elements componentDidMount() { this.animate(); } //Receiving props and set selected date componentWillReceiveProps(nextProps) { if (nextProps.selectedDate !== this.props.selectedDate) { const selectedDate = this.setLocale(moment(nextProps.selectedDate)); this.setState({ selectedDate }); } } //Only animate CalendarDays if the selectedDate is the same //Prevents animation on pressing on a date componentWillUpdate(nextProps, nextState) { if (nextState.selectedDate === this.state.selectedDate) { this.resetAnimation(); this.animate(); } } //Function that checks if the locale is passed to the component and sets it to the passed moment instance setLocale(momentInstance) { if (this.props.locale) { momentInstance.locale(this.props.locale.name); } return momentInstance; } //Set startingDate to the previous week getPreviousWeek() { const previousWeekStartDate = this.state.startingDate.subtract(1, 'w'); this.setState({startingDate: previousWeekStartDate}); if (this.props.onWeekChanged) { this.props.onWeekChanged(previousWeekStartDate.clone().startOf(this.props.useIsoWeekday ? 'isoweek' : 'week')); } const selectedDate = this.setLocale(moment(this.state.startingDate)); this.setState({ selectedDate }); } //Set startingDate to the next week getNextWeek() { const nextWeekStartDate = this.state.startingDate.add(1, 'w'); this.setState({startingDate: nextWeekStartDate}); if (this.props.onWeekChanged) { this.props.onWeekChanged(nextWeekStartDate.clone().startOf(this.props.useIsoWeekday ? 'isoweek' : 'week')); } const selectedDate = this.setLocale(moment(this.state.startingDate)); this.setState({ selectedDate }); } //Get dates for the week based on the startingDate //Using isoWeekday so that it will start from Monday getDatesForWeek() { const me = this; let dates = []; let startDate = moment(this.state.startingDate); arr.forEach((item, index) => { let date; if (me.props.useIsoWeekday) { date = me.setLocale(moment(startDate.isoWeekday(index + 1))); } else { date = me.setLocale(moment(startDate).add(index, 'days')); } dates.push(date); }); return dates; } //Handling press on date/selecting date onDateSelected(date) { this.setState({selectedDate: date}); if (this.props.onDateSelected) { this.props.onDateSelected(date); } } //Function to check if provided date is the same as selected one, hence date is selected //using isSame moment query with 'day' param so that it check years, months and day isDateSelected(date) { return date.isSame(this.state.selectedDate, 'day'); } //Function for reseting animations resetAnimation() { this.animatedValue = []; arr.forEach((value) => { this.animatedValue[value] = new Animated.Value(0); }); } //Function to animate showing the CalendarDay elements. //Possible cases for animations are sequence and parallel animate() { if (this.props.calendarAnimation) { let animations = arr.map((item) => { return Animated.timing( this.animatedValue[item], { toValue: 1, duration: this.props.calendarAnimation.duration, easing: Easing.linear } ); }); if (this.props.calendarAnimation.type.toLowerCase() === 'sequence') { Animated.sequence(animations).start(); } else { if (this.props.calendarAnimation.type.toLowerCase() === 'parallel') { Animated.parallel(animations).start(); } else { throw new Error('CalendarStrip Error! Type of animation is incorrect!'); } } } } //Function that formats the calendar header //It also formats the month section if the week is in between months formatCalendarHeader() { let firstDay = this.getDatesForWeek()[0]; let lastDay = this.getDatesForWeek()[this.getDatesForWeek().length - 1]; let monthFormatting = ''; //Parsing the month part of the user defined formating if ((this.props.calendarHeaderFormat.match(/Mo/g) || []).length > 0) { monthFormatting = 'Mo'; } else { if ((this.props.calendarHeaderFormat.match(/M/g) || []).length > 0) { for (let i = (this.props.calendarHeaderFormat.match(/M/g) || []).length; i > 0; i--) { monthFormatting += 'M'; } } } if (firstDay.month() === lastDay.month()) { return firstDay.format(this.props.calendarHeaderFormat); } if (firstDay.year() !== lastDay.year()) { return `${firstDay.format(this.props.calendarHeaderFormat)} / ${lastDay.format(this.props.calendarHeaderFormat)}`; } return `${monthFormatting.length > 1 ? firstDay.format(monthFormatting) : ''} ${monthFormatting.length > 1 ? '/' : ''} ${lastDay.format(this.props.calendarHeaderFormat)}`; } render() { let opacityAnim = 1; let datesRender = this.getDatesForWeek().map((date, index) => { if (this.props.calendarAnimation) { opacityAnim = this.animatedValue[index]; } return ( <Animated.View key={date} style={{opacity: opacityAnim, flex: 1}}> <CalendarDay date={date} key={date} selected={this.isDateSelected(date)} onDateSelected={this.onDateSelected} calendarColor={this.props.calendarColor} highlightColor={this.props.highlightColor} dateNameStyle={this.props.dateNameStyle} dateNumberStyle={this.props.dateNumberStyle} weekendDateNameStyle={this.props.weekendDateNameStyle} weekendDateNumberStyle={this.props.weekendDateNumberStyle} highlightDateNameStyle={this.props.highlightDateNameStyle} highlightDateNumberStyle={this.props.highlightDateNumberStyle} styleWeekend={this.props.styleWeekend} selection={this.props.selection} selectionAnimation={this.props.selectionAnimation} borderHighlightColor={this.props.borderHighlightColor} /> </Animated.View> ); }); return ( <View style={[styles.calendarContainer, {backgroundColor: this.props.calendarColor}, this.props.style]}> <Text style={[styles.calendarHeader, this.props.calendarHeaderStyle]}>{this.formatCalendarHeader()}</Text> <View style={styles.datesStrip}> <TouchableOpacity style={[styles.iconContainer, this.props.iconContainer]} onPress={this.getPreviousWeek}> <Image style={[styles.icon, this.props.iconStyle, this.props.iconLeftStyle]} source={this.props.iconLeft}/> </TouchableOpacity> <View style={styles.calendarDates}> {datesRender} </View> <TouchableOpacity style={[styles.iconContainer, this.props.iconContainer]} onPress={this.getNextWeek}> <Image style={[styles.icon, this.props.iconStyle, this.props.iconRightStyle]} source={this.props.iconRight}/> </TouchableOpacity> </View> </View> ); } }