master
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};