import { useEffect } from "react"; import { isRouteErrorResponse, useNavigate, useRouteError, useSearchParams, } from "react-router"; import useSyncStorage from "../client/hooks/useSyncStorage.ts"; import config from "../config.ts"; import { hasLogoutIntentParam } from "../logoutIntent.ts"; import { tokenVerifyErrorCode } from "../user/getUserFromRequest.ts"; import TrySigninSilent from "./TrySigninSilent.tsx"; export const next_withAuthErrorBoundary = ( ErrorBoundary: React.ComponentType, { VerifyToken = () => null, UnauthorizedWhileLogout = () => null, Unauthorized = () => null, }: { VerifyToken?: React.ComponentType; UnauthorizedWhileLogout?: React.ComponentType; Unauthorized?: React.ComponentType; } = {}, ) => function WithAuthErrorBoundary(props: any) { const isLoggingOutProtectedRoute = useHandleLogoutProtectedRoute(); const isUnauthorizedRouteError = useIsUnauthorizedRouteError(); useSyncStorage(); if (isLoggingOutProtectedRoute) { return ; } if (isUnauthorizedRouteError) { // Server was unable to verify token. Try silent sign-in. if (props.error?.data?.code === tokenVerifyErrorCode) { return ( ); } return ; } return ; }; /** * @deprecated Use `withAuthErrorBoundary` with the new signature instead. */ const legacy_withAuthErrorBoundary = ( Unauthorized: React.ComponentType, ErrorBoundary: React.ComponentType, ) => next_withAuthErrorBoundary(ErrorBoundary, { Unauthorized, VerifyToken: Unauthorized, }); export function withAuthErrorBoundary( ...args: | Parameters | Parameters ) { if (typeof args[1] === "function") { return legacy_withAuthErrorBoundary( ...(args as Parameters), ); } else { return next_withAuthErrorBoundary( ...(args as Parameters), ); } } export function useIsUnauthorizedRouteError() { const error = useRouteError(); return isRouteErrorResponse(error) && error.status === 401; } export function useHandleLogoutProtectedRoute() { const isUnauthorized = useIsUnauthorizedRouteError(); const [searchParams] = useSearchParams(); const navigate = useNavigate(); const isLoggingOut = hasLogoutIntentParam(searchParams); // Got unauthorized error while logging out. Logout occurred in a protected route. const isLoggingOutProtectedRoute = isUnauthorized && isLoggingOut; useEffect(() => { if (isLoggingOutProtectedRoute) { navigate(config.paths.fallback, { replace: true, preventScrollReset: true, }); } }, [isLoggingOutProtectedRoute, navigate]); return isLoggingOutProtectedRoute; }