first commit
This commit is contained in:
commit
367533c02b
171 files changed
+101175
No files matched your search
@@ -0,0 +1,70 @@
|
||||
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { api, ApiError, AUTH_UNAUTHORIZED_EVENT } from '../services/apiClient.ts';
|
||||
import type { User } from '../types/api.ts';
|
||||
|
||||
type AuthContextValue = {
|
||||
user: User | null;
|
||||
loading: boolean;
|
||||
login: (userName: string, password: string) => Promise<void>;
|
||||
logout: () => Promise<void>;
|
||||
};
|
||||
|
||||
const AuthContext = createContext<AuthContextValue | null>(null);
|
||||
|
||||
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const onUnauthorized = () => setUser(null);
|
||||
window.addEventListener(AUTH_UNAUTHORIZED_EVENT, onUnauthorized);
|
||||
return () => window.removeEventListener(AUTH_UNAUTHORIZED_EVENT, onUnauthorized);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
const me = await api.auth.me();
|
||||
if (!cancelled) setUser(me);
|
||||
} catch (err) {
|
||||
if (
|
||||
!cancelled &&
|
||||
!(err instanceof ApiError && (err.status === 401 || err.status === 403))
|
||||
) {
|
||||
console.error(err);
|
||||
}
|
||||
if (!cancelled) setUser(null);
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const login = useCallback(async (userName: string, password: string) => {
|
||||
await api.auth.csrf();
|
||||
const next = await api.auth.login(userName, password);
|
||||
setUser(next);
|
||||
}, []);
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
try {
|
||||
await api.auth.logout();
|
||||
} finally {
|
||||
setUser(null);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const value = useMemo(() => ({ user, loading, login, logout }), [user, loading, login, logout]);
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
||||
};
|
||||
|
||||
export function useAuth(): AuthContextValue {
|
||||
const ctx = useContext(AuthContext);
|
||||
if (!ctx) throw new Error('useAuth must be used within AuthProvider');
|
||||
return ctx;
|
||||
}
|
||||
Reference in new issue
Block a user