import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/solid"; import dayjs, { Dayjs } from "dayjs"; // Then, include dayjs-business-time import dayjsBusinessTime from "dayjs-business-time"; import timezone from "dayjs/plugin/timezone"; import utc from "dayjs/plugin/utc"; import { useEffect, useState } from "react"; import classNames from "@lib/classNames"; import { useLocale } from "@lib/hooks/useLocale"; import getSlots from "@lib/slots"; dayjs.extend(dayjsBusinessTime); dayjs.extend(utc); dayjs.extend(timezone); // FIXME prop types function DatePicker({ weekStart, onDatePicked, workingHours, organizerTimeZone, eventLength, date, periodType = "unlimited", periodStartDate, periodEndDate, periodDays, periodCountCalendarDays, minimumBookingNotice, }: any): JSX.Element { const { t } = useLocale(); const [days, setDays] = useState<({ disabled: boolean; date: number } | null)[]>([]); const [selectedMonth, setSelectedMonth] = useState( date ? periodType === "range" ? dayjs(periodStartDate).utcOffset(date.utcOffset()).month() : date.month() : dayjs().month() /* High chance server is going to have the same month */ ); useEffect(() => { if (dayjs().month() !== selectedMonth) { setSelectedMonth(dayjs().month()); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Handle month changes const incrementMonth = () => { setSelectedMonth((selectedMonth ?? 0) + 1); }; const decrementMonth = () => { setSelectedMonth((selectedMonth ?? 0) - 1); }; const inviteeDate = (): Dayjs => (date || dayjs()).month(selectedMonth); useEffect(() => { // Create placeholder elements for empty days in first week let weekdayOfFirst = inviteeDate().date(1).day(); if (weekStart === "Monday") { weekdayOfFirst -= 1; if (weekdayOfFirst < 0) weekdayOfFirst = 6; } const days = Array(weekdayOfFirst).fill(null); const isDisabled = (day: number) => { const date: Dayjs = inviteeDate().date(day); switch (periodType) { case "rolling": { const periodRollingEndDay = periodCountCalendarDays ? dayjs().tz(organizerTimeZone).add(periodDays, "days").endOf("day") : dayjs().tz(organizerTimeZone).addBusinessTime(periodDays, "days").endOf("day"); return ( date.endOf("day").isBefore(dayjs().utcOffset(date.utcOffset())) || date.endOf("day").isAfter(periodRollingEndDay) || !getSlots({ inviteeDate: date, frequency: eventLength, minimumBookingNotice, workingHours, organizerTimeZone, }).length ); } case "range": { const periodRangeStartDay = dayjs(periodStartDate).tz(organizerTimeZone).endOf("day"); const periodRangeEndDay = dayjs(periodEndDate).tz(organizerTimeZone).endOf("day"); return ( date.endOf("day").isBefore(dayjs().utcOffset(date.utcOffset())) || date.endOf("day").isBefore(periodRangeStartDay) || date.endOf("day").isAfter(periodRangeEndDay) || !getSlots({ inviteeDate: date, frequency: eventLength, minimumBookingNotice, workingHours, organizerTimeZone, }).length ); } case "unlimited": default: return ( date.endOf("day").isBefore(dayjs().utcOffset(date.utcOffset())) || !getSlots({ inviteeDate: date, frequency: eventLength, minimumBookingNotice, workingHours, organizerTimeZone, }).length ); } }; const daysInMonth = inviteeDate().daysInMonth(); for (let i = 1; i <= daysInMonth; i++) { days.push({ disabled: isDisabled(i), date: i }); } setDays(days); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedMonth]); return (
{t(inviteeDate().format("MMMM").toLowerCase())} {" "} {inviteeDate().format("YYYY")}
{["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] .sort((a, b) => (weekStart.startsWith(a) ? -1 : weekStart.startsWith(b) ? 1 : 0)) .map((weekDay) => (
{t(weekDay.toLowerCase()).substring(0, 3)}
))}
{days.map((day, idx) => (
{day === null ? (
) : ( )}
))}
); } export default DatePicker;