refactor: v2 and booker atom booking fields (#17168)

* handle storing disableOnPrefill

* feat: allow overriding properties of default name and email fields

* feat: allow overriding properties of default name and email fields

* feat: output booking fields

* fix: event type test

* refactor: booker atom booking fields handling

* tests

* fix: boolean booking field

* update platform libraries

* fix: unit tests
This commit is contained in:
Lauris Skraucis authored and GitHub committed 2024-10-21 13:45:30 +03:00
1 parent b7792d0d0a
commit 4e90b65884
16 files changed
+1155 -1292

No files matched your search

+1 -1
View File
@@ -28,7 +28,7 @@
"dependencies": {
"@calcom/platform-constants": "*",
"@calcom/platform-enums": "*",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.46",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.47",
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
"@calcom/platform-types": "*",
"@calcom/platform-utils": "*",
@@ -662,7 +662,6 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(responseBody.data).toBeDefined();
const data: (BookingOutput_2024_08_13 | RecurringBookingOutput_2024_08_13)[] = responseBody.data;
expect(data.length).toEqual(2);
console.log("asap data", JSON.stringify(data, null, 2));
expect(data[0].start).toEqual(createdBooking.start);
expect(data[1].start).toEqual(bookingInThePast.startTime.toISOString());
});
@@ -31,6 +31,7 @@ import {
ApiSuccessResponse,
CreateEventTypeInput_2024_06_14,
EventTypeOutput_2024_06_14,
NameFieldInput_2024_06_14,
UpdateEventTypeInput_2024_06_14,
} from "@calcom/platform-types";
import { SchedulingType } from "@calcom/prisma/enums";
@@ -199,6 +200,13 @@ describe("Event types Endpoints", () => {
});
it("should create an event type", async () => {
const nameBookingField: NameFieldInput_2024_06_14 = {
type: "name",
label: "Your name sir / madam",
placeholder: "john doe",
disableOnPrefill: false,
};
const body: CreateEventTypeInput_2024_06_14 = {
title: "Coding class",
slug: "coding-class",
@@ -211,6 +219,7 @@ describe("Event types Endpoints", () => {
},
],
bookingFields: [
nameBookingField,
{
type: "select",
label: "select which language you want to learn",
@@ -218,6 +227,7 @@ describe("Event types Endpoints", () => {
required: true,
placeholder: "select language",
options: ["javascript", "python", "cobol"],
disableOnPrefill: true,
},
],
scheduleId: firstSchedule.id,
@@ -304,12 +314,14 @@ describe("Event types Endpoints", () => {
);
expect(createdEventType.color).toEqual(body.color);
const responseBookingFields = body.bookingFields || [];
const requestBookingFields = body.bookingFields || [];
const expectedBookingFields = [
{ isDefault: true, required: true, slug: "name", type: "name" },
{ isDefault: true, required: true, slug: "name", ...nameBookingField },
{ isDefault: true, required: true, slug: "email", type: "email" },
{ isDefault: true, required: false, slug: "rescheduleReason", type: "textarea" },
...responseBookingFields.map((field) => ({ isDefault: false, ...field })),
...requestBookingFields
.filter((field) => field.type !== "name" && field.type !== "email")
.map((field) => ({ isDefault: false, ...field })),
];
expect(createdEventType.bookingFields).toEqual(expectedBookingFields);
@@ -630,11 +642,30 @@ describe("Event types Endpoints", () => {
});
it("should update event type", async () => {
const nameBookingField: NameFieldInput_2024_06_14 = {
type: "name",
label: "Your name sir / madam",
placeholder: "john doe",
disableOnPrefill: true,
};
const newTitle = "Coding class in Italian!";
const body: UpdateEventTypeInput_2024_06_14 = {
title: newTitle,
scheduleId: secondSchedule.id,
bookingFields: [
nameBookingField,
{
type: "select",
label: "select which language you want to learn",
slug: "select-language",
required: true,
placeholder: "select language",
options: ["javascript", "python", "cobol"],
disableOnPrefill: false,
},
],
bookingLimitsCount: {
day: 4,
week: 10,
@@ -694,7 +725,19 @@ describe("Event types Endpoints", () => {
expect(updatedEventType.description).toEqual(eventType.description);
expect(updatedEventType.lengthInMinutes).toEqual(eventType.lengthInMinutes);
expect(updatedEventType.locations).toEqual(eventType.locations);
expect(updatedEventType.bookingFields).toEqual(eventType.bookingFields);
const requestBookingFields = body.bookingFields || [];
const expectedBookingFields = [
{ isDefault: true, required: true, slug: "name", ...nameBookingField },
{ isDefault: true, required: true, slug: "email", type: "email" },
{ isDefault: true, required: false, slug: "rescheduleReason", type: "textarea" },
...requestBookingFields
.filter((field) => field.type !== "name" && field.type !== "email")
.map((field) => ({ isDefault: false, ...field })),
];
expect(updatedEventType.bookingFields).toEqual(expectedBookingFields);
expect(updatedEventType.ownerId).toEqual(user.id);
expect(updatedEventType.scheduleId).toEqual(secondSchedule.id);
expect(updatedEventType.bookingLimitsCount).toEqual(body.bookingLimitsCount);
@@ -732,6 +775,7 @@ describe("Event types Endpoints", () => {
eventType.hideCalendarEventDetails = updatedEventType.hideCalendarEventDetails;
eventType.lockTimeZoneToggleOnBookingPage = updatedEventType.lockTimeZoneToggleOnBookingPage;
eventType.color = updatedEventType.color;
eventType.bookingFields = updatedEventType.bookingFields;
});
});
@@ -20,6 +20,8 @@ import {
transformEventColorsApiToInternal,
validateCustomEventName,
transformSeatsApiToInternal,
SystemField,
CustomField,
} from "@calcom/platform-libraries";
import {
CreateEventTypeInput_2024_06_14,
@@ -211,16 +213,27 @@ export class InputEventTypesService_2024_06_14 {
inputBookingFields: CreateEventTypeInput_2024_06_14["bookingFields"],
hasMultipleLocations: boolean
) {
const defaultFieldsBefore = [systemBeforeFieldName, systemBeforeFieldEmail];
const customFields: (SystemField | CustomField)[] = inputBookingFields
? transformBookingFieldsApiToInternal(inputBookingFields)
: [];
const customFieldsWithoutNameEmail = customFields.filter(
(field) => field.type !== "name" && field.type !== "email"
);
const customNameField = customFields?.find((field) => field.type === "name");
const customEmailField = customFields?.find((field) => field.type === "email");
const defaultFieldsBefore: (SystemField | CustomField)[] = [
customNameField || systemBeforeFieldName,
customEmailField || systemBeforeFieldEmail,
];
// note(Lauris): if event type has multiple locations then a radio button booking field has to be displayed to allow booker to pick location
if (hasMultipleLocations) {
defaultFieldsBefore.push(systemBeforeFieldLocation);
}
const customFields = transformBookingFieldsApiToInternal(inputBookingFields);
const defaultFieldsAfter = [systemAfterFieldRescheduleReason];
return [...defaultFieldsBefore, ...customFields, ...defaultFieldsAfter];
return [...defaultFieldsBefore, ...customFieldsWithoutNameEmail, ...defaultFieldsAfter];
}
transformInputIntervalLimits(inputBookingFields: CreateEventTypeInput_2024_06_14["bookingLimitsCount"]) {
+172 -10
View File
@@ -5977,6 +5977,10 @@
},
"placeholder": {
"type": "string"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `phone` and the URL contains query parameter `&phone=1234567890`, the phone field will be prefilled with this value and disabled."
}
},
"required": [
@@ -6010,6 +6014,10 @@
"placeholder": {
"type": "string",
"example": "e.g., 1234 Main St"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `address` and the URL contains query parameter `&address=1234 Main St, London`, the address field will be prefilled with this value and disabled."
}
},
"required": [
@@ -6043,6 +6051,10 @@
"placeholder": {
"type": "string",
"example": "e.g., Enter text here"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `who-referred-you` and the URL contains query parameter `&who-referred-you=bob`, the text field will be prefilled with this value and disabled."
}
},
"required": [
@@ -6076,6 +6088,10 @@
"placeholder": {
"type": "string",
"example": "e.g., 100"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `calories-per-day` and the URL contains query parameter `&calories-per-day=3000`, the number field will be prefilled with this value and disabled."
}
},
"required": [
@@ -6109,6 +6125,10 @@
"placeholder": {
"type": "string",
"example": "e.g., Detailed description here..."
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `dear-diary` and the URL contains query parameter `&dear-diary=Today I shipped a feature`, the text area will be prefilled with this value and disabled."
}
},
"required": [
@@ -6152,6 +6172,10 @@
"items": {
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `language` and options of this select field are ['english', 'italian'] and the URL contains query parameter `&language=italian`, the 'italian' will be selected and the select field will be disabled."
}
},
"required": [
@@ -6192,6 +6216,10 @@
"items": {
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `consultants` and the URL contains query parameter `&consultants=en&language=it`, the 'en' and 'it' will be selected and the select field will be disabled."
}
},
"required": [
@@ -6225,6 +6253,10 @@
"placeholder": {
"type": "string",
"example": "e.g., example@example.com"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `consultants` and the URL contains query parameter `&consultants=alice@gmail.com&consultants=bob@gmail.com`, the these emails will be added and none more can be added."
}
},
"required": [
@@ -6264,6 +6296,10 @@
"items": {
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `notify-me` and the URL contains query parameter `&notify-me=true`, the checkbox will be selected and the checkbox field will be disabled."
}
},
"required": [
@@ -6303,6 +6339,10 @@
"items": {
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `language` and options of this select field are ['english', 'italian'] and the URL contains query parameter `&language=italian`, the 'italian' radio buttom will be selected and the select field will be disabled."
}
},
"required": [
@@ -6332,6 +6372,9 @@
},
"required": {
"type": "boolean"
},
"disableOnPrefill": {
"type": "boolean"
}
},
"required": [
@@ -6875,6 +6918,37 @@
"EmailDefaultFieldOutput_2024_06_14": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
"number",
"textarea",
"select",
"multiselect",
"multiemail",
"checkbox",
"radio",
"boolean"
],
"example": "email",
"description": "only allowed value for type is `email`",
"default": "email"
},
"label": {
"type": "string"
},
"placeholder": {
"type": "string"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if URL contains query parameter `&email=bob@gmail.com`, the email field will be prefilled with this value and disabled."
},
"isDefault": {
"type": "object",
"default": true,
@@ -6885,24 +6959,51 @@
"type": "string",
"default": "email"
},
"type": {
"type": "string",
"default": "email"
},
"required": {
"type": "boolean"
}
},
"required": [
"type",
"isDefault",
"slug",
"type",
"required"
]
},
"NameDefaultFieldOutput_2024_06_14": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
"number",
"textarea",
"select",
"multiselect",
"multiemail",
"checkbox",
"radio",
"boolean"
],
"example": "name",
"description": "only allowed value for type is `name`",
"default": "name"
},
"label": {
"type": "string"
},
"placeholder": {
"type": "string"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if URL contains query parameter `&name=bob`, the name field will be prefilled with this value and disabled."
},
"isDefault": {
"type": "object",
"default": true,
@@ -6913,18 +7014,14 @@
"type": "string",
"default": "name"
},
"type": {
"type": "string",
"default": "name"
},
"required": {
"type": "boolean"
}
},
"required": [
"type",
"isDefault",
"slug",
"type",
"required"
]
},
@@ -7074,6 +7171,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7105,6 +7204,10 @@
"type": "string",
"example": "e.g., 1234 Main St"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `address` and the URL contains query parameter `&address=1234 Main St, London`, the address field will be prefilled with this value and disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7126,6 +7229,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7153,6 +7258,9 @@
"required": {
"type": "boolean"
},
"disableOnPrefill": {
"type": "boolean"
},
"isDefault": {
"type": "object",
"default": false,
@@ -7174,6 +7282,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7211,6 +7321,10 @@
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `notify-me` and the URL contains query parameter `&notify-me=true`, the checkbox will be selected and the checkbox field will be disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7233,6 +7347,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7264,6 +7380,10 @@
"type": "string",
"example": "e.g., example@example.com"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `consultants` and the URL contains query parameter `&consultants=alice@gmail.com&consultants=bob@gmail.com`, the these emails will be added and none more can be added."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7285,6 +7405,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7322,6 +7444,10 @@
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `consultants` and the URL contains query parameter `&consultants=en&language=it`, the 'en' and 'it' will be selected and the select field will be disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7344,6 +7470,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7375,6 +7503,10 @@
"type": "string",
"example": "e.g., 100"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `calories-per-day` and the URL contains query parameter `&calories-per-day=3000`, the number field will be prefilled with this value and disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7396,6 +7528,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7425,6 +7559,10 @@
"placeholder": {
"type": "string"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `phone` and the URL contains query parameter `&phone=1234567890`, the phone field will be prefilled with this value and disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7446,6 +7584,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7483,6 +7623,10 @@
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `language` and options of this select field are ['english', 'italian'] and the URL contains query parameter `&language=italian`, the 'italian' radio buttom will be selected and the select field will be disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7505,6 +7649,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7546,6 +7692,10 @@
"type": "string"
}
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `language` and options of this select field are ['english', 'italian'] and the URL contains query parameter `&language=italian`, the 'italian' will be selected and the select field will be disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7568,6 +7718,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7599,6 +7751,10 @@
"type": "string",
"example": "e.g., Detailed description here..."
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `dear-diary` and the URL contains query parameter `&dear-diary=Today I shipped a feature`, the text area will be prefilled with this value and disabled."
},
"isDefault": {
"type": "object",
"default": false,
@@ -7620,6 +7776,8 @@
"type": {
"type": "string",
"enum": [
"name",
"email",
"phone",
"address",
"text",
@@ -7651,6 +7809,10 @@
"type": "string",
"example": "e.g., Enter text here"
},
"disableOnPrefill": {
"type": "boolean",
"description": "Disable this booking field if the URL contains query parameter with key equal to the slug and prefill it with the provided value. For example, if the slug is `who-referred-you` and the URL contains query parameter `&who-referred-you=bob`, the text field will be prefilled with this value and disabled."
},
"isDefault": {
"type": "object",
"default": false,