react-native-future-date-range-calendar
Version:
React Native calendar to pick future date ranges only
131 lines (130 loc) • 7.58 kB
JavaScript
/* eslint-disable @typescript-eslint/restrict-plus-operands */
import React from 'react';
import { Dimensions, FlatList } from 'react-native';
import { findTwoDatesDifference, initializeCalendarData, pushCalendarDaysStructureForCurrentMonth, pushCalendarDaysStructureForNextMonth, pushCalendarDaysStructureForPreviousMonth, resetCalendarDaysStructureForCurrentMonth, resetCalendarDaysStructureForNextMonth, resetCalendarDaysStructureForPreviousMonth, } from './utils';
import moment from 'moment';
import { DateRangeHandler, disablePreviousDays } from './calendar-helper';
import { CommonState } from './context/common-provider';
import { CalendarRenderer } from './calendar-renderer';
export const FutureDateRangeCalendarRenderer = React.memo((props) => {
const [disableDays, setDisableDays] = React.useState([]);
const { selectedDate, dateSelected } = CommonState();
const flatListRef = React.useRef(null);
const [currentIndex, setCurrentIndex] = React.useState(0);
const renderMonthsLimit = props?.totalMonthsRenderLimit ?? 12;
const cardWidth = props?.width ?? Dimensions.get("screen").width;
const { calendarType = 'type1', horizontal = true } = props;
const handlePrev = () => {
if (currentIndex > 0) {
const nextIndex = currentIndex - 1;
setCurrentIndex(nextIndex);
flatListRef.current.scrollToIndex({ index: nextIndex });
}
};
const handleNext = () => {
if (currentIndex < renderMonthsLimit) {
const nextIndex = currentIndex + 1;
setCurrentIndex(nextIndex);
flatListRef.current.scrollToIndex({ index: nextIndex });
}
};
const handleScroll = (event) => {
const index = Math.round(event.nativeEvent.contentOffset.x / cardWidth);
setCurrentIndex(index);
if (props?.onSwipe) {
props?.onSwipe(index);
}
};
const monthsToScroll = React.useMemo(() => {
return new Array(1).fill(0);
}, []);
const { currentYear, currentMonth, currentDate, currentMonthDate, _currentYear, _currentMonth, calendarDaysList, monthLimit } = initializeCalendarData();
let count = 0;
const renderCalendar = ({ index }) => {
const month = moment([_currentYear, _currentMonth])
.add(index, "months")
.month();
let year = moment([_currentYear, _currentMonth]).year();
if (index > 0 && month === 0) {
if (count < 1) {
count += 1;
}
}
if (index > monthLimit) {
year = moment([_currentYear + count, _currentMonth]).year();
}
const firstDayOfTheMonth = moment([_currentYear, _currentMonth])
.add(index, "months")
.startOf("month")
.day();
const lastDateOfTheMonth = moment([_currentYear, _currentMonth])
.add(index, "months")
.endOf("month")
.date();
const lastDateOfTheLastMonth = moment([_currentYear, _currentMonth])
.add(index, "months")
.subtract(1, "months")
.endOf("month")
.date();
const lastDayOfTheMonth = moment([_currentYear, _currentMonth])
.add(index, "months")
.endOf("month")
.day();
resetCalendarDaysStructureForPreviousMonth(calendarDaysList);
resetCalendarDaysStructureForCurrentMonth(calendarDaysList);
resetCalendarDaysStructureForNextMonth(calendarDaysList);
for (let i = firstDayOfTheMonth; i > 0; i--) {
const data = {
date: lastDateOfTheLastMonth - i + 1,
month: month + 1,
year,
};
pushCalendarDaysStructureForPreviousMonth(calendarDaysList, data);
}
const daysDiff = findTwoDatesDifference(currentDate, currentMonthDate);
for (let i = 1; i <= lastDateOfTheMonth; i++) {
const data = {
date: i,
month: month + 1,
year,
firstDayOfTheMonth,
lastDateOfTheMonth,
completeDate: moment({ year, month, day: i }).format('YYYY-MM-DD'),
type: i <= daysDiff && month + 1 === currentMonth && year === currentYear
? 'disable'
: 'enable',
};
pushCalendarDaysStructureForCurrentMonth(calendarDaysList, data);
}
for (let i = lastDayOfTheMonth; i < 6; i++) {
const data = {
date: i - lastDayOfTheMonth + 1,
month: month + 1,
year,
};
pushCalendarDaysStructureForNextMonth(calendarDaysList, data);
}
return (React.createElement(CalendarRenderer, { width: props?.width, horizontal: horizontal, calendarType: calendarType, renderPreviousIcon: props?.renderPreviousIcon, renderNextIcon: props?.renderNextIcon, disableHeaderYearAppearance: props?.disableHeaderYearAppearance, monthTextCustomStyle: props?.monthTextCustomStyle, weekDaysCustomStyle: props?.weekDaysCustomStyle, weekDayCustomStyle: props?.weekDayCustomStyle, dayCustomStyle: props?.dayCustomStyle, disabledDaysCustomStyle: props?.disabledDaysCustomStyle, disabledDaysCustomTextStyle: props?.disabledDaysCustomTextStyle, activeOpacity: props?.activeOpacity, nonRangeDaysCustomStyle: props?.nonRangeDaysCustomStyle, nonRangeDaysCustomTextStyle: props?.nonRangeDaysCustomTextStyle, rangeDaysBackgroundColor: props?.rangeDaysBackgroundColor, startAndEndDateBackgroundColor: props?.startAndEndDateBackgroundColor, startAndEndDateTextColor: props?.startAndEndDateTextColor, rangeDaysTextColor: props?.rangeDaysTextColor, months: props?.months, weekDays: props?.weekDays, totalMonthsRenderLimit: props?.totalMonthsRenderLimit, days: calendarDaysList, month: month, year: year, handleNext: handleNext, handlePrev: handlePrev }));
};
React.useEffect(() => {
// markedDates()
if (selectedDate === '') {
setDisableDays(disablePreviousDays(currentMonthDate, currentDate, renderMonthsLimit, _currentMonth, _currentYear, currentMonth).listOfDisabledDates);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedDate, dateSelected]);
return (React.createElement(React.Fragment, null,
React.createElement(DateRangeHandler, { disablePreviousDateSelection: props?.disablePreviousDateSelection, onDateSelect: props?.onDateSelect }),
horizontal ?
React.createElement(FlatList, { ref: flatListRef, onScroll: handleScroll, scrollEventThrottle: 16, horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, snapToInterval: cardWidth, decelerationRate: "fast" // Optional: makes swipe faster and snappier
, bounces: false, overScrollMode: 'never', showsVerticalScrollIndicator: false, data: monthsToScroll, keyExtractor: (item, index) => index.toString(), renderItem: renderCalendar, onEndReached: () => {
if (monthsToScroll?.length <= renderMonthsLimit) {
monthsToScroll.push(0);
}
} })
: React.createElement(FlatList, { showsVerticalScrollIndicator: false, data: monthsToScroll, keyExtractor: (item, index) => index.toString(), renderItem: renderCalendar, onEndReached: () => {
if (monthsToScroll?.length <= renderMonthsLimit) {
monthsToScroll.push(0);
}
} })));
});