Files
calendar/packages/platform/atoms/router/Router.tsx
T
MorganandGitHub 14ec3813ee chore: enable more router props (#19088)
* chore: enable more router props

* chore: expose booker props via router atom
2025-02-05 08:36:34 +00:00

150 lines
4.7 KiB
TypeScript

import type { ReactElement } from "react";
import React, { useState } from "react";
import { BookerEmbed } from "../booker-embed";
import type { BookerPlatformWrapperAtomPropsForTeam } from "../booker/BookerPlatformWrapper";
/**
* Renders the Router component with predefined props.
* Depending on the routing form either renders a custom message, redirects or display Booker embed atom.
* formResponsesURLParams contains the answers to the questions fields defined in the form.
* ```tsx
* <Router
* formId="1a1a1a1a-2b2b-3c3c-4d4d-5e5e5e5e5e5e"
* formResponsesURLParams={new URLSearchParams({ Territory: "Europe" })}
* bookerProps={{
* customClassNames: { bookerWrapper: "dark" },
* bannerUrl: "https://i0.wp.com/mahala.co.uk/wp-content/uploads/2014/12/img_banner-thin_mountains.jpg?fit=800%2C258&ssl=1",
* onCreateBookingSuccess: (data) => console.log(data),
* onCreateBookingError: (err) => console.error(err)
* />
* ```
*/
export const Router = React.memo(
({
formId,
formResponsesURLParams,
onExternalRedirect,
onDisplayBookerEmbed,
renderMessage,
onSubmitFormStart,
onSubmitFormEnd,
renderLoader,
bookerProps,
}: {
formId: string;
formResponsesURLParams?: URLSearchParams;
onExternalRedirect?: () => void;
onDisplayBookerEmbed?: () => void;
onSubmitFormStart?: () => void;
onSubmitFormEnd?: () => void;
renderMessage?: (message?: string) => ReactElement | ReactElement[];
bookerProps?: Pick<
Partial<BookerPlatformWrapperAtomPropsForTeam>,
| "customClassNames"
| "bannerUrl"
| "onCreateBookingSuccess"
| "onCreateBookingError"
| "onCreateRecurringBookingSuccess"
| "onCreateRecurringBookingError"
| "onReserveSlotSuccess"
| "onReserveSlotError"
| "onDeleteSlotSuccess"
| "onDeleteSlotError"
| "view"
| "onDryRunSuccess"
| "hostsLimit"
| "metadata"
| "handleCreateBooking"
>;
renderLoader?: (isLoading?: boolean) => ReactElement | ReactElement[];
}) => {
const [isLoading, setIsLoading] = useState<boolean>();
const [routerUrl, setRouterUrl] = useState<string>();
const [routingData, setRoutingData] = useState<{ message: string } | undefined>();
const [isError, setIsError] = useState<boolean>();
React.useEffect(() => {
if (!isLoading) {
setIsLoading(true);
setIsError(false);
setRoutingData(undefined);
setRouterUrl("");
const baseUrl = import.meta.env.VITE_BOOKER_EMBED_API_URL;
onSubmitFormStart?.();
fetch(`${baseUrl}/router/forms/${formId}/submit`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: formResponsesURLParams
? JSON.stringify(Object.fromEntries(formResponsesURLParams))
: undefined,
})
.then(async (response) => {
const body:
| { status: string; data: string; redirect: true }
| { status: string; data: { message: string }; redirect: false } = await response.json();
if (body.redirect) {
setRouterUrl(body.data);
} else {
setRoutingData({ message: body.data?.message ?? "" });
}
})
.catch((err) => {
console.error(err);
setIsError(true);
})
.finally(() => {
setIsLoading(false);
onSubmitFormEnd?.();
});
}
}, []);
const isRedirect = !!routerUrl;
if (isLoading && renderLoader) {
return <>{renderLoader?.(isLoading)}</>;
}
if (isLoading || isError) {
return <></>;
}
if (!isLoading && isRedirect && routerUrl) {
const redirectParams = new URLSearchParams(routerUrl);
if (redirectParams.get("cal.action") === "eventTypeRedirectUrl") {
// display booker with redirect URL
onDisplayBookerEmbed?.();
return <BookerEmbed routingFormUrl={routerUrl} {...bookerProps} />;
} else if (redirectParams.get("cal.action") === "externalRedirectUrl") {
onExternalRedirect?.();
window.location.href = routerUrl;
return <></>;
}
}
if (!isRedirect && routingData?.message) {
if (renderMessage) {
return <>{renderMessage(routingData?.message)}</>;
}
return (
<div className="mx-auto my-0 max-w-3xl md:my-24">
<div className="w-full max-w-4xl ltr:mr-2 rtl:ml-2">
<div className="text-default bg-default -mx-4 rounded-sm border border-neutral-200 p-4 py-6 sm:mx-0 sm:px-8">
<div>{routingData?.message}</div>
</div>
</div>
</div>
);
}
return <></>;
}
);
Router.displayName = "RouterAtom";