revert: booking rejection reason from booking success page (#16584)
This commit is contained in:
@@ -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
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user