import { memo, useCallback, useMemo, useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import { useLatest } from '../../hooks';
import { areDatesOnSameDay, dateToUnix, getEndOfDay, getInitialIndex } from './dateUtils';
import Swiper from './Swiper';
import Month from './Month';
import YearPicker from './YearPicker';
import type {
DatePickerInlineBaseProps,
SingleChange,
CalendarDate,
RangeChange,
MultiChange,
CalendarDates,
} from './types';
import MonthPicker from './MonthPicker';
import { Provider, defaultValue, useDatePickerStore } from './DatePickerContext';
function DatePickerInlineBase(props: DatePickerInlineBaseProps) {
return (
);
}
function DatePickerInlineBaseChild(props: DatePickerInlineBaseProps) {
const {
locale = 'en',
mode = 'single',
onChange,
startYear = 1800,
endYear = 2200,
startDate,
endDate,
date,
disableWeekDays,
dates,
validRange,
dateMode = 'start',
style,
HeaderComponent,
onToggle,
monthStyle,
} = props;
const [pickerType, setStore] = useDatePickerStore(state => state.pickerType);
const scrollMode = mode === 'range' || mode === 'multiple' ? 'vertical' : 'horizontal';
const isHorizontal = scrollMode === 'horizontal';
useEffect(() => {
setStore(() => ({
localDate: date || new Date(),
startDateYear: startYear,
endDateYear: endYear,
}));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// prevent re-rendering all months when something changed we only need the
// latest version of the props and we don't want the useCallback to change
const startDateRef = useLatest(startDate);
const endDateRef = useLatest(endDate);
const onChangeRef = useLatest(onChange);
const datesRef = useLatest(dates);
const onPressDate = useCallback(
(d: Date) => {
if (mode === 'single') {
(onChangeRef.current as SingleChange)({
date: dateMode === 'start' ? d : getEndOfDay(d),
});
} else if (mode === 'range') {
const sd = startDateRef.current;
const ed = endDateRef.current;
let isStart: boolean = true;
if (sd && !ed && dateToUnix(d) >= dateToUnix(sd!)) {
isStart = false;
}
(onChangeRef.current as RangeChange)({
startDate: isStart ? d : sd,
endDate: !isStart ? getEndOfDay(d) : undefined,
});
} else if (mode === 'multiple') {
datesRef.current = datesRef.current || [];
const exists = datesRef.current.some(ed => areDatesOnSameDay(ed, d));
const newDates = exists
? datesRef.current.filter(ed => !areDatesOnSameDay(ed, d))
: [...datesRef.current, d];
newDates.sort((a, b) => a.getTime() - b.getTime());
(onChangeRef.current as MultiChange)({
dates: newDates,
datePressed: d,
change: exists ? 'removed' : 'added',
});
}
onToggle?.();
},
[mode, dateMode, onChangeRef, startDateRef, endDateRef, datesRef, onToggle],
);
const { containerStyle, initialIndex } = useMemo(() => {
return {
containerStyle: [styles.root, style],
initialIndex: getInitialIndex(startDate || date || dates?.[0]),
};
}, [date, dates, startDate, style]);
const renderMonthComponent = useCallback(
(index: number) => {
return (
);
},
[
locale,
mode,
validRange,
date,
dates,
startDate,
endDate,
onPressDate,
scrollMode,
disableWeekDays,
monthStyle,
],
);
const renderCalenderHeader = useCallback(() => {
if (HeaderComponent) {
return (
);
}
return null;
}, [HeaderComponent, scrollMode, disableWeekDays, locale]);
return (
{isHorizontal && pickerType === 'year' && }
{isHorizontal && pickerType === 'month' && }
);
}
const styles = StyleSheet.create({
root: { flex: 1 },
});
const DatePickerInlineComponent = memo(DatePickerInlineBaseChild);
export default memo(DatePickerInlineBase);