import { useImperativeHandle, useLayoutEffect, forwardRef, useEffect, useState, type Ref, useRef } from "react"; import { TouchableOpacity, type ViewStyle, View } from "react-native"; import type { IYearSelectorRef, CalendarYear } from "./type"; import type IYearSelectorProps from "./type"; import stylesheet, { useStyles } from "./stylesheet"; import { dateSelect } from "./util"; import { NCoreUIKitLocalize, NCoreUIKitTheme, NCoreUIKitToast } from "../../core/hooks"; import { type Mutable } from "../../types"; import { ChevronRight as ChevronRightIcon, ChevronLeft as ChevronLeftIcon } from "lucide-react-native"; import moment from "moment"; import Text from "../text"; import { webStyle } from "../../utils"; const YEAR_LINES = [ [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ], [ 9, 10, 11 ] ]; const YearSelector = ({ multipleSelectMinimumRequiredDayCount, isShowTodayIndicator = true, viewDate: viewDateProp, multipleSelectDayLimit, setIsSheetContentReady, selectMultipleObject, selectObject, dateRange, maxDate, minDate, variant, date }: IYearSelectorProps, ref: Ref) => { const { radiuses, borders, spaces, colors } = NCoreUIKitTheme.useContext(); const { localize } = NCoreUIKitLocalize.useContext(); const selectDate = dateSelect({ dateRange, variant, date }); const [ viewDate, setViewDate ] = useState(viewDateProp ? viewDateProp : selectDate); const [ years, setYears ] = useState>([]); const allSelectedYears = useRef>([]); const { nextPrevToolChevronButton: nextPrevToolChevronButtonDynamicStyle, nextPrevToolContainer: nextPrevToolContainerDynamicStyle, todayIndicator: todayIndicatorDynamicStyle, day: dayDynamicStyle } = useStyles({ radiuses, borders, colors, spaces }); useEffect(() => { const allYears = getViewYears({ tDate: viewDate }); setYears(allYears); }, [ dateRange, viewDate, date ]); useLayoutEffect(() => { if(years && years.length) setIsSheetContentReady(true); }, [ years ]); useEffect(() => { if(viewDateProp) { setViewDate(viewDateProp); } }, [ viewDateProp ]); useImperativeHandle( ref, () => ({ changeCurrentView: (date: Date) => { setViewDate(date); } }), [] ); const getViewYears = ({ tDate }: { tDate: Date }): Array => { allSelectedYears.current = []; const targetDate = moment(new Date(tDate)); const startOfCalendar = targetDate.clone().subtract(5, "years").startOf("year"); const totalYears = 12; const allYears = Array.from({ length: totalYears }).map((_, index) => { const currentYear = startOfCalendar.clone().add(index, "years"); let isSelected = false; if(variant === "single" && date) { allSelectedYears.current = [ date ]; if(moment(currentYear).isSame(date, "year")) isSelected = true; } else if(variant === "range" && dateRange && dateRange.start) { if(dateRange.end) { allSelectedYears.current = Array.from({ length: moment(dateRange.end).diff(dateRange.start, "years") + 1 }, (_, i) => moment(dateRange.start).clone().add(i, "years").toDate() ); if(moment(currentYear).isBetween(dateRange.start, dateRange.end, "year", "[]")) isSelected = true; } else if(moment(currentYear).isSame(dateRange.start, "year")) { allSelectedYears.current = [ dateRange.start ]; isSelected = true; } } let isDisabled = false; if(minDate && moment(currentYear).isBefore(moment(minDate).startOf("year"))) { isDisabled = true; } if(maxDate && moment(currentYear).isAfter(moment(maxDate).endOf("year"))) { isDisabled = true; } const currentYearNumber = currentYear.year(); return { originalIndex: allSelectedYears.current.findIndex((day) => moment(currentYear).isSame(day, "year")), isToday: currentYear.isSame(moment(), "year"), title: String(currentYearNumber), yearNumber: currentYearNumber, year: currentYearNumber, date: currentYear, isDisabled, isSelected }; }); return allYears; }; const renderDay = ({ yearIndex, yearItem }: { yearItem: CalendarYear; yearIndex: number; }) => { const isLastItemSelected = yearItem.isSelected && yearItem.originalIndex === allSelectedYears.current.length - 1; const isFirstItemSelected = yearItem.isSelected && yearItem.originalIndex === 0; const selectionStyle: Array | null> = [ isFirstItemSelected && allSelectedYears.current.length > 1 ? { borderBottomRightRadius: 0, borderTopRightRadius: 0 } : null, isLastItemSelected && allSelectedYears.current.length > 1 ? { borderBottomLeftRadius: 0, borderTopLeftRadius: 0 } : null ]; let dayTitleColor: keyof NCoreUIKit.TextContentColors = "mid"; if(yearItem.isSelected && !isLastItemSelected && !isFirstItemSelected) { dayTitleColor = "emphasized"; selectionStyle.push({ borderBottomRightRadius: 0, borderBottomLeftRadius: 0, borderTopRightRadius: 0, borderTopLeftRadius: 0 }); } else if(yearItem.isSelected) { dayTitleColor = "onPrimary"; } if(yearItem.isDisabled) { dayTitleColor = "disabled"; } return { if(variant === "single") { const newDate = date as Date; newDate.setFullYear(yearItem.date.toDate().getFullYear()); selectObject(newDate); } else if(variant === "range") { if(!dateRange || !dateRange.start) { selectMultipleObject({ start: new Date(yearItem.date.toDate().setHours(0, 0, 0)), end: undefined }); return; } if(dateRange && moment(dateRange.start).isSame(yearItem.date, "year")) { selectMultipleObject({ start: undefined, end: undefined }); return; } if(dateRange && !dateRange.end) { if(multipleSelectDayLimit && moment(yearItem.date).diff(dateRange.start, "days") >= multipleSelectDayLimit) { NCoreUIKitToast.open({ title: localize("maximum-selection-number-of-days-limit-exceeds") }); return; } if(multipleSelectMinimumRequiredDayCount && moment(yearItem.date).diff(dateRange.start, "days") + 1 < multipleSelectMinimumRequiredDayCount) { NCoreUIKitToast.open({ title: localize("minimum-selection-number-of-days-required-not-provided") }); return; } if(moment(yearItem.date).isBefore(dateRange.start)) { selectMultipleObject({ start: new Date(yearItem.date.toDate().setHours(0, 0, 0)), end: undefined }); } else { selectMultipleObject({ end: new Date(yearItem.date.toDate().setHours(23, 59, 59)), start: dateRange?.start }); } return; } selectMultipleObject({ start: yearItem.date.toDate(), end: undefined }); } }} style={[ stylesheet.day, dayDynamicStyle, yearItem.isSelected ? { backgroundColor: colors.content.container.primary, borderColor: colors.content.container.primary } : null, yearItem.isSelected && !isLastItemSelected && !isFirstItemSelected ? { backgroundColor: colors.content.container.emphasized, borderColor: colors.content.container.emphasized } : null, yearItem.isSelected && (yearItem.isDisabled) ? { opacity: 0.33 } : null, ...selectionStyle ]} > {yearItem.title} { isShowTodayIndicator && yearItem.isToday ? : null } ; }; const renderNextPrevTool = () => { return { const prevViewDate = moment(viewDate).clone().subtract(12, "years"); setViewDate(prevViewDate.toDate()); }} style={[ nextPrevToolChevronButtonDynamicStyle ]} > { years && years.length ? `${moment(years[0]?.date.toDate()).format("YYYY")} - ${moment(years[years.length - 1]?.date.toDate()).format("YYYY")}` : null } { const nextViewDate = moment(viewDate).clone().add(12, "years"); setViewDate(nextViewDate.toDate()); }} style={[ nextPrevToolChevronButtonDynamicStyle ]} > ; }; return {renderNextPrevTool()} {years && years.length ? YEAR_LINES.map((yItem, yIndex) => { const currentYears = yItem.map(yI => years[yI]); return {currentYears.map((yearItem, yearIndex) => { return renderDay({ yearItem: yearItem as CalendarYear, yearIndex }); })} ; }) : null} ; }; export default forwardRef(YearSelector);