1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
import { useCallback, useSyncExternalStore } from "react";
import { apiLogin } from "../api/client";
import {
type User,
clearToken,
getToken,
getUserFromToken,
isTokenExpired,
setToken,
} from "../auth";
// Simple external store to trigger re-renders when auth state changes.
let authVersion = 0;
const listeners = new Set<() => void>();
function subscribe(callback: () => void) {
listeners.add(callback);
return () => listeners.delete(callback);
}
function getSnapshot() {
return authVersion;
}
function notifyAuthChange() {
authVersion++;
for (const listener of listeners) {
listener();
}
}
export function useAuth(): {
user: User | null;
token: string | null;
isLoggedIn: boolean;
login: (username: string, password: string) => Promise<void>;
logout: () => void;
} {
useSyncExternalStore(subscribe, getSnapshot);
const token = getToken();
const isExpired = isTokenExpired();
const user = isExpired ? null : getUserFromToken();
const isLoggedIn = user !== null && !isExpired;
const login = useCallback(async (username: string, password: string) => {
const { token } = await apiLogin(username, password);
setToken(token);
notifyAuthChange();
}, []);
const logout = useCallback(() => {
clearToken();
notifyAuthChange();
}, []);
return { user, token: isLoggedIn ? token : null, isLoggedIn, login, logout };
}
|