fix: embed non-transparent dark background on success page (#9085)
* Fix colorscheme dark on success page due to embed not detected properly there * Use calNamespace in getEmbediframe * Fix missing variable * Update basic.e2e.ts --------- Co-authored-by: Omar López <zomars@me.com>
This commit is contained in:
co-authored by
Omar López
parent
b0c5b629d7
commit
6308955e89
@@ -1133,12 +1133,7 @@ export const EmbedDialog = () => {
|
||||
const router = useRouter();
|
||||
const embedUrl: string = router.query.embedUrl as string;
|
||||
return (
|
||||
<Dialog
|
||||
name="embed"
|
||||
clearQueryParamsOnClose={queryParamsForDialog}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) window.resetEmbedStatus();
|
||||
}}>
|
||||
<Dialog name="embed" clearQueryParamsOnClose={queryParamsForDialog}>
|
||||
{!router.query.embedType ? (
|
||||
<ChooseEmbedTypesDialogContent />
|
||||
) : (
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
import type { EmbedThemeConfig } from "./embed-iframe";
|
||||
|
||||
export default function EmbedInitIframe() {
|
||||
if (typeof window === "undefined" || window.isEmbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const calEmbedMode = typeof new URL(document.URL).searchParams.get("embed") === "string";
|
||||
const embedNameSpaceFromQueryParam = new URL(document.URL).searchParams.get("embed");
|
||||
|
||||
/* Iframe Name */
|
||||
window.name.includes("cal-embed");
|
||||
// Namespace is initially set in query param `embed` but the query param might get lost during soft navigation
|
||||
// So, we also check for the namespace in `window.name` which is set when iframe is created by embed.ts and persists for the duration of iframe's life
|
||||
// Note that, window.name isn't lost during hard navigation as well. Though, hard navigation isn't something that would happen in the app, but it's critical to be able to detect embed mode even after that(just in case)
|
||||
// We might just use window.name but if just in case something resets the `window.name`, we will still have the namespace in query param
|
||||
const embedNamespace =
|
||||
typeof embedNameSpaceFromQueryParam === "string"
|
||||
? embedNameSpaceFromQueryParam
|
||||
: window.name.replace(/cal-embed=(.*)/, "$1").trim();
|
||||
|
||||
window.isEmbed = () => {
|
||||
// Once an embed mode always an embed mode
|
||||
return calEmbedMode;
|
||||
};
|
||||
|
||||
window.resetEmbedStatus = () => {
|
||||
try {
|
||||
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
|
||||
window.sessionStorage.removeItem("calEmbedMode");
|
||||
} catch (e) {}
|
||||
// By default namespace is "". That would also work if we just check the type of variable
|
||||
return typeof embedNamespace == "string";
|
||||
};
|
||||
|
||||
window.getEmbedTheme = () => {
|
||||
// Note that embedStore.theme is lost if hard navigation occurs.(Though, it isn't something that we expect to happen normally)
|
||||
if (window.CalEmbed.embedStore.theme) {
|
||||
// It is important to ensure that the theme is consistent during browsing so that ThemeProvider doesn't get different themes to show and it avoids theme switching.
|
||||
return window.CalEmbed.embedStore.theme;
|
||||
}
|
||||
const url = new URL(document.URL);
|
||||
return url.searchParams.get("theme") as "light" | "dark" | null;
|
||||
return url.searchParams.get("theme") as EmbedThemeConfig | null;
|
||||
};
|
||||
|
||||
window.getEmbedNamespace = () => {
|
||||
const url = new URL(document.URL);
|
||||
const namespace = url.searchParams.get("embed");
|
||||
return namespace;
|
||||
return embedNamespace;
|
||||
};
|
||||
|
||||
window.CalEmbed = window.CalEmbed || {};
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
<div id="namespaces-test">
|
||||
<div class="inline-embed-container" id="cal-booking-place-default">
|
||||
<h3>
|
||||
<a href="?only=ns:default">[Dark Theme][Guests(janedoe@example.com and test@example.com)]</a>
|
||||
<a href="?only=ns:default">[Dark Theme][Guests(janedoe@example.com and test@example.com)](Default Namespace)</a>
|
||||
</h3>
|
||||
<button onclick="Cal('ui',{theme:'light'})">Toggle to Light</button>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { GlobalCal, GlobalCalWithoutNs } from "./src/embed";
|
||||
import type { GlobalCal } from "./src/embed";
|
||||
|
||||
type A = GlobalCalWithoutNs;
|
||||
const Cal = window.Cal as GlobalCal;
|
||||
const callback = function (e) {
|
||||
const detail = e.detail;
|
||||
@@ -8,7 +7,7 @@ const callback = function (e) {
|
||||
};
|
||||
|
||||
const searchParams = new URL(document.URL).searchParams;
|
||||
const only = window.only;
|
||||
const only = searchParams.get("only");
|
||||
|
||||
if (only === "all" || only === "ns:default") {
|
||||
Cal("init", {
|
||||
|
||||
@@ -34,7 +34,15 @@ export const getBooking = async (bookingId: string) => {
|
||||
return booking;
|
||||
};
|
||||
|
||||
export const getEmbedIframe = async ({ page, pathname }: { page: Page; pathname: string }) => {
|
||||
export const getEmbedIframe = async ({
|
||||
calNamespace,
|
||||
page,
|
||||
pathname,
|
||||
}: {
|
||||
calNamespace: string;
|
||||
page: Page;
|
||||
pathname: string;
|
||||
}) => {
|
||||
// We can't seem to access page.frame till contentWindow is available. So wait for that.
|
||||
const iframeReady = await page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
@@ -66,7 +74,7 @@ export const getEmbedIframe = async ({ page, pathname }: { page: Page; pathname:
|
||||
|
||||
// We just verified that iframeReady is true here, so obviously embedIframe is not null
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const embedIframe = page.frame("cal-embed")!;
|
||||
const embedIframe = page.frame(`cal-embed=${calNamespace}`)!;
|
||||
const u = new URL(embedIframe.url());
|
||||
if (u.pathname === pathname + "/embed") {
|
||||
return embedIframe;
|
||||
|
||||
@@ -32,7 +32,7 @@ async function bookFirstFreeUserEventThroughEmbed({
|
||||
|
||||
await embedButtonLocator.click();
|
||||
|
||||
const embedIframe = await getEmbedIframe({ page, pathname: "/free" });
|
||||
const embedIframe = await getEmbedIframe({ calNamespace, page, pathname: "/free" });
|
||||
|
||||
await expect(embedIframe).toBeEmbedCalLink(calNamespace, getActionFiredDetails, {
|
||||
pathname: "/free",
|
||||
@@ -58,12 +58,12 @@ test.describe("Popup Tests", () => {
|
||||
const calNamespace = "prerendertestLightTheme";
|
||||
await addEmbedListeners(calNamespace);
|
||||
await page.goto("/?only=prerender-test");
|
||||
let embedIframe = await getEmbedIframe({ page, pathname: "/free" });
|
||||
let embedIframe = await getEmbedIframe({ calNamespace, page, pathname: "/free" });
|
||||
expect(embedIframe).toBeFalsy();
|
||||
|
||||
await page.click('[data-cal-link="free?light&popup"]');
|
||||
|
||||
embedIframe = await getEmbedIframe({ page, pathname: "/free" });
|
||||
embedIframe = await getEmbedIframe({ calNamespace, page, pathname: "/free" });
|
||||
|
||||
await expect(embedIframe).toBeEmbedCalLink(calNamespace, getActionFiredDetails, {
|
||||
pathname: "/free",
|
||||
@@ -93,7 +93,7 @@ test.describe("Popup Tests", () => {
|
||||
await page.goto(`/?popupRescheduleId=${booking.uid}`);
|
||||
await page.click('[data-cal-namespace="popupReschedule"]');
|
||||
|
||||
const embedIframe = await getEmbedIframe({ page, pathname: booking.eventSlug });
|
||||
const embedIframe = await getEmbedIframe({ calNamespace, page, pathname: booking.eventSlug });
|
||||
if (!embedIframe) {
|
||||
throw new Error("Embed iframe not found");
|
||||
}
|
||||
@@ -117,12 +117,20 @@ test.describe("Popup Tests", () => {
|
||||
const calNamespace = "routingFormAuto";
|
||||
await addEmbedListeners(calNamespace);
|
||||
await page.goto("/?only=prerender-test");
|
||||
let embedIframe = await getEmbedIframe({ page, pathname: "/forms/948ae412-d995-4865-875a-48302588de03" });
|
||||
let embedIframe = await getEmbedIframe({
|
||||
calNamespace,
|
||||
page,
|
||||
pathname: "/forms/948ae412-d995-4865-875a-48302588de03",
|
||||
});
|
||||
expect(embedIframe).toBeFalsy();
|
||||
await page.click(
|
||||
`[data-cal-namespace=${calNamespace}][data-cal-link="forms/948ae412-d995-4865-875a-48302588de03"]`
|
||||
);
|
||||
embedIframe = await getEmbedIframe({ page, pathname: "/forms/948ae412-d995-4865-875a-48302588de03" });
|
||||
embedIframe = await getEmbedIframe({
|
||||
calNamespace,
|
||||
page,
|
||||
pathname: "/forms/948ae412-d995-4865-875a-48302588de03",
|
||||
});
|
||||
if (!embedIframe) {
|
||||
throw new Error("Routing Form embed iframe not found");
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ test("Inline Iframe - Configured with Dark Theme", async ({
|
||||
await deleteAllBookingsByEmail("embed-user@example.com");
|
||||
await addEmbedListeners("");
|
||||
await page.goto("/?only=ns:default");
|
||||
const embedIframe = await getEmbedIframe({ page, pathname: "/pro" });
|
||||
expect(embedIframe).toBeEmbedCalLink("", getActionFiredDetails, {
|
||||
const calNamespace = "";
|
||||
const embedIframe = await getEmbedIframe({ calNamespace, page, pathname: "/pro" });
|
||||
expect(embedIframe).toBeEmbedCalLink(calNamespace, getActionFiredDetails, {
|
||||
pathname: "/pro",
|
||||
searchParams: {
|
||||
theme: "dark",
|
||||
|
||||
@@ -11,7 +11,8 @@ type Theme = "dark" | "light";
|
||||
export type EmbedThemeConfig = Theme | "auto";
|
||||
export type UiConfig = {
|
||||
hideEventTypeDetails?: boolean;
|
||||
theme?: EmbedThemeConfig;
|
||||
// If theme not provided we would get null
|
||||
theme?: EmbedThemeConfig | null;
|
||||
styles?: EmbedStyles & EmbedNonStylesConfig;
|
||||
//TODO: Extract from tailwind the list of all custom variables and support them in auto-completion as well as runtime validation. Followup with listing all variables in Embed Snippet Generator UI.
|
||||
cssVarsPerTheme?: Record<Theme, Record<string, string>>;
|
||||
@@ -46,9 +47,8 @@ declare global {
|
||||
};
|
||||
CalComPageStatus: string;
|
||||
isEmbed?: () => boolean;
|
||||
resetEmbedStatus: () => void;
|
||||
getEmbedNamespace: () => string | null;
|
||||
getEmbedTheme: () => "dark" | "light" | null;
|
||||
getEmbedTheme: () => EmbedThemeConfig | null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ if (isBrowser) {
|
||||
// Exposes certain global variables/fns that are used by the app to get interface with the embed.
|
||||
embedInit();
|
||||
const url = new URL(document.URL);
|
||||
embedStore.theme = window?.getEmbedTheme?.() as UiConfig["theme"];
|
||||
embedStore.theme = window?.getEmbedTheme?.();
|
||||
if (url.searchParams.get("prerender") !== "true" && window?.isEmbed?.()) {
|
||||
log("Initializing embed-iframe");
|
||||
// HACK
|
||||
|
||||
@@ -215,7 +215,7 @@ export class Cal {
|
||||
}) {
|
||||
const iframe = (this.iframe = document.createElement("iframe"));
|
||||
iframe.className = "cal-embed";
|
||||
iframe.name = "cal-embed";
|
||||
iframe.name = `cal-embed=${this.namespace}`;
|
||||
const config = this.getConfig();
|
||||
const { iframeAttrs, ...restQueryObject } = queryObject;
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ test.describe("Inline Embed", () => {
|
||||
//TODO: Do it with page.goto automatically
|
||||
await addEmbedListeners("");
|
||||
await page.goto("/");
|
||||
const embedIframe = await getEmbedIframe({ page, pathname: "/pro" });
|
||||
const calNamespace = "";
|
||||
const embedIframe = await getEmbedIframe({ calNamespace, page, pathname: "/pro" });
|
||||
expect(embedIframe).toBeEmbedCalLink("", getActionFiredDetails, {
|
||||
pathname: "/pro",
|
||||
searchParams: {
|
||||
|
||||
Reference in New Issue
Block a user