import { useState, type ReactNode } from "react"; import { ModalDialog } from "../ModalDialog/index.tsx"; import { useCurrentUser } from "../store/index.tsx"; import { AccountIssueView } from "./AccountIssueView.tsx"; import { LoginView } from "./LoginView.tsx"; import { useFetchCurrentUser } from "./useFetchCurrentUser.tsx"; import { UserMismatchView } from "./UserMismatchView.tsx"; import { VerifyAccountView } from "./VerifyPage.tsx"; type CurrentUserFetcherProps = { children: ReactNode; }; /** * Fetches fresh current user data if a local user exists in the app store. * * This component uses the Indie Tabletop Client under the hood, so if new * data is successfully fetched, the onCurrentUser callback will be invoked, * and it is up to the configuration of the client to store the data. * * Importantly, this component also handles the various user account issues * that we could run into: expired session, user mismatch and account deletion. * * All other errors are ignored. This allows users to use the app in offline * mode, and doesn't interrupt their session if some unexpected error happens, * which they cannot do anything about anyways. */ export function CurrentUserFetcher(props: CurrentUserFetcherProps) { const { children } = props; const localUser = useCurrentUser(); const [isOpen, setOpen] = useState(true); const { result, reload } = useFetchCurrentUser({ // We only want to fetch the current user if they exist in the store, i.e. // they have logged into the app previously. performFetch: !!localUser, // If we are performing a fetch, we want to make sure that it is up to date // every time the user focuses the window. revalidateOnFocus: true, }); if (result.isFailure && result.failure.type === "API_ERROR") { // The user's session has expired. They should be prompted to // re-authenticate, as any syncing attemps will fail. if (result.failure.code === 401) { return ( <> reload()} description={undefined} reload={reload} /> {children} ); } if (result.failure.code === 404) { // The user account is not found. The user might have been deleted. // The user should be notified and instructed to log out, as many // interactions acrosss the app will be broken. return ( <> {children} ); } } if (localUser && result.isSuccess) { const serverUser = result.value; // The cookie (server) user and the user in local storage are a different // user. The current user needs to decide which account to use. if (serverUser.id !== localUser.id) { return ( <> {children} ); } if (!serverUser.isVerified) { return ( <> setOpen(false)} reload={reload} /> {children} ); } } // In all other cases we simply render the children return <>{children}; }