react-native-datetimepicker-pro
Version:
A customizable calendar, time & month picker for React Native (including Persian Jalaali calendar & locale)
245 lines (218 loc) • 7.57 kB
JavaScript
import {useRef, useState} from 'react';
import {Animated, Easing, I18nManager} from 'react-native';
import moment from 'moment-jalaali';
const m = moment();
const jalaaliConfigs = {
dayNames: ['شنبه', 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'],
dayNamesShort: ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'],
monthNames: [
'فروردین',
'اردیبهشت',
'خرداد',
'تیر',
'مرداد',
'شهریور',
'مهر',
'آبان',
'آذر',
'دی',
'بهمن',
'اسفند',
],
selectedFormat: 'jYYYY/jMM/jDD',
dateFormat: 'jYYYY/jMM/jDD',
monthYearFormat: 'jYYYY jMM',
timeFormat: 'HH:mm ',
hour: 'ساعت',
minute: 'دقیقه',
timeSelect: 'انتخاب',
timeClose: 'بستن',
};
const gregorianConfigs = {
dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
dayNamesShort: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
monthNames: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
selectedFormat: 'YYYY/MM/DD',
dateFormat: 'YYYY/MM/DD',
monthYearFormat: 'YYYY MM',
timeFormat: 'HH:mm',
hour: 'Hour',
minute: 'Minute',
timeSelect: 'Select',
timeClose: 'Close',
};
class utils {
constructor({minimumDate, maximumDate, isGregorian, mode, reverse, configs}) {
this.data = {
minimumDate,
maximumDate,
isGregorian,
reverse: reverse === 'unset' ? !isGregorian : reverse,
};
this.config = isGregorian ? gregorianConfigs : jalaaliConfigs;
this.config = {...this.config, ...configs};
if (mode === 'time' || mode === 'datepicker') {
this.config.selectedFormat = this.config.dateFormat + ' ' + this.config.timeFormat;
}
}
get flexDirection() {
return {flexDirection: this.data.reverse ? (I18nManager.isRTL ? 'row' : 'row-reverse') : 'row'};
}
getFormated = (date, formatName = 'selectedFormat') => date.format(this.config[formatName]);
getFormatedDate = (date = new Date(), format = 'YYYY/MM/DD') => moment(date).format(format);
getFormatedDateTime = (date = new Date(), format = 'YYYY/MM/DD HH:mm') => moment(date).format(format);
getTime = (time) => this.getDate(time).format(this.config.timeFormat);
getToday = () => this.getFormated(m, 'dateFormat');
getMonthName = (month) => this.config.monthNames[month];
toPersianNumber = (value) => {
const {isGregorian} = this.data;
return isGregorian
? this.toEnglish(String(value))
: String(value).replace(/[0-9]/g, (w) =>
String.fromCharCode(w.charCodeAt(0) + '۰'.charCodeAt(0) - 48),
);
};
toEnglish = (value) => {
const charCodeZero = '۰'.charCodeAt(0);
return value.replace(/[۰-۹]/g, (w) => w.charCodeAt(0) - charCodeZero);
};
getDate = (time) => moment(time, this.config.selectedFormat);
getMonthYearText = (time) => {
const {isGregorian} = this.data;
const date = this.getDate(time);
const year = this.toPersianNumber(isGregorian ? date.year() : date.jYear());
const month = this.getMonthName(isGregorian ? date.month() : date.jMonth());
return `${month} ${year}`;
};
checkMonthDisabled = (time) => {
const {minimumDate, maximumDate, isGregorian} = this.data;
const date = this.getDate(time);
let disabled = false;
if (minimumDate) {
const lastDayInMonth = isGregorian ? date.date(29) : date.jDate(29);
disabled = lastDayInMonth < this.getDate(minimumDate);
}
if (maximumDate && !disabled) {
const firstDayInMonth = isGregorian ? date.date(1) : date.jDate(1);
disabled = firstDayInMonth > this.getDate(maximumDate);
}
return disabled;
};
checkArrowMonthDisabled = (time, next) => {
const {isGregorian} = this.data;
const date = this.getDate(time);
return this.checkMonthDisabled(
this.getFormated(date.add(next ? -1 : 1, isGregorian ? 'month' : 'jMonth')),
);
};
checkYearDisabled = (year, next) => {
const {minimumDate, maximumDate, isGregorian} = this.data;
const y = isGregorian
? this.getDate(next ? maximumDate : minimumDate).year()
: this.getDate(next ? maximumDate : minimumDate).jYear();
return next ? year >= y : year <= y;
};
checkSelectMonthDisabled = (time, month) => {
const {isGregorian} = this.data;
const date = this.getDate(time);
const dateWithNewMonth = isGregorian ? date.month(month) : date.jMonth(month);
return this.checkMonthDisabled(this.getFormated(dateWithNewMonth));
};
validYear = (time, year) => {
const {minimumDate, maximumDate, isGregorian} = this.data;
const date = isGregorian ? this.getDate(time).year(year) : this.getDate(time).jYear(year);
let validDate = this.getFormated(date);
if (minimumDate && date < this.getDate(minimumDate)) {
validDate = minimumDate;
}
if (maximumDate && date > this.getDate(maximumDate)) {
validDate = maximumDate;
}
return validDate;
};
getMonthDays = (time) => {
const {minimumDate, maximumDate, isGregorian} = this.data;
let date = this.getDate(time);
const currentMonthDays = isGregorian
? date.daysInMonth()
: moment.jDaysInMonth(date.jYear(), date.jMonth());
const firstDay = isGregorian ? date.date(1) : date.jDate(1);
const dayOfMonth = (firstDay.day() + Number(!isGregorian)) % 7;
return [
...new Array(dayOfMonth),
...[...new Array(currentMonthDays)].map((i, n) => {
const thisDay = isGregorian ? date.date(n + 1) : date.jDate(n + 1);
let disabled = false;
if (minimumDate) {
disabled = thisDay < this.getDate(minimumDate);
}
if (maximumDate && !disabled) {
disabled = thisDay > this.getDate(maximumDate);
}
date = this.getDate(time);
return {
dayString: this.toPersianNumber(n + 1),
day: n + 1,
date: this.getFormated(isGregorian ? date.date(n + 1) : date.jDate(n + 1)),
disabled,
};
}),
];
};
useMonthAnimation = (activeDate, distance, onEnd = () => null) => {
const [lastDate, setLastDate] = useState(activeDate);
const [changeWay, setChangeWay] = useState(null);
const monthYearAnimation = useRef(new Animated.Value(0)).current;
const changeMonthAnimation = (type) => {
setChangeWay(type);
setLastDate(activeDate);
monthYearAnimation.setValue(1);
Animated.timing(monthYearAnimation, {
toValue: 0,
duration: 300,
useNativeDriver: true,
easing: Easing.bezier(0.33, 0.66, 0.54, 1),
}).start(onEnd);
};
const shownAnimation = {
opacity: monthYearAnimation.interpolate({
inputRange: [0, 1],
outputRange: [1, 1],
}),
transform: [
{
translateX: monthYearAnimation.interpolate({
inputRange: [0, 1],
outputRange: [0, changeWay === 'NEXT' ? -distance : distance],
}),
},
],
};
const hiddenAnimation = {
opacity: monthYearAnimation,
transform: [
{
translateX: monthYearAnimation.interpolate({
inputRange: [0, 1],
outputRange: [changeWay === 'NEXT' ? distance : -distance, 0],
}),
},
],
};
return [{lastDate, shownAnimation, hiddenAnimation}, changeMonthAnimation];
};
}
export {utils};