fix: add Session and Login

This commit is contained in:
julius 2025-02-17 23:11:06 +01:00
parent df94b151a6
commit 96f04e6d90
Signed by: julius
GPG Key ID: C80A63E6A5FD7092
2 changed files with 126 additions and 0 deletions

86
src/Login.tsx Normal file
View File

@ -0,0 +1,86 @@
import { FormEvent, useContext, useState } from "react";
import { useNavigate } from "react-router";
import { currentUser, login, LoginRequest, User } from "./api";
export interface LoginProps {
onLogin: (user: User) => void;
}
export const Login = ({ onLogin }: LoginProps) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<unknown>(null);
const [loading, setLoading] = useState(false);
async function doLogin() {
setLoading(true);
setError(null);
const timeout = new Promise((r) => setTimeout(r, 1500));
let user: User;
try {
login({ username, password });
user = await currentUser();
} catch (e) {
await timeout;
setError(e);
setLoading(false);
return
}
await timeout;
onLogin(user);
}
function handleClick() {
doLogin();
}
function handleSubmit(e: React.FormEvent) {
e.preventDefault();
doLogin();
}
return (
<form onSubmit={handleSubmit}>
<div>
<input type="text" id="username" name="username" placeholder="username" required value={username} onChange={evt => setUsername(evt.target.value)} />
</div>
<div>
<input type="password" id="password" name="password" placeholder="password" minLength={8} value={password} required onChange={evt => setPassword(evt.target.value)} />
</div>
<button type="submit" value="login" style={{ fontSize: "small" }} onClick={handleClick} >login</button>
{loading && <span className="loader" />}
</form>
)
}
/*
export default function Login(props: { onLogin: (user: User) => void }) {
const { onLogin } = props;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
async function handleLogin(e: FormEvent) {
e.preventDefault()
const timeout = new Promise((r) => setTimeout(r, 1500));
let user: User;
try {
login({ username, password })
user = await currentUser()
} catch (e) { await timeout; return }
await timeout;
onLogin(user);
}
return <div>
<form onSubmit={handleLogin}>
<div>
<input type="text" id="username" name="username" placeholder="username" required value={username} onChange={evt => setUsername(evt.target.value)} />
</div>
<div>
<input type="password" id="password" name="password" placeholder="password" minLength={8} value={password} required onChange={evt => setPassword(evt.target.value)} />
</div>
<input className="button" type="submit" value="login" onSubmit={handleLogin} />
</form>
</div>
} */

40
src/Session.tsx Normal file
View File

@ -0,0 +1,40 @@
import { createContext, ReactNode, useContext, useLayoutEffect, useState } from "react";
import { currentUser, User } from "./api";
import { Login } from "./Login";
export interface SessionProviderProps {
children: ReactNode;
}
const sessionContext = createContext<User | null>(null);
export function SessionProvider(props: SessionProviderProps) {
const { children } = props;
const [user, setUser] = useState<User | null>(null);
const [err, setErr] = useState<unknown>(null);
function loadUser() {
currentUser()
.then((user) => { setUser(user); setErr(null); })
.catch((err) => { setUser(null); setErr(err); });
}
useLayoutEffect(() => { loadUser(); }, [err]);
function onLogin(user: User) {
setUser(user);
setErr(null);
}
let content: ReactNode;
if (!err && !user) content = <span className="loader" />;
else if (err) content = <Login onLogin={onLogin} />;
else content = <sessionContext.Provider value={user}>{children}</sessionContext.Provider>;
return content;
}
export function useSession() {
return useContext(sessionContext);
}