Skip to content

Commit 09b1643

Browse files
PeerRichdevin-ai-integration[bot]hariombalhara
authored
chore: added headless routing link to embed (#22921)
* added headless routing link to embed * Update apps/web/public/static/locales/en/common.json * Update apps/web/public/static/locales/en/common.json * fix: add missing headless embed type handlers to resolve TypeScript errors - Add headless handlers for react, react-atom, and HTML frameworks in EmbedCodes.tsx - Add headless case handling in EmbedTabs.tsx getEmbedTypeSpecificString function - Add embedCalOrigin parameter to HTML framework handlers for type consistency - All handlers return documentation comments directing users to headless routing docs Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * temp: enable IS_CALCOM for localhost testing Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: change headless handlers to return null instead of documentation code Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * revert: remove temporary IS_CALCOM localhost change Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: remove unnecessary parameter destructuring from headless embed handlers - Headless handlers now take no parameters since they only return null - Simplified function signatures to avoid unused parameter warnings - Maintains existing functionality while improving code clarity Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: hariom@cal.com <hariombalhara@gmail.com>
1 parent 86f6e8b commit 09b1643

File tree

6 files changed

+82
-6
lines changed

6 files changed

+82
-6
lines changed

apps/web/public/static/locales/en/common.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,8 @@
22512251
"floating_button_trigger_modal": "Puts a floating button on your site that triggers a modal with your event type.",
22522252
"pop_up_element_click": "Pop up via element click",
22532253
"open_dialog_with_element_click": "Open your calendar as a dialog when someone clicks an element.",
2254+
"use_my_own_form": "Use my own form",
2255+
"use_our_headless_routing_api": "Use our headless routing API and use your own form for submissions.",
22542256
"need_help_embedding": "Need help? See our guides for embedding Cal on Wix, Squarespace, or WordPress, check our common questions, or explore advanced embed options.",
22552257
"book_my_cal": "Book my Cal",
22562258
"first_name": "First name",

packages/features/embed/Embed.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,13 @@ const ChooseEmbedTypesDialogContent = ({
207207
key={index}
208208
data-testid={embed.type}
209209
onClick={() => {
210-
gotoState({
211-
embedType: embed.type as EmbedType,
212-
});
210+
if (embed.type === "headless") {
211+
window.open("https://cal.com/help/routing/headless-routing", "_blank");
212+
} else {
213+
gotoState({
214+
embedType: embed.type as EmbedType,
215+
});
216+
}
213217
}}>
214218
<div className="bg-default order-none box-border flex-none rounded-md border border-solid transition dark:bg-transparent dark:invert">
215219
{embed.illustration}

packages/features/embed/RoutingFormEmbed.tsx

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,72 @@
11
import type { ComponentProps } from "react";
22

33
import { EmbedDialog, EmbedButton } from "@calcom/features/embed/Embed";
4+
import { IS_CALCOM } from "@calcom/lib/constants";
5+
import { useLocale } from "@calcom/lib/hooks/useLocale";
46
import { trpc } from "@calcom/trpc/react";
57

68
import { tabs } from "./lib/EmbedTabs";
79
import { useEmbedTypes } from "./lib/hooks";
810

911
export const RoutingFormEmbedDialog = () => {
1012
const types = useEmbedTypes();
13+
const { t } = useLocale();
1114
const { data: user } = trpc.viewer.me.get.useQuery();
1215
const routingFormTypes = types.filter((type) => type.type !== "email");
16+
17+
// Add the headless option specifically for routing forms
18+
const headlessType = {
19+
title: t("use_my_own_form"),
20+
subtitle: t("use_our_headless_routing_api"),
21+
type: "headless",
22+
illustration: (
23+
<svg
24+
width="100%"
25+
height="100%"
26+
className="rounded-md"
27+
viewBox="0 0 308 265"
28+
fill="none"
29+
xmlns="http://www.w3.org/2000/svg">
30+
<path
31+
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
32+
fill="white"
33+
/>
34+
<rect x="24" width="260" height="38.5" rx="6" fill="#F3F4F6" />
35+
<rect x="24" y="50.5" width="139" height="163" rx="6" fill="#F8F8F8" />
36+
<g opacity="0.8">
37+
<rect x="42" y="74" width="20" height="20" rx="2" fill="#374151" />
38+
<path
39+
d="M48 81L52 85L56 81"
40+
stroke="white"
41+
strokeWidth="2"
42+
strokeLinecap="round"
43+
strokeLinejoin="round"
44+
/>
45+
</g>
46+
<rect x="48" y="106" width="80" height="8" rx="6" fill="#F3F4F6" />
47+
<rect x="48" y="118" width="48" height="4" rx="6" fill="#F3F4F6" />
48+
<rect x="48" y="130" width="64" height="4" rx="6" fill="#F3F4F6" />
49+
<rect x="48" y="142" width="32" height="4" rx="6" fill="#F3F4F6" />
50+
<rect x="48" y="160" width="72" height="6" rx="3" fill="#292929" />
51+
<rect x="176" y="50.5" width="108" height="164" rx="6" fill="#F3F4F6" />
52+
<text x="220" y="120" textAnchor="middle" className="fill-gray-400" fontSize="8">
53+
API
54+
</text>
55+
<rect x="200" y="125" width="40" height="2" rx="1" fill="#9CA3AF" />
56+
<rect x="200" y="130" width="32" height="2" rx="1" fill="#9CA3AF" />
57+
<rect x="200" y="135" width="36" height="2" rx="1" fill="#9CA3AF" />
58+
<rect x="24" y="226.5" width="260" height="38.5" rx="6" fill="#F3F4F6" />
59+
</svg>
60+
),
61+
};
62+
63+
const routingFormTypesWithHeadless = IS_CALCOM
64+
? [...routingFormTypes, headlessType]
65+
: routingFormTypes;
66+
1367
return (
1468
<EmbedDialog
15-
types={routingFormTypes}
69+
types={routingFormTypesWithHeadless}
1670
tabs={tabs}
1771
eventTypeHideOptionDisabled={true}
1872
defaultBrandColor={user ? { brandColor: user.brandColor, darkBrandColor: user.darkBrandColor } : null}

packages/features/embed/lib/EmbedCodes.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ export default function MyApp() {
113113
>Click me</button>;
114114
};`;
115115
},
116+
headless: () => {
117+
return null;
118+
},
116119
},
117120
"react-atom": {
118121
inline: ({
@@ -230,17 +233,22 @@ export default function Booker( props : BookerProps ) {
230233
);
231234
};`;
232235
},
236+
headless: () => {
237+
return null;
238+
},
233239
},
234240
HTML: {
235241
inline: ({
236242
calLink,
237243
uiInstructionCode,
238244
previewState,
245+
embedCalOrigin,
239246
namespace,
240247
}: {
241248
calLink: string;
242249
uiInstructionCode: string;
243250
previewState: PreviewState["inline"];
251+
embedCalOrigin: string;
244252
namespace: string;
245253
}) => {
246254
return code`${getApiNameForVanillaJsSnippet({ namespace, mainApiName: "Cal" })}("inline", {
@@ -251,16 +259,17 @@ export default function Booker( props : BookerProps ) {
251259
252260
${uiInstructionCode}`;
253261
},
254-
255262
"floating-popup": ({
256263
calLink,
257264
uiInstructionCode,
258265
previewState,
266+
embedCalOrigin,
259267
namespace,
260268
}: {
261269
calLink: string;
262270
uiInstructionCode: string;
263271
previewState: PreviewState["floatingPopup"];
272+
embedCalOrigin: string;
264273
namespace: string;
265274
}) => {
266275
const floatingButtonArg = JSON.stringify({
@@ -277,11 +286,13 @@ export default function Booker( props : BookerProps ) {
277286
calLink,
278287
uiInstructionCode,
279288
previewState,
289+
embedCalOrigin,
280290
namespace,
281291
}: {
282292
calLink: string;
283293
uiInstructionCode: string;
284294
previewState: PreviewState["elementClick"];
295+
embedCalOrigin: string;
285296
namespace: string;
286297
}) => {
287298
return code`
@@ -292,6 +303,9 @@ export default function Booker( props : BookerProps ) {
292303
293304
${uiInstructionCode}`;
294305
},
306+
headless: () => {
307+
return null;
308+
},
295309
},
296310
};
297311

packages/features/embed/lib/EmbedTabs.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ const getEmbedTypeSpecificString = ({
283283
...codeGeneratorInput,
284284
previewState: previewState.elementClick,
285285
});
286+
} else if (embedType === "headless") {
287+
return frameworkCodes[embedType]();
286288
}
287289
return "";
288290
};

packages/features/embed/types/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Brand } from "@calcom/types/utils";
33
import type { tabs } from "../lib/EmbedTabs";
44
import type { useEmbedTypes } from "../lib/hooks";
55

6-
export type EmbedType = "inline" | "floating-popup" | "element-click" | "email";
6+
export type EmbedType = "inline" | "floating-popup" | "element-click" | "email" | "headless";
77
type EmbedConfig = {
88
layout?: BookerLayouts;
99
theme?: Theme;

0 commit comments

Comments
 (0)