diff --git a/src/components/AppShell.deeplink.test.ts b/src/components/AppShell.deeplink.test.ts index e91a401c..192ee580 100644 --- a/src/components/AppShell.deeplink.test.ts +++ b/src/components/AppShell.deeplink.test.ts @@ -147,7 +147,7 @@ vi.mock("./app-shell/useOnboardingFlow", () => ({ }), })); -import { AppShell } from "./AppShell"; +import { AppShell, buildAuthStartPath } from "./AppShell"; const waitForCondition = async (check: () => boolean, timeoutMs = 2500): Promise => { const started = Date.now(); @@ -284,6 +284,12 @@ describe("AppShell deeplink cold-load flow", () => { window.history.replaceState(null, "", "/H%C3%B8gevarde-hyttefelt/Fyrisj%C3%B8vegen"); }); + it("builds direct auth-start navigation for explicit sign-in clicks", () => { + expect(buildAuthStartPath({ pathname: "/sim/site", search: "?mode=demo", hash: "#panel" })).toBe( + "/api/auth-start?returnTo=%2Fsim%2Fsite%3Fmode%3Ddemo%23panel", + ); + }); + it("loads the resolved simulation id and does not emit unavailable", async () => { const view = await renderAppShell(); diff --git a/src/components/AppShell.tsx b/src/components/AppShell.tsx index 5622361f..54bae555 100644 --- a/src/components/AppShell.tsx +++ b/src/components/AppShell.tsx @@ -54,6 +54,11 @@ const ACCESS_CHECKING_NOTICE_ID = "access-checking"; const AUTH_DEGRADED_NOTICE_ID = "auth-degraded"; const OFFLINE_SYNC_NOTICE_ID = "offline-sync"; const BLANK_SIM_NOTICE_ID = "blank-simulation-guidance"; + +export const buildAuthStartPath = (location: Pick): string => { + const returnTo = `${location.pathname}${location.search}${location.hash}`; + return `/api/auth-start?returnTo=${encodeURIComponent(returnTo || "/")}`; +}; // Shell vocabulary mapping for cleanup work: // - navigator => LeftSidePanel // - inspector => RightSidePanel (legacy term retained in code for stability) @@ -275,7 +280,6 @@ export function AppShell() { const authRetryQuickAttemptRef = useRef(0); const authRetryTimerRef = useRef(null); const authCheckGenerationRef = useRef(0); - const userInitiatedSignInRef = useRef(false); const runAccessCheckRef = useRef<(reason: "initial" | "retry" | "online") => void>(() => {}); const setShowWelcomeModalRef = useRef<(show: boolean) => void>(() => {}); const isInitializingRef = useRef(isInitializing); @@ -559,9 +563,8 @@ export function AppShell() { }, []); const handleUserSignInRequested = useCallback(() => { - userInitiatedSignInRef.current = true; clearAuthRetryTimer(); - runAccessCheckRef.current("retry"); + window.location.href = buildAuthStartPath(window.location); }, [clearAuthRetryTimer]); const scheduleAuthRecoveryRetry = useCallback( @@ -611,7 +614,6 @@ export function AppShell() { authRecoveryActiveRef.current = false; authRecoveryDisabledRef.current = false; authRetryQuickAttemptRef.current = 0; - userInitiatedSignInRef.current = false; setAccessDiagnosticMessage(null); setCurrentUser(profile); setAuthState("signed_in"); @@ -686,12 +688,6 @@ export function AppShell() { online: typeof navigator === "undefined" ? true : navigator.onLine, isInitializing: isInitializingRef.current, }); - if (userInitiatedSignInRef.current) { - userInitiatedSignInRef.current = false; - const returnTo = `${window.location.pathname}${window.location.search}${window.location.hash}`; - window.location.href = `/api/auth-start?returnTo=${encodeURIComponent(returnTo || "/")}`; - return; - } setAuthDegraded( "Cloud save is unavailable. Your changes may not be saved. The sign-in check timed out; LinkSim is retrying automatically.", "timeout", @@ -799,12 +795,6 @@ export function AppShell() { setAccessState("readonly"); return; } - if (userInitiatedSignInRef.current) { - userInitiatedSignInRef.current = false; - const returnTo = `${window.location.pathname}${window.location.search}${window.location.hash}`; - window.location.href = `/api/auth-start?returnTo=${encodeURIComponent(returnTo || "/")}`; - return; - } setAuthDegraded( isServerTimeout ? "Cloud save is unavailable. Your changes may not be saved. The sign-in service timed out; LinkSim is retrying automatically." diff --git a/src/components/UserAdminPanel.tsx b/src/components/UserAdminPanel.tsx index 13bcc834..98162581 100644 --- a/src/components/UserAdminPanel.tsx +++ b/src/components/UserAdminPanel.tsx @@ -81,8 +81,7 @@ type UserAdminPanelProps = { */ onOpenSettings?: () => void; /** - * When provided, clicking "Sign in" triggers a silent auth check first; - * only if that fails does it redirect to the CF Access login page. + * When provided, clicking "Sign in" delegates sign-in handling to the shell. */ onSignInRequested?: () => void; };