diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index c3892521de..218524b1ff 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -2202,6 +2202,7 @@ "booking_confirmation_failed": "Booking confirmation failed", "not_enough_seats": "Not enough seats", "form_builder_field_already_exists": "A field with this name already exists", + "guests_field_must_be_multiemail": "Guests field must be of type 'Multiple emails'", "show_on_booking_page": "Show on booking page", "visit_cancelled_booking": "You can visit the canceled booking page", "get_started_zapier_templates": "Get started with Zapier templates", diff --git a/packages/features/form-builder/FormBuilder.test.tsx b/packages/features/form-builder/FormBuilder.test.tsx index c47efa97a5..1427e1f278 100644 --- a/packages/features/form-builder/FormBuilder.test.tsx +++ b/packages/features/form-builder/FormBuilder.test.tsx @@ -1,10 +1,12 @@ import { TooltipProvider } from "@radix-ui/react-tooltip"; -import { render } from "@testing-library/react"; +import { render, screen, waitFor } from "@testing-library/react"; import type { ReactNode } from "react"; import * as React from "react"; import { FormProvider, useForm } from "react-hook-form"; import { vi } from "vitest"; +import { showToast } from "@calcom/ui/components/toast"; + import { FormBuilder } from "./FormBuilder"; import { mockProps, @@ -32,6 +34,10 @@ vi.mock("next/navigation", async (importOriginal) => { }; }); +vi.mock("@calcom/ui/components/toast", () => ({ + showToast: vi.fn(), +})); + const renderComponent = ({ formBuilderProps: formBuilderProps, formDefaultValues: formDefaultValues, @@ -219,7 +225,6 @@ describe("FormBuilder", () => { ], }); - verifier.verifyOptionPrices({ identifier, prices: [20, 25] }); }); @@ -271,4 +276,40 @@ describe("FormBuilder", () => { verifier.verifyOptionPrices({ identifier, prices: [50, 75, 100] }); }); }); + + describe("Guests Field Validation Tests", () => { + beforeEach(() => { + renderComponent({ formBuilderProps: mockProps, formDefaultValues: {} }); + }); + + it("Should prevent saving guests field with non-multiemail type", async () => { + const dialog = pageObject.openAddFieldDialog(); + + pageObject.dialog.selectFieldType({ dialog, fieldType: "text" }); + pageObject.dialog.fillInFieldIdentifier({ dialog, identifier: "guests" }); + pageObject.dialog.fillInFieldLabel({ dialog, label: "Guests", fieldType: "text" }); + + pageObject.dialog.saveField({ dialog }); + + await waitFor(() => { + expect(showToast).toHaveBeenCalledWith("guests_field_must_be_multiemail", "error"); + }); + + expect(screen.queryByTestId("field-guests")).not.toBeInTheDocument(); + }); + + it("Should allow saving guests field with multiemail type", async () => { + const dialog = pageObject.openAddFieldDialog(); + + pageObject.dialog.selectFieldType({ dialog, fieldType: "multiemail" }); + pageObject.dialog.fillInFieldIdentifier({ dialog, identifier: "guests" }); + pageObject.dialog.fillInFieldLabel({ dialog, label: "Guests", fieldType: "multiemail" }); + + pageObject.dialog.saveField({ dialog }); + + await waitFor(() => { + expect(screen.getByTestId("field-guests")).toBeInTheDocument(); + }); + }); + }); }); diff --git a/packages/features/form-builder/FormBuilder.tsx b/packages/features/form-builder/FormBuilder.tsx index 7bbd3aa948..c9b187db71 100644 --- a/packages/features/form-builder/FormBuilder.tsx +++ b/packages/features/form-builder/FormBuilder.tsx @@ -380,6 +380,12 @@ export const FormBuilder = function FormBuilder({ handleSubmit={(data: Parameters>[0]) => { const type = data.type || "text"; const isNewField = !fieldDialog.data; + + if (data.name === "guests" && type !== "multiemail") { + showToast(t("guests_field_must_be_multiemail"), "error"); + return; + } + if (isNewField && fields.some((f) => f.name === data.name)) { showToast(t("form_builder_field_already_exists"), "error"); return;