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:
Hariom Balhara
2023-08-02 13:03:22 -07:00
committed by GitHub
co-authored by zomars
parent a56b19e618
commit 1b6d1b3a5a
3 changed files with 65 additions and 28 deletions
+49 -18
View File
@@ -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(() => {
+13 -9
View File
@@ -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 {};