import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/solid"; import { useEffect, useState } from "react"; import dayjs, { Dayjs } from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; import getSlots from "@lib/slots"; import dayjsBusinessDays from "dayjs-business-days"; import classNames from "@lib/classNames"; dayjs.extend(dayjsBusinessDays); dayjs.extend(utc); dayjs.extend(timezone); const DatePicker = ({ weekStart, onDatePicked, workingHours, organizerTimeZone, eventLength, date, periodType = "unlimited", periodStartDate, periodEndDate, periodDays, periodCountCalendarDays, minimumBookingNotice, }) => { 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 + 1); }; const decrementMonth = () => { setSelectedMonth(selectedMonth - 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).businessDaysAdd(periodDays, "days").endOf("day"); return ( date.endOf("day").isBefore(dayjs().utcOffsett(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 (
{inviteeDate().format("MMMM")} {inviteeDate().format("YYYY")}
{["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] .sort((a, b) => (weekStart.startsWith(a) ? -1 : weekStart.startsWith(b) ? 1 : 0)) .map((weekDay) => (
{weekDay}
))}
{days.map((day, idx) => (
{day === null ? (
) : ( )}
))}
); }; export default DatePicker;