master
Raw Download raw file
 1import React from "react";
 2
 3interface User {
 4	user: string;
 5}
 6
 7interface UserContextValue {
 8	user: {
 9		loading: boolean;
10		value?: User;
11	};
12	login: (username: string, password: string) => Promise<boolean>;
13	register: (username: string, password: string) => Promise<boolean>;
14	logout: () => void;
15}
16
17const UserContext = React.createContext<UserContextValue | undefined>(undefined);
18
19export const UserProvider = ({ children }: { children: React.ReactNode }) => {
20	const [user, setUser] = React.useState<UserContextValue["user"]>({
21		loading: true,
22	});
23
24	const refresh = React.useCallback(async () => {
25		setUser({ loading: true });
26		const res = await fetch("/api/me");
27		if (res.ok) {
28			const user = await res.json();
29			setUser({ loading: false, value: user });
30		} else {
31			setUser({ loading: false });
32		}
33	}, []);
34
35	const login = React.useCallback(
36		async (username: string, password: string) => {
37			const res = await fetch("/api/login", {
38				method: "POST",
39				headers: {
40					"Content-Type": "application/json",
41				},
42				body: JSON.stringify({ username, password }),
43			});
44
45			if (res.ok) {
46				await refresh();
47				return true;
48			} else {
49				return false;
50			}
51		},
52		[refresh],
53	);
54
55	const register = React.useCallback(
56		async (username: string, password: string) => {
57			const res = await fetch("/api/register", {
58				method: "POST",
59				headers: {
60					"Content-Type": "application/json",
61				},
62				body: JSON.stringify({ username, password }),
63			});
64
65			if (res.ok) {
66				return true;
67			} else {
68				return false;
69			}
70		},
71		[refresh],
72	);
73
74	const logout = React.useCallback(async () => {
75		const res = await fetch("/api/logout", {
76			method: "POST",
77		});
78
79		if (res.ok) {
80			await refresh();
81		}
82	}, [refresh]);
83
84	React.useEffect(() => {
85		refresh();
86	}, [refresh]);
87
88	return <UserContext.Provider value={{ user, login, register, logout }}>{children}</UserContext.Provider>;
89};
90
91export const useUser = () => {
92	const context = React.useContext(UserContext);
93	if (!context) {
94		throw new Error("useUser must be used within a UserProvider");
95	}
96	return context;
97};