Created
August 20, 2015 09:54
-
-
Save PhilippKrone/1e759ee26f86d9d4ebf8 to your computer and use it in GitHub Desktop.
Calendar based on react-native-calendar
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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