feat: add booker lifecycle SDK events for embed tracking (#25569)

* feat: add embed prerendering support and enhance event handling

- Introduced `useIsEmbedPrerendering` hook to determine if the embed is in prerender mode.
- Updated `useAvailabilityEvents` to prevent firing events during prerendering.
- Added `bookerLoadedEvent` and `availabilityRefreshed` types to `EventDataMap`.
- Implemented `useFirebookerLoadedEvent` to manage firing the booker loaded event conditionally.
- Refactored event firing logic in `useSchedule` and `BookerWebWrapper` components to utilize new hooks.

* feat: add embed prerendering support and enhance event handling

- Introduced `useIsEmbedPrerendering` hook to determine if the embed is in prerender mode.
- Updated `useAvailabilityEvents` to prevent firing events during prerendering.
- Added `bookerLoadedEvent` and `availabilityRefreshed` types to `EventDataMap`.
- Implemented `useFirebookerLoadedEvent` to manage firing the booker loaded event conditionally.
- Refactored event firing logic in `useSchedule` and `BookerWebWrapper` components to utilize new hooks.

* feat: enhance embed event handling and introduce link reopening detection

- Added `useEmbedReopened` hook to track when the embed is reopened.
- Updated `BookerWebWrapper` to reset event firing state upon embed reopening.
- Refactored event firing logic to use `bookerViewed` instead of `bookerLoadedEvent`.
- Introduced scheduling for event firing in `useSchedule` to ensure correct order of events during prerendering.

* feat: add lifecycle diagrams for inline and modal embeds

- Introduced `inline-embed-lifecycle.mermaid` and `modal-embed-lifecycle.mermaid` files to visualize the lifecycle events and states of inline and modal embeds.
- Updated `LIFECYCLE.md` to reference the new diagrams and provide a clearer explanation of the embed lifecycle processes.
- Added `modal-prerendering-flow.mermaid` to illustrate the prerendering flow for modal embeds.
- Enhanced the routing playground with new features and improved event handling for availability and booking events.

* refactor: update event handling for booker lifecycle events

- Replaced `availabilityLoaded` event with `bookerReady` to better reflect the state when the booker view is fully loaded and ready for interaction.
- Updated related documentation and diagrams to reflect changes in event triggers and descriptions.
- Adjusted internal state management to track `viewId` instead of `reopenCount` for distinguishing between initial views and reopens.
- Added tests for new event handling logic to ensure correct firing of `bookerViewed`, `bookerReopened`, and `bookerReady` events.

* refactor: enhance embed event handling and state management

- Updated event handling for booker lifecycle events, replacing `resetViewVariables` with `resetPageData` to manage page-specific state.
- Introduced new utility functions for managing event firing states and reload initiation.
- Refactored `fireBookerViewedEvent` and `fireBookerReadyEvent` to utilize the new state management functions.
- Added comprehensive tests for the updated event handling logic and state resets to ensure correct functionality across various scenarios.

* refactor: update embed iframe configuration and utility functions

- Reduced `slotsStaleTimeMs` from 30 seconds to 10 seconds and `iframeForceReloadThresholdMs` from 100 seconds to 30 seconds for improved responsiveness.
- Refactored utility functions to use `isBrowser` for client-side checks instead of `isClientSide`.
- Removed unused `isPrerendering` function and updated related documentation for clarity.
- Enhanced event handling by exporting `useBookerEmbedEvents` from the appropriate module for better accessibility.

* refactor: update embed iframe configuration and utility functions

- Reduced `slotsStaleTimeMs` from 30 seconds to 10 seconds and `iframeForceReloadThresholdMs` from 100 seconds to 30 seconds for improved responsiveness.
- Refactored utility functions to use `isBrowser` for client-side checks instead of `isClientSide`.
- Removed unused `isPrerendering` function and updated related documentation for clarity.
- Enhanced event handling by exporting `useBookerEmbedEvents` from the appropriate module for better accessibility.

* fix cubic feedback
This commit is contained in:
Hariom Balhara
2025-12-11 09:11:38 -03:00
committed by GitHub
parent f6642c17f8
commit 6f0c09d2be
21 changed files with 2105 additions and 609 deletions
+25 -26
View File
@@ -3,13 +3,16 @@
import { useEffect, useRef, useState, useCallback } from "react";
import { mapOldToNewCssVars } from "./ui/cssVarsMap";
import type { Message } from "./embed";
import { embedStore, EMBED_IFRAME_STATE } from "./embed-iframe/lib/embedStore";
import { embedStore, EMBED_IFRAME_STATE, resetPageData, setReloadInitiated, incrementView } from "./embed-iframe/lib/embedStore";
import {
runAsap,
isBookerReady,
isLinkReady,
recordResponseIfQueued,
keepParentInformedAboutDimensionChanges,
isPrerendering,
isBrowser,
log,
} from "./embed-iframe/lib/utils";
import { sdkActionManager } from "./sdk-event";
import type {
@@ -24,6 +27,7 @@ import type {
setNonStylesConfig,
} from "./types";
import { useCompatSearchParams } from "./useCompatSearchParams";
export { useBookerEmbedEvents } from "./embed-iframe/react-hooks";
// We don't import it from Booker/types because the types from this module are published to npm and we can't import packages that aren't published
type BookerState = "loading" | "selecting_date" | "selecting_time" | "booking";
@@ -34,10 +38,11 @@ const eventsAllowedInPrerendering = [
"__iframeReady",
// so that iframe height is adjusted according to the content, and iframe is ready to be shown when needed
"__dimensionChanged",
// When this event is fired, the iframe is still in prerender state but is going to be moved out of prerender state
"__connectInitiated",
"linkPrerendered",
// For other events, we should consider introducing prerender specific events and not reuse existing events
];
@@ -54,7 +59,6 @@ declare global {
}
let isSafariBrowser = false;
const isBrowser = typeof window !== "undefined";
if (isBrowser) {
window.CalEmbed = window?.CalEmbed || {};
@@ -66,24 +70,6 @@ if (isBrowser) {
}
}
function log(...args: unknown[]) {
if (isBrowser) {
const namespace = getNamespace();
const searchParams = new URL(document.URL).searchParams;
const logQueue = (window.CalEmbed.__logQueue = window.CalEmbed.__logQueue || []);
args.push({
ns: namespace,
url: document.URL,
});
args.unshift("CAL:");
logQueue.push(args);
if (searchParams.get("debug")) {
console.log("Child:", ...args);
}
}
}
const setEmbedStyles = (stylesConfig: EmbedStyles) => {
embedStore.styles = stylesConfig;
for (const [, setEmbedStyle] of Object.entries(embedStore.reactStylesStateSetters)) {
@@ -431,7 +417,11 @@ export const methods = {
makeBodyVisible();
log("renderState is 'completed'");
embedStore.renderState = "completed";
sdkActionManager?.fire("linkReady", {});
if (isPrerendering()) {
sdkActionManager?.fire("linkPrerendered", {});
} else {
sdkActionManager?.fire("linkReady", {});
}
});
},
/**
@@ -496,6 +486,10 @@ export const methods = {
toRemoveParams,
});
},
__reloadInitiated: function __reloadInitiated(_unused: unknown) {
log("Method: __reloadInitiated called");
setReloadInitiated(true);
},
};
export type InterfaceWithParent = {
@@ -568,6 +562,15 @@ function main() {
}
});
sdkActionManager?.on("linkReady", () => {
// Even though linkReady isn't fired in prerendering phase, this is a safe guard for future
if (isPrerendering()) {
return;
}
resetPageData();
incrementView();
});
sdkActionManager?.on("*", (e) => {
if (isPrerendering() && !eventsAllowedInPrerendering.includes(e.detail.type)) {
return;
@@ -676,10 +679,6 @@ async function connectPreloadedEmbed({
};
}
const isPrerendering = () => {
return new URL(document.URL).searchParams.get("prerender") === "true";
};
export function getEmbedBookerState({
bookerState,
slotsQuery,