singularity-forge/web/components/sf/Login.tsx
2026-05-17 20:07:36 +02:00

63 lines
2.1 KiB
TypeScript

import { useState } from "react";
export default function Login() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError("");
const res = await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password }),
});
if (res.ok) {
const { token } = await res.json();
localStorage.setItem("sf-auth-token", token);
window.location.href = "/";
} else {
setError("Invalid credentials");
}
};
return (
<div className="flex min-h-screen items-center justify-center bg-background px-6 text-foreground">
<form
onSubmit={handleSubmit}
className="w-full max-w-sm space-y-4 rounded border border-border bg-card p-6 shadow-sm"
>
<div>
<h1 className="text-lg font-semibold">Sign in to SF</h1>
<p className="mt-1 text-sm text-muted-foreground">
Enter the local web credentials for this server.
</p>
</div>
<input
type="text"
placeholder="Username"
value={username}
autoComplete="username"
onChange={(e) => setUsername(e.target.value)}
className="h-10 w-full rounded border border-input bg-background px-3 text-sm outline-none ring-offset-background placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring"
/>
<input
type="password"
placeholder="Password"
value={password}
autoComplete="current-password"
onChange={(e) => setPassword(e.target.value)}
className="h-10 w-full rounded border border-input bg-background px-3 text-sm outline-none ring-offset-background placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring"
/>
<button
type="submit"
className="h-10 w-full rounded bg-primary px-4 text-sm font-medium text-primary-foreground hover:bg-primary/90"
>
Sign In
</button>
{error && <div className="text-sm text-destructive">{error}</div>}
</form>
</div>
);
}