fix: improve booking page error boundary + remove dynamic imports from Booker (#20560)
* improve booking page error boundary + remove dynamic imports from Booker * safer * fix * fix test * change name
This commit is contained in:
1 parent
d158a1e007
commit
5c7d7579ee
5 files changed
+28
-18
No files matched your search
@@ -17,7 +17,7 @@ export type ErrorProps = {
|
||||
reset?: () => void;
|
||||
};
|
||||
|
||||
export default function Error({ error }: ErrorProps) {
|
||||
export default function Error({ error, reset }: ErrorProps) {
|
||||
React.useEffect(() => {
|
||||
log.error(error);
|
||||
|
||||
@@ -51,6 +51,7 @@ export default function Error({ error }: ErrorProps) {
|
||||
|
||||
return (
|
||||
<ErrorPage
|
||||
reset={reset}
|
||||
statusCode={processedError.statusCode}
|
||||
error={processedError}
|
||||
message={processedError.message}
|
||||
|
||||
@@ -7,8 +7,11 @@ import { ErrorPage } from "./error-page";
|
||||
export default function BookingPageErrorBoundary({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ErrorBoundary
|
||||
fallbackRender={({ error }) => <ErrorPage error={error} message={`${error}`} displayDebug={true} />}
|
||||
fallbackRender={({ error, resetErrorBoundary }) => (
|
||||
<ErrorPage reset={resetErrorBoundary} error={error} message={`${error}`} displayDebug={true} />
|
||||
)}
|
||||
onError={(error, info) => {
|
||||
console.error(error);
|
||||
captureReactException(error, info);
|
||||
}}>
|
||||
{children}
|
||||
|
||||
@@ -12,6 +12,7 @@ type Props = {
|
||||
/** Display debugging information */
|
||||
displayDebug?: boolean;
|
||||
children?: never;
|
||||
reset?: () => void;
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@@ -53,7 +54,10 @@ const ErrorDebugPanel: React.FC<{ error: Props["error"]; children?: never }> = (
|
||||
|
||||
export const ErrorPage: React.FC<Props> = (props) => {
|
||||
const { message, statusCode, error, displayDebug } = { ...defaultProps, ...props };
|
||||
|
||||
const handleReset = () => {
|
||||
window.location.reload();
|
||||
props.reset?.();
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="bg-subtle flex h-screen">
|
||||
@@ -77,8 +81,8 @@ export const ErrorPage: React.FC<Props> = (props) => {
|
||||
</div>
|
||||
|
||||
<Button href="mailto:support@cal.com">Contact Support</Button>
|
||||
<Button color="secondary" href="javascript:history.back()" className="ml-2">
|
||||
Go back
|
||||
<Button color="secondary" className="ml-2" onClick={handleReset}>
|
||||
Try again
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { AnimatePresence, LazyMotion, m } from "framer-motion";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import StickyBox from "react-sticky-box";
|
||||
import { Toaster } from "sonner";
|
||||
@@ -8,6 +7,8 @@ import { shallow } from "zustand/shallow";
|
||||
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
|
||||
import { useIsPlatformBookerEmbed } from "@calcom/atoms/hooks/useIsPlatformBookerEmbed";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import PoweredBy from "@calcom/ee/components/PoweredBy";
|
||||
import TurnstileCaptcha from "@calcom/features/auth/Turnstile";
|
||||
import useSkipConfirmStep from "@calcom/features/bookings/Booker/components/hooks/useSkipConfirmStep";
|
||||
import { getQueryParam } from "@calcom/features/bookings/Booker/utils/query-param";
|
||||
import { useNonEmptyScheduleDays } from "@calcom/features/schedules";
|
||||
@@ -16,11 +17,13 @@ import { CLOUDFLARE_SITE_ID, CLOUDFLARE_USE_TURNSTILE_IN_BOOKER } from "@calcom/
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { UnpublishedEntity } from "@calcom/ui/components/unpublished-entity";
|
||||
|
||||
import { VerifyCodeDialog } from "../components/VerifyCodeDialog";
|
||||
import { AvailableTimeSlots } from "./components/AvailableTimeSlots";
|
||||
import { BookEventForm } from "./components/BookEventForm";
|
||||
import { BookFormAsModal } from "./components/BookEventForm/BookFormAsModal";
|
||||
import { DatePicker } from "./components/DatePicker";
|
||||
import { DryRunMessage } from "./components/DryRunMessage";
|
||||
import { EventMeta } from "./components/EventMeta";
|
||||
import { HavingTroubleFindingTime } from "./components/HavingTroubleFindingTime";
|
||||
@@ -33,22 +36,12 @@ import { BookerSection } from "./components/Section";
|
||||
import { NotFound } from "./components/Unavailable";
|
||||
import { useIsQuickAvailabilityCheckFeatureEnabled } from "./components/hooks/useIsQuickAvailabilityCheckFeatureEnabled";
|
||||
import { fadeInLeft, getBookerSizeClassNames, useBookerResizeAnimation } from "./config";
|
||||
import framerFeatures from "./framer-features";
|
||||
import { useBookerStore } from "./store";
|
||||
import type { BookerProps, WrappedBookerProps } from "./types";
|
||||
import { isBookingDryRun } from "./utils/isBookingDryRun";
|
||||
import { isTimeSlotAvailable } from "./utils/isTimeslotAvailable";
|
||||
|
||||
const TurnstileCaptcha = dynamic(() => import("@calcom/features/auth/Turnstile"), { ssr: false });
|
||||
|
||||
const loadFramerFeatures = () => import("./framer-features").then((res) => res.default);
|
||||
const PoweredBy = dynamic(() => import("@calcom/ee/components/PoweredBy").then((mod) => mod.default));
|
||||
const UnpublishedEntity = dynamic(() =>
|
||||
import("@calcom/ui/components/unpublished-entity").then((mod) => mod.UnpublishedEntity)
|
||||
);
|
||||
const DatePicker = dynamic(() => import("./components/DatePicker").then((mod) => mod.DatePicker), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const BookerComponent = ({
|
||||
username,
|
||||
eventSlug,
|
||||
@@ -586,7 +579,7 @@ const BookerComponent = ({
|
||||
|
||||
export const Booker = (props: BookerProps & WrappedBookerProps) => {
|
||||
return (
|
||||
<LazyMotion strict features={loadFramerFeatures}>
|
||||
<LazyMotion strict features={framerFeatures}>
|
||||
<BookerComponent {...props} />
|
||||
</LazyMotion>
|
||||
);
|
||||
|
||||
@@ -20,6 +20,13 @@ import { Booker } from "../Booker";
|
||||
import { useBookerStore } from "../store";
|
||||
import type { BookerState } from "../types";
|
||||
|
||||
vi.mock("framer-motion", async (importOriginal) => {
|
||||
const actual = await importOriginal();
|
||||
return {
|
||||
...actual,
|
||||
};
|
||||
});
|
||||
|
||||
// Mock components that we don't want to test
|
||||
vi.mock("../components/BookEventForm", () => ({
|
||||
BookEventForm: ({
|
||||
@@ -176,6 +183,8 @@ describe("Booker", () => {
|
||||
beforeEach(() => {
|
||||
constantsScenarios.set({
|
||||
PUBLIC_QUICK_AVAILABILITY_ROLLOUT: 100,
|
||||
POWERED_BY_URL: "https://go.cal.com/booking",
|
||||
APP_NAME: "Cal.com",
|
||||
});
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user