fix: New Booker Rewrites (#9557)
* Solve the problem using Next.config.js only * Debug * Avoid infinite rewritees * Apply suggestions from code review * Apply suggestions from code review * Remove stale comments * Update packages/embeds/embed-core/src/embed-iframe.ts
This commit is contained in:
1 parent
66ebf18fa9
commit
344241cfbf
5 files changed
+86
-77
No files matched your search
@@ -12,21 +12,10 @@ const middleware: NextMiddleware = async (req) => {
|
||||
const url = req.nextUrl;
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(req.headers.get("host") ?? "");
|
||||
const isEmbedRequest = typeof url.searchParams.get("embed") === "string";
|
||||
|
||||
/**
|
||||
* We are using env variable to toggle new-booker because using flags would be an unnecessary delay for booking pages
|
||||
* Also, we can't easily identify the booker page requests here(to just fetch the flags for those requests)
|
||||
*/
|
||||
// Enable New Booker for All but embed Requests
|
||||
if (process.env.NEW_BOOKER_ENABLED_FOR_NON_EMBED === "1" && !isEmbedRequest) {
|
||||
requestHeaders.set("new-booker-enabled", "1");
|
||||
}
|
||||
|
||||
// Enable New Booker for Embed Requests
|
||||
if (process.env.NEW_BOOKER_ENABLED_FOR_EMBED === "1" && isEmbedRequest) {
|
||||
requestHeaders.set("new-booker-enabled", "1");
|
||||
}
|
||||
|
||||
// Make sure we are in the presence of an organization
|
||||
if (isValidOrgDomain && url.pathname === "/") {
|
||||
@@ -79,13 +68,6 @@ const middleware: NextMiddleware = async (req) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that embed query param is there in when /embed is added.
|
||||
// query param is the way in which client side code knows that it is in embed mode.
|
||||
if (url.pathname.endsWith("/embed") && typeof url.searchParams.get("embed") !== "string") {
|
||||
url.searchParams.set("embed", "");
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
|
||||
// Don't 404 old routing_forms links
|
||||
if (url.pathname.startsWith("/apps/routing_forms")) {
|
||||
url.pathname = url.pathname.replace("/apps/routing_forms", "/apps/routing-forms");
|
||||
|
||||
+76
-54
@@ -183,7 +183,12 @@ const nextConfig = {
|
||||
return config;
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
// .* matches / as well(Note: *(i.e wildcard) doesn't match / but .*(i.e. RegExp) does)
|
||||
// It would match /free/30min but not /bookings/upcoming because 'bookings' is an item in pages
|
||||
// It would also not match /free/30min/embed because we are ensuring just two slashes
|
||||
const userTypeRouteRegExp = `/:user((?!${pages.join("|")})[^/]*)/:type`;
|
||||
|
||||
let rewrites = [
|
||||
{
|
||||
source: "/org/:slug",
|
||||
destination: "/team/:slug",
|
||||
@@ -219,68 +224,85 @@ const nextConfig = {
|
||||
source: "/cancel/:path*",
|
||||
destination: "/booking/:path*",
|
||||
},
|
||||
// Keep cookie based booker enabled just in case we disable new-booker globally
|
||||
...[
|
||||
{
|
||||
source: userTypeRouteRegExp,
|
||||
destination: "/new-booker/:user/:type",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type",
|
||||
destination: "/new-booker/team/:slug/:type",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/d/:link/:slug",
|
||||
destination: "/new-booker/d/:link/:slug",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
],
|
||||
// Keep cookie based booker enabled to test new-booker embed in production
|
||||
...[
|
||||
{
|
||||
source: `/:user((?!${pages.join("|")}).*)/:type/embed`,
|
||||
destination: "/new-booker/:user/:type/embed",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type/embed",
|
||||
destination: "/new-booker/team/:slug/:type/embed",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
],
|
||||
/* TODO: have these files being served from another deployment or CDN {
|
||||
source: "/embed/embed.js",
|
||||
destination: process.env.NEXT_PUBLIC_EMBED_LIB_URL?,
|
||||
}, */
|
||||
/**
|
||||
* Header allows us to enable new-booker using middleware which uses env variables to enable/disable new booker
|
||||
*/
|
||||
{
|
||||
source: `/:user((?!${pages.join("|")}).*)/:type`,
|
||||
destination: "/new-booker/:user/:type",
|
||||
has: [{ type: "header", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: `/:user((?!${pages.join("|")}).*)/:type/embed`,
|
||||
destination: "/new-booker/:user/:type/embed",
|
||||
has: [{ type: "header", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type",
|
||||
destination: "/new-booker/team/:slug/:type",
|
||||
has: [{ type: "header", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type/embed",
|
||||
destination: "/new-booker/team/:slug/:type/embed",
|
||||
has: [{ type: "header", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/d/:link/:slug",
|
||||
destination: "/new-booker/d/:link/:slug",
|
||||
has: [{ type: "header", key: "new-booker-enabled" }],
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables new booker using cookie. It works even if NEW_BOOKER_ENABLED_FOR_NON_EMBED, NEW_BOOKER_ENABLED_FOR_EMBED are disabled
|
||||
*/
|
||||
{
|
||||
source: `/:user((?!${pages.join("|")}).*)/:type`,
|
||||
destination: "/new-booker/:user/:type",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: `/:user((?!${pages.join("|")}).*)/:type/embed`,
|
||||
destination: "/new-booker/:user/:type/embed",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type",
|
||||
destination: "/new-booker/team/:slug/:type",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type/embed",
|
||||
destination: "/new-booker/team/:slug/:type/embed",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
{
|
||||
source: "/d/:link/:slug",
|
||||
destination: "/new-booker/d/:link/:slug",
|
||||
has: [{ type: "cookie", key: "new-booker-enabled" }],
|
||||
},
|
||||
];
|
||||
|
||||
// Enable New Booker for all Embed Requests
|
||||
if (process.env.NEW_BOOKER_ENABLED_FOR_EMBED === "1") {
|
||||
console.log("Enabling New Booker for Embed");
|
||||
rewrites.push(
|
||||
...[
|
||||
{
|
||||
source: `/:user((?!${pages.join("|")}).*)/:type/embed`,
|
||||
destination: "/new-booker/:user/:type/embed",
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type/embed",
|
||||
destination: "/new-booker/team/:slug/:type/embed",
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// Enable New Booker for All but embed Requests
|
||||
if (process.env.NEW_BOOKER_ENABLED_FOR_NON_EMBED === "1") {
|
||||
console.log("Enabling New Booker for Non-Embed");
|
||||
rewrites.push(
|
||||
...[
|
||||
{
|
||||
source: userTypeRouteRegExp,
|
||||
destination: "/new-booker/:user/:type",
|
||||
},
|
||||
{
|
||||
source: "/team/:slug/:type",
|
||||
destination: "/new-booker/team/:slug/:type",
|
||||
},
|
||||
{
|
||||
source: "/d/:link/:slug",
|
||||
destination: "/new-booker/d/:link/:slug",
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
return rewrites;
|
||||
},
|
||||
async headers() {
|
||||
return [
|
||||
|
||||
@@ -5,7 +5,10 @@ export default function EmbedInitIframe() {
|
||||
return;
|
||||
}
|
||||
|
||||
const embedNameSpaceFromQueryParam = new URL(document.URL).searchParams.get("embed");
|
||||
const url = new URL(document.URL);
|
||||
const embedNameSpaceFromQueryParam = url.searchParams.get("embed");
|
||||
const hasEmbedPath = url.pathname.endsWith("/embed");
|
||||
const defaultNamespace = "";
|
||||
|
||||
// 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
|
||||
@@ -17,6 +20,8 @@ export default function EmbedInitIframe() {
|
||||
? embedNameSpaceFromQueryParam
|
||||
: window.name.includes("cal-embed=")
|
||||
? window.name.replace(/cal-embed=(.*)/, "$1").trim()
|
||||
: hasEmbedPath
|
||||
? defaultNamespace // If query param is not there but /embed is used then assume default namespace.
|
||||
: null;
|
||||
|
||||
window.isEmbed = () => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useRouter } from "next/router";
|
||||
import type { CSSProperties } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import embedInit from "@calcom/embed-core/embed-iframe-init";
|
||||
import type { BookerStore } from "@calcom/features/bookings/Booker/store";
|
||||
import type { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
|
||||
@@ -439,8 +438,6 @@ function keepParentInformedAboutDimensionChanges() {
|
||||
|
||||
if (isBrowser) {
|
||||
log("Embed SDK loaded", { isEmbed: window?.isEmbed?.() || false });
|
||||
// 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?.();
|
||||
if (url.searchParams.get("prerender") !== "true" && window?.isEmbed?.()) {
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
* @file
|
||||
* This module is supposed to instantiate the SDK with appropriate namespace
|
||||
*/
|
||||
import embedInit from "@calcom/embed-core/embed-iframe-init";
|
||||
|
||||
import { SdkActionManager } from "./sdk-action-manager";
|
||||
|
||||
export let sdkActionManager: SdkActionManager | null = null;
|
||||
if (typeof window !== "undefined") {
|
||||
sdkActionManager = new SdkActionManager(new URL(document.URL).searchParams.get("embed"));
|
||||
embedInit();
|
||||
sdkActionManager = new SdkActionManager(window.getEmbedNamespace());
|
||||
}
|
||||
Reference in new issue
Block a user