Use a lightweight cookie (multica_logged_in) + Next.js 16 proxy to 302-redirect authenticated users visiting / straight to /issues. Unauthenticated visitors (and search engine crawlers) continue to see the full landing page with zero flash. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, type ReactNode } from "react";
|
|
import { useAuthStore } from "./store";
|
|
import { useWorkspaceStore } from "@/features/workspace";
|
|
import { api } from "@/shared/api";
|
|
import { createLogger } from "@/shared/logger";
|
|
import { setLoggedInCookie, clearLoggedInCookie } from "./auth-cookie";
|
|
|
|
const logger = createLogger("auth");
|
|
|
|
/**
|
|
* Initializes auth + workspace state from localStorage on mount.
|
|
* Fires getMe() and listWorkspaces() in parallel when a cached token exists.
|
|
*/
|
|
export function AuthInitializer({ children }: { children: ReactNode }) {
|
|
useEffect(() => {
|
|
const token = localStorage.getItem("multica_token");
|
|
if (!token) {
|
|
clearLoggedInCookie();
|
|
useAuthStore.setState({ isLoading: false });
|
|
return;
|
|
}
|
|
|
|
api.setToken(token);
|
|
const wsId = localStorage.getItem("multica_workspace_id");
|
|
|
|
// Fire getMe and listWorkspaces in parallel
|
|
const mePromise = api.getMe();
|
|
const wsPromise = api.listWorkspaces();
|
|
|
|
Promise.all([mePromise, wsPromise])
|
|
.then(([user, wsList]) => {
|
|
setLoggedInCookie();
|
|
useAuthStore.setState({ user, isLoading: false });
|
|
useWorkspaceStore.getState().hydrateWorkspace(wsList, wsId);
|
|
})
|
|
.catch((err) => {
|
|
logger.error("auth init failed", err);
|
|
api.setToken(null);
|
|
api.setWorkspaceId(null);
|
|
localStorage.removeItem("multica_token");
|
|
localStorage.removeItem("multica_workspace_id");
|
|
clearLoggedInCookie();
|
|
useAuthStore.setState({ user: null, isLoading: false });
|
|
});
|
|
}, []);
|
|
|
|
return <>{children}</>;
|
|
}
|