revert: booking rejection reason from booking success page (#16584)

This commit is contained in:
Anik Dhabal Babu
2024-09-11 03:51:36 +05:30
committed by GitHub
parent c168df4df0
commit 7269b3ea60
4 changed files with 48 additions and 122 deletions
@@ -28,6 +28,10 @@ import type { ActionType } from "@calcom/ui";
import {
Badge,
Button,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
Dropdown,
DropdownItem,
DropdownMenuCheckboxItem,
@@ -40,6 +44,7 @@ import {
MeetingTimeInTimezones,
showToast,
TableActions,
TextAreaField,
Tooltip,
} from "@calcom/ui";
@@ -73,12 +78,19 @@ function BookingListItem(booking: BookingItemProps) {
i18n: { language },
} = useLocale();
const utils = trpc.useUtils();
const [rejectionReason, setRejectionReason] = useState<string>("");
const [rejectionDialogIsOpen, setRejectionDialogIsOpen] = useState(false);
const [chargeCardDialogIsOpen, setChargeCardDialogIsOpen] = useState(false);
const [viewRecordingsDialogIsOpen, setViewRecordingsDialogIsOpen] = useState<boolean>(false);
const cardCharged = booking?.payment[0]?.success;
const mutation = trpc.viewer.bookings.confirm.useMutation({
onSuccess: () => {
showToast(t("booking_confirmation_success"), "success");
onSuccess: (data) => {
if (data?.status === BookingStatus.REJECTED) {
setRejectionDialogIsOpen(false);
showToast(t("booking_rejection_success"), "success");
} else {
showToast(t("booking_confirmation_success"), "success");
}
utils.viewer.bookings.invalidate();
},
onError: () => {
@@ -119,7 +131,7 @@ function BookingListItem(booking: BookingItemProps) {
let body = {
bookingId: booking.id,
confirmed: confirm,
reason: "",
reason: rejectionReason,
};
/**
* Only pass down the recurring event id when we need to confirm the entire series, which happens in
@@ -142,7 +154,9 @@ function BookingListItem(booking: BookingItemProps) {
{
id: "reject",
label: (isTabRecurring || isTabUnconfirmed) && isRecurring ? t("reject_all") : t("reject"),
href: `/booking/${booking.uid}?reject=true`,
onClick: () => {
setRejectionDialogIsOpen(true);
},
icon: "ban",
disabled: mutation.isPending,
},
@@ -376,6 +390,35 @@ function BookingListItem(booking: BookingItemProps) {
timeFormat={userTimeFormat ?? null}
/>
)}
<Dialog open={rejectionDialogIsOpen} onOpenChange={setRejectionDialogIsOpen}>
<DialogContent title={t("rejection_reason_title")} description={t("rejection_reason_description")}>
<div>
<TextAreaField
name="rejectionReason"
label={
<>
{t("rejection_reason")}
<span className="text-subtle font-normal"> (Optional)</span>
</>
}
value={rejectionReason}
onChange={(e) => setRejectionReason(e.target.value)}
/>
</div>
<DialogFooter>
<DialogClose />
<Button
disabled={mutation.isPending}
data-testid="rejection-confirm"
onClick={() => {
bookingConfirm(false);
}}>
{t("rejection_confirmation")}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<tr data-testid="booking-item" className="hover:bg-muted group flex flex-col transition sm:flex-row">
<td className="hidden align-top ltr:pl-3 rtl:pr-6 sm:table-cell sm:min-w-[12rem]">
<div className="flex h-full items-center">
@@ -1,88 +0,0 @@
import { useCallback, useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button, TextArea } from "@calcom/ui";
type Props = {
booking: {
uid?: string | null;
id: number;
recurringEventId: string | null;
};
setIsRejectionMode: () => void;
};
export default function RejectBooking(props: Props) {
const [rejectionReason, setRejectionReason] = useState<string>("");
const { t } = useLocale();
const utils = trpc.useUtils();
const { booking } = props;
const isRecurring = booking.recurringEventId !== null;
const mutation = trpc.viewer.bookings.confirm.useMutation({
onSuccess: () => {
props.setIsRejectionMode();
utils.viewer.bookings.invalidate();
},
onError: () => {
utils.viewer.bookings.invalidate();
},
});
const bookingConfirm = async (confirm: boolean) => {
let body = {
bookingId: booking.id,
confirmed: confirm,
reason: rejectionReason,
};
if (isRecurring) {
body = Object.assign({}, body, { recurringEventId: booking.recurringEventId });
}
mutation.mutate(body);
};
const rejectBookingRef = useCallback((node: HTMLTextAreaElement) => {
if (node !== null) {
node.scrollIntoView({ behavior: "smooth" });
node.focus();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<>
<div className="mt-5 sm:mt-6">
<label className="text-default font-medium">
<>
{t("rejection_reason")}
<span className="text-subtle font-normal"> (Optional)</span>
</>
</label>
<TextArea
ref={rejectBookingRef}
placeholder={t("rejection_reason_placeholder")}
value={rejectionReason}
onChange={(e) => setRejectionReason(e.target.value)}
className="mb-4 mt-2 w-full "
rows={3}
/>
<div className="flex flex-col-reverse rtl:space-x-reverse ">
<div className="ml-auto flex w-full space-x-4 ">
<Button className="ml-auto" color="secondary" onClick={() => props.setIsRejectionMode()}>
{t("nevermind")}
</Button>
<Button
loading={mutation.isPending}
data-testid="rejection-confirm"
onClick={() => {
bookingConfirm(false);
}}>
{t("rejection_confirmation")}
</Button>
</div>
</div>
</div>
</>
);
}
@@ -63,7 +63,6 @@ import {
} from "@calcom/ui";
import PageWrapper from "@calcom/web/components/PageWrapper";
import CancelBooking from "@calcom/web/components/booking/CancelBooking";
import RejectBooking from "@calcom/web/components/booking/RejectBooking";
import EventReservationSchema from "@calcom/web/components/schemas/EventReservationSchema";
import { timeZone } from "@calcom/web/lib/clock";
@@ -79,7 +78,6 @@ const querySchema = z.object({
email: z.string().optional(),
eventTypeSlug: z.string().optional(),
cancel: stringToBoolean,
reject: stringToBoolean,
allRemainingBookings: stringToBoolean,
changes: stringToBoolean,
reschedule: stringToBoolean,
@@ -116,7 +114,6 @@ export default function Success(props: PageProps) {
allRemainingBookings,
isSuccessBookingPage,
cancel: isCancellationMode,
reject: isRejectionMode,
formerTime,
email,
seatReferenceUid,
@@ -214,16 +211,6 @@ export default function Success(props: PageProps) {
router.replace(`${pathname}?${_searchParams.toString()}`);
}
function setIsRejectionMode() {
const _searchParams = new URLSearchParams(searchParams ?? undefined);
if (_searchParams.get("reject")) {
_searchParams.delete("reject");
}
router.replace(`${pathname}?${_searchParams.toString()}`);
}
let evtName = eventType.eventName;
if (eventType.isDynamic && bookingInfo.responses?.title) {
evtName = bookingInfo.responses.title as string;
@@ -693,7 +680,6 @@ export default function Success(props: PageProps) {
{!requiresLoginToUpdate &&
(!needsConfirmation || !userIsOwner) &&
isReschedulable &&
!isRejectionMode &&
(!isCancellationMode ? (
<>
<hr className="border-subtle mb-8" />
@@ -753,19 +739,6 @@ export default function Success(props: PageProps) {
/>
</>
))}
{!isCancelled && isRejectionMode && (
<>
<hr className="border-subtle" />
<RejectBooking
booking={{
id: bookingInfo.id,
uid: bookingInfo?.uid,
recurringEventId: bookingInfo.recurringEventId,
}}
setIsRejectionMode={setIsRejectionMode}
/>
</>
)}
{userIsOwner &&
!needsConfirmation &&
!isCancellationMode &&
@@ -9,8 +9,6 @@ export const OrganizerRequestEmail = (props: React.ComponentProps<typeof Organiz
const token = symmetricEncrypt(JSON.stringify(seedData), process.env.CALENDSO_ENCRYPTION_KEY || "");
//TODO: We should switch to using org domain if available
const actionHref = `${WEBAPP_URL}/api/link/?token=${encodeURIComponent(token)}`;
const rejectLink = new URL(`${props.calEvent.bookerUrl ?? WEBAPP_URL}/booking/${props.calEvent.uid}`);
rejectLink.searchParams.append("reject", "true");
return (
<OrganizerScheduledEmail
title={
@@ -31,7 +29,7 @@ export const OrganizerRequestEmail = (props: React.ComponentProps<typeof Organiz
<Separator />
<CallToAction
label={props.calEvent.organizer.language.translate("reject")}
href={rejectLink.toString()}
href={`${actionHref}&action=reject`}
startIconName="rejectIcon"
secondary
/>