game_list/frontend/src/Login.tsx

77 lines
2.1 KiB
TypeScript

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" style={{ maxWidth: "400px", margin: "4rem auto" }}>
<h2 style={{ textAlign: "center", marginBottom: "2rem" }}>Login</h2>
<form onSubmit={handleSubmit} className="form-group">
<div className="form-group">
<label>Username</label>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Enter your username"
/>
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter your password"
/>
</div>
<button type="submit" style={{ marginTop: "1rem" }}>
Login
</button>
</form>
{error && (
<p style={{ color: "#ff6b6b", marginTop: "1rem", textAlign: "center" }}>
{error}
</p>
)}
</div>
);
}