"use client" import { parseDate } from "@internationalized/date" import { useEffect } from "react" import { useController, useFormContext, useWatch } from "react-hook-form" import { useIntl } from "react-intl" import { useMediaQuery } from "usehooks-ts" import { dt } from "@scandic-hotels/common/dt" import { Select } from "@scandic-hotels/design-system/Select" import useLang from "@/hooks/useLang" import { getLocalizedMonthName } from "@/utils/dateFormatting" import { rangeArray } from "@/utils/rangeArray" import ErrorMessage from "../ErrorMessage" import { DateName, type DateProps } from "./date" import styles from "./date.module.css" export default function DateSelect({ name, registerOptions = {} }: DateProps) { const intl = useIntl() const lang = useLang() const isDesktop = useMediaQuery("(min-width: 768px)", { initializeWithValue: false, }) const { control, setValue, formState, watch } = useFormContext() const { field, fieldState } = useController({ control, name, rules: registerOptions, }) const currentDateValue: string = useWatch({ name }) const year = watch(DateName.year) const month = watch(DateName.month) const day = watch(DateName.day) const minAgeDate = dt().subtract(18, "year").toDate() // age 18 const minAgeYear = minAgeDate.getFullYear() const minAgeMonth = year === minAgeYear ? minAgeDate.getMonth() + 1 : null const minAgeDay = Number(year) === minAgeYear && Number(month) === minAgeMonth ? minAgeDate.getDate() : null const months = rangeArray(1, minAgeMonth ?? 12).map((month) => ({ value: month, label: getLocalizedMonthName(month, lang), })) const years = rangeArray(1900, minAgeYear) .reverse() .map((year) => ({ value: year, label: year.toString() })) // Calculate available days based on selected year and month const daysInMonth = getDaysInMonth( year ? Number(year) : null, month ? Number(month) - 1 : null ) const days = rangeArray(1, minAgeDay ?? daysInMonth).map((day) => ({ value: day, label: `${day}`, })) useEffect(() => { if (formState.isSubmitting) return if (month && day) { const maxDays = getDaysInMonth( year ? Number(year) : null, Number(month) - 1 ) const adjustedDay = Number(day) > maxDays ? maxDays : Number(day) if (adjustedDay !== Number(day)) { setValue(DateName.day, adjustedDay) } } const newDate = dt() .year(Number(year)) .month(Number(month) - 1) .date(Number(day)) if (newDate.isValid()) { setValue(name, newDate.format("YYYY-MM-DD"), { shouldDirty: true, shouldTouch: true, shouldValidate: true, }) } }, [year, month, day, setValue, name, formState.isSubmitting]) let dateValue = null try { /** * parseDate throws when its not a valid * date, but we can't check isNan since * we recieve the date as "1999-01-01" */ dateValue = dt(currentDateValue).isValid() ? parseDate(currentDateValue) : null } catch (error) { console.warn("Known error for parse date in DateSelect: ", error) } useEffect(() => { if (formState.isSubmitting) return if (!(day && month && year) && dateValue) { setValue(DateName.day, Number(dateValue.day)) setValue(DateName.month, Number(dateValue.month)) setValue(DateName.year, Number(dateValue.year)) } }, [setValue, formState.isSubmitting, dateValue, day, month, year]) return ( <>
setValue(DateName.month, Number(key))} isRequired enableFiltering={isDesktop} isInvalid={fieldState.invalid} onBlur={field.onBlur} defaultSelectedKey={dateValue?.month} data-testid={DateName.month} />