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
+34 -7
View File
@@ -369,8 +369,8 @@ export class Cal {
urlInstance.searchParams.append(key, value);
}
// Very Important:Reset iframe ready flag, as iframe might load a fresh URL and we need to check when it is ready.
this.iframeReady = false;
// Very Important:Reset iframe ready flag and clear queue, as iframe might load a fresh URL and we need to check when it is ready.
this.iframeReset();
if (iframe.src === urlInstance.toString()) {
// Ensure reload occurs even if the url is same - Though browser normally does it, but would be better to ensure it
@@ -409,6 +409,11 @@ export class Cal {
}
}
iframeReset() {
this.iframeReady = false;
this.iframeDoQueue = [];
}
constructor(namespace: string, q: Queue) {
this.__config = {
// Use WEBAPP_URL till full page reload problem with website URL is solved
@@ -458,6 +463,7 @@ export class Cal {
this.iframeDoQueue.forEach((doInIframeArg) => {
this.doInIframe(doInIframeArg);
});
this.iframeDoQueue = [];
});
this.actionManager.on("__routeChanged", () => {
@@ -477,6 +483,7 @@ export class Cal {
this.actionManager.on("linkReady", () => {
if (this.isPrerendering) {
// Ensure that we don't mark embed as loaded if it's prerendering otherwise prerendered embed could show-up without any user action
// linkReady event isn't received anyway by parent as it isn't whitelisted to be sent to parent but it is a safe guard
return;
}
this.iframe!.style.visibility = "";
@@ -1180,6 +1187,9 @@ class CalApi {
iframe: this.cal.iframe,
config: enrichedConfig,
});
// Send reloadInitiated message to iframe so it can track it
// Send it after loadInIframe so that new iframe can process it.
this.cal.doInIframe({ method: "__reloadInitiated", arg: {} });
} else if (actionToTake === "connect" || actionToTake === "connect-no-slots-fetch") {
const paramsToAdd = fromEntriesWithDuplicateKeys(calLinkUrlObject.searchParams.entries());
this.cal.connect({
@@ -1423,16 +1433,33 @@ class CalApi {
calOrigin?: string;
options?: {
/**
* Time in milliseconds after which the prerendered slots/availability should be considered stale and would be requested again when the modal is opened. This could slow down the booking page load by the time taken by slots loading request which shouldn't be too high
* Time in milliseconds after which the prerendered slots/availability should be considered stale and would be requested again when the modal is opened.
*
* Default value is 1 min
* The threshold is measured from the time of the last prerender or modal API call (not from when the embed was first opened).
* **Important**: Each time the modal is opened, the timer resets. This means if you frequently close and reopen the modal
* (before the threshold is crossed), the slots will never be considered stale.
*
* When slots are considered stale, only the availability/slots are refetched (not a full iframe reload), which could
* slow down the booking page load by the time taken by the slots loading request.
*
* Default value is 1 min (60000 ms)
*/
slotsStaleTimeMs?: number;
/**
* Time in milliseconds after which the iframe would be forcefully reloaded when the modal is opened and thus booking page load could slow down drastically showing the skeleton loader in the meantime
* To avoid reaching this threshold, the user could prerender before this time is reached in usecases where prerender has been done long time ago.
* Time in milliseconds after which the iframe would be forcefully reloaded when the modal is opened.
*
* Default value is 15 mins
* The threshold is measured from the time of the last prerender or modal API call (not from when the embed was first opened).
* **Important**: Each time the modal is opened, the timer resets. This means if you frequently close and reopen the modal
* (before the threshold is crossed), the iframe will never be forcefully reloaded.
*
* When this threshold is crossed, a full iframe reload occurs (not just a slots refetch), which causes the booking page
* load to slow down drastically, showing the skeleton loader in the meantime. This full reload also means that any form
* response data would be resubmitted.
*
* To avoid reaching this threshold, you could prerender again before this time is reached in usecases where prerender
* has been done a long time ago.
*
* Default value is 15 mins (900000 ms)
*/
iframeForceReloadThresholdMs?: number;
};