import { Trans, useLingui } from "@lingui/react/macro";
import { LOCAL_SETTINGS_PAGE } from "@rakazo/contracts";
import { Button, Skeleton } from "@rakazo/ui-web";
import { Suspense, useEffect, useLayoutEffect, useRef, useState } from "react";
import { Navigate, Route, Routes, useSearchParams } from "react-router-dom";
import { LoadingState } from "./components/ai/primitives";
import { authClient } from "./lib/auth";
import { lazyWithRecovery } from "./lib/lazy-recovery";
import { markAfterPaint, markOnce } from "./lib/performance";
import {
holdUnreachableGate,
sessionGate,
sessionRetryDelayMs,
showSessionUnavailable,
} from "./lib/session-gate";
import { IntegrationSetupPage } from "./pages/IntegrationSetup";
import { McpOAuthCallbackPage } from "./pages/McpOAuthCallback";
import { ShellPage } from "./pages/Shell";
const AuthPage = lazyWithRecovery("pages/Auth", () =>
import("./pages/Auth").then((module) => ({ default: module.AuthPage })),
);
const PasswordResetPage = lazyWithRecovery("pages/Auth", () =>
import("./pages/Auth").then((module) => ({ default: module.PasswordResetPage })),
);
const OnboardingPage = lazyWithRecovery("pages/Onboarding", () =>
import("./pages/Onboarding").then((module) => ({ default: module.OnboardingPage })),
);
const WelcomePage = lazyWithRecovery("pages/Welcome", () =>
import("./pages/Welcome").then((module) => ({ default: module.WelcomePage })),
);
const LocalSettingsPage = lazyWithRecovery("pages/LocalSettings", () =>
import("./pages/LocalSettings").then((module) => ({ default: module.LocalSettingsPage })),
);
export function App() {
if (window.location.pathname === LOCAL_SETTINGS_PAGE) {
return (
}>
);
}
return ;
}
function SessionApp() {
const [searchParams] = useSearchParams();
const signInDestination =
searchParams.get("next") === "/integrations/setup" ? "/integrations/setup" : "/app";
const session = authClient.useSession();
const gate = sessionGate(session);
const [holdingUnreachable, setHoldingUnreachable] = useState(false);
const nextHolding = holdUnreachableGate(gate, holdingUnreachable);
if (nextHolding !== holdingUnreachable) setHoldingUnreachable(nextHolding);
useLayoutEffect(() => {
if (session.isPending) return;
markOnce("rk:renderer:session-committed");
markAfterPaint("rk:renderer:session-painted");
}, [session.isPending]);
if (showSessionUnavailable(gate, nextHolding)) {
return ;
}
if (gate === "loading") {
return window.location.pathname.startsWith("/app") ? (
) : (
Loading…
);
}
const user = session.data?.user;
return (
}>
: } />
:
}
/>
: }
/>
:
}
/>
} />
: }
/>
: }
/>
) : (
)
}
/>
: } />
: }
/>
: }
/>
);
}
/**
* A session lookup that never reached the server is not a sign-out, so the app
* waits and retries here instead of routing to sign-in and stranding a signed-in
* user. Better Auth only polls once a session exists, so the retry lives here.
*/
function SessionUnavailable({ refetch }: { refetch: () => Promise }) {
const { t } = useLingui();
const [attempt, setAttempt] = useState(0);
const [retryKey, setRetryKey] = useState(0);
const retryImmediately = useRef(false);
const refetchRef = useRef(refetch);
refetchRef.current = refetch;
useEffect(() => {
let cancelled = false;
const delay = retryImmediately.current ? 0 : sessionRetryDelayMs(attempt);
retryImmediately.current = false;
const timer = setTimeout(() => {
void refetchRef.current().finally(() => {
if (!cancelled) setAttempt((value) => value + 1);
});
}, delay);
return () => {
cancelled = true;
clearTimeout(timer);
};
}, [attempt, retryKey]);
return (
Can't reach the server.
);
}
function ShellSkeleton() {
return (
);
}