import { Component, ReactNode, startTransition, use, useEffect } from "react"; import { Context } from "../../apps/client/contexts/routing-context"; type Props = { children?: ReactNode; }; export class RedirectBoundary extends Component< Props, { error: (Error & { digest: string }) | null; } > { constructor(props: Props) { super(props); this.state = { error: null, }; } static getDerivedStateFromError(error: unknown) { if ( error instanceof Error && "digest" in error && typeof error.digest === "string" ) { let [name, status, url] = error.digest.split(":"); if (name === "TwofoldRedirectError") { return { error, }; } } throw error; } reset() { this.setState({ error: null, }); } render() { if (this.state.error) { let url = getUrlFromError(this.state.error); return this.reset()} />; } else { return this.props.children; } } } function getUrlFromError(error: Error & { digest: string }) { let [_name, _status, url] = error.digest.split(":"); if (!url) { throw new Error("Invalid redirect URL"); } return decodeURIComponent(url); } function TriggerRedirect({ url, reset }: { url: string; reset: () => void }) { let { replace } = use(Context); useEffect(() => { startTransition(() => { if (url.startsWith("/")) { replace(url); reset(); } else { window.location.replace(url); } }); }, [replace, url, reset]); return null; }