fix: Embed Code Generator - Fixes 404 in preview of embed for orgs (#10417)
Co-authored-by: zomars <zomars@me.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import { useNonEmptyScheduleDays } from "@calcom/features/schedules";
|
||||
import { useSlotsForDate } from "@calcom/features/schedules/lib/use-schedule/useSlotsForDate";
|
||||
import { APP_NAME, CAL_URL, EMBED_LIB_URL, IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { weekdayToWeekIndex } from "@calcom/lib/date-fns";
|
||||
import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
@@ -54,8 +55,14 @@ const enum Theme {
|
||||
dark = "dark",
|
||||
}
|
||||
|
||||
const EMBED_CAL_ORIGIN = WEBAPP_URL;
|
||||
const EMBED_CAL_JS_URL = `${WEBAPP_URL}/embed/embed.js`;
|
||||
// Preview HTML and embed lib doesn't need org context. They are static per instance
|
||||
const EMBED_PREVIEW_HTML_URL = `${WEBAPP_URL}/embed/preview.html`;
|
||||
const embedLibUrl = EMBED_LIB_URL;
|
||||
|
||||
const useEmbedCalOrigin = () => {
|
||||
const bookerUrl = useBookerUrl();
|
||||
return bookerUrl;
|
||||
};
|
||||
|
||||
type PreviewState = {
|
||||
inline: {
|
||||
@@ -195,16 +202,18 @@ const getEmbedUIInstructionString = ({
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const Codes: Record<string, Record<string, (...args: any[]) => string>> = {
|
||||
const Codes = {
|
||||
react: {
|
||||
inline: ({
|
||||
calLink,
|
||||
uiInstructionCode,
|
||||
previewState,
|
||||
embedCalOrigin,
|
||||
}: {
|
||||
calLink: string;
|
||||
uiInstructionCode: string;
|
||||
previewState: PreviewState;
|
||||
embedCalOrigin: string;
|
||||
}) => {
|
||||
const width = getDimension(previewState.inline.width);
|
||||
const height = getDimension(previewState.inline.height);
|
||||
@@ -224,8 +233,8 @@ export default function MyApp() {
|
||||
${previewState.layout ? "config={{layout: '" + previewState.layout + "'}}" : ""}${
|
||||
IS_SELF_HOSTED
|
||||
? `
|
||||
calOrigin="${EMBED_CAL_ORIGIN}"
|
||||
calJsUrl="${EMBED_CAL_JS_URL}"`
|
||||
calOrigin="${embedCalOrigin}"
|
||||
calJsUrl="${embedLibUrl}"`
|
||||
: ""
|
||||
}
|
||||
/>;
|
||||
@@ -244,7 +253,7 @@ import { useEffect } from "react";
|
||||
export default function App() {
|
||||
useEffect(()=>{
|
||||
(async function () {
|
||||
const cal = await getCalApi(${IS_SELF_HOSTED ? `"${EMBED_CAL_JS_URL}"` : ""});
|
||||
const cal = await getCalApi(${IS_SELF_HOSTED ? `"${embedLibUrl}"` : ""});
|
||||
cal("floatingButton", ${floatingButtonArg});
|
||||
${uiInstructionCode}
|
||||
})();
|
||||
@@ -255,10 +264,12 @@ export default function App() {
|
||||
calLink,
|
||||
uiInstructionCode,
|
||||
previewState,
|
||||
embedCalOrigin,
|
||||
}: {
|
||||
calLink: string;
|
||||
uiInstructionCode: string;
|
||||
previewState: PreviewState;
|
||||
embedCalOrigin: string;
|
||||
}) => {
|
||||
return code`
|
||||
import { getCalApi } from "@calcom/embed-react";
|
||||
@@ -266,12 +277,12 @@ import { useEffect } from "react";
|
||||
export default function App() {
|
||||
useEffect(()=>{
|
||||
(async function () {
|
||||
const cal = await getCalApi(${IS_SELF_HOSTED ? `"${EMBED_CAL_JS_URL}"` : ""});
|
||||
const cal = await getCalApi(${IS_SELF_HOSTED ? `"${embedLibUrl}"` : ""});
|
||||
${uiInstructionCode}
|
||||
})();
|
||||
}, [])
|
||||
return <button
|
||||
data-cal-link="${calLink}"${IS_SELF_HOSTED ? `\ndata-cal-origin="${EMBED_CAL_ORIGIN}"` : ""}
|
||||
data-cal-link="${calLink}"${IS_SELF_HOSTED ? `\ndata-cal-origin="${embedCalOrigin}"` : ""}
|
||||
${`data-cal-config='${JSON.stringify({
|
||||
layout: previewState.layout,
|
||||
})}'`}
|
||||
@@ -327,7 +338,7 @@ ${uiInstructionCode}`;
|
||||
${uiInstructionCode}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
} satisfies Record<string, Record<string, (...args: any[]) => string>>;
|
||||
|
||||
type EmbedCommonProps = { embedType: EmbedType; calLink: string; previewState: PreviewState };
|
||||
|
||||
@@ -336,8 +347,10 @@ const getEmbedTypeSpecificString = ({
|
||||
embedType,
|
||||
calLink,
|
||||
previewState,
|
||||
embedCalOrigin,
|
||||
}: {
|
||||
embedFramework: EmbedFramework;
|
||||
embedCalOrigin: string;
|
||||
} & EmbedCommonProps) => {
|
||||
const frameworkCodes = Codes[embedFramework];
|
||||
if (!frameworkCodes) {
|
||||
@@ -376,23 +389,24 @@ const getEmbedTypeSpecificString = ({
|
||||
calLink,
|
||||
uiInstructionCode: getEmbedUIInstructionString(uiInstructionStringArg),
|
||||
previewState,
|
||||
embedCalOrigin,
|
||||
});
|
||||
} else if (embedType === "floating-popup") {
|
||||
const floatingButtonArg = {
|
||||
calLink,
|
||||
...(IS_SELF_HOSTED ? { calOrigin: EMBED_CAL_ORIGIN } : null),
|
||||
...(IS_SELF_HOSTED ? { calOrigin: embedCalOrigin } : null),
|
||||
...previewState.floatingPopup,
|
||||
};
|
||||
return frameworkCodes[embedType]({
|
||||
floatingButtonArg: JSON.stringify(floatingButtonArg),
|
||||
uiInstructionCode: getEmbedUIInstructionString(uiInstructionStringArg),
|
||||
previewState,
|
||||
});
|
||||
} else if (embedType === "element-click") {
|
||||
return frameworkCodes[embedType]({
|
||||
calLink,
|
||||
uiInstructionCode: getEmbedUIInstructionString(uiInstructionStringArg),
|
||||
previewState,
|
||||
embedCalOrigin,
|
||||
});
|
||||
}
|
||||
return "";
|
||||
@@ -829,6 +843,8 @@ const tabs = [
|
||||
Component: forwardRef<HTMLTextAreaElement | HTMLIFrameElement | null, EmbedCommonProps>(
|
||||
function EmbedHtml({ embedType, calLink, previewState }, ref) {
|
||||
const { t } = useLocale();
|
||||
const embedSnippetString = useGetEmbedSnippetString();
|
||||
const embedCalOrigin = useEmbedCalOrigin();
|
||||
if (ref instanceof Function || !ref) {
|
||||
return null;
|
||||
}
|
||||
@@ -857,8 +873,14 @@ const tabs = [
|
||||
)};overflow:scroll" id="my-cal-inline"></div>\n`
|
||||
: "") +
|
||||
`<script type="text/javascript">
|
||||
${getEmbedSnippetString()}
|
||||
${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previewState })}
|
||||
${embedSnippetString}
|
||||
${getEmbedTypeSpecificString({
|
||||
embedFramework: "HTML",
|
||||
embedType,
|
||||
calLink,
|
||||
previewState,
|
||||
embedCalOrigin,
|
||||
})}
|
||||
</script>
|
||||
<!-- Cal ${embedType} embed code ends -->`
|
||||
}
|
||||
@@ -876,6 +898,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
|
||||
type: "code",
|
||||
Component: forwardRef<HTMLTextAreaElement | HTMLIFrameElement | null, EmbedCommonProps>(
|
||||
function EmbedReact({ embedType, calLink, previewState }, ref) {
|
||||
const embedCalOrigin = useEmbedCalOrigin();
|
||||
const { t } = useLocale();
|
||||
if (ref instanceof Function || !ref) {
|
||||
return null;
|
||||
@@ -900,7 +923,13 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
|
||||
|
||||
/* If you are using npm */
|
||||
// npm install @calcom/embed-react
|
||||
${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, previewState })}
|
||||
${getEmbedTypeSpecificString({
|
||||
embedFramework: "react",
|
||||
embedType,
|
||||
calLink,
|
||||
previewState,
|
||||
embedCalOrigin,
|
||||
})}
|
||||
`}
|
||||
/>
|
||||
</>
|
||||
@@ -917,6 +946,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, prev
|
||||
{ calLink, embedType },
|
||||
ref
|
||||
) {
|
||||
const bookerUrl = useBookerUrl();
|
||||
if (ref instanceof Function || !ref) {
|
||||
return null;
|
||||
}
|
||||
@@ -930,17 +960,18 @@ ${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, prev
|
||||
className="h-[100vh] border"
|
||||
width="100%"
|
||||
height="100%"
|
||||
src={`${WEBAPP_URL}/embed/preview.html?embedType=${embedType}&calLink=${calLink}`}
|
||||
src={`${EMBED_PREVIEW_HTML_URL}?embedType=${embedType}&calLink=${calLink}&embedLibUrl=${embedLibUrl}&bookerUrl=${bookerUrl}`}
|
||||
/>
|
||||
);
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
function getEmbedSnippetString() {
|
||||
function useGetEmbedSnippetString() {
|
||||
const bookerUrl = useBookerUrl();
|
||||
// TODO: Import this string from @calcom/embed-snippet
|
||||
return `(function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; typeof namespace === "string" ? (cal.ns[namespace] = api) && p(api, ar) : p(cal, ar); return; } p(cal, ar); }; })(window, "${EMBED_LIB_URL}", "init");
|
||||
Cal("init", {origin:"${WEBAPP_URL}"});
|
||||
return `(function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; typeof namespace === "string" ? (cal.ns[namespace] = api) && p(api, ar) : p(cal, ar); return; } p(cal, ar); }; })(window, "${embedLibUrl}", "init");
|
||||
Cal("init", {origin:"${bookerUrl}"});
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ import { test } from "@calcom/web/playwright/lib/fixtures";
|
||||
|
||||
test.describe("Preview", () => {
|
||||
test("Preview - embed-core should load", async ({ page }) => {
|
||||
await page.goto("http://localhost:3000/embed/preview.html");
|
||||
await page.goto(
|
||||
"http://localhost:3000/embed/preview.html?embedLibUrl=http://localhost:3000/embed/embed.js&bookerUrl=http://localhost:3000&calLink=pro/30min"
|
||||
);
|
||||
const libraryLoaded = await page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
setInterval(() => {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const WEBAPP_URL =
|
||||
import.meta.env.EMBED_PUBLIC_WEBAPP_URL || `https://${import.meta.env.EMBED_PUBLIC_VERCEL_URL}`;
|
||||
const EMBED_LIB_URL = import.meta.env.EMBED_PUBLIC_EMBED_LIB_URL || `${WEBAPP_URL}/embed/embed.js`;
|
||||
|
||||
const searchParams = new URL(document.URL).searchParams;
|
||||
const embedType = searchParams.get("embedType");
|
||||
const calLink = searchParams.get("calLink");
|
||||
const bookerUrl = searchParams.get("bookerUrl");
|
||||
const embedLibUrl = searchParams.get("embedLibUrl");
|
||||
if (!bookerUrl || !embedLibUrl) {
|
||||
throw new Error('Can\'t Preview: Missing "bookerUrl" or "embedLibUrl" query parameter');
|
||||
}
|
||||
// Install Cal Embed Code Snippet
|
||||
(function (C, A, L) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -36,17 +40,15 @@ const EMBED_LIB_URL = import.meta.env.EMBED_PUBLIC_EMBED_LIB_URL || `${WEBAPP_UR
|
||||
}
|
||||
p(cal, ar);
|
||||
};
|
||||
})(window, EMBED_LIB_URL, "init");
|
||||
})(window, embedLibUrl, "init");
|
||||
|
||||
const previewWindow = window;
|
||||
previewWindow.Cal.fingerprint = import.meta.env.EMBED_PUBLIC_EMBED_FINGER_PRINT as string;
|
||||
|
||||
previewWindow.Cal("init", {
|
||||
origin: WEBAPP_URL,
|
||||
origin: bookerUrl,
|
||||
});
|
||||
const searchParams = new URL(document.URL).searchParams;
|
||||
const embedType = searchParams.get("embedType");
|
||||
const calLink = searchParams.get("calLink");
|
||||
|
||||
if (!calLink) {
|
||||
throw new Error('Missing "calLink" query parameter');
|
||||
}
|
||||
@@ -114,3 +116,5 @@ function makePreviewPageUseSystemPreference() {
|
||||
|
||||
// This makes preview page behave like a website that has system preference enabled. This provides a better experience of preview when user switch their system theme to dark
|
||||
makePreviewPageUseSystemPreference();
|
||||
|
||||
export {};
|
||||
|
||||
Reference in New Issue
Block a user