fix: Add booking related events for recurring bookings as well (#16180)

* Add bookingSuccessful event for recurring booking

* Remove unused variable
This commit is contained in:
Hariom Balhara
2024-08-13 10:25:52 +00:00
committed by GitHub
parent 3666c260ee
commit c36249b5a7
5 changed files with 108 additions and 34 deletions
@@ -30,6 +30,11 @@ export type EventDataMap = {
eventTypeId: number | null | undefined;
status: string | undefined;
paymentRequired: boolean;
isRecurring: boolean;
/**
* This is only used for recurring bookings
*/
allBookings?: { startTime: string; endTime: string }[];
};
/**
@@ -56,6 +61,11 @@ export type EventDataMap = {
eventTypeId: number | null | undefined;
status: string | undefined;
paymentRequired: boolean;
isRecurring: boolean;
/**
* This is only used for recurring bookings
*/
allBookings?: { startTime: string; endTime: string }[];
};
/**
* @deprecated Use `rescheduleBookingSuccessfulV2` instead. We restrict the data heavily there, only sending what is absolutely needed and keeping it light as well. Plus, more importantly that can be documented well.
@@ -50,6 +50,29 @@ export interface IUseBookings {
teamMemberEmail?: string;
}
const getBookingSuccessfulEventPayload = (booking: {
title?: string;
startTime: string;
endTime: string;
eventTypeId?: number | null;
status?: BookingStatus;
paymentRequired: boolean;
uid?: string;
isRecurring: boolean;
}) => {
return {
uid: booking.uid,
title: booking.title,
startTime: booking.startTime,
endTime: booking.endTime,
eventTypeId: booking.eventTypeId,
status: booking.status,
paymentRequired: booking.paymentRequired,
isRecurring: booking.isRecurring,
};
};
const getRescheduleBookingSuccessfulEventPayload = getBookingSuccessfulEventPayload;
export interface IUseBookingLoadingStates {
creatingBooking: boolean;
creatingRecurringBooking: boolean;
@@ -113,8 +136,8 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata, teamMemb
const createBookingMutation = useMutation({
mutationFn: createBooking,
onSuccess: (responseData) => {
const { uid, paymentUid } = responseData;
onSuccess: (booking) => {
const { uid, paymentUid } = booking;
const fullName = getFullName(bookingForm.getValues("responses.name"));
const users = !!event.data?.hosts?.length
@@ -126,44 +149,48 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata, teamMemb
: duration && event.data?.metadata?.multipleDuration?.includes(duration)
? duration
: event.data?.length;
const eventPayload = {
uid: responseData.uid,
title: responseData.title,
startTime: responseData.startTime,
endTime: responseData.endTime,
eventTypeId: responseData.eventTypeId,
status: responseData.status,
paymentRequired: responseData.paymentRequired,
};
if (isRescheduling) {
sdkActionManager?.fire("rescheduleBookingSuccessful", {
booking: responseData,
booking: booking,
eventType: event.data,
date: responseData?.startTime?.toString() || "",
date: booking?.startTime?.toString() || "",
duration: validDuration,
organizer: {
name: users?.[0]?.name || "Nameless",
email: responseData?.userPrimaryEmail || responseData.user?.email || "Email-less",
timeZone: responseData.user?.timeZone || "Europe/London",
email: booking?.userPrimaryEmail || booking.user?.email || "Email-less",
timeZone: booking.user?.timeZone || "Europe/London",
},
confirmed: !(responseData.status === BookingStatus.PENDING && event.data?.requiresConfirmation),
confirmed: !(booking.status === BookingStatus.PENDING && event.data?.requiresConfirmation),
});
sdkActionManager?.fire("rescheduleBookingSuccessfulV2", eventPayload);
sdkActionManager?.fire(
"rescheduleBookingSuccessfulV2",
getRescheduleBookingSuccessfulEventPayload({
...booking,
isRecurring: false,
})
);
} else {
sdkActionManager?.fire("bookingSuccessful", {
booking: responseData,
booking: booking,
eventType: event.data,
date: responseData?.startTime?.toString() || "",
date: booking?.startTime?.toString() || "",
duration: validDuration,
organizer: {
name: users?.[0]?.name || "Nameless",
email: responseData?.userPrimaryEmail || responseData.user?.email || "Email-less",
timeZone: responseData.user?.timeZone || "Europe/London",
email: booking?.userPrimaryEmail || booking.user?.email || "Email-less",
timeZone: booking.user?.timeZone || "Europe/London",
},
confirmed: !(responseData.status === BookingStatus.PENDING && event.data?.requiresConfirmation),
confirmed: !(booking.status === BookingStatus.PENDING && event.data?.requiresConfirmation),
});
sdkActionManager?.fire("bookingSuccessfulV2", eventPayload);
sdkActionManager?.fire(
"bookingSuccessfulV2",
getBookingSuccessfulEventPayload({
...booking,
isRecurring: false,
})
);
}
if (paymentUid) {
@@ -188,7 +215,7 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata, teamMemb
isSuccessBookingPage: true,
email: bookingForm.getValues("responses.email"),
eventTypeSlug: eventSlug,
seatReferenceUid: "seatReferenceUid" in responseData ? responseData.seatReferenceUid : null,
seatReferenceUid: "seatReferenceUid" in booking ? booking.seatReferenceUid : null,
formerTime:
isRescheduling && bookingData?.startTime ? dayjs(bookingData.startTime).toString() : undefined,
};
@@ -196,7 +223,7 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata, teamMemb
bookingSuccessRedirect({
successRedirectUrl: event?.data?.successRedirectUrl || "",
query,
booking: responseData,
booking: booking,
forwardParamsSuccessRedirect:
event?.data?.forwardParamsSuccessRedirect === undefined
? true
@@ -223,8 +250,8 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata, teamMemb
const createRecurringBookingMutation = useMutation({
mutationFn: createRecurringBooking,
onSuccess: async (responseData) => {
const booking = responseData[0] || {};
onSuccess: async (bookings) => {
const booking = bookings[0] || {};
const { uid } = booking;
if (!uid) {
@@ -241,6 +268,31 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata, teamMemb
isRescheduling && bookingData?.startTime ? dayjs(bookingData.startTime).toString() : undefined,
};
if (isRescheduling) {
// NOTE: It is recommended to define the event payload in the argument itself to provide a better type safety.
sdkActionManager?.fire("rescheduleBookingSuccessfulV2", {
...getRescheduleBookingSuccessfulEventPayload({
...booking,
isRecurring: true,
}),
allBookings: bookings.map((booking) => ({
startTime: booking.startTime,
endTime: booking.endTime,
})),
});
} else {
sdkActionManager?.fire("bookingSuccessfulV2", {
...getBookingSuccessfulEventPayload({
...booking,
isRecurring: true,
}),
allBookings: bookings.map((booking) => ({
startTime: booking.startTime,
endTime: booking.endTime,
})),
});
}
bookingSuccessRedirect({
successRedirectUrl: event?.data?.successRedirectUrl || "",
query,
@@ -4,8 +4,9 @@ import type { BookingCreateBody, BookingResponse } from "../types";
export const createBooking = async (data: BookingCreateBody) => {
const response = await post<
Omit<BookingCreateBody, "startTime" | "endTime">,
BookingResponse & {
BookingCreateBody,
// fetch response can't have a Date type, it must be a string
Omit<BookingResponse, "startTime" | "endTime"> & {
startTime: string;
endTime: string;
}
@@ -3,6 +3,13 @@ import { post } from "@calcom/lib/fetch-wrapper";
import type { BookingCreateBody, InstantBookingResponse } from "../types";
export const createInstantBooking = async (data: BookingCreateBody) => {
const response = await post<BookingCreateBody, InstantBookingResponse>("/api/book/instant-event", data);
const response = await post<
BookingCreateBody,
// fetch response can't have a Date type, it must be a string
Omit<InstantBookingResponse, "startTime" | "endTime"> & {
startTime: string;
endTime: string;
}
>("/api/book/instant-event", data);
return response;
};
@@ -3,9 +3,13 @@ import { post } from "@calcom/lib/fetch-wrapper";
import type { RecurringBookingCreateBody, BookingResponse } from "../types";
export const createRecurringBooking = async (data: RecurringBookingCreateBody[]) => {
const response = await post<RecurringBookingCreateBody[], BookingResponse[]>(
"/api/book/recurring-event",
data
);
const response = await post<
RecurringBookingCreateBody[],
// fetch response can't have a Date type, it must be a string
(Omit<BookingResponse, "startTime" | "endTime"> & {
startTime: string;
endTime: string;
})[]
>("/api/book/recurring-event", data);
return response;
};