From f3d60b141f2a989a8394fc5c1007b7ed7565331b Mon Sep 17 00:00:00 2001 From: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> Date: Tue, 23 Sep 2025 05:14:46 +0530 Subject: [PATCH] fix: resolve 404 error when rescheduling seated event bookings (#23956) * fix: skip select field validation for existing responses during reschedule - Modify hasRequiredBookingFieldsResponses to detect reschedule context - Skip validation for select, multiselect, checkbox, and radio fields during reschedule to preserve existing responses - Fixes validation error when rescheduling bookings with select field responses that may no longer match current field options Resolves issue where reschedule operations fail with 'Value Travel, Adventure & Wildlife is not valid for type select for field Niche-project' error Co-Authored-By: anik@cal.com * fix: skip frontend validation for existing select field responses during reschedule - Revert backend changes in bookings.service.ts as the issue is frontend-only - Add reschedule detection in getBookingResponsesSchema.ts preprocess function - Skip option validation for select, radio, multiselect, and checkbox fields during reschedule - Preserves existing booking responses that may no longer match current field options - Fixes error 'Value Travel, Adventure & Wildlife is not valid for type select for field Niche-project' during slot selection Co-Authored-By: anik@cal.com * fix: extend reschedule validation skip to handle multiemail fields like guests - Add reschedule-aware logic to multiemail validation in getBookingResponsesSchema.ts - Skip validation for existing multiemail responses during reschedule to avoid type mismatch errors - Fixes 'Value is not valid for type text for field guests' error during slot selection - Complements existing fix for select/radio field validation during reschedule Co-Authored-By: anik@cal.com * fix: disable guests field inputs for seated events - Disable type SelectField for guests field in seated events - Disable identifier InputField for guests field in seated events - Add validation to prevent saving guests field changes for seated events - Pass seatsEnabled prop from EventAdvancedTab to FormBuilder - Use condition: seatsEnabled && formFieldType === 'multiemail' && fieldForm.getValues('name') === 'guests' - Fix linting warnings: remove unused variable and add missing dependency Co-Authored-By: anik@cal.com * Update getBookingResponsesSchema.ts * Update FormBuilder.tsx * Update FormBuilder.tsx * update --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- apps/web/public/static/locales/en/common.json | 1 + .../form-builder/FormBuilder.test.tsx | 45 ++++++++++++++++++- .../features/form-builder/FormBuilder.tsx | 6 +++ 3 files changed, 50 insertions(+), 2 deletions(-) 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;