fix: Embed - Better support for layout config(without flash of default toggle) (#9714)
This commit is contained in:
@@ -10,7 +10,7 @@ import { components } from "react-select";
|
||||
|
||||
import type { BookerLayout } from "@calcom/features/bookings/Booker/types";
|
||||
import { useFlagMap } from "@calcom/features/flags/context/provider";
|
||||
import { APP_NAME, EMBED_LIB_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { APP_NAME, EMBED_LIB_URL, IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
import {
|
||||
@@ -38,13 +38,21 @@ const enum Theme {
|
||||
dark = "dark",
|
||||
}
|
||||
|
||||
const EMBED_CAL_ORIGIN = WEBAPP_URL;
|
||||
const EMBED_CAL_JS_URL = `${WEBAPP_URL}/embed/embed.js`;
|
||||
|
||||
type PreviewState = {
|
||||
inline: {
|
||||
width: string;
|
||||
height: string;
|
||||
};
|
||||
theme: Theme;
|
||||
floatingPopup: Record<string, string | boolean | undefined>;
|
||||
floatingPopup: {
|
||||
config?: {
|
||||
layout: BookerLayouts;
|
||||
};
|
||||
[key: string]: string | boolean | undefined | Record<string, string>;
|
||||
};
|
||||
elementClick: Record<string, string>;
|
||||
palette: {
|
||||
brandColor: string;
|
||||
@@ -175,14 +183,24 @@ const Codes: Record<string, Record<string, (...args: any[]) => string>> = {
|
||||
return code`
|
||||
import Cal, { getCalApi } from "@calcom/embed-react";
|
||||
import { useEffect } from "react";
|
||||
function MyComponent() {
|
||||
export default function MyApp() {
|
||||
useEffect(()=>{
|
||||
(async function () {
|
||||
const cal = await getCalApi();
|
||||
${uiInstructionCode}
|
||||
})();
|
||||
}, [])
|
||||
return <Cal calLink="${calLink}" style={{width:"${width}",height:"${height}",overflow:"scroll"}} />;
|
||||
return <Cal
|
||||
calLink="${calLink}"
|
||||
style={{width:"${width}",height:"${height}",overflow:"scroll"}}
|
||||
${previewState.layout ? "config={{layout: '" + previewState.layout + "'}}" : ""}${
|
||||
IS_SELF_HOSTED
|
||||
? `
|
||||
calOrigin="${EMBED_CAL_ORIGIN}"
|
||||
calJsUrl="${EMBED_CAL_JS_URL}"`
|
||||
: ""
|
||||
}
|
||||
/>;
|
||||
};`;
|
||||
},
|
||||
"floating-popup": ({
|
||||
@@ -193,38 +211,60 @@ function MyComponent() {
|
||||
uiInstructionCode: string;
|
||||
}) => {
|
||||
return code`
|
||||
import Cal, { getCalApi } from "@calcom/embed-react";
|
||||
import { getCalApi } from "@calcom/embed-react";
|
||||
import { useEffect } from "react";
|
||||
function MyComponent() {
|
||||
export default function App() {
|
||||
useEffect(()=>{
|
||||
(async function () {
|
||||
const cal = await getCalApi();
|
||||
const cal = await getCalApi(${IS_SELF_HOSTED ? `"${EMBED_CAL_JS_URL}"` : ""});
|
||||
cal("floatingButton", ${floatingButtonArg});
|
||||
${uiInstructionCode}
|
||||
})();
|
||||
}, [])
|
||||
};`;
|
||||
},
|
||||
"element-click": ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => {
|
||||
"element-click": ({
|
||||
calLink,
|
||||
uiInstructionCode,
|
||||
previewState,
|
||||
}: {
|
||||
calLink: string;
|
||||
uiInstructionCode: string;
|
||||
previewState: PreviewState;
|
||||
}) => {
|
||||
return code`
|
||||
import Cal, { getCalApi } from "@calcom/embed-react";
|
||||
import { getCalApi } from "@calcom/embed-react";
|
||||
import { useEffect } from "react";
|
||||
function MyComponent() {
|
||||
export default function App() {
|
||||
useEffect(()=>{
|
||||
(async function () {
|
||||
const cal = await getCalApi();
|
||||
const cal = await getCalApi(${IS_SELF_HOSTED ? `"${EMBED_CAL_JS_URL}"` : ""});
|
||||
${uiInstructionCode}
|
||||
})();
|
||||
}, [])
|
||||
return <button data-cal-link="${calLink}" />;
|
||||
return <button
|
||||
data-cal-link="${calLink}"${IS_SELF_HOSTED ? `\ndata-cal-origin="${EMBED_CAL_ORIGIN}"` : ""}
|
||||
${`data-cal-config='${JSON.stringify({
|
||||
layout: previewState.layout,
|
||||
})}'`}
|
||||
>Click me</button>;
|
||||
};`;
|
||||
},
|
||||
},
|
||||
HTML: {
|
||||
inline: ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => {
|
||||
inline: ({
|
||||
calLink,
|
||||
uiInstructionCode,
|
||||
previewState,
|
||||
}: {
|
||||
calLink: string;
|
||||
uiInstructionCode: string;
|
||||
previewState: PreviewState;
|
||||
}) => {
|
||||
return code`Cal("inline", {
|
||||
elementOrSelector:"#my-cal-inline",
|
||||
calLink: "${calLink}"
|
||||
calLink: "${calLink}",
|
||||
layout: "${previewState.layout}"
|
||||
});
|
||||
|
||||
${uiInstructionCode}`;
|
||||
@@ -240,8 +280,22 @@ ${uiInstructionCode}`;
|
||||
return code`Cal("floatingButton", ${floatingButtonArg});
|
||||
${uiInstructionCode}`;
|
||||
},
|
||||
"element-click": ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => {
|
||||
return code`// Important: Make sure to add \`data-cal-link="${calLink}"\` attribute to the element you want to open Cal on click
|
||||
"element-click": ({
|
||||
calLink,
|
||||
uiInstructionCode,
|
||||
previewState,
|
||||
}: {
|
||||
calLink: string;
|
||||
uiInstructionCode: string;
|
||||
previewState: PreviewState;
|
||||
}) => {
|
||||
return code`
|
||||
// Important: Please add following attributes to the element you want to open Cal on click
|
||||
// \`data-cal-link="${calLink}"\`
|
||||
// \`data-cal-config='${JSON.stringify({
|
||||
layout: previewState.layout,
|
||||
})}'\`
|
||||
|
||||
${uiInstructionCode}`;
|
||||
},
|
||||
},
|
||||
@@ -298,6 +352,7 @@ const getEmbedTypeSpecificString = ({
|
||||
} else if (embedType === "floating-popup") {
|
||||
const floatingButtonArg = {
|
||||
calLink,
|
||||
...(IS_SELF_HOSTED ? { calOrigin: EMBED_CAL_ORIGIN } : null),
|
||||
...previewState.floatingPopup,
|
||||
};
|
||||
return frameworkCodes[embedType]({
|
||||
@@ -710,13 +765,13 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
height: "100%",
|
||||
},
|
||||
theme: Theme.auto,
|
||||
layout: BookerLayouts.MONTH_VIEW,
|
||||
floatingPopup: {},
|
||||
elementClick: {},
|
||||
hideEventTypeDetails: false,
|
||||
palette: {
|
||||
brandColor: "#000000",
|
||||
},
|
||||
layout: BookerLayouts.MONTH_VIEW,
|
||||
});
|
||||
|
||||
const close = () => {
|
||||
@@ -778,8 +833,8 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
name: "ui",
|
||||
arg: {
|
||||
theme: previewState.theme,
|
||||
hideEventTypeDetails: previewState.hideEventTypeDetails,
|
||||
layout: previewState.layout,
|
||||
hideEventTypeDetails: previewState.hideEventTypeDetails,
|
||||
styles: {
|
||||
branding: {
|
||||
...previewState.palette,
|
||||
@@ -1102,8 +1157,15 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
return;
|
||||
}
|
||||
setPreviewState((previewState) => {
|
||||
const config = {
|
||||
...(previewState.floatingPopup.config ?? {}),
|
||||
layout: option.value,
|
||||
};
|
||||
return {
|
||||
...previewState,
|
||||
floatingPopup: {
|
||||
config,
|
||||
},
|
||||
layout: option.value,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -100,7 +100,7 @@ plugins.push(withAxiom);
|
||||
const userTypeRouteRegExp = `/:user((?!${pages.join("/|")})[^/]*)/:type((?!book$)[^/]+)`;
|
||||
const teamTypeRouteRegExp = "/team/:slug/:type((?!book$)[^/]+)";
|
||||
const privateLinkRouteRegExp = "/d/:link/:slug((?!book$)[^/]+)";
|
||||
const embedUserTypeRouteRegExp = `/:user((?!${pages.join("|")}).*)/:type/embed`;
|
||||
const embedUserTypeRouteRegExp = `/:user((?!${pages.join("/|")})[^/]*)/:type/embed`;
|
||||
const embedTeamTypeRouteRegExp = "/team/:slug/:type/embed";
|
||||
|
||||
/** @type {import("next").NextConfig} */
|
||||
@@ -312,11 +312,11 @@ const nextConfig = {
|
||||
afterFiles.push(
|
||||
...[
|
||||
{
|
||||
source: `/:user((?!${pages.join("|")}).*)/:type/embed`,
|
||||
source: embedUserTypeRouteRegExp,
|
||||
destination: "/new-booker/:user/:type/embed",
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type/embed",
|
||||
source: embedTeamTypeRouteRegExp,
|
||||
destination: "/new-booker/team/:slug/:type/embed",
|
||||
},
|
||||
]
|
||||
|
||||
@@ -47,8 +47,8 @@ describe('next.config.js - RegExp', ()=>{
|
||||
// privateLinkRouteRegExp = "/d/:link/:slug((?!book$)[^/]+)";
|
||||
privateLinkRouteRegExp = getRegExpFromNextJsRewriteRegExp("/d/(?<link>[^/]+)/(?<slug>((?!book$)[^/]+))");
|
||||
|
||||
// embedUserTypeRouteRegExp = `/:user((?!${pages.join("|")}).*)/:type/embed`;
|
||||
embedUserTypeRouteRegExp = getRegExpFromNextJsRewriteRegExp(`/(?<user>((?!${pages.join("|")}).*))/(?<type>[^/]+)/embed`);
|
||||
// embedUserTypeRouteRegExp = `/:user((?!${pages.join("/|")})[^/]*)/:type/embed`;
|
||||
embedUserTypeRouteRegExp = getRegExpFromNextJsRewriteRegExp(`/(?<user>((?!${pages.join("/|")})[^/]*))/(?<type>[^/]+)/embed`);
|
||||
|
||||
// embedTeamTypeRouteRegExp = "/team/:slug/:type/embed";
|
||||
embedTeamTypeRouteRegExp = getRegExpFromNextJsRewriteRegExp("/team/(?<slug>[^/]+)/(?<type>[^/]+)/embed");
|
||||
@@ -94,6 +94,12 @@ describe('next.config.js - RegExp', ()=>{
|
||||
type:'30'
|
||||
})
|
||||
|
||||
// Edgecase of username starting with team also works
|
||||
expect(embedUserTypeRouteRegExp.exec('/teampro/30/embed')?.groups).toContain({
|
||||
user: 'teampro',
|
||||
type: '30'
|
||||
})
|
||||
|
||||
expect(teamTypeRouteRegExp.exec('/team/seeded/30')?.groups).toContain({
|
||||
slug: 'seeded',
|
||||
type: '30'
|
||||
|
||||
@@ -168,7 +168,9 @@
|
||||
<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>
|
||||
|
||||
<button onclick="Cal('ui',{layout:'week_view'})">Toggle to Week View</button>
|
||||
<button onclick="Cal('ui',{layout:'month_view'})">Toggle to Month View</button>
|
||||
<button onclick="Cal('ui',{layout:'column_view'})">Toggle to Column View</button>
|
||||
<i class="last-action"> You would see last Booking page action in my place </i>
|
||||
<div>
|
||||
<div class="place" style="width: 100%"></div>
|
||||
@@ -253,6 +255,14 @@
|
||||
<i>Note that one of the embeds would stay in loading state as they are using the same namespace and it is not supported to have more than 1 embeds using same namespace</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-embed-container" id="cal-booking-place-weekView">
|
||||
<h3><a href="?only=ns:weekView">Test Weekly View</a></h3>
|
||||
<div class="place" style="width: 100%"></div>
|
||||
</div>
|
||||
<div class="inline-embed-container" id="cal-booking-place-columnView">
|
||||
<h3><a href="?only=ns:columnView">Test Column View</a></h3>
|
||||
<div class="place" style="width: 100%"></div>
|
||||
</div>
|
||||
<script src="./playground.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -344,3 +344,59 @@ if (only === "all" || only == "ns:floatingButton") {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (only === "all" || only == "ns:weekView") {
|
||||
// Create a namespace "second". It can be accessed as Cal.ns.second with the exact same API as Cal
|
||||
Cal("init", "weekView", {
|
||||
debug: true,
|
||||
origin: "http://localhost:3000",
|
||||
});
|
||||
|
||||
Cal.ns.weekView(
|
||||
"inline",
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
{
|
||||
elementOrSelector: "#cal-booking-place-weekView .place",
|
||||
calLink: "pro/paid",
|
||||
config: {
|
||||
iframeAttrs: {
|
||||
id: "cal-booking-place-weekView-iframe",
|
||||
},
|
||||
layout: "week_view",
|
||||
},
|
||||
}
|
||||
);
|
||||
Cal.ns.weekView("on", {
|
||||
action: "*",
|
||||
callback,
|
||||
});
|
||||
}
|
||||
|
||||
if (only === "all" || only == "ns:columnView") {
|
||||
// Create a namespace "second". It can be accessed as Cal.ns.second with the exact same API as Cal
|
||||
Cal("init", "columnView", {
|
||||
debug: true,
|
||||
origin: "http://localhost:3000",
|
||||
});
|
||||
|
||||
Cal.ns.columnView(
|
||||
"inline",
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
{
|
||||
elementOrSelector: "#cal-booking-place-columnView .place",
|
||||
calLink: "pro/paid",
|
||||
config: {
|
||||
iframeAttrs: {
|
||||
id: "cal-booking-place-columnView-iframe",
|
||||
},
|
||||
layout: "column_view",
|
||||
},
|
||||
}
|
||||
);
|
||||
Cal.ns.columnView("on", {
|
||||
action: "*",
|
||||
callback,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { CSSProperties } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import type { BookerStore } from "@calcom/features/bookings/Booker/store";
|
||||
import type { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
import { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import type { Message } from "./embed";
|
||||
import { sdkActionManager } from "./sdk-event";
|
||||
@@ -23,6 +23,9 @@ export type UiConfig = {
|
||||
type SetStyles = React.Dispatch<React.SetStateAction<EmbedStyles>>;
|
||||
type setNonStylesConfig = React.Dispatch<React.SetStateAction<EmbedNonStylesConfig>>;
|
||||
|
||||
/**
|
||||
* This is in-memory persistence needed so that when user browses through the embed, the configurations from the instructions aren't lost.
|
||||
*/
|
||||
const embedStore = {
|
||||
// Store all embed styles here so that as and when new elements are mounted, styles can be applied to it.
|
||||
styles: {} as EmbedStyles | undefined,
|
||||
@@ -37,7 +40,11 @@ const embedStore = {
|
||||
setTheme: undefined as ((arg0: EmbedThemeConfig) => void) | undefined,
|
||||
theme: undefined as UiConfig["theme"],
|
||||
uiConfig: undefined as Omit<UiConfig, "styles" | "theme"> | undefined,
|
||||
setUiConfig: undefined as ((arg0: UiConfig) => void) | undefined,
|
||||
/**
|
||||
* We maintain a list of all setUiConfig setters that are in use at the moment so that we can update all those components.
|
||||
*/
|
||||
setUiConfig: [] as ((arg0: UiConfig) => void)[],
|
||||
layout: BookerLayouts,
|
||||
};
|
||||
|
||||
declare global {
|
||||
@@ -183,9 +190,21 @@ export const useEmbedTheme = () => {
|
||||
return theme;
|
||||
};
|
||||
|
||||
/**
|
||||
* It serves following purposes
|
||||
* - Gives consistent values for ui config even after Soft Navigation. When a new React component mounts, it would ensure that the component get's the correct value of ui config
|
||||
* - Ensures that all the components using useEmbedUiConfig are updated when ui config changes. It is done by maintaining a list of all non-stale setters.
|
||||
*/
|
||||
export const useEmbedUiConfig = () => {
|
||||
const [uiConfig, setUiConfig] = useState(embedStore.uiConfig || {});
|
||||
embedStore.setUiConfig = setUiConfig;
|
||||
embedStore.setUiConfig.push(setUiConfig);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
const foundAtIndex = embedStore.setUiConfig.findIndex((item) => item === setUiConfig);
|
||||
// Keep removing the setters that are stale
|
||||
embedStore.setUiConfig.splice(foundAtIndex, 1);
|
||||
};
|
||||
});
|
||||
return uiConfig;
|
||||
};
|
||||
|
||||
@@ -307,19 +326,18 @@ const methods = {
|
||||
}
|
||||
}
|
||||
|
||||
// Set the value here so that if setUiConfig state isn't available and later it's defined,it uses this value
|
||||
embedStore.uiConfig = uiConfig;
|
||||
// Merge new values over the old values
|
||||
uiConfig = {
|
||||
...embedStore.uiConfig,
|
||||
...uiConfig,
|
||||
};
|
||||
|
||||
if (uiConfig.cssVarsPerTheme) {
|
||||
window.CalEmbed.applyCssVars(uiConfig.cssVarsPerTheme);
|
||||
}
|
||||
|
||||
if (embedStore.setUiConfig) {
|
||||
embedStore.setUiConfig(uiConfig);
|
||||
}
|
||||
|
||||
if (uiConfig.layout) {
|
||||
window.CalEmbed.setLayout?.(uiConfig.layout);
|
||||
runAllUiSetters(uiConfig);
|
||||
}
|
||||
|
||||
setEmbedStyles(stylesConfig || {});
|
||||
@@ -440,6 +458,13 @@ if (isBrowser) {
|
||||
log("Embed SDK loaded", { isEmbed: window?.isEmbed?.() || false });
|
||||
const url = new URL(document.URL);
|
||||
embedStore.theme = window?.getEmbedTheme?.();
|
||||
|
||||
embedStore.uiConfig = {
|
||||
// TODO: Add theme as well here
|
||||
// theme:
|
||||
layout: url.searchParams.get("layout") as BookerLayouts,
|
||||
};
|
||||
|
||||
if (url.searchParams.get("prerender") !== "true" && window?.isEmbed?.()) {
|
||||
log("Initializing embed-iframe");
|
||||
// HACK
|
||||
@@ -492,3 +517,9 @@ if (isBrowser) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function runAllUiSetters(uiConfig: UiConfig) {
|
||||
// Update EmbedStore so that when a new react component mounts, useEmbedUiConfig can get the persisted value from embedStore.uiConfig
|
||||
embedStore.uiConfig = uiConfig;
|
||||
embedStore.setUiConfig.forEach((setUiConfig) => setUiConfig(uiConfig));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/// <reference types="../env" />
|
||||
import type { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { FloatingButton } from "./FloatingButton/FloatingButton";
|
||||
import { Inline } from "./Inline/inline";
|
||||
import { ModalBox } from "./ModalBox/ModalBox";
|
||||
@@ -125,10 +127,21 @@ type SingleInstruction = SingleInstructionMap[keyof SingleInstructionMap];
|
||||
export type Instruction = SingleInstruction | SingleInstruction[];
|
||||
export type InstructionQueue = Instruction[];
|
||||
|
||||
/**
|
||||
* All types of config that are critical to be processed as soon as possible are provided as query params to the iframe
|
||||
*/
|
||||
export type PrefillAndIframeAttrsConfig = Record<string, string | string[] | Record<string, string>> & {
|
||||
// TODO: iframeAttrs shouldn't be part of it as that configures the iframe element and not the iframed app.
|
||||
iframeAttrs?: Record<string, string> & {
|
||||
id?: string;
|
||||
};
|
||||
|
||||
// TODO: It should have a dedicated prefill prop
|
||||
// prefill: {},
|
||||
|
||||
// TODO: Move layout and theme as nested props of ui as it makes it clear that these two can be configured using `ui` instruction as well any time.
|
||||
// ui: {layout; theme}
|
||||
layout?: `${BookerLayouts}`;
|
||||
theme?: EmbedThemeConfig;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { LazyMotion, domAnimation, m, AnimatePresence } from "framer-motion";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useEffect, useRef, useMemo } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import StickyBox from "react-sticky-box";
|
||||
import { shallow } from "zustand/shallow";
|
||||
|
||||
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
|
||||
import { useEmbedUiConfig } from "@calcom/embed-core/embed-iframe";
|
||||
import { useEmbedUiConfig, useIsEmbed } from "@calcom/embed-core/embed-iframe";
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import useMediaQuery from "@calcom/lib/hooks/useMediaQuery";
|
||||
import { BookerLayouts, defaultBookerLayoutSettings } from "@calcom/prisma/zod-utils";
|
||||
@@ -23,7 +23,6 @@ import { useBookerStore, useInitializeBookerStore } from "./store";
|
||||
import type { BookerLayout, BookerProps } from "./types";
|
||||
import { useEvent } from "./utils/event";
|
||||
import { validateLayout } from "./utils/layout";
|
||||
import { getQueryParam } from "./utils/query-param";
|
||||
import { useBrandColors } from "./utils/use-brand-colors";
|
||||
|
||||
const PoweredBy = dynamic(() => import("@calcom/ee/components/PoweredBy"));
|
||||
@@ -46,10 +45,14 @@ const BookerComponent = ({
|
||||
const rescheduleUid =
|
||||
typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("rescheduleUid") : null;
|
||||
const event = useEvent();
|
||||
const [layout, setLayout] = useBookerStore((state) => [state.layout, state.setLayout], shallow);
|
||||
if (typeof window !== "undefined") {
|
||||
window.CalEmbed.setLayout = setLayout;
|
||||
}
|
||||
const [_layout, setLayout] = useBookerStore((state) => [state.layout, state.setLayout], shallow);
|
||||
|
||||
const isEmbed = useIsEmbed();
|
||||
const embedUiConfig = useEmbedUiConfig();
|
||||
|
||||
// In Embed we give preference to embed configuration for the layout.If that's not set, we use the App configuration for the event layout
|
||||
const layout = isEmbed ? validateLayout(embedUiConfig.layout) || _layout : _layout;
|
||||
|
||||
const [bookerState, setBookerState] = useBookerStore((state) => [state.state, state.setState], shallow);
|
||||
const selectedDate = useBookerStore((state) => state.selectedDate);
|
||||
const [selectedTimeslot, setSelectedTimeslot] = useBookerStore(
|
||||
@@ -60,13 +63,10 @@ const BookerComponent = ({
|
||||
const extraDays = isTablet ? extraDaysConfig[layout].tablet : extraDaysConfig[layout].desktop;
|
||||
const bookerLayouts = event.data?.profile?.bookerLayouts || defaultBookerLayoutSettings;
|
||||
const animationScope = useBookerResizeAnimation(layout, bookerState);
|
||||
const isEmbed = typeof window !== "undefined" && window?.isEmbed?.();
|
||||
|
||||
// We only want the initial url value, that's why we memo it. The embed seems to change the url, which sometimes drops
|
||||
// the layout query param.
|
||||
const layoutFromQueryParam = useMemo(() => validateLayout(getQueryParam("layout") as BookerLayouts), []);
|
||||
// I would expect isEmbed to be not needed here as it's handled in derived variable layout, but somehow removing it breaks the views.
|
||||
const defaultLayout = isEmbed
|
||||
? layoutFromQueryParam || BookerLayouts.MONTH_VIEW
|
||||
? validateLayout(embedUiConfig.layout) || bookerLayouts.defaultLayout
|
||||
: bookerLayouts.defaultLayout;
|
||||
|
||||
useBrandColors({
|
||||
@@ -107,7 +107,6 @@ const BookerComponent = ({
|
||||
}
|
||||
}, [layout]);
|
||||
|
||||
const embedUiConfig = useEmbedUiConfig();
|
||||
const hideEventTypeDetails = isEmbed ? embedUiConfig.hideEventTypeDetails : false;
|
||||
|
||||
if (event.isSuccess && !event.data) {
|
||||
@@ -149,7 +148,8 @@ const BookerComponent = ({
|
||||
!isEmbed && "sm:transition-[width] sm:duration-300",
|
||||
isEmbed && layout === BookerLayouts.MONTH_VIEW && "border-booker sm:border-booker-width",
|
||||
!isEmbed && layout === BookerLayouts.MONTH_VIEW && "border-subtle",
|
||||
layout === BookerLayouts.MONTH_VIEW && isEmbed && "mt-20"
|
||||
// We don't want any margins for Embed. Any margin needed should be added by Embed user.
|
||||
layout === BookerLayouts.MONTH_VIEW && isEmbed && "mt-0"
|
||||
)}>
|
||||
<AnimatePresence>
|
||||
<BookerSection
|
||||
|
||||
Reference in New Issue
Block a user