fix: disable booking actions for cancelled/rejected/past bookings (#26926)

* fix: disable booking actions for cancelled/rejected/past bookings

* test: add tests for bookign actions disabled states
This commit is contained in:
Eesh Midha
2026-01-21 20:22:47 +00:00
committed by GitHub
parent f7f4df6922
commit 38cdf3b23f
2 changed files with 222 additions and 6 deletions
@@ -374,6 +374,87 @@ describe("Booking Actions", () => {
expect(rescheduleAction?.disabled).toBe(true);
expect(rescheduleRequestAction?.disabled).toBe(true);
});
it("should disable change_location for past bookings", () => {
const context = createMockContext({ isBookingInPast: true });
const actions = getEditEventActions(context);
const changeLocationAction = actions.find((a) => a.id === "change_location");
expect(changeLocationAction?.disabled).toBe(true);
});
it("should disable change_location for cancelled bookings", () => {
const context = createMockContext({ isCancelled: true });
const actions = getEditEventActions(context);
const changeLocationAction = actions.find((a) => a.id === "change_location");
expect(changeLocationAction?.disabled).toBe(true);
});
it("should disable add_members for rejected bookings", () => {
const context = createMockContext({ isRejected: true });
const actions = getEditEventActions(context);
const addMembersAction = actions.find((a) => a.id === "add_members");
expect(addMembersAction?.disabled).toBe(true);
});
it("should disable reroute for past bookings from routing form", () => {
const context = createMockContext({
isBookingFromRoutingForm: true,
isBookingInPast: true,
});
const actions = getEditEventActions(context);
const rerouteAction = actions.find((a) => a.id === "reroute");
expect(rerouteAction?.disabled).toBe(true);
});
it("should disable reassign for cancelled round robin bookings", () => {
const context = createMockContext({
isCancelled: true,
booking: {
...createMockContext().booking,
eventType: {
...createMockContext().booking.eventType,
schedulingType: SchedulingType.ROUND_ROBIN,
hostGroups: [],
},
},
});
const actions = getEditEventActions(context);
const reassignAction = actions.find((a) => a.id === "reassign");
expect(reassignAction?.disabled).toBe(true);
});
it("should enable edit actions for upcoming active bookings", () => {
const context = createMockContext({
isBookingInPast: false,
isCancelled: false,
isRejected: false,
isBookingFromRoutingForm: true,
booking: {
...createMockContext().booking,
eventType: {
...createMockContext().booking.eventType,
schedulingType: SchedulingType.ROUND_ROBIN,
hostGroups: [],
},
},
});
const actions = getEditEventActions(context);
const changeLocationAction = actions.find((a) => a.id === "change_location");
const addMembersAction = actions.find((a) => a.id === "add_members");
const rerouteAction = actions.find((a) => a.id === "reroute");
const reassignAction = actions.find((a) => a.id === "reassign");
expect(changeLocationAction?.disabled).toBe(false);
expect(addMembersAction?.disabled).toBe(false);
expect(rerouteAction?.disabled).toBe(false);
expect(reassignAction?.disabled).toBe(false);
});
});
describe("getAfterEventActions", () => {
@@ -523,6 +604,134 @@ describe("Booking Actions", () => {
expect(isActionDisabled("charge_card", context)).toBe(true);
});
describe("change_location action", () => {
it("should be disabled for past bookings", () => {
const context = createMockContext({ isBookingInPast: true });
expect(isActionDisabled("change_location", context)).toBe(true);
});
it("should be disabled for cancelled bookings", () => {
const context = createMockContext({ isCancelled: true });
expect(isActionDisabled("change_location", context)).toBe(true);
});
it("should be disabled for rejected bookings", () => {
const context = createMockContext({ isRejected: true });
expect(isActionDisabled("change_location", context)).toBe(true);
});
it("should be enabled for upcoming active bookings", () => {
const context = createMockContext({
isBookingInPast: false,
isCancelled: false,
isRejected: false,
});
expect(isActionDisabled("change_location", context)).toBe(false);
});
});
describe("add_members action", () => {
it("should be disabled for past bookings", () => {
const context = createMockContext({ isBookingInPast: true });
expect(isActionDisabled("add_members", context)).toBe(true);
});
it("should be disabled for cancelled bookings", () => {
const context = createMockContext({ isCancelled: true });
expect(isActionDisabled("add_members", context)).toBe(true);
});
it("should be disabled for rejected bookings", () => {
const context = createMockContext({ isRejected: true });
expect(isActionDisabled("add_members", context)).toBe(true);
});
it("should be enabled for upcoming active bookings", () => {
const context = createMockContext({
isBookingInPast: false,
isCancelled: false,
isRejected: false,
});
expect(isActionDisabled("add_members", context)).toBe(false);
});
});
describe("reroute action", () => {
it("should be disabled for past bookings", () => {
const context = createMockContext({ isBookingInPast: true });
expect(isActionDisabled("reroute", context)).toBe(true);
});
it("should be disabled for cancelled bookings", () => {
const context = createMockContext({ isCancelled: true });
expect(isActionDisabled("reroute", context)).toBe(true);
});
it("should be disabled for rejected bookings", () => {
const context = createMockContext({ isRejected: true });
expect(isActionDisabled("reroute", context)).toBe(true);
});
it("should be enabled for upcoming active bookings", () => {
const context = createMockContext({
isBookingInPast: false,
isCancelled: false,
isRejected: false,
});
expect(isActionDisabled("reroute", context)).toBe(false);
});
});
describe("reassign action", () => {
it("should be disabled for past bookings", () => {
const context = createMockContext({ isBookingInPast: true });
expect(isActionDisabled("reassign", context)).toBe(true);
});
it("should be disabled for cancelled bookings", () => {
const context = createMockContext({ isCancelled: true });
expect(isActionDisabled("reassign", context)).toBe(true);
});
it("should be disabled for rejected bookings", () => {
const context = createMockContext({ isRejected: true });
expect(isActionDisabled("reassign", context)).toBe(true);
});
it("should be enabled for upcoming active bookings", () => {
const context = createMockContext({
isBookingInPast: false,
isCancelled: false,
isRejected: false,
});
expect(isActionDisabled("reassign", context)).toBe(false);
});
});
describe("cancel action with cancelled/rejected states", () => {
it("should be disabled for already cancelled bookings", () => {
const context = createMockContext({ isCancelled: true });
expect(isActionDisabled("cancel", context)).toBe(true);
});
it("should be disabled for rejected bookings", () => {
const context = createMockContext({ isRejected: true });
expect(isActionDisabled("cancel", context)).toBe(true);
});
});
describe("reschedule_request action with cancelled/rejected states", () => {
it("should be disabled for cancelled bookings", () => {
const context = createMockContext({ isCancelled: true });
expect(isActionDisabled("reschedule_request", context)).toBe(true);
});
it("should be disabled for rejected bookings", () => {
const context = createMockContext({ isRejected: true });
expect(isActionDisabled("reschedule_request", context)).toBe(true);
});
});
});
describe("getActionLabel", () => {
@@ -148,14 +148,14 @@ export function getEditEventActions(context: BookingActionContext): ActionType[]
id: "reroute",
label: t("reroute"),
icon: "waypoints",
disabled: false,
disabled: isActionDisabled("reroute", context),
}
: null,
{
id: "change_location",
label: t("edit_location"),
icon: "map-pin",
disabled: false,
disabled: isActionDisabled("change_location", context),
},
booking.eventType?.disableGuests
? null
@@ -163,14 +163,14 @@ export function getEditEventActions(context: BookingActionContext): ActionType[]
id: "add_members",
label: t("additional_guests"),
icon: "user-plus",
disabled: false,
disabled: isActionDisabled("add_members", context),
},
isReassignable
? {
id: "reassign",
label: t("reassign"),
icon: "users",
disabled: false,
disabled: isActionDisabled("reassign", context),
}
: null,
];
@@ -237,7 +237,7 @@ export function shouldShowIndividualReportButton(context: BookingActionContext):
}
export function isActionDisabled(actionId: string, context: BookingActionContext): boolean {
const { booking, isBookingInPast, isDisabledRescheduling, isDisabledCancelling, isAttendee } = context;
const { booking, isBookingInPast, isDisabledRescheduling, isDisabledCancelling, isAttendee, isCancelled, isRejected } = context;
switch (actionId) {
case "reschedule":
@@ -256,18 +256,25 @@ export function isActionDisabled(actionId: string, context: BookingActionContext
booking.eventType.minimumRescheduleNotice ?? null
);
return (
isCancelled ||
isRejected ||
(isBookingInPast && !booking.eventType.allowReschedulingPastBookings) ||
isDisabledRescheduling ||
isWithinMinimumNotice
);
case "cancel":
return isDisabledCancelling || isBookingInPast;
return isDisabledCancelling || isBookingInPast || isCancelled || isRejected;
case "view_recordings":
return !(isBookingInPast && booking.status === BookingStatus.ACCEPTED && context.isCalVideoLocation);
case "meeting_session_details":
return !(isBookingInPast && booking.status === BookingStatus.ACCEPTED && context.isCalVideoLocation);
case "charge_card":
return context.cardCharged;
case "reroute":
case "reassign":
case "change_location":
case "add_members":
return isBookingInPast || isCancelled || isRejected;
default:
return false;
}