react-native-persian-calendar-modal
Version:
Persian Calendar Modal Component for React Native
583 lines (517 loc) • 19.4 kB
JavaScript
/**
* 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;