fix: ensure linkFailed event fires for 404, 500, and 403 errors in embeds (#25261)
- Add CalComPageStatus handling in NotFound and ErrorPage components using useLayoutEffect - Remove redundant pageStatus logic from PageWrapperAppDir.tsx since App Router error/notFound pages set status themselves - Refactor embed-iframe.ts: split checkPageStatusAndHandleError into hasPageError() and handlePageError() - Add page status checks before firing linkReady to catch errors set after initialization - Ensures linkFailed event fires correctly for all error status codes in embed scenarios Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent
945ded951f
commit
71792bdeaa
@@ -2,6 +2,7 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
import {
|
||||
getOrgDomainConfigFromHostname,
|
||||
@@ -40,9 +41,8 @@ function getPageInfo(pathname: string, host: string) {
|
||||
return {
|
||||
username: currentOrgDomain ?? "",
|
||||
pageType: PageType.ORG,
|
||||
url: `${WEBSITE_URL}/signup?callbackUrl=settings/organizations/new%3Fslug%3D${
|
||||
currentOrgDomain?.replace("/", "") ?? ""
|
||||
}`,
|
||||
url: `${WEBSITE_URL}/signup?callbackUrl=settings/organizations/new%3Fslug%3D${currentOrgDomain?.replace("/", "") ?? ""
|
||||
}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,12 @@ export function NotFound({ host }: { host: string }) {
|
||||
const isSubpage = pathname?.includes("/", 2) || isBookingSuccessPage;
|
||||
const isInsights = pathname?.startsWith("/insights");
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
window.CalComPageStatus = "404";
|
||||
}
|
||||
}, []);
|
||||
|
||||
const links = [
|
||||
{
|
||||
title: t("enterprise"),
|
||||
@@ -156,9 +162,8 @@ export function NotFound({ host }: { host: string }) {
|
||||
<span className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{t("register")}{" "}
|
||||
<strong className="text-green-500">{`${
|
||||
pageType === PageType.TEAM ? `${new URL(WEBSITE_URL).host}/team/` : ""
|
||||
}${username}${pageType === PageType.ORG ? `.${subdomainSuffix()}` : ""}`}</strong>
|
||||
<strong className="text-green-500">{`${pageType === PageType.TEAM ? `${new URL(WEBSITE_URL).host}/team/` : ""
|
||||
}${username}${pageType === PageType.ORG ? `.${subdomainSuffix()}` : ""}`}</strong>
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { usePathname } from "next/navigation";
|
||||
import Script from "next/script";
|
||||
|
||||
import "@calcom/embed-core/src/embed-iframe";
|
||||
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||
|
||||
@@ -16,16 +13,6 @@ export type PageWrapperProps = Readonly<{
|
||||
}>;
|
||||
|
||||
function PageWrapper(props: PageWrapperProps) {
|
||||
const pathname = usePathname();
|
||||
let pageStatus = "200";
|
||||
|
||||
if (pathname === "/404") {
|
||||
pageStatus = "404";
|
||||
} else if (pathname === "/500") {
|
||||
pageStatus = "500";
|
||||
} else if (pathname === "/403") {
|
||||
pageStatus = "403";
|
||||
}
|
||||
|
||||
// On client side don't let nonce creep into DOM
|
||||
// It also avoids hydration warning that says that Client has the nonce value but server has "" because browser removes nonce attributes before DOM is built
|
||||
@@ -41,13 +28,6 @@ function PageWrapper(props: PageWrapperProps) {
|
||||
<>
|
||||
<AppProviders {...providerProps}>
|
||||
<>
|
||||
<Script
|
||||
nonce={nonce}
|
||||
id="page-status"
|
||||
// It is strictly not necessary to disable, but in a future update of react/no-danger this will error.
|
||||
// And we don't want it to error here anyways
|
||||
dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}
|
||||
/>
|
||||
{props.requiresLicense ? (
|
||||
<LicenseRequired>{props.children}</LicenseRequired>
|
||||
) : (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
import "@calcom/embed-core/src/embed-iframe";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
@@ -59,6 +59,14 @@ export const ErrorPage: React.FC<Props> = (props) => {
|
||||
window.location.reload();
|
||||
props.reset?.();
|
||||
};
|
||||
|
||||
// useLayoutEffect runs synchronously before browser paint, ensuring it's set early
|
||||
useLayoutEffect(() => {
|
||||
if (statusCode && typeof window !== "undefined") {
|
||||
window.CalComPageStatus = statusCode.toString();
|
||||
}
|
||||
}, [statusCode]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="bg-subtle flex h-screen">
|
||||
|
||||
@@ -414,6 +414,12 @@ export const methods = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check page status again before firing linkReady, in case it was set after initialization
|
||||
if (hasPageError()) {
|
||||
handlePageError(window.CalComPageStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
makeBodyVisible();
|
||||
log("renderState is 'completed'");
|
||||
embedStore.renderState = "completed";
|
||||
@@ -587,6 +593,29 @@ function main() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there's a page error (non-200 status).
|
||||
* @returns true if an error exists, false otherwise
|
||||
*/
|
||||
function hasPageError() {
|
||||
const pageStatus = window.CalComPageStatus;
|
||||
return !!(pageStatus && pageStatus != "200");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a page error by firing the linkFailed event.
|
||||
* @param pageStatus - The error status code (e.g., "404", "500", "403")
|
||||
*/
|
||||
function handlePageError(pageStatus: string) {
|
||||
sdkActionManager?.fire("linkFailed", {
|
||||
code: pageStatus,
|
||||
msg: "Problem loading the link",
|
||||
data: {
|
||||
url: document.URL,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function initializeAndSetupEmbed() {
|
||||
sdkActionManager?.fire("__iframeReady", {
|
||||
isPrerendering: isPrerendering(),
|
||||
@@ -604,16 +633,12 @@ function initializeAndSetupEmbed() {
|
||||
// HACK
|
||||
const pageStatus = window.CalComPageStatus;
|
||||
|
||||
if (!pageStatus || pageStatus == "200") {
|
||||
if (hasPageError()) {
|
||||
handlePageError(pageStatus);
|
||||
return;
|
||||
} else {
|
||||
keepParentInformedAboutDimensionChanges({ embedStore });
|
||||
} else
|
||||
sdkActionManager?.fire("linkFailed", {
|
||||
code: pageStatus,
|
||||
msg: "Problem loading the link",
|
||||
data: {
|
||||
url: document.URL,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function runAllUiSetters(uiConfig: UiConfig) {
|
||||
@@ -665,6 +690,13 @@ async function connectPreloadedEmbed({
|
||||
runAsap(tryToFireLinkReady);
|
||||
return;
|
||||
}
|
||||
// Check page status again before firing linkReady, in case it was set after initialization
|
||||
if (hasPageError()) {
|
||||
handlePageError(window.CalComPageStatus);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// link is ready now, so we could stop doing it.
|
||||
// Also the page is visible to user now.
|
||||
stopEnsuringQueryParamsInUrl();
|
||||
|
||||
Reference in New Issue
Block a user