Files
helios-evcs/apps/web/app/login/page.tsx

108 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Alert, Button, Card, CloseButton, Input, Label, TextField } from "@heroui/react";
import { Thunderbolt } from "@gravity-ui/icons";
import { authClient } from "@/lib/auth-client";
export default function LoginPage() {
const router = useRouter();
const searchParams = useSearchParams();
const justSetup = searchParams.get("setup") === "1";
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError("");
setLoading(true);
try {
const res = await authClient.signIn.username({
username,
password,
fetchOptions: { credentials: "include" },
});
if (res.error) {
setError(res.error.message ?? "登录失败,请检查用户名和密码");
} else {
router.push("/dashboard");
router.refresh();
}
} catch {
setError("网络错误,请稍后重试");
} finally {
setLoading(false);
}
};
return (
<div className="flex min-h-dvh flex-col items-center justify-center bg-background px-4">
{/* Brand */}
<div className="mb-8 flex flex-col items-center gap-3">
<div className="flex size-14 items-center justify-center rounded-2xl bg-accent shadow-lg">
<Thunderbolt className="size-7 text-accent-foreground" />
</div>
<div className="text-center">
<h1 className="text-2xl font-bold tracking-tight text-foreground">Helios EVCS</h1>
<p className="mt-1 text-sm text-muted"></p>
</div>
</div>
<Card className="w-full max-w-sm">
<Card.Content>
<form onSubmit={handleSubmit} className="space-y-4">
{justSetup && (
<Alert status="success">
<Alert.Indicator />
<Alert.Content>
<Alert.Title></Alert.Title>
<Alert.Description></Alert.Description>
</Alert.Content>
</Alert>
)}
<TextField fullWidth>
<Label className="text-sm font-medium"></Label>
<Input
required
autoComplete="username"
placeholder="admin"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</TextField>
<TextField fullWidth>
<Label className="text-sm font-medium"></Label>
<Input
required
autoComplete="current-password"
placeholder="••••••••"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</TextField>
{error && (
<Alert status="danger">
<Alert.Indicator />
<Alert.Content>
<Alert.Title></Alert.Title>
<Alert.Description>{error}</Alert.Description>
</Alert.Content>
<CloseButton onPress={() => setError("")} />
</Alert>
)}
<Button className="mt-2 w-full" isDisabled={loading} type="submit">
{loading ? "登录中…" : "登录"}
</Button>
</form>
</Card.Content>
</Card>
<p className="mt-6 text-xs text-muted/60">OCPP 1.6-J Protocol v0.1.0</p>
</div>
);
}