This commit is contained in:
2025-11-30 21:47:03 +01:00
parent d38f8891f5
commit 73791a0760
12 changed files with 3226 additions and 70 deletions
+77
View File
@@ -0,0 +1,77 @@
import { useState } from "react";
import { LoginRequest, LoginResponse } from "../items";
interface LoginProps {
onLogin: (token: string) => void;
}
export function Login({ onLogin }: LoginProps) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError("");
try {
const req = LoginRequest.create({ username, password });
const body = LoginRequest.encode(req).finish();
const res = await fetch("/auth/login", {
method: "POST",
body,
headers: {
"Content-Type": "application/octet-stream",
},
});
const buffer = await res.arrayBuffer();
const response = LoginResponse.decode(new Uint8Array(buffer));
if (response.success) {
onLogin(response.token);
} else {
setError(response.message);
}
} catch (err) {
console.error("Login error:", err);
setError("Failed to login");
}
};
return (
<div className="card">
<h2>Login</h2>
<form
onSubmit={handleSubmit}
style={{ display: "flex", flexDirection: "column", gap: "1rem" }}
>
<div>
<label style={{ display: "block", marginBottom: "0.5rem" }}>
Username:{" "}
</label>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
style={{ padding: "0.5rem" }}
/>
</div>
<div>
<label style={{ display: "block", marginBottom: "0.5rem" }}>
Password:{" "}
</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
style={{ padding: "0.5rem" }}
/>
</div>
<button type="submit">Login</button>
</form>
{error && <p style={{ color: "red", marginTop: "1rem" }}>{error}</p>}
</div>
);
}