Files
calendar/packages/features/calendars/NoAvailabilityDialog.tsx
T
417acdaacb fix: Improves dialog window that appears when there is no availability in a month. Adding a description to clarify limits when rolling or range period types are in use. (#20451)
* init

* updated typing, english localization text, used existing calculatePeriodLimits and isTimeViolatingFutureLimit to determine if go to next month button should be disabled

* improving copy

* semantic dialog heading tag, proper EN localization,

* reverting

* force local to origin

* Translations by LLM

* intit tests

* moving NoAvailability to its own file.

* refactor overlay component to encpsulate logic in hooks

* improved tests

* remove unintended change

* fix: period data type import. Providing default periodData values

* fix: type errors on event object

* fix: updates case in type import

* removing translations

* remove unnecessary import

* remove unnecessary import

* improving mocks for booker and logger

* moving tests to __tests__ folder

---------

Co-authored-by: Tushar Bhatt <95581504+TusharBhatt1@users.noreply.github.com>
2025-04-15 23:46:01 +05:30

105 lines
3.4 KiB
TypeScript

import { useState } from "react";
import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { calculatePeriodLimits, isTimeViolatingFutureLimit } from "@calcom/lib/isOutOfBounds";
import type { PeriodData } from "@calcom/types/Event";
import { Button } from "@calcom/ui/components/button";
import { Dialog, DialogContent, DialogFooter, DialogClose } from "@calcom/ui/components/dialog";
// Determines if the next month will pass the booking limits for 'ROLLING' and 'RANGE' period types
const useNoFutureAvailability = (browsingDate: Dayjs, periodData: PeriodData) => {
const { periodDays, periodType, periodCountCalendarDays, periodEndDate, periodStartDate } = periodData;
const periodLimits = calculatePeriodLimits({
periodType,
periodDays,
periodCountCalendarDays,
periodStartDate,
periodEndDate,
allDatesWithBookabilityStatusInBookerTz: null, // Temporary workaround
_skipRollingWindowCheck: true,
eventUtcOffset: 0,
bookerUtcOffset: 0,
});
// Check if limit is before start of next month
const isOutOfBoundsByPeriod = isTimeViolatingFutureLimit({
time: browsingDate.add(1, "month").startOf("month").toDate(),
periodLimits,
});
return isOutOfBoundsByPeriod;
};
// Creates message to use in dialog explaining lack of availability based on period type
const useDescription = (noFutureAvailability: boolean, p: PeriodData) => {
const { t } = useLocale();
if (!noFutureAvailability) return "";
if (p.periodType === "ROLLING") {
const daysDescription = p.periodCountCalendarDays ? t("calendar_days") : t("business_days");
return t("no_availability_rolling", { days: `${p.periodDays} ${daysDescription}` });
}
if (p.periodType === "RANGE") {
return t("no_availability_range", { date: dayjs(p.periodEndDate).format("MMMM D YYYY") });
}
return "";
};
// This component is used to show a dialog when there is no availability in the selected month.
const NoAvailabilityDialog = ({
month,
nextMonthButton,
browsingDate,
periodData,
}: {
month: string | null;
nextMonthButton: () => void;
browsingDate: Dayjs;
periodData: PeriodData;
}) => {
const { t } = useLocale();
const [isOpenDialog, setIsOpenDialog] = useState(true);
const noFutureAvailability = useNoFutureAvailability(browsingDate, periodData);
const description = useDescription(noFutureAvailability, periodData);
const closeDialog = () => {
setIsOpenDialog(false);
};
return (
<Dialog
open={isOpenDialog}
onOpenChange={(open) => {
setIsOpenDialog(open);
}}>
<DialogContent
title={t("no_availability_in_month", { month: month })}
type="creation"
description={description}
preventCloseOnOutsideClick={false}>
<DialogFooter>
<DialogClose
color={noFutureAvailability ? "primary" : "secondary"}
onClick={closeDialog}
data-testid="close_dialog_button">
{t("close")}
</DialogClose>
{!noFutureAvailability && (
<Button
color="primary"
onClick={nextMonthButton}
data-testid="view_next_month"
EndIcon="arrow-right">
{t("view_next_month")}
</Button>
)}
</DialogFooter>
</DialogContent>
</Dialog>
);
};
export default NoAvailabilityDialog;