Files
triggershell/src/app/login/login-form.tsx
T

96 lines
2.8 KiB
TypeScript
Raw Normal View History

2026-08-15 18:37:30 +02:00
"use client";
import { useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Terminal } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription } from "@/components/ui/alert";
export function LoginForm() {
const router = useRouter();
const searchParams = useSearchParams();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
const [pending, setPending] = useState(false);
async function handleSubmit(event: React.FormEvent) {
event.preventDefault();
setPending(true);
setError(null);
const response = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password }),
});
if (response.ok) {
const next = searchParams.get("next") ?? "/";
router.push(next);
router.refresh();
return;
}
const data = await response.json().catch(() => ({}));
setError(data.error ?? "Login failed");
setPending(false);
}
return (
<Card className="w-full max-w-sm">
<CardHeader>
<div className="flex items-center gap-2">
<Terminal className="size-5" />
<CardTitle>TriggerShell</CardTitle>
</div>
<CardDescription>
Sign in to run and monitor your configured scripts.
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
{error && (
<Alert variant="destructive">
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<div className="flex flex-col gap-2">
<Label htmlFor="username">Username</Label>
<Input
id="username"
autoComplete="username"
value={username}
onChange={(event) => setUsername(event.target.value)}
required
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
autoComplete="current-password"
value={password}
onChange={(event) => setPassword(event.target.value)}
required
/>
</div>
<Button type="submit" disabled={pending} className="mt-2">
{pending ? "Signing in..." : "Sign in"}
</Button>
</form>
</CardContent>
</Card>
);
}