Files
geniusrun/frontend/src/LoginGate.tsx

51 lines
1.6 KiB
TypeScript
Raw Normal View History

import { useEffect, useState } from "react";
import { api, BASE_URL } from "./api/client";
import "./LoginGate.css";
import App from "./App";
import type { SessionInfo } from "./types/api";
type Status = "loading" | "authenticated" | "unauthenticated";
const AUTH_ERROR_MESSAGES: Record<string, string> = {
forbidden: "Your account isn't authorized for geniusrun.",
failed: "Login failed, please try again.",
};
// Wraps App: on mount, asks the backend whether this browser already has a
// valid session (GET /api/session/me). geniusrun has no anonymous view, so
// this is the only fork in the whole frontend between "show the login
// screen" and "show the app."
export function LoginGate() {
const [status, setStatus] = useState<Status>("loading");
const [session, setSession] = useState<SessionInfo | null>(null);
useEffect(() => {
api
.getSessionInfo()
.then((s) => {
setSession(s);
setStatus("authenticated");
})
.catch(() => setStatus("unauthenticated"));
}, []);
if (status === "loading") {
return <div className="login-gate-loading">Loading</div>;
}
if (status === "unauthenticated") {
const authError = new URLSearchParams(window.location.search).get("auth_error");
return (
<div className="login-gate">
<h1>🧞 geniusrun</h1>
{authError && <p className="login-gate-error">{AUTH_ERROR_MESSAGES[authError] ?? "Login failed, please try again."}</p>}
<a className="login-gate-button" href={`${BASE_URL}/api/session/login`}>
Log in
</a>
</div>
);
}
return <App session={session!} />;
}