feat: "cal.isBookingDryRun" to be used for Routing form as well (#18832)
This commit is contained in:
1 parent
161aece3a1
commit
b3f946dd0b
6 files changed
+57
-25
No files matched your search
@@ -1,7 +1,6 @@
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { stringify } from "querystring";
|
||||
import z from "zod";
|
||||
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enrichFormWithMigrationData";
|
||||
import { getAbsoluteEventTypeRedirectUrlWithEmbedSupport } from "@calcom/app-store/routing-forms/getEventTypeRedirectUrl";
|
||||
import getFieldIdentifier from "@calcom/app-store/routing-forms/lib/getFieldIdentifier";
|
||||
@@ -20,7 +19,6 @@ import { RoutingFormRepository } from "@calcom/lib/server/repository/routingForm
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: ["[routing-forms]", "[router]"] });
|
||||
|
||||
const querySchema = z
|
||||
.object({
|
||||
form: z.string(),
|
||||
@@ -46,8 +44,16 @@ export const getServerSideProps = async function getServerSideProps(context: Get
|
||||
};
|
||||
}
|
||||
|
||||
// Known params reserved by Cal.com are form, embed, layout. We should exclude all of them.
|
||||
const { form: formId, ...fieldsResponses } = queryParsed.data;
|
||||
// TODO: Known params reserved by Cal.com are form, embed, layout and other cal. prefixed params. We should exclude all of them from fieldsResponses.
|
||||
// But they must be present in `paramsToBeForwardedAsIs` as they could be needed by Booking Page as well.
|
||||
const { form: formId, "cal.isBookingDryRun": isBookingDryRunParam, ...fieldsResponses } = queryParsed.data;
|
||||
const isBookingDryRun = isBookingDryRunParam === "true";
|
||||
const paramsToBeForwardedAsIs = {
|
||||
...fieldsResponses,
|
||||
// Must be forwarded if present to Booking Page. Setting it explicitly here as it is critical to be present in the URL.
|
||||
...(isBookingDryRunParam ? { "cal.isBookingDryRun": isBookingDryRunParam } : null),
|
||||
};
|
||||
|
||||
const { currentOrgDomain } = orgDomainConfig(context.req);
|
||||
|
||||
let timeTaken: Record<string, number | null> = {};
|
||||
@@ -115,6 +121,7 @@ export const getServerSideProps = async function getServerSideProps(context: Get
|
||||
formFillerId: uuidv4(),
|
||||
response: response,
|
||||
chosenRouteId: matchingRoute.id,
|
||||
isPreview: isBookingDryRun,
|
||||
});
|
||||
teamMembersMatchingAttributeLogic = result.teamMembersMatchingAttributeLogic;
|
||||
formResponseId = result.formResponse.id;
|
||||
@@ -162,7 +169,7 @@ export const getServerSideProps = async function getServerSideProps(context: Get
|
||||
allURLSearchParams: getUrlSearchParamsToForward({
|
||||
formResponse: response,
|
||||
fields: serializableForm.fields,
|
||||
searchParams: new URLSearchParams(stringify(fieldsResponses)),
|
||||
searchParams: new URLSearchParams(stringify(paramsToBeForwardedAsIs)),
|
||||
teamMembersMatchingAttributeLogic,
|
||||
// formResponseId is guaranteed to be set because in catch block of trpc request we return from the function and otherwise it would have been set
|
||||
formResponseId: formResponseId!,
|
||||
|
||||
@@ -35,11 +35,13 @@ export const handleResponse = async ({
|
||||
// Unused but probably should be used
|
||||
// formFillerId,
|
||||
chosenRouteId,
|
||||
isPreview,
|
||||
}: {
|
||||
response: z.infer<typeof ZResponseInputSchema>["response"];
|
||||
form: Form;
|
||||
formFillerId: string;
|
||||
chosenRouteId: string | null;
|
||||
isPreview: boolean;
|
||||
}) => {
|
||||
try {
|
||||
if (!form.fields) {
|
||||
@@ -162,25 +164,39 @@ export const handleResponse = async ({
|
||||
// It currently happens for a Router route. Such a route id isn't present in the form.routes
|
||||
}
|
||||
|
||||
const dbFormResponse = await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
// TODO: Why do we not save formFillerId available in the input?
|
||||
// formFillerId,
|
||||
formId: form.id,
|
||||
response: response,
|
||||
chosenRouteId,
|
||||
},
|
||||
});
|
||||
let dbFormResponse;
|
||||
if (!isPreview) {
|
||||
dbFormResponse = await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
// TODO: Why do we not save formFillerId available in the input?
|
||||
// formFillerId,
|
||||
formId: form.id,
|
||||
response: response,
|
||||
chosenRouteId,
|
||||
},
|
||||
});
|
||||
|
||||
await onFormSubmission(
|
||||
{ ...serializableFormWithFields, userWithEmails },
|
||||
dbFormResponse.response as FormResponse,
|
||||
dbFormResponse.id,
|
||||
chosenRoute ? ("action" in chosenRoute ? chosenRoute.action : undefined) : undefined
|
||||
);
|
||||
await onFormSubmission(
|
||||
{ ...serializableFormWithFields, userWithEmails },
|
||||
dbFormResponse.response as FormResponse,
|
||||
dbFormResponse.id,
|
||||
chosenRoute ? ("action" in chosenRoute ? chosenRoute.action : undefined) : undefined
|
||||
);
|
||||
} else {
|
||||
moduleLogger.debug("Dry run mode - Form response not stored and also webhooks and emails not sent");
|
||||
// Create a mock response for dry run
|
||||
dbFormResponse = {
|
||||
id: 0,
|
||||
formId: form.id,
|
||||
response,
|
||||
chosenRouteId,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isPreview: false,
|
||||
isPreview: !!isPreview,
|
||||
formResponse: dbFormResponse,
|
||||
teamMembersMatchingAttributeLogic: teamMemberIdsMatchingAttributeLogic,
|
||||
attributeRoutingConfig: chosenRoute
|
||||
|
||||
@@ -54,6 +54,8 @@ function RoutingForm({ form, profile, ...restProps }: Props) {
|
||||
});
|
||||
|
||||
const [response, setResponse] = usePrefilledResponse(form);
|
||||
const pageSearchParams = useCompatSearchParams();
|
||||
const isBookingDryRun = pageSearchParams?.get("cal.isBookingDryRun") === "true";
|
||||
|
||||
// TODO: We might want to prevent spam from a single user by having same formFillerId across pageviews
|
||||
// But technically, a user can fill form multiple times due to any number of reasons and we currently can't differentiate b/w that.
|
||||
@@ -79,6 +81,7 @@ function RoutingForm({ form, profile, ...restProps }: Props) {
|
||||
formFillerId,
|
||||
response: response,
|
||||
chosenRouteId: chosenRoute.id,
|
||||
isPreview: isBookingDryRun,
|
||||
});
|
||||
|
||||
chosenRouteWithFormResponseRef.current = {
|
||||
|
||||
@@ -92,6 +92,9 @@ export function getFieldResponse({
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Not called in preview mode or dry run mode
|
||||
*/
|
||||
export async function onFormSubmission(
|
||||
form: Ensure<
|
||||
SerializableForm<App_RoutingForms_Form> & { user: Pick<User, "id" | "email">; userWithEmails?: string[] },
|
||||
|
||||
@@ -73,7 +73,10 @@ export const BookEventForm = ({
|
||||
|
||||
// Cloudflare Turnstile Captcha
|
||||
const shouldRenderCaptcha =
|
||||
renderCaptcha && CLOUDFLARE_SITE_ID && CLOUDFLARE_USE_TURNSTILE_IN_BOOKER === "1";
|
||||
!process.env.NEXT_PUBLIC_IS_E2E &&
|
||||
renderCaptcha &&
|
||||
CLOUDFLARE_SITE_ID &&
|
||||
CLOUDFLARE_USE_TURNSTILE_IN_BOOKER === "1";
|
||||
|
||||
const [responseVercelIdHeader] = useState<string | null>(null);
|
||||
const { t } = useLocale();
|
||||
|
||||
@@ -13,7 +13,7 @@ interface ResponseHandlerOptions {
|
||||
}
|
||||
export const responseHandler = async ({ ctx, input }: ResponseHandlerOptions) => {
|
||||
const { prisma } = ctx;
|
||||
const { formId, response, formFillerId, chosenRouteId = null } = input;
|
||||
const { formId, response, formFillerId, chosenRouteId = null, isPreview = false } = input;
|
||||
const form = await prisma.app_RoutingForms_Form.findFirst({
|
||||
where: {
|
||||
id: formId,
|
||||
@@ -43,7 +43,7 @@ export const responseHandler = async ({ ctx, input }: ResponseHandlerOptions) =>
|
||||
form,
|
||||
});
|
||||
|
||||
return handleResponse({ response, form: serializableForm, formFillerId, chosenRouteId });
|
||||
return handleResponse({ response, form: serializableForm, formFillerId, chosenRouteId, isPreview });
|
||||
};
|
||||
|
||||
export default responseHandler;
|
||||
Reference in new issue
Block a user