feat: Allow cancellation & reschedule on past bookings (#16118)
* option to cancel/reschedule in past bookings * allows reschedule and cancellation on past bookings * make headline checks readable * -- * -- * review feedback
This commit is contained in:
@@ -515,7 +515,7 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
</div>
|
||||
</Link>
|
||||
</td>
|
||||
<td className="flex w-full justify-end py-4 pl-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4 sm:pl-0">
|
||||
<td className="flex w-full flex-col flex-wrap items-end justify-end space-x-2 space-y-2 py-4 pl-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4 sm:flex-row sm:flex-nowrap sm:items-start sm:space-y-0 sm:pl-0">
|
||||
{isUpcoming && !isCancelled ? (
|
||||
<>
|
||||
{isPending && (userId === booking.user?.id || booking.isUserTeamAdminOrOwner) && (
|
||||
@@ -526,6 +526,7 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
</>
|
||||
) : null}
|
||||
{isBookingInPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
||||
{isBookingInPast && isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
||||
{(showViewRecordingsButton || showCheckRecordingButton) && (
|
||||
<TableActions actions={showRecordingActions} />
|
||||
)}
|
||||
|
||||
@@ -310,7 +310,7 @@ export default function Success(props: PageProps) {
|
||||
function getTitle(): string {
|
||||
const titleSuffix = props.recurringBookings ? "_recurring" : "";
|
||||
const titlePrefix = isRoundRobin ? "round_robin_" : "";
|
||||
if (isCancelled || isBookingInPast) {
|
||||
if (isCancelled) {
|
||||
return "";
|
||||
}
|
||||
if (needsConfirmation) {
|
||||
@@ -355,7 +355,7 @@ export default function Success(props: PageProps) {
|
||||
const providerName = guessEventLocationType(location)?.label;
|
||||
const rescheduleProviderName = guessEventLocationType(rescheduleLocation)?.label;
|
||||
const isBookingInPast = new Date(bookingInfo.endTime) < new Date();
|
||||
const isReschedulable = !isCancelled && !isBookingInPast;
|
||||
const isReschedulable = !isCancelled;
|
||||
|
||||
const bookingCancelledEventProps = {
|
||||
booking: bookingInfo,
|
||||
@@ -367,6 +367,32 @@ export default function Success(props: PageProps) {
|
||||
eventType,
|
||||
};
|
||||
|
||||
const isRecurringBooking = props.recurringBookings;
|
||||
const needsConfirmationAndReschedulable = needsConfirmation && isReschedulable;
|
||||
const isNotAttendingSeatedEvent = isCancelled && seatReferenceUid;
|
||||
const isEventCancelled = isCancelled && !seatReferenceUid;
|
||||
const isPastBooking = isBookingInPast;
|
||||
|
||||
const successPageHeadline = (() => {
|
||||
if (needsConfirmationAndReschedulable) {
|
||||
return isRecurringBooking ? t("booking_submitted_recurring") : t("booking_submitted");
|
||||
}
|
||||
|
||||
if (isNotAttendingSeatedEvent) {
|
||||
return t("no_longer_attending");
|
||||
}
|
||||
|
||||
if (isEventCancelled) {
|
||||
return t("event_cancelled");
|
||||
}
|
||||
|
||||
if (isPastBooking) {
|
||||
return t("event_is_in_the_past");
|
||||
}
|
||||
|
||||
return isRecurringBooking ? t("meeting_is_scheduled_recurring") : t("meeting_is_scheduled");
|
||||
})();
|
||||
|
||||
return (
|
||||
<div className={isEmbed ? "" : "h-screen"} data-testid="success-page">
|
||||
{!isEmbed && !isFeedbackMode && (
|
||||
@@ -439,7 +465,7 @@ export default function Success(props: PageProps) {
|
||||
"border-cal-bg dark:border-cal-bg-muted absolute bottom-0 right-0 z-10 h-12 w-12 border-8",
|
||||
!giphyImage && isReschedulable && !needsConfirmation ? "bg-success" : "",
|
||||
!giphyImage && isReschedulable && needsConfirmation ? "bg-subtle" : "",
|
||||
isCancelled || isBookingInPast ? "bg-error" : ""
|
||||
isCancelled ? "bg-error" : ""
|
||||
)}>
|
||||
{!giphyImage && !needsConfirmation && isReschedulable && (
|
||||
<Icon name="check" className="h-5 w-5 text-green-600 dark:text-green-400" />
|
||||
@@ -447,9 +473,7 @@ export default function Success(props: PageProps) {
|
||||
{needsConfirmation && isReschedulable && (
|
||||
<Icon name="calendar" className="text-emphasis h-5 w-5" />
|
||||
)}
|
||||
{(isCancelled || isBookingInPast) && (
|
||||
<Icon name="x" className="h-5 w-5 text-red-600 dark:text-red-200" />
|
||||
)}
|
||||
{isCancelled && <Icon name="x" className="h-5 w-5 text-red-600 dark:text-red-200" />}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-8 mt-6 text-center last:mb-0">
|
||||
@@ -457,19 +481,7 @@ export default function Success(props: PageProps) {
|
||||
className="text-emphasis text-2xl font-semibold leading-6"
|
||||
data-testid={isCancelled ? "cancelled-headline" : ""}
|
||||
id="modal-headline">
|
||||
{needsConfirmation && isReschedulable
|
||||
? props.recurringBookings
|
||||
? t("booking_submitted_recurring")
|
||||
: t("booking_submitted")
|
||||
: isCancelled
|
||||
? seatReferenceUid
|
||||
? t("no_longer_attending")
|
||||
: t("event_cancelled")
|
||||
: isBookingInPast
|
||||
? t("event_expired")
|
||||
: props.recurringBookings
|
||||
? t("meeting_is_scheduled_recurring")
|
||||
: t("meeting_is_scheduled")}
|
||||
{successPageHeadline}
|
||||
</h3>
|
||||
<div className="mt-3">
|
||||
<p className="text-default">{getTitle()}</p>
|
||||
|
||||
@@ -129,16 +129,6 @@ const NoAvailabilityOverlay = ({
|
||||
);
|
||||
};
|
||||
|
||||
const ReschedulingNotPossibleOverlay = () => {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<div className="bg-muted border-subtle absolute left-1/2 top-40 -mt-10 w-2/3 -translate-x-1/2 -translate-y-1/2 transform break-all rounded-md border p-8 shadow-sm">
|
||||
<h4 className="text-emphasis font-medium">{t("rescheduling_not_possible")}</h4>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Days = ({
|
||||
minDate,
|
||||
excludedDates = [],
|
||||
@@ -291,8 +281,6 @@ const Days = ({
|
||||
</div>
|
||||
))}
|
||||
|
||||
{isBookingInPast && <ReschedulingNotPossibleOverlay />}
|
||||
|
||||
{!props.isPending && !isBookingInPast && includedDates && includedDates?.length === 0 && (
|
||||
<NoAvailabilityOverlay month={month} nextMonthButton={nextMonthButton} />
|
||||
)}
|
||||
@@ -374,13 +362,11 @@ const DatePicker = ({
|
||||
<Button
|
||||
className={classNames(
|
||||
`group p-1 opacity-70 transition hover:opacity-100 rtl:rotate-180`,
|
||||
isBookingInPast && `disabled:text-bookinglighter hover:bg-background hover:opacity-70`,
|
||||
`${customClassNames?.datePickerToggle}`
|
||||
)}
|
||||
onClick={() => changeMonth(+1)}
|
||||
data-testid="incrementMonth"
|
||||
color="minimal"
|
||||
disabled={isBookingInPast}
|
||||
variant="icon"
|
||||
StartIcon="chevron-right"
|
||||
/>
|
||||
@@ -406,13 +392,13 @@ const DatePicker = ({
|
||||
datePickerDateActive: customClassNames?.datePickerDatesActive,
|
||||
}}
|
||||
weekStart={weekStart}
|
||||
selected={!isBookingInPast ? selected : null}
|
||||
selected={selected}
|
||||
{...passThroughProps}
|
||||
browsingDate={browsingDate}
|
||||
month={month}
|
||||
nextMonthButton={() => changeMonth(+1)}
|
||||
slots={!isBookingInPast ? slots : {}}
|
||||
includedDates={!isBookingInPast ? includedDates : []}
|
||||
slots={slots}
|
||||
includedDates={includedDates}
|
||||
isBookingInPast={isBookingInPast}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user