From 1d5228ef3820f0496a5f1a39d9b1a4e0348b7fbf Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:28:34 -0500 Subject: [PATCH] fix: skip duplicate CRM lookup when router already performed it (#27487) When the routing form redirects to an event type, it now passes cal.crmLookupDone=true to indicate that the CRM contact owner lookup was already performed. The event type SSR checks for this flag and skips the duplicate CRM lookup, improving performance. This fixes the scenario where no CRM contact owner exists - previously the lookup would be performed twice (once in the router, once in SSR), but now it's only performed once. Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../team/[slug]/[type]/queries.ts | 7 +- .../team/[slug]/[type]/getServerSideProps.tsx | 7 +- .../routing-forms/lib/getRoutedUrl.ts | 1 + .../lib/getUrlSearchParamsToForward.test.ts | 70 +++++++++++++++++++ .../lib/getUrlSearchParamsToForward.ts | 3 + 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/queries.ts b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/queries.ts index 0e0894befb..51db301c64 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/queries.ts +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/queries.ts @@ -124,6 +124,7 @@ export async function getCRMData( const crmContactOwnerRecordType = query["cal.crmContactOwnerRecordType"]; const crmAppSlugParam = query["cal.crmAppSlug"]; const crmRecordIdParam = query["cal.crmRecordId"]; + const crmLookupDoneParam = query["cal.crmLookupDone"]; let teamMemberEmail = Array.isArray(crmContactOwnerEmail) ? crmContactOwnerEmail[0] : crmContactOwnerEmail; let crmOwnerRecordType = Array.isArray(crmContactOwnerRecordType) @@ -132,7 +133,11 @@ export async function getCRMData( let crmAppSlug = Array.isArray(crmAppSlugParam) ? crmAppSlugParam[0] : crmAppSlugParam; let crmRecordId = Array.isArray(crmRecordIdParam) ? crmRecordIdParam[0] : crmRecordIdParam; - if (!teamMemberEmail || !crmOwnerRecordType || !crmAppSlug) { + // If crmLookupDone is true, the router already performed the CRM lookup, so skip it here + const crmLookupDone = + (Array.isArray(crmLookupDoneParam) ? crmLookupDoneParam[0] : crmLookupDoneParam) === "true"; + + if (!crmLookupDone && (!teamMemberEmail || !crmOwnerRecordType || !crmAppSlug)) { const { getTeamMemberEmailForResponseOrContactUsingUrlQuery } = await import( "@calcom/features/ee/teams/lib/getTeamMemberEmailFromCrm" ); diff --git a/apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx b/apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx index fcd939cd87..57cf20a313 100644 --- a/apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx +++ b/apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx @@ -96,6 +96,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => const crmContactOwnerRecordType = query["cal.crmContactOwnerRecordType"]; const crmAppSlugParam = query["cal.crmAppSlug"]; const crmRecordIdParam = query["cal.crmRecordId"]; + const crmLookupDoneParam = query["cal.crmLookupDone"]; // Handle string[] type from query params let teamMemberEmail = Array.isArray(crmContactOwnerEmail) ? crmContactOwnerEmail[0] : crmContactOwnerEmail; @@ -107,7 +108,11 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => let crmAppSlug = Array.isArray(crmAppSlugParam) ? crmAppSlugParam[0] : crmAppSlugParam; let crmRecordId = Array.isArray(crmRecordIdParam) ? crmRecordIdParam[0] : crmRecordIdParam; - if (!teamMemberEmail || !crmOwnerRecordType || !crmAppSlug) { + // If crmLookupDone is true, the router already performed the CRM lookup, so skip it here + const crmLookupDone = + (Array.isArray(crmLookupDoneParam) ? crmLookupDoneParam[0] : crmLookupDoneParam) === "true"; + + if (!crmLookupDone && (!teamMemberEmail || !crmOwnerRecordType || !crmAppSlug)) { const { getTeamMemberEmailForResponseOrContactUsingUrlQuery } = await import( "@calcom/features/ee/teams/lib/getTeamMemberEmailFromCrm" ); diff --git a/packages/features/routing-forms/lib/getRoutedUrl.ts b/packages/features/routing-forms/lib/getRoutedUrl.ts index 8e0eea5c7e..26ae5703dc 100644 --- a/packages/features/routing-forms/lib/getRoutedUrl.ts +++ b/packages/features/routing-forms/lib/getRoutedUrl.ts @@ -249,6 +249,7 @@ const _getRoutedUrl = async (context: Pick { expect(fromEntriesWithDuplicateKeys(result.entries())).toEqual(expectedParams); }); }); + + describe("CRM Lookup Done", () => { + it("should add cal.crmLookupDone when crmLookupDone is true", () => { + const searchParams = new URLSearchParams("?query1=value1"); + const expectedParams = { + query1: "value1", + "cal.routingFormResponseId": "1", + "cal.crmLookupDone": "true", + }; + + const result = getUrlSearchParamsToForward({ + formResponse: {}, + fields: [], + searchParams, + teamMembersMatchingAttributeLogic: null, + formResponseId: 1, + queuedFormResponseId: null, + attributeRoutingConfig: null, + crmLookupDone: true, + }); + expect(fromEntriesWithDuplicateKeys(result.entries())).toEqual(expectedParams); + }); + + it("should not add cal.crmLookupDone when crmLookupDone is false", () => { + const searchParams = new URLSearchParams("?query1=value1"); + const expectedParams = { + query1: "value1", + "cal.routingFormResponseId": "1", + }; + + const result = getUrlSearchParamsToForward({ + formResponse: {}, + fields: [], + searchParams, + teamMembersMatchingAttributeLogic: null, + formResponseId: 1, + queuedFormResponseId: null, + attributeRoutingConfig: null, + crmLookupDone: false, + }); + expect(fromEntriesWithDuplicateKeys(result.entries())).toEqual(expectedParams); + }); + + it("should add both CRM contact owner email and crmLookupDone when both are provided", () => { + const searchParams = new URLSearchParams("?query1=value1"); + const expectedParams = { + query1: "value1", + "cal.routingFormResponseId": "1", + "cal.crmContactOwnerEmail": "owner@example.com", + "cal.crmContactOwnerRecordType": "Contact", + "cal.crmAppSlug": "salesforce", + "cal.crmLookupDone": "true", + }; + + const result = getUrlSearchParamsToForward({ + formResponse: {}, + fields: [], + searchParams, + teamMembersMatchingAttributeLogic: null, + formResponseId: 1, + queuedFormResponseId: null, + attributeRoutingConfig: null, + crmContactOwnerEmail: "owner@example.com", + crmContactOwnerRecordType: "Contact", + crmAppSlug: "salesforce", + crmLookupDone: true, + }); + expect(fromEntriesWithDuplicateKeys(result.entries())).toEqual(expectedParams); + }); + }); }); diff --git a/packages/features/routing-forms/lib/getUrlSearchParamsToForward.ts b/packages/features/routing-forms/lib/getUrlSearchParamsToForward.ts index ee81ef610c..160406f1dc 100644 --- a/packages/features/routing-forms/lib/getUrlSearchParamsToForward.ts +++ b/packages/features/routing-forms/lib/getUrlSearchParamsToForward.ts @@ -30,6 +30,7 @@ type GetUrlSearchParamsToForwardOptions = { crmContactOwnerEmail?: string | null; crmContactOwnerRecordType?: string | null; crmAppSlug?: string | null; + crmLookupDone?: boolean; reroutingFormResponses?: FormResponseValueOnly; teamId?: number | null; orgId?: number | null; @@ -46,6 +47,7 @@ export function getUrlSearchParamsToForward({ crmContactOwnerEmail, crmContactOwnerRecordType, crmAppSlug, + crmLookupDone, reroutingFormResponses, teamId, orgId, @@ -132,6 +134,7 @@ export function getUrlSearchParamsToForward({ ...(crmContactOwnerEmail ? { ["cal.crmContactOwnerEmail"]: crmContactOwnerEmail } : null), ...(crmContactOwnerRecordType ? { ["cal.crmContactOwnerRecordType"]: crmContactOwnerRecordType } : null), ...(crmAppSlug ? { ["cal.crmAppSlug"]: crmAppSlug } : null), + ...(crmLookupDone ? { ["cal.crmLookupDone"]: "true" } : null), ...(reroutingFormResponses ? { ["cal.reroutingFormResponses"]: JSON.stringify(reroutingFormResponses) } : null),