mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-06 11:20:56 -05:00
fix: add error handling for cal.com embeds in credentialless environments
- Add 5-second timeout to detect embed load failures - Show error message with fallback direct booking link - Handle COEP/Cross-Origin Embedder Policy blocks gracefully Fixes #7457
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import snippet from "@calcom/embed-snippet";
|
||||
import { useEffect, useMemo } from "preact/hooks";
|
||||
import { useEffect, useMemo, useState } from "preact/hooks";
|
||||
import { type TSurveyCalElement } from "@formbricks/types/surveys/elements";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -9,6 +9,9 @@ interface CalEmbedProps {
|
||||
}
|
||||
|
||||
export function CalEmbed({ element, onSuccessfulBooking }: CalEmbedProps) {
|
||||
const [error, setError] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
const cal = useMemo(() => {
|
||||
const calInline = snippet("https://cal.com/embed.js");
|
||||
|
||||
@@ -46,16 +49,57 @@ export function CalEmbed({ element, onSuccessfulBooking }: CalEmbedProps) {
|
||||
document.querySelectorAll("cal-inline").forEach((el) => {
|
||||
el.remove();
|
||||
});
|
||||
setError(false);
|
||||
setErrorMessage("");
|
||||
cal("init", { calOrigin: element.calHost ? `https://${element.calHost}` : "https://cal.com" });
|
||||
cal("inline", {
|
||||
elementOrSelector: "#cal-embed",
|
||||
calLink: element.calUserName,
|
||||
});
|
||||
|
||||
// Set up error detection via MutationObserver for COEP/credentialless failures
|
||||
const timer = setTimeout(() => {
|
||||
const embedContainer = document.getElementById("cal-embed");
|
||||
if (embedContainer) {
|
||||
const iframe = embedContainer.querySelector("iframe");
|
||||
if (!iframe) {
|
||||
setError(true);
|
||||
setErrorMessage("Failed to load booking widget. Your environment may be blocking cross-origin resources.");
|
||||
}
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [cal, element.calHost, element.calUserName]);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="relative mt-4 overflow-auto">
|
||||
<div className="border-border rounded-input border p-4 text-center">
|
||||
<p className="text-sm text-red-600">
|
||||
{errorMessage}
|
||||
</p>
|
||||
<p className="text-muted-foreground mt-2 text-xs">
|
||||
Try opening the booking page directly at{" "}
|
||||
<a
|
||||
href={`https://${element.calHost || "cal.com"}/${element.calUserName}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline">
|
||||
{element.calHost || "cal.com"}/{element.calUserName}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative mt-4 overflow-auto">
|
||||
<div id="cal-embed" className={cn("border-border rounded-input border")} />
|
||||
<div id="cal-embed" className={cn("border-border rounded-input border")}>
|
||||
{/* The cal.com widget renders here. If COEP/credentialless blocks the iframe,
|
||||
the timeout above will trigger an error state with a fallback link. */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user