"use client";
import { useEffect, useState } from "react";
import { LoginScreen } from "@/components/auth/login-screen";
import { ChatApp } from "@/components/chat/chat-app";
import {
authFetch,
clearStoredToken,
getStoredToken,
storeToken,
} from "@/lib/auth/client";
import { parseAuthIdentity, type AuthIdentity } from "@/lib/auth/types";
type AuthState =
| { status: "checking" }
| { status: "anonymous" }
| { status: "authenticated"; user: AuthIdentity };
type IdentityResponse = { user: AuthIdentity };
export function AuthGate() {
const [state, setState] = useState<AuthState>({ status: "checking" });
useEffect(() => {
let active = true;
async function validateToken() {
await Promise.resolve();
const token = getStoredToken();
if (!token) {
if (active) {
setState({ status: "anonymous" });
}
return;
}
try {
const response = await authFetch("/api/auth/me", { cache: "no-store" });
if (response.status === 401) {
clearStoredToken();
}
if (!response.ok) {
if (active) {
setState({ status: "anonymous" });
}
return;
}
const payload: unknown = await response.json();
if (!isIdentityResponse(payload)) {
if (active) {
setState({ status: "anonymous" });
}
return;
}
if (active) {
setState({ status: "authenticated", user: payload.user });
}
} catch {
if (active) {
setState({ status: "anonymous" });
}
}
}
void validateToken();
return () => {
active = false;
};
}, []);
function handleAuthenticated(token: string, user: AuthIdentity) {
storeToken(token);
setState({ status: "authenticated", user });
}
function handleLogout() {
clearStoredToken();
setState({ status: "anonymous" });
}
if (state.status === "checking") {
return (
<main
aria-label="Проверяем доступ"
className="flex min-h-screen items-center justify-center bg-muted/30 p-6"
>
<p role="status" className="text-sm text-muted-foreground">
Проверяем доступ
</p>
</main>
);
}
if (state.status === "authenticated") {
return <ChatApp key={state.user.id} onLogout={handleLogout} user={state.user} />;
}
return <LoginScreen onAuthenticated={handleAuthenticated} />;
}
function isIdentityResponse(value: unknown): value is IdentityResponse {
if (typeof value !== "object" || value === null || !("user" in value)) {
return false;
}
return parseAuthIdentity(value.user) !== null;
}