daterangepicker
unknown
typescript
a month ago
6.3 kB
5
Indexable
Never
"use client"; import React, { useState, useCallback, useEffect, Fragment } from "react"; import { Datepicker, CalendarPrev, CalendarNav, CalendarNext, CalendarToday, setOptions, localeNl, formatDate } from "@mobiscroll/react"; import { cn } from "@/lib/utils"; import useDateStore from "../../../state/useDateStore"; import { Button } from "./ui/Button"; import "@/styles/datepicker.modules.scss"; import "@mobiscroll/react/dist/css/mobiscroll.min.css"; import useSWR from "swr"; type DateRangeSelectorProps = { openChange: (isOpen: boolean) => void; isOpen: boolean; }; type ValidProps = { start: Date; end: Date; }; setOptions({ locale: localeNl, theme: "ios", themeVariant: "light", }); const now = new Date(); const dateFormat = "YYYY-MM-DD"; let startingFromDate = formatDate(dateFormat, new Date(now.getFullYear(), now.getMonth(), 1)); // format datum naar YYYY-MM-DD let startingEndDate = formatDate(dateFormat, new Date(now.getFullYear(), now.getMonth() + 2, 0)); // format datum naar YYYY-MM-DD /** * Updates the valid dates for the DateRangeSelector based on the arrivals data. * @param arrivals - An array of arrival data. * @returns An array of ValidProps objects representing the valid date ranges. */ const updateValidDates = (arrivals: any[]): ValidProps[] => { const valids: ValidProps[] = []; arrivals.map((arrival: any) => { if (arrival.departures) { arrival.departures.map((depature: any) => { valids.push({ start: arrival.date, end: depature.date }); }); } }); return valids; }; /** * A component that allows the user to select a date range, it fetches arrival data from the API and updates the valid dates accordingly. * Then the user can select a date range that is only within the valid dates. * @param openChange - A callback function to handle changes in the open state of the DateRangeSelector. * @param isOpen - A boolean indicating whether the DateRangeSelector is open or not. * @returns A DateRangeSelector component. */ export const DateRangeSelector = ({ openChange, isOpen }: DateRangeSelectorProps) => { const addDate = useDateStore((state) => state.addDate); const [fromDate, setFromDate] = useState(startingFromDate); const [tillDate, setTillDate] = useState(startingEndDate); const [selectedDate, setSelectedDate] = useState<[string, string] | null>(null); const [inputValue, setInputValue] = useState(); const [calenderOpen, setCalenderOpen] = useState(false); /** * Handles the new date range on page switch, and updates the state accordingly. * @param event - The event object containing information about the next selected date. */ const handlePageChange = (event: any) => { const newCurrMonth = event.firstDay.toLocaleDateString("en-CA"); const newNextMonth = new Date(event.firstDay.getFullYear(), event.firstDay.getMonth() + 2, 0).toLocaleDateString("en-CA"); // setTimeout nodig om errors in the console te voorkomen setTimeout(() => { setFromDate(newCurrMonth); setTillDate(newNextMonth); }, 0); }; function fetcher(url: string) { return fetch(url).then((res) => res.json()); } function useFetchDates() { const { data } = useSWR(`/api/availability?fromDate=${fromDate}&tillDate=${tillDate}`, fetcher); return data; } /** * Retrieves the availability data for the given date range. * @param fromDate - The start date of the date range. * @param tillDate - The end date of the date range. */ function useAvailableDates(data: any) { const [valid, setValid] = useState<ValidProps[]>([]); useEffect(() => { if (isOpen && data) { const valids = updateValidDates(data.data.arrivals); setValid(valids); } }, [isOpen, data]); return valid; } const valid = useAvailableDates(useFetchDates()); const applyClick = useCallback(() => { if (!selectedDate) return; openChange(false); setCalenderOpen(false); addDate(selectedDate); }, [selectedDate]); const onDateChange = useCallback( (event: any) => { const date = event.value; const selectedFrom = formatDate(dateFormat, new Date(date[0] as string)); const selectedTill = formatDate(dateFormat, new Date(date[1] as string)); setSelectedDate([selectedFrom, selectedTill]); }, [selectedDate] ); const cancelClick = () => { openChange(false); }; const calendarHeader = useCallback(() => { return ( <Fragment> <CalendarNav /> <CalendarPrev /> <CalendarToday /> <CalendarNext /> </Fragment> ); }, []); return ( <div className={cn( ` ${isOpen === true ? "block" : "hidden"} fixed left-0 top-0 bg-white w-full h-full flex flex-col z-20 overflow-y-scroll ` )} > <Datepicker controls={["calendar"]} cssClass="md-book-rental" select="range" display="inline" calendarType="month" calendarSize={2} refDate={startingFromDate} min={now} startInput={now} showRangeLabels={false} inRangeInvalid={false} rangeEndInvalid={true} valid={valid} onClose={cancelClick} renderCalendarHeader={calendarHeader} onPageChange={handlePageChange} onChange={onDateChange} /> <div className={cn( ` h-20 p-5 flex space-around justify-around bg-white fixed md:absolute z-50 bottom-0 left-0 w-full !shadow-lg !border-t-2 !border-gray-300 ` )} > <Button onClick={cancelClick} variant="outline" style={{ backgroundColor: "var(--theme-color-tertiary)" }}> Selectie wissen </Button> <Button onClick={applyClick} style={{ backgroundColor: "var(--theme-color-primary)" }}> Selecteren </Button> </div> </div> ); }; export default DateRangeSelector;