"use client" import { useCallback, useEffect, useRef, useState } from "react" import { useFormContext, useWatch } from "react-hook-form" import { useIntl } from "react-intl" import { dt } from "@/lib/dt" import Body from "@/components/TempDesignSystem/Text/Body" import useLang from "@/hooks/useLang" import DatePickerRangeDesktop from "./Range/Desktop" import DatePickerRangeMobile from "./Range/Mobile" import styles from "./date-picker.module.css" import type { DateRange } from "react-day-picker" import type { DatePickerFormProps } from "@/types/components/datepicker" export default function DatePickerForm({ name = "date" }: DatePickerFormProps) { const lang = useLang() const intl = useIntl() const [isOpen, setIsOpen] = useState(false) const selectedDate = useWatch({ name }) const { register, setValue } = useFormContext() const ref = useRef(null) const close = useCallback(() => { if (!selectedDate.toDate) { setValue(name, { fromDate: selectedDate.fromDate, toDate: dt(selectedDate.fromDate).add(1, "day").format("YYYY-MM-DD"), }) } setIsOpen(false) }, [name, setValue, selectedDate]) function showOnFocus() { setIsOpen(true) } function handleSelectDate( _nextRange: DateRange | undefined, selectedDay: Date ) { const now = dt() const dateClicked = dt(selectedDay) const dateClickedFormatted = dateClicked.format("YYYY-MM-DD") /* check if selected date is not before todays date, which happens when "Enter" key is pressed in any other input field of the form */ if (!dateClicked.isBefore(now, "day")) { // Handle form value updates based on the requirements if (selectedDate.fromDate && selectedDate.toDate) { // Both dates were previously selected, starting fresh with new date setValue(name, { fromDate: dateClickedFormatted, toDate: undefined, }) } else if (selectedDate.fromDate && !selectedDate.toDate) { // If the selected day is the same as the first date, we don't need to update the form value if (dateClicked.isSame(selectedDate.fromDate)) { return } // We're selecting the second date if (dateClicked.isBefore(selectedDate.fromDate)) { // If second selected date is before first date, swap them setValue(name, { fromDate: dateClickedFormatted, toDate: selectedDate.fromDate, }) } else { // If second selected date is after first date, keep order setValue(name, { fromDate: selectedDate.fromDate, toDate: dateClickedFormatted, }) } } } } const closeIfOutside = useCallback( (target: HTMLElement) => { if (ref.current && target && !ref.current.contains(target)) { close() } }, [close, ref] ) function closeOnBlur(evt: FocusEvent) { if (isOpen) { const target = evt.relatedTarget as HTMLElement closeIfOutside(target) } } useEffect(() => { function handleClickOutside(evt: Event) { if (isOpen) { const target = evt.target as HTMLElement closeIfOutside(target) } } document.body.addEventListener("click", handleClickOutside) return () => { document.body.removeEventListener("click", handleClickOutside) } }, [closeIfOutside, isOpen]) const selectedFromDate = dt(selectedDate.fromDate) .locale(lang) .format("ddd D MMM") const selectedToDate = !!selectedDate.toDate ? dt(selectedDate.toDate).locale(lang).format("ddd D MMM") : "" return (
{ closeOnBlur(e.nativeEvent) }} data-isopen={isOpen} ref={ref} >
) }