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);