From d3acf4160d1370f20fcfb83fb05ae5d6b3fba7ed Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Wed, 23 Aug 2023 20:42:51 +0530 Subject: [PATCH] fix: data collection for headless router (#9183) Co-authored-by: Wesley <100464352+ologbonowiwi@users.noreply.github.com> Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> --- .../routing-forms/lib/transformResponse.ts | 22 +++++++++++-- .../pages/router/[...appPages].tsx | 33 +++++++++++++------ .../pages/routing-link/[...appPages].tsx | 4 ++- .../app-store/routing-forms/trpc/utils.ts | 8 +++-- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/app-store/routing-forms/lib/transformResponse.ts b/packages/app-store/routing-forms/lib/transformResponse.ts index e87ad5b12c..f7e3d41152 100644 --- a/packages/app-store/routing-forms/lib/transformResponse.ts +++ b/packages/app-store/routing-forms/lib/transformResponse.ts @@ -5,8 +5,26 @@ export default function transformResponse({ value, }: { field: Field; - value: Response[string]["value"]; + value: Response[string]["value"] | undefined; }) { + if (!value) { + return ""; + } // type="number" still gives value as a string but we need to store that as number so that number operators can work. - return field.type === "number" && typeof value === "string" ? Number(value) : value; + if (field.type === "number") { + if (typeof value === "string") { + return Number(value); + } + return value; + } + if (field.type === "multiselect") { + if (value instanceof Array) { + return value; + } + return value + .toString() + .split(",") + .map((v) => v.trim()); + } + return value; } diff --git a/packages/app-store/routing-forms/pages/router/[...appPages].tsx b/packages/app-store/routing-forms/pages/router/[...appPages].tsx index bde18dd502..200c1ef0a1 100644 --- a/packages/app-store/routing-forms/pages/router/[...appPages].tsx +++ b/packages/app-store/routing-forms/pages/router/[...appPages].tsx @@ -1,7 +1,9 @@ import Head from "next/head"; import z from "zod"; +import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains"; import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; +import logger from "@calcom/lib/logger"; import type { AppGetServerSidePropsContext, AppPrisma } from "@calcom/types/AppGetServerSideProps"; import type { inferSSRProps } from "@calcom/types/inferSSRProps"; @@ -11,6 +13,7 @@ import { processRoute } from "../../lib/processRoute"; import transformResponse from "../../lib/transformResponse"; import type { Response } from "../../types/types"; +const log = logger.getChildLogger({ prefix: ["[routing-forms]", "[router]"] }); export default function Router({ form, message }: inferSSRProps) { return ( <> @@ -34,7 +37,7 @@ const querySchema = z slug: z.string(), pages: z.array(z.string()), }) - .catchall(z.string()); + .catchall(z.string().or(z.array(z.string()))); export const getServerSideProps = async function getServerSideProps( context: AppGetServerSidePropsContext, @@ -42,6 +45,7 @@ export const getServerSideProps = async function getServerSideProps( ) { const queryParsed = querySchema.safeParse(context.query); if (!queryParsed.success) { + log.warn("Error parsing query", queryParsed.error); return { notFound: true, }; @@ -54,11 +58,7 @@ export const getServerSideProps = async function getServerSideProps( where: { id: formId, user: { - organization: isValidOrgDomain - ? { - slug: currentOrgDomain, - } - : null, + organization: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null, }, }, }); @@ -70,13 +70,13 @@ export const getServerSideProps = async function getServerSideProps( } const serializableForm = await getSerializableForm({ form }); - const response: Record> = {}; + const response: Response = {}; serializableForm.fields?.forEach((field) => { const fieldResponse = fieldsResponses[getFieldIdentifier(field)] || ""; - const value = - field.type === "multiselect" ? fieldResponse.split(",").map((r) => r.trim()) : fieldResponse; + response[field.id] = { - value: transformResponse({ field, value }), + label: field.label, + value: transformResponse({ field, value: fieldResponse }), }; }); @@ -86,6 +86,18 @@ export const getServerSideProps = async function getServerSideProps( throw new Error("No matching route could be found"); } + const { createContext } = await import("@calcom/trpc/server/createContext"); + const ctx = await createContext(context); + + const { default: trpcRouter } = await import("@calcom/app-store/routing-forms/trpc/_router"); + const caller = trpcRouter.createCaller(ctx); + const { v4: uuidv4 } = await import("uuid"); + await caller.public.response({ + formId: form.id, + formFillerId: uuidv4(), + response: response, + }); + //TODO: Maybe take action after successful mutation if (decidedAction.type === "customPageMessage") { return { @@ -109,6 +121,7 @@ export const getServerSideProps = async function getServerSideProps( }, }; } + return { props: { form: serializableForm, diff --git a/packages/app-store/routing-forms/pages/routing-link/[...appPages].tsx b/packages/app-store/routing-forms/pages/routing-link/[...appPages].tsx index e5be7f2703..8ff57e60ea 100644 --- a/packages/app-store/routing-forms/pages/routing-link/[...appPages].tsx +++ b/packages/app-store/routing-forms/pages/routing-link/[...appPages].tsx @@ -20,6 +20,7 @@ import FormInputFields from "../../components/FormInputFields"; import getFieldIdentifier from "../../lib/getFieldIdentifier"; import { getSerializableForm } from "../../lib/getSerializableForm"; import { processRoute } from "../../lib/processRoute"; +import transformResponse from "../../lib/transformResponse"; import type { Response, Route } from "../../types/types"; type Props = inferSSRProps; @@ -303,8 +304,9 @@ const usePrefilledResponse = (form: Props["form"]) => { const valuesFromQuery = searchParams?.getAll(getFieldIdentifier(field)).filter(Boolean); // We only want to keep arrays if the field is a multi-select const value = valuesFromQuery.length > 1 ? valuesFromQuery : valuesFromQuery[0]; + prefillResponse[field.id] = { - value: value || "", + value: transformResponse({ field, value }), label: field.label, }; }); diff --git a/packages/app-store/routing-forms/trpc/utils.ts b/packages/app-store/routing-forms/trpc/utils.ts index a3899491b2..16741cb299 100644 --- a/packages/app-store/routing-forms/trpc/utils.ts +++ b/packages/app-store/routing-forms/trpc/utils.ts @@ -6,7 +6,6 @@ import logger from "@calcom/lib/logger"; import { WebhookTriggerEvents } from "@calcom/prisma/client"; import type { Ensure } from "@calcom/types/utils"; -import ResponseEmail from "../emails/templates/response-email"; import type { Response, SerializableForm } from "../types/types"; export async function onFormSubmission( @@ -58,8 +57,11 @@ export const sendResponseEmail = async ( ownerEmail: string ) => { try { - const email = new ResponseEmail({ form: form, toAddresses: [ownerEmail], response: response }); - await email.sendEmail(); + if (typeof window === "undefined") { + const { default: ResponseEmail } = await import("../emails/templates/response-email"); + const email = new ResponseEmail({ form: form, toAddresses: [ownerEmail], response: response }); + await email.sendEmail(); + } } catch (e) { logger.error("Error sending response email", e); }