diff --git a/packages/embeds/embed-core/playground.ts b/packages/embeds/embed-core/playground.ts index f6986c8b0f2d22..4eb4141f65992b 100644 --- a/packages/embeds/embed-core/playground.ts +++ b/packages/embeds/embed-core/playground.ts @@ -1,7 +1,8 @@ -import type { GlobalCal } from "./src/embed"; +import type { GlobalCal, EmbedEvent } from "./src/embed"; const Cal = window.Cal as GlobalCal; -const callback = function (e) { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const callback = function (e: any) { const detail = e.detail; console.log("Event: ", e.type, detail); }; @@ -27,6 +28,7 @@ const only = searchParams.get("only"); const colorScheme = searchParams.get("color-scheme"); const prerender = searchParams.get("prerender"); +// @ts-expect-error We haven't defined ENABLE_FUTURE_ROUTES as it is a playground specific variable. window.ENABLE_FUTURE_ROUTES = searchParams.get("future-routes") === "true"; if (colorScheme) { @@ -469,10 +471,6 @@ if (only === "all" || only == "ns:monthView") { }, } ); - Cal.ns.monthView("on", { - action: "*", - callback, - }); } if (only === "all" || only == "ns:weekView") { @@ -532,3 +530,24 @@ if (only === "all" || only == "ns:columnView") { callback, }); } + +// Verifies that the type of e.detail.data is valid. type-check will fail if we accidentally break it. +const bookingSuccessfulV2Callback = (e: EmbedEvent<"bookingSuccessfulV2">) => { + const data = e.detail.data; + console.log("bookingSuccessfulV2", { + endTime: data.endTime, + startTime: data.startTime, + title: data.title, + }); + + // Remove the event listener after it is fired once + Cal("off", { + action: "bookingSuccessfulV2", + callback: bookingSuccessfulV2Callback, + }); +}; + +Cal("on", { + action: "bookingSuccessfulV2", + callback: bookingSuccessfulV2Callback, +}); diff --git a/packages/embeds/embed-core/src/embed.ts b/packages/embeds/embed-core/src/embed.ts index 5ad5554fc98dce..10a947cf6b5e33 100644 --- a/packages/embeds/embed-core/src/embed.ts +++ b/packages/embeds/embed-core/src/embed.ts @@ -10,6 +10,10 @@ import allCss from "./tailwind.generated.css?inline"; import type { UiConfig } from "./types"; export type { PrefillAndIframeAttrsConfig } from "./embed-iframe"; + +// Exporting for consumption by @calcom/embed-core user +export type { EmbedEvent } from "./sdk-action-manager"; + // eslint-disable-next-line @typescript-eslint/no-explicit-any type Rest = T extends [any, ...infer U] ? U : never; export type Message = { @@ -141,10 +145,20 @@ function withColorScheme( return queryObject; } +type allPossibleCallbacksAndActions = { + [K in keyof EventDataMap]: { + action: K; + callback: (arg0: CustomEvent>) => void; + }; +}[keyof EventDataMap]; + type SingleInstructionMap = { - // TODO: This makes api("on", {}) loose it's generic type. Find a way to fix it. - // e.g. api("on", { action: "__dimensionChanged", callback: (e) => { /* `e.detail.data` has all possible values for all events/actions */} }); - [K in keyof CalApi]: CalApi[K] extends (...args: never[]) => void ? [K, ...Parameters] : never; + on: ["on", allPossibleCallbacksAndActions]; + off: ["off", allPossibleCallbacksAndActions]; +} & { + [K in Exclude]: CalApi[K] extends (...args: never[]) => void + ? [K, ...Parameters] + : never; }; type SingleInstruction = SingleInstructionMap[keyof SingleInstructionMap]; diff --git a/packages/embeds/embed-core/src/sdk-action-manager.ts b/packages/embeds/embed-core/src/sdk-action-manager.ts index a3804059f30ec3..28d3b709247843 100644 --- a/packages/embeds/embed-core/src/sdk-action-manager.ts +++ b/packages/embeds/embed-core/src/sdk-action-manager.ts @@ -117,6 +117,8 @@ export type EventData = { }; }[T]; +export type EmbedEvent = CustomEvent>; + export class SdkActionManager { namespace: Namespace; diff --git a/packages/embeds/embed-core/tsconfig.json b/packages/embeds/embed-core/tsconfig.json index 05fc61c2441aef..b8e3b55b65e7d5 100644 --- a/packages/embeds/embed-core/tsconfig.json +++ b/packages/embeds/embed-core/tsconfig.json @@ -12,6 +12,6 @@ "@calcom/embed-snippet": ["../embed-snippet/src"] } }, - "include": ["src", "env.d.ts", "index.ts"], + "include": ["src", "env.d.ts", "index.ts", "*.ts"], "exclude": ["dist", "build", "node_modules"] } diff --git a/packages/embeds/embed-react/inline.tsx b/packages/embeds/embed-react/inline.tsx index a5e704f1cb8b45..d9d070b9cb2fa6 100644 --- a/packages/embeds/embed-react/inline.tsx +++ b/packages/embeds/embed-react/inline.tsx @@ -8,7 +8,7 @@ import ReactDom from "react-dom"; // Because we don't import from @calcom/embed-react, this file isn't able to test if the build is successful or not and thus npm package would work or not correctly. // There are tests in test/built which verifiy that the types from built package are correctly generated and exported correctly. -import Cal, { getCalApi } from "./src/index"; +import Cal, { getCalApi, type EmbedEvent } from "./src/index"; const api = getCalApi({ namespace: "inline", @@ -49,6 +49,27 @@ function App() { action: "*", callback, }); + + // Also, validates the type of e.detail.data as TS runs on this file + const bookingSuccessfulV2Callback = (e: EmbedEvent<"bookingSuccessfulV2">) => { + const data = e.detail.data; + console.log("bookingSuccessfulV2", { + endTime: data.endTime, + startTime: data.startTime, + title: data.title, + }); + + // Remove the event listener after it is fired once as I don't need it. + api("off", { + action: "bookingSuccessfulV2", + callback: bookingSuccessfulV2Callback, + }); + }; + + api("on", { + action: "bookingSuccessfulV2", + callback: bookingSuccessfulV2Callback, + }); }); }; }, []); diff --git a/packages/embeds/embed-react/src/index.ts b/packages/embeds/embed-react/src/index.ts index ae5fbc3a6e184a..a6a96716bb4899 100644 --- a/packages/embeds/embed-react/src/index.ts +++ b/packages/embeds/embed-react/src/index.ts @@ -5,6 +5,9 @@ import EmbedSnippet from "@calcom/embed-snippet"; import Cal from "./Cal"; +// Exporting for consumption by @calcom/embed-react user +export type { EmbedEvent } from "@calcom/embed-core"; + export function getCalApi(options?: { embedJsUrl?: string; namespace?: string; diff --git a/packages/embeds/embed-react/tsconfig.json b/packages/embeds/embed-react/tsconfig.json index ccbd96a5d86dcc..5d5e3df9943a8f 100644 --- a/packages/embeds/embed-react/tsconfig.json +++ b/packages/embeds/embed-react/tsconfig.json @@ -13,7 +13,7 @@ "@calcom/embed-snippet": ["../embed-snippet/src"] } }, - "include": ["src/**/*.ts", "src/**/*.tsx", "env.d.ts"], + "include": ["src/**/*.ts", "src/**/*.tsx", "env.d.ts", "*.tsx", "*.ts"], // Exclude "test" because that has `api.test.ts` which imports @calcom/embed-react which needs it to be built using this tsconfig.json first. Excluding it here prevents type-check from validating test folder "exclude": ["node_modules", "test"] }