Skip to content

Commit b28d60b

Browse files
API Support: Manage Booking Questions and responses (#8115)
1 parent a716eda commit b28d60b

File tree

2 files changed

+70
-24
lines changed

2 files changed

+70
-24
lines changed

packages/features/bookings/lib/handleNewBooking.ts

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import { updateWebUser as syncServicesUpdateWebUser } from "@calcom/lib/sync/Syn
5353
import { TimeFormat } from "@calcom/lib/timeFormat";
5454
import prisma, { userSelect } from "@calcom/prisma";
5555
import type { BookingReference } from "@calcom/prisma/client";
56-
import type { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod-utils";
56+
import { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod-utils";
5757
import {
5858
bookingCreateBodySchemaForApi,
5959
customInputSchema,
@@ -394,21 +394,81 @@ function getBookingData({
394394
isNotAnApiCall: boolean;
395395
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>>;
396396
}) {
397+
const responsesSchema = getBookingResponsesSchema({
398+
eventType: {
399+
bookingFields: eventType.bookingFields,
400+
},
401+
view: req.body.rescheduleUid ? "reschedule" : "booking",
402+
});
397403
const bookingDataSchema = isNotAnApiCall
398404
? extendedBookingCreateBody.merge(
399405
z.object({
400-
responses: getBookingResponsesSchema({
401-
eventType: {
402-
bookingFields: eventType.bookingFields,
403-
},
404-
view: req.body.rescheduleUid ? "reschedule" : "booking",
405-
}),
406+
responses: responsesSchema,
406407
})
407408
)
408-
: bookingCreateBodySchemaForApi;
409+
: bookingCreateBodySchemaForApi
410+
.merge(
411+
z.object({
412+
responses: responsesSchema.optional(),
413+
})
414+
)
415+
.superRefine((val, ctx) => {
416+
if (val.responses && val.customInputs) {
417+
ctx.addIssue({
418+
code: "custom",
419+
message:
420+
"Don't use both customInputs and responses. `customInputs` is only there for legacy support.",
421+
});
422+
return;
423+
}
424+
const legacyProps = Object.keys(bookingCreateSchemaLegacyPropsForApi.shape);
425+
426+
if (val.responses) {
427+
const unwantedProps: string[] = [];
428+
legacyProps.forEach((legacyProp) => {
429+
if (val[legacyProp as keyof typeof val]) {
430+
unwantedProps.push(legacyProp);
431+
}
432+
});
433+
if (unwantedProps.length) {
434+
ctx.addIssue({
435+
code: "custom",
436+
message: `Legacy Props: ${unwantedProps.join(",")}. They can't be used with \`responses\``,
437+
});
438+
return;
439+
}
440+
} else if (val.customInputs) {
441+
const { success } = bookingCreateSchemaLegacyPropsForApi.safeParse(val);
442+
if (!success) {
443+
ctx.addIssue({
444+
code: "custom",
445+
message: `With \`customInputs\` you must specify legacy props ${legacyProps.join(",")}`,
446+
});
447+
}
448+
}
449+
});
409450

410451
const reqBody = bookingDataSchema.parse(req.body);
411-
if ("responses" in reqBody) {
452+
if ("customInputs" in reqBody) {
453+
if (reqBody.customInputs) {
454+
// Check if required custom inputs exist
455+
handleCustomInputs(eventType.customInputs as EventTypeCustomInput[], reqBody.customInputs);
456+
}
457+
const reqBodyWithLegacyProps = bookingCreateSchemaLegacyPropsForApi.parse(reqBody);
458+
return {
459+
...reqBody,
460+
name: reqBodyWithLegacyProps.name,
461+
email: reqBodyWithLegacyProps.email,
462+
guests: reqBodyWithLegacyProps.guests,
463+
location: reqBodyWithLegacyProps.location || "",
464+
smsReminderNumber: reqBodyWithLegacyProps.smsReminderNumber,
465+
notes: reqBodyWithLegacyProps.notes,
466+
rescheduleReason: reqBodyWithLegacyProps.rescheduleReason,
467+
};
468+
} else {
469+
if (!reqBody.responses) {
470+
throw new Error("`responses` must not be nullish");
471+
}
412472
const responses = reqBody.responses;
413473
const { userFieldsResponses: calEventUserFieldsResponses, responses: calEventResponses } =
414474
getCalEventResponses({
@@ -427,20 +487,6 @@ function getBookingData({
427487
rescheduleReason: responses.rescheduleReason,
428488
calEventResponses,
429489
};
430-
} else {
431-
// Check if required custom inputs exist
432-
handleCustomInputs(eventType.customInputs as EventTypeCustomInput[], reqBody.customInputs);
433-
434-
return {
435-
...reqBody,
436-
name: reqBody.name,
437-
email: reqBody.email,
438-
guests: reqBody.guests,
439-
location: reqBody.location || "",
440-
smsReminderNumber: reqBody.smsReminderNumber,
441-
notes: reqBody.notes,
442-
rescheduleReason: reqBody.rescheduleReason,
443-
};
444490
}
445491
}
446492

packages/prisma/zod-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ export const bookingCreateSchemaLegacyPropsForApi = z.object({
220220

221221
// This is the schema that is used for the API. It has all the legacy props that are part of `responses` now.
222222
export const bookingCreateBodySchemaForApi = extendedBookingCreateBody.merge(
223-
bookingCreateSchemaLegacyPropsForApi
223+
bookingCreateSchemaLegacyPropsForApi.partial()
224224
);
225225

226226
export const schemaBookingCancelParams = z.object({

0 commit comments

Comments
 (0)