UNPKG

react-native-persian-calendar-modal

Version:

Persian Calendar Modal Component for React Native

583 lines (517 loc) 19.4 kB
/** * Persian Calendar Picker Component * * Copyright 2016 Reza (github.com/rghorbani) * Licensed under the terms of the MIT license. See LICENSE file in the project root for terms. */ 'use strict'; const React = require('react'); const jMoment = require('moment-jalaali'); const {Dimensions, View, ScrollView, Text} = require('react-native'); const DaysGridView = require('./days-grid'); const HeaderControls = require('./header-controls'); const Weekdays = require('./weekdays'); // const Swiper = require('./swiper'); const Utils = require('./utils'); const makeStyles = require('./style'); import SwiperFlatList from 'react-native-swiper-flatlist'; class PersianCalendarPicker extends React.Component { offset = 0; static defaultProps = { isRTL: false, initialDate: jMoment.utc(), scaleFactor: 375, enableSwipe: true, onDateChange: () => console.log('onDateChange() not provided'), enableDateChange: true, }; constructor(props) { super(props); this.state = { currentMonth: null, currentYear: null, months: [1, 0, -1, -2], currentIndex: 1, monthIndex: 1, mainIndex: 1, selectedStartDate: props.selectedStartDate || null, selectedEndDate: props.selectedEndDate || null, styles: {}, ...this.updateScaledStyles(props), ...this.updateMonthYear(props.initialDate), }; this.updateScaledStyles = this.updateScaledStyles.bind(this); this.updateMonthYear = this.updateMonthYear.bind(this); this.handleOnPressPrevious = this.handleOnPressPrevious.bind(this); this.handleOnPressNext = this.handleOnPressNext.bind(this); this.handleOnPressDay = this.handleOnPressDay.bind(this); this.resetSelections = this.resetSelections.bind(this); } componentDidUpdate(prevProps, prevState) { let newStyles = {}; let doStateUpdate = false; if ( prevProps.width !== this.props.width || prevProps.height !== this.props.height ) { newStyles = this.updateScaledStyles(this.props); doStateUpdate = true; } let selectedDateRanges = {}; if ( (this.props.selectedStartDate && !jMoment .utc(prevState.selectedStartDate) .isSame(this.props.selectedStartDate, 'day')) || (this.props.selectedEndDate && !jMoment .utc(prevState.selectedEndDate) .isSame(this.props.selectedEndDate, 'day')) ) { const {selectedStartDate = null, selectedEndDate = null} = this.props; selectedDateRanges = { selectedStartDate, selectedEndDate, }; doStateUpdate = true; } if (doStateUpdate) { this.setState({...newStyles, ...newMonthYear, ...selectedDateRanges}); } } goToToday = () => { let newMonthYear = {}; newMonthYear = { currentMonth: parseInt(jMoment.utc().jMonth()), currentYear: parseInt(jMoment.utc().jYear()), }; this.setState({...newMonthYear}); }; updateScaledStyles(props) { const { isRTL, scaleFactor, selectedDayColor, selectedDayTextColor, todayBackgroundColor, width, height, } = props; // The styles in makeStyles are intially scaled to this width const containerWidth = width ? width : Dimensions.get('window').width; const containerHeight = height ? height : Dimensions.get('window').height; const initialScale = Math.min(containerWidth, containerHeight) / scaleFactor; return { styles: makeStyles({ isRTL, initialScale, backgroundColor: selectedDayColor, textColor: selectedDayTextColor, todayBackgroundColor, }), }; } updateMonthYear(initialDate = this.props.initialDate) { return { currentMonth: parseInt(jMoment.utc(initialDate).jMonth()), currentYear: parseInt(jMoment.utc(initialDate).jYear()), }; } handleOnPressDay(day, item) { const { currentYear, currentMonth, selectedStartDate, selectedEndDate, monthNum } = this.state; const {allowRangeSelection, onDateChange, enableDateChange} = this.props; if (!enableDateChange) { return; } let mon, year; if (item) { if (monthNum !== undefined) { // if (item > 0) { // mon = monthNum - 1; // } else mon = monthNum; } else mon = currentMonth; let num = currentMonth + item; if (num < 0) { //last year num += 1; num = Math.abs(num); num = Math.floor(num / 12); num += 1; //tedad salhayi ke bayad az sale jari kam shavad year = currentYear - num; } else { num = Math.floor(num / 12); year = currentYear + num; } } else { year = currentYear; mon = currentMonth; } const date = jMoment .utc() .jYear(year) .jMonth(mon) .jDate(day); if ( allowRangeSelection && selectedStartDate && date.isSameOrAfter(selectedStartDate) && !selectedEndDate ) { this.setState({ selectedEndDate: date, }); // propagate to parent date has changed onDateChange(date, Utils.END_DATE); } else { this.setState({ selectedStartDate: date, selectedEndDate: null, }); // propagate to parent date has changed onDateChange(date, Utils.START_DATE); } } handleOnPressNext() { let {monthIndex} = this.state; monthIndex += 1; let monthNum; if (this.state.monthNum === undefined) { monthNum = this.state.currentMonth - 1; } else monthNum = this.state.monthNum - 1; if (monthNum === -1) { monthNum = 11; } if (this.state.months[monthIndex + 1] === undefined) { //preMonth not exist and must create pre month let tempArr = this.state.months.slice(); let value = this.state.months[monthIndex] - 1; tempArr.push(value); this.setState({ months: tempArr, monthNum: monthNum, monthIndex: monthIndex, mainIndex: this.state.mainIndex + 1 }, () => { this.refs.swiper.scrollToIndex({index: this.state.mainIndex}); }); } else { this.setState({ monthNum: monthNum, monthIndex: monthIndex, mainIndex: this.state.mainIndex + 1 }, () => { this.refs.swiper.scrollToIndex({index: this.state.mainIndex}); }); } } handleOnPressPrevious() { let {monthIndex} = this.state; if (monthIndex !== 0) { monthIndex -= 1; } let monthNum; if (this.state.monthNum === undefined) { monthNum = this.state.currentMonth + 1; } else monthNum = this.state.monthNum + 1; if (monthNum === 12) { monthNum = 0; } let tempMainIndex=this.state.mainIndex-1; if(tempMainIndex===-1){ tempMainIndex=0 } if(this.state.mainIndex===1) { //preMonth not exist and must create pre month let tempArr = this.state.months.slice(); let value = this.state.months[monthIndex] + 1; tempArr.unshift(value); this.setState({ months: tempArr, monthNum: monthNum, monthIndex: monthIndex, mainIndex: 1 }, () => { this.refs.swiper.scrollToIndex({index: this.state.mainIndex}) }); } else { this.setState({ monthNum: monthNum, monthIndex: monthIndex, mainIndex: tempMainIndex },()=>{ this.refs.swiper.scrollToIndex({index: this.state.mainIndex}); }); } } resetSelections() { this.setState({ selectedStartDate: null, selectedEndDate: null, }); } componentDidMount() { // console.log('ref',this.refs.myScroll) // this.myScroll.scrollTo({ animated: false, index: 1 }) } updateMonths = ({index}) => { let current = this.state.currentIndex; if (current <= index) { //pre Month let monthNum = this.state.months[index]; monthNum = monthNum + this.state.currentMonth; if (monthNum < 0) { if (1 < Math.abs(monthNum) < 11) { monthNum = monthNum + 12; } else { monthNum = monthNum % 12; } } if (this.state.months[index + 1] === undefined) { //preMonth not exist and must create pre month let tempArr = this.state.months.slice(); let value = this.state.months[index] - 1; tempArr.push(value); value = this.state.months[index] - 2; tempArr.push(value); this.setState({ months: tempArr, monthNum: monthNum, monthIndex: index }); } else { // let tempArr = this.state.months.slice(); // console.log('temArr1',tempArr); // console.log('index',index,this.state.months[index]); // let value = this.state.months[index] - 2; // console.log('value',value); // tempArr.push(value); // console.log('tem',tempArr); this.setState({ // months: tempArr, monthNum: monthNum, monthIndex: index }); } } else if (current > index) { let monthNum = this.state.months[index] + 1; monthNum = monthNum + this.state.currentMonth; if (monthNum > 11) { monthNum = monthNum % 12; } if (this.state.months[index - 1] === undefined) { //preMonth not exist and must create pre month let tempArr = this.state.months.slice(); let value = this.state.months[index] + 1; tempArr.unshift(value); this.setState({ months: tempArr, monthNum: monthNum, monthIndex: index }); } else { this.setState({ monthNum: monthNum, monthIndex: index }); } } }; month = ({item}) => { const { currentMonth, currentYear, selectedStartDate, selectedEndDate, styles, } = this.state; // console.log('in month',currentMonth,currentYear); let num = currentMonth + item; let year; if (num < 0) { //last year num += 1; num = Math.abs(num); num = Math.floor(num / 12); num += 1; //tedad salhayi ke bayad az sale jari kam shavad year = currentYear - num; } else { num = Math.floor(num / 12); year = currentYear + num; } const { allowRangeSelection, startFromMonday, initialDate, minDate, maxDate, weekdays, months, previousTitle, nextTitle, textStyle, todayTextStyle, selectedDayStyle, selectedRangeStartStyle, selectedRangeStyle, selectedRangeEndStyle, disabledDates, minRangeDuration, maxRangeDuration, swipeConfig, customDatesStyles, enableDateChange, } = this.props; let disabledDatesTime = []; // Convert input date into timestamp if (disabledDates && Array.isArray(disabledDates)) { disabledDates.map(date => { let thisDate = jMoment.utc(date); // thisDate.set({'hour': 0, 'minute': 0, 'second': 0, 'millisecond': 0}); disabledDatesTime.push(thisDate.valueOf()); }); } let minRangeDurationTime = []; if (allowRangeSelection && minRangeDuration) { if (Array.isArray(minRangeDuration)) { minRangeDuration.map(minRangeDuration => { let thisDate = jMoment.utc(minRangeDuration.date); // thisDate.set({'hour': 0, 'minute': 0, 'second': 0, 'millisecond': 0}); minRangeDurationTime.push({ date: thisDate.valueOf(), minDuration: minRangeDuration.minDuration, }); }); } else { minRangeDurationTime = minRangeDuration; } } let maxRangeDurationTime = []; if (allowRangeSelection && maxRangeDuration) { if (Array.isArray(maxRangeDuration)) { maxRangeDuration.map(maxRangeDuration => { let thisDate = jMoment.utc(maxRangeDuration.date); // thisDate.set({'hour': 0, 'minute': 0, 'second': 0, 'millisecond': 0}); maxRangeDurationTime.push({ date: thisDate.valueOf(), maxDuration: maxRangeDuration.maxDuration, }); }); } else { maxRangeDurationTime = maxRangeDuration; } } // console.log('curentyear in renderitem', currentYear, currentMonth + item, item); return ( <View style={styles.calendar}> <HeaderControls styles={styles} currentMonth={currentMonth + item} currentYear={year} initialDate={jMoment.utc(initialDate)} onPressPrevious={this.handleOnPressPrevious} onPressNext={this.handleOnPressNext} months={months} previousTitle={previousTitle} nextTitle={nextTitle} textStyle={textStyle} changeCalendar={this.props.changeCalendar} /> <Weekdays styles={styles} startFromMonday={startFromMonday} weekdays={weekdays} textStyle={textStyle} /> <DaysGridView enableDateChange={enableDateChange} month={currentMonth + item} year={currentYear} item={item} styles={styles} onPressDay={this.handleOnPressDay} disabledDates={disabledDatesTime} minRangeDuration={minRangeDurationTime} maxRangeDuration={maxRangeDurationTime} startFromMonday={startFromMonday} allowRangeSelection={allowRangeSelection} selectedStartDate={ selectedStartDate && jMoment.utc(selectedStartDate) } selectedEndDate={selectedEndDate && jMoment.utc(selectedEndDate)} minDate={minDate && jMoment.utc(minDate)} maxDate={maxDate && jMoment.utc(maxDate)} textStyle={textStyle} todayTextStyle={todayTextStyle} selectedDayStyle={selectedDayStyle} selectedRangeStartStyle={selectedRangeStartStyle} selectedRangeStyle={selectedRangeStyle} selectedRangeEndStyle={selectedRangeEndStyle} customDatesStyles={customDatesStyles} /> </View> ) }; render() { const {styles} = this.state; const { allowRangeSelection, disabledDates, minRangeDuration, maxRangeDuration, } = this.props; let disabledDatesTime = []; // Convert input date into timestamp if (disabledDates && Array.isArray(disabledDates)) { disabledDates.map(date => { let thisDate = jMoment.utc(date); // thisDate.set({'hour': 0, 'minute': 0, 'second': 0, 'millisecond': 0}); disabledDatesTime.push(thisDate.valueOf()); }); } let minRangeDurationTime = []; if (allowRangeSelection && minRangeDuration) { if (Array.isArray(minRangeDuration)) { minRangeDuration.map(minRangeDuration => { let thisDate = jMoment.utc(minRangeDuration.date); // thisDate.set({'hour': 0, 'minute': 0, 'second': 0, 'millisecond': 0}); minRangeDurationTime.push({ date: thisDate.valueOf(), minDuration: minRangeDuration.minDuration, }); }); } else { minRangeDurationTime = minRangeDuration; } } let maxRangeDurationTime = []; if (allowRangeSelection && maxRangeDuration) { if (Array.isArray(maxRangeDuration)) { maxRangeDuration.map(maxRangeDuration => { let thisDate = jMoment.utc(maxRangeDuration.date); // thisDate.set({'hour': 0, 'minute': 0, 'second': 0, 'millisecond': 0}); maxRangeDurationTime.push({ date: thisDate.valueOf(), maxDuration: maxRangeDuration.maxDuration, }); }); } else { maxRangeDurationTime = maxRangeDuration; } } return ( <View style={[styles.calendar]}> <SwiperFlatList index={this.state.currentIndex} data={this.state.months} renderItem={this.month} onMomentumScrollEnd={(index, v, b) => this.updateMonths(index)} ref='swiper' extraData={this.state} /> </View> ); } } module.exports = PersianCalendarPicker;