M8: add operational authentication mode
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import { createContext, useCallback, useContext, useEffect, useState, type ReactNode } from "react";
|
||||
import { api, onUnauthorized } from "../api/client";
|
||||
import type { CurrentUser, Role } from "../api/types";
|
||||
import type { CurrentUser, Role, SystemStatus } from "../api/types";
|
||||
|
||||
interface AuthState {
|
||||
user: CurrentUser | null;
|
||||
loading: boolean;
|
||||
demoMode: boolean;
|
||||
loginAs: (role: Role) => Promise<void>;
|
||||
loginWithPassword: (email: string, password: string) => Promise<void>;
|
||||
logout: () => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -32,11 +34,15 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
// confirmed (or rejected) the session cookie.
|
||||
const [user, setUser] = useState<CurrentUser | null>(() => readCachedUser());
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [demoMode, setDemoMode] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
api
|
||||
.get<CurrentUser>("/api/v1/demo/session")
|
||||
api.get<SystemStatus>("/api/v1/system/status")
|
||||
.then((system) => setDemoMode(system.demo_mode))
|
||||
.catch(() => setDemoMode(true))
|
||||
.finally(() => api
|
||||
.get<CurrentUser>("/api/v1/auth/session")
|
||||
.then((confirmed) => {
|
||||
if (cancelled) return;
|
||||
setUser(confirmed);
|
||||
@@ -49,7 +55,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setLoading(false);
|
||||
});
|
||||
}));
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
@@ -75,11 +81,22 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const loginWithPassword = useCallback(async (email: string, password: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const loggedIn = await api.post<CurrentUser>("/api/v1/auth/login", { email, password });
|
||||
setUser(loggedIn);
|
||||
cacheUser(loggedIn);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
setUser(null);
|
||||
cacheUser(null);
|
||||
try {
|
||||
await api.post("/api/v1/demo/logout");
|
||||
await api.post("/api/v1/auth/logout");
|
||||
} catch {
|
||||
// Best effort: the cookie is cleared server-side when it works, and the client has
|
||||
// already dropped its own state either way.
|
||||
@@ -87,7 +104,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ user, loading, loginAs, logout }}>{children}</AuthContext.Provider>
|
||||
<AuthContext.Provider value={{ user, loading, demoMode, loginAs, loginWithPassword, logout }}>{children}</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user