fix(deploy): pin distinct image tags per compose (booklib/{api,web}:{dev,prod}); same project name shared default tags so dev up without --build ran the prod image
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { useState, type FormEvent } from "react";
|
||||
import { Navigate, useLocation } from "react-router-dom";
|
||||
import { useAuth } from "../auth/AuthContext";
|
||||
import { toast } from "../components/Toaster";
|
||||
import { btnPrimary, card, input } from "../components/ui";
|
||||
|
||||
export default function Login() {
|
||||
const { login, user } = useAuth();
|
||||
const loc = useLocation() as { state?: { from?: string } };
|
||||
const [u, setU] = useState("");
|
||||
const [p, setP] = useState("");
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
if (user) return <Navigate to={loc.state?.from ?? "/"} replace />;
|
||||
|
||||
async function submit(e: FormEvent) {
|
||||
e.preventDefault();
|
||||
setBusy(true);
|
||||
try {
|
||||
await login(u, p);
|
||||
} catch (err) {
|
||||
toast("err", err instanceof Error ? err.message : "登录失败");
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid h-full place-items-center p-4">
|
||||
<form onSubmit={submit} className={`${card} w-full max-w-sm space-y-4 p-6`}>
|
||||
<h1 className="text-lg font-semibold">BookLib 登录</h1>
|
||||
<input className={input + " w-full"} value={u} onChange={(e) => setU(e.target.value)}
|
||||
placeholder="用户名" autoFocus autoComplete="username" />
|
||||
<input className={input + " w-full"} type="password" value={p} onChange={(e) => setP(e.target.value)}
|
||||
placeholder="密码" autoComplete="current-password" />
|
||||
<button className={btnPrimary + " w-full"} disabled={busy || !u || !p}>
|
||||
{busy ? "登录中…" : "登录"}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user