Skip to content

Instantly share code, notes, and snippets.

@PhilippKrone
Created August 20, 2015 09:54
Show Gist options
  • Save PhilippKrone/1e759ee26f86d9d4ebf8 to your computer and use it in GitHub Desktop.
Save PhilippKrone/1e759ee26f86d9d4ebf8 to your computer and use it in GitHub Desktop.
Calendar based on react-native-calendar
'use strict';
var React = require('react-native');
var PropTypes = require('ReactPropTypes');
var Dimensions = require('Dimensions');
var moment = require('moment');
var Icon = require('react-native-vector-icons/Ionicons');
var config = require('../../config/config.js');
var {
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
TouchableWithoutFeedback,
View
} = React;
// var StyleSheet = require('react-native-debug-stylesheet');
var
MAX_COLUMNS = 7,
MAX_ROWS = 6,
VIEW_INDEX = 0;
var Calendar = React.createClass({
propTypes: {
dayHeadings: PropTypes.array,
onDateSelect: PropTypes.func,
scrollEnabled: PropTypes.bool,
showControls: PropTypes.bool,
prevButtonText: PropTypes.string,
nextButtonText: PropTypes.string,
titleFormat: PropTypes.string,
onSwipeNext: PropTypes.func,
onSwipePrev: PropTypes.func,
onTouchNext: PropTypes.func,
onTouchPrev: PropTypes.func,
startDay: PropTypes.number,
monthHeadings: PropTypes.array,
},
getDefaultProps() {
return {
scrollEnabled: false,
showControls: false,
prevButtonText: 'Prev',
nextButtonText: 'Next',
titleFormat: 'MMMM YYYY',
dayHeadings: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
startDay: 0,
}
},
getInitialState() {
return {
calendarDates: this.getInitialStack(),
currentMonth: moment().format(),
};
},
getInitialStack() {
return ([
moment().format(),
]);
},
renderTopBar(date) {
if(this.props.showControls) {
return (
<View style={styles.calendarControls}>
<TouchableOpacity onPress={this._onPrev}>
<View><Icon
name='chevron-left'
size={24}
color={config.COLOR.TINTCOLOR}
style={styles.backIcon}/></View>
</TouchableOpacity>
<Text style={[styles.textColor, styles.title, styles.textFontFamily]}>
{this.props.monthHeadings[parseInt(moment(this.state.currentMonth).format('M')) - 1]} {moment(this.state.currentMonth).format(this.props.titleFormat)}
</Text>
<TouchableOpacity onPress={this._onNext}>
<View><Icon
name='chevron-right'
size={24}
color={config.COLOR.TINTCOLOR}
style={styles.backIcon}/></View>
</TouchableOpacity>
</View>
)
} else {
return (
<View style={styles.calendarControls}>
<Text style={[styles.textColor, styles.title, styles.textFontFamily]}>{moment(this.state.currentMonth).format(this.props.titleFormat)}</Text>
</View>
)
}
},
renderHeading() {
return (
<View style={styles.calendarHeading}>
{this.props.dayHeadings.map((day) => { return (<Text key={day} style={[styles.textColor, styles.dayHeading, styles.textFontFamily]}>{day}</Text>) })}
</View>
)
},
renderMonthView(date) {
var newDay = moment(date).startOf('month').format(),
today = new Date(),
daysInMonth = moment(newDay).daysInMonth(),
offset = moment(newDay).get('day'),
preFiller = this.props.startDay,
currentDay = 0,
weekRows = [];
var startDate = new Date(this.props.startDate);
var endDate = new Date(this.props.endDate);
var end = false, k, isToday = false, isSelected = false;
for (var i = 0; i < MAX_ROWS; i++) {
var days = [];
for (var j = 0; j < MAX_COLUMNS; j++) {
k = i + '.' + j;
if (preFiller < offset) {
days.push(<TouchableWithoutFeedback key={k}><Text style={[styles.textFontFamily, styles.dayButton]}></Text></TouchableWithoutFeedback>);
} else {
if(!moment(newDay).isSame(date, 'month')) {
end = true;
}
var isToday = (moment().isSame(newDay, 'month') && moment().isSame(newDay, 'day')) ? true : false;
var isEqualAfterStart = ((moment(newDay).diff(startDate, 'days') >= 0) && (moment(newDay).diff(startDate, 'month') >= 0)) ? true : false;
var isEqualBeforeEnd = (((moment(newDay).diff(endDate, 'days') <= 0) && (moment(newDay).diff(endDate, 'month') <= 0)) || (this.props.endDate == null && moment(newDay).diff(startDate, 'days') == 0)) ? true : false;
var isSelected = (isEqualAfterStart && isEqualBeforeEnd) ? true : false;
days.push((
<View key={k} style={[styles.flex1, isSelected && styles.isSelected]}>
<TouchableOpacity
onPress={this._selectDate.bind(this, newDay)}>
<Text style={[styles.textFontFamily, styles.textColor, styles.dayButton, isToday && styles.currentDay, end && styles.nextMonth, isSelected && styles.isSelectedText]}>{moment(newDay).format('D')}</Text>
</TouchableOpacity>
</View>
));
newDay = moment(newDay).add(1, 'day');
}
preFiller++;
} // row
if(days.length > 0 && days.length < 7) {
for (var x = days.length; x < 7; x++) {
days.push(<TouchableWithoutFeedback><Text style={[styles.textFontFamily, styles.dayButton]}></Text></TouchableWithoutFeedback>);
}
weekRows.push(<View key={weekRows.length} style={styles.weekRow}>{days}</View>);
} else {
weekRows.push(<View key={weekRows.length} style={styles.weekRow}>{days}</View>);
}
} // column
return (<View key={moment(newDay).month()} style={styles.calendarContainer}>{weekRows}</View>);
},
_prependMonth() {
var calendarDates = this.state.calendarDates;
calendarDates.unshift(moment(calendarDates[0]).subtract(1, 'month').format());
calendarDates.pop();
this.setState({
calendarDates: calendarDates,
currentMonth: calendarDates[VIEW_INDEX]
});
},
_appendMonth(){
var calendarDates = this.state.calendarDates;
calendarDates.push(moment(calendarDates[calendarDates.length - 1]).add(1, 'month').format());
calendarDates.shift();
this.setState({
calendarDates: calendarDates,
currentMonth: calendarDates[VIEW_INDEX]
});
},
_goToMonth(date){
var calendarDates = this.state.calendarDates;
calendarDates.push(moment(date).format());
calendarDates.shift();
this.setState({
calendarDates: calendarDates,
currentMonth: calendarDates[VIEW_INDEX]
});
},
_selectDate(date) {
if (this.props.endDate == null) {
if (moment(this.props.startDate).isAfter(date, 'day') || moment(this.props.startDate).isSame(date, 'day')) {
this.props.onDateSelect && this.props.onDateSelect(date, null);
} else {
this.props.onDateSelect && this.props.onDateSelect(this.props.startDate, date);
}
} else {
this.props.onDateSelect && this.props.onDateSelect(date, null);
}
},
_onPrev(){
this._prependMonth();
},
_onNext(){
this._appendMonth();
},
render() {
return (
<View style={styles.calendarContainer}>
{this.renderTopBar()}
{this.renderHeading(this.props.titleFormat)}
<View
ref='calendar'>
{this.state.calendarDates.map((date) => { return this.renderMonthView(date) })}
</View>
</View>
)
}
});
// var StyleSheet = require('react-native-debug-stylesheet');
var styles = StyleSheet.create({
flex1: {
flex: 1,
},
calendarContainer: {
flex: 1,
},
calendarControls: {
flexDirection: 'row',
alignItems: 'center',
margin: 10,
},
controlButtonLeft: {
flex: 0.2,
fontSize: 28,
padding: 5,
textAlign: 'left'
},
controlButtonRight: {
flex: 0.2,
fontSize: 28,
padding: 5,
textAlign: 'right'
},
title: {
flex: 0.6,
textAlign: 'center',
fontSize: 16,
},
calendarHeading: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
borderTopWidth: 0.5,
borderBottomWidth: 0.5,
borderColor: config.COLOR.YOLOCI_MIDDLEBLUE,
},
dayHeading: {
padding: 5,
flex: 1,
textAlign: 'center',
fontSize: 16,
justifyContent: 'flex-start',
},
weekRow: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
},
dayButton: {
padding: 1,
flex: 1,
textAlign: 'center',
fontSize: 16,
justifyContent: 'flex-start',
height: 20,
},
currentDay: {
fontWeight: 'bold',
},
isSelected: {
backgroundColor: config.COLOR.YOLOCI_MIDDLEBLUE,
},
isSelectedText: {
color: '#FFFFFF',
},
nextMonth: {
color: '#A0A0A0',
},
textColor: {
color: config.COLOR.TEXTCOLOR,
},
backIcon: {
width: 50,
height: 50,
justifyContent: 'center',
},
textFontFamily: {
fontFamily: 'Asap',
},
});
module.exports = Calendar;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment