import { BanIcon, CheckIcon, ClockIcon, PaperAirplaneIcon, PencilAltIcon, XIcon, } from "@heroicons/react/outline"; import { RefreshIcon } from "@heroicons/react/solid"; import { BookingStatus } from "@prisma/client"; import dayjs from "dayjs"; import { useRouter } from "next/router"; import { useState } from "react"; import { useMutation } from "react-query"; import { Frequency as RRuleFrequency } from "rrule"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import Button from "@calcom/ui/Button"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui/Dialog"; import { Tooltip } from "@calcom/ui/Tooltip"; import { TextArea } from "@calcom/ui/form/fields"; import { HttpError } from "@lib/core/http/error"; import useMeQuery from "@lib/hooks/useMeQuery"; import { parseRecurringDates } from "@lib/parseDate"; import { inferQueryInput, inferQueryOutput, trpc } from "@lib/trpc"; import { RescheduleDialog } from "@components/dialog/RescheduleDialog"; import TableActions, { ActionType } from "@components/ui/TableActions"; type BookingListingStatus = inferQueryInput<"viewer.bookings">["status"]; type BookingItem = inferQueryOutput<"viewer.bookings">["bookings"][number]; type BookingItemProps = BookingItem & { listingStatus: BookingListingStatus; recurringCount?: number; }; function BookingListItem(booking: BookingItemProps) { // Get user so we can determine 12/24 hour format preferences const query = useMeQuery(); const user = query.data; const { t, i18n } = useLocale(); const utils = trpc.useContext(); const router = useRouter(); const [rejectionReason, setRejectionReason] = useState(""); const [rejectionDialogIsOpen, setRejectionDialogIsOpen] = useState(false); const mutation = useMutation( async (confirm: boolean) => { let body = { id: booking.id, confirmed: confirm, language: i18n.language, reason: rejectionReason, }; /** * Only pass down the recurring event id when we need to confirm the entire series, which happens in * the "Upcoming" tab, to support confirming discretionally in the "Recurring" tab. */ if (booking.listingStatus === "upcoming" && booking.recurringEventId !== null) { body = Object.assign({}, body, { recurringEventId: booking.recurringEventId }); } const res = await fetch("/api/book/confirm", { method: "PATCH", body: JSON.stringify(body), headers: { "Content-Type": "application/json", }, }); if (!res.ok) { throw new HttpError({ statusCode: res.status }); } }, { async onSettled() { await utils.invalidateQueries(["viewer.bookings"]); }, } ); const isUpcoming = new Date(booking.endTime) >= new Date(); const isCancelled = booking.status === BookingStatus.CANCELLED; const pendingActions: ActionType[] = [ { id: "reject", label: booking.listingStatus === "upcoming" && booking.recurringEventId !== null ? t("reject_all") : t("reject"), onClick: (e) => { e.stopPropagation(); setRejectionDialogIsOpen(true); }, icon: BanIcon, disabled: mutation.isLoading, }, { id: "confirm", label: booking.listingStatus === "upcoming" && booking.recurringEventId !== null ? t("confirm_all") : t("confirm"), onClick: (e) => { e.stopPropagation(); mutation.mutate(true); }, icon: CheckIcon, disabled: mutation.isLoading, color: "primary", }, ]; const bookedActions: ActionType[] = [ { id: "cancel", label: t("cancel"), href: `/cancel/${booking.uid}`, icon: XIcon, }, { id: "reschedule", label: t("reschedule"), icon: ClockIcon, actions: [ { id: "edit", icon: PencilAltIcon, label: t("edit_booking"), href: `/reschedule/${booking.uid}`, }, { id: "reschedule_request", icon: ClockIcon, label: t("send_reschedule_request"), onClick: (e) => { e.stopPropagation(); setIsOpenRescheduleDialog(true); }, }, ], }, ]; const RequestSentMessage = () => { return (

{t("reschedule_request_sent")}

); }; const startTime = dayjs(booking.startTime).format(isUpcoming ? "ddd, D MMM" : "D MMMM YYYY"); const [isOpenRescheduleDialog, setIsOpenRescheduleDialog] = useState(false); // Calculate the booking date(s) let recurringStrings: string[] = []; if (booking.recurringCount && booking.eventType.recurringEvent?.freq !== null) { [recurringStrings] = parseRecurringDates( { startDate: booking.startTime, recurringEvent: booking.eventType.recurringEvent, recurringCount: booking.recurringCount, }, i18n ); } return ( <> {/* NOTE: Should refactor this dialog component as is being rendered multiple times */}

{t("rejection_reason_description")}

{t("rejection_reason")} (Optional)