- Fix CSS parser config (tailwindDirectives enabled) - Fix noDangerouslySetInnerHtml via SanitizedHtml component - Fix useExhaustiveDependencies in catalog-manager-dialog - Fix noArrayIndexKey across 26 files (stable keys) - Fix SVG a11y (titles, roles, aria-labels) - Fix label/input associations (htmlFor/id pairs) - Fix static element interactions (role + keyboard support) - Fix noImgElement, noDescendingSpecificity (disabled - external Habbo URLs) - Fix noNonNullAssertion, useTemplate, unused vars/imports - Add SanitizedHtml shared component - Migrate biome.json to 2.5.4 schema
122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { signIn } from "next-auth/react";
|
|
import { type FormEvent, useState } from "react";
|
|
import { precheckLogin } from "@/actions/auth-precheck";
|
|
|
|
export function HomeLoginForm() {
|
|
const [username, setUsername] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
const [code, setCode] = useState("");
|
|
const [needs2fa, setNeeds2fa] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [pending, setPending] = useState(false);
|
|
|
|
async function onSubmit(e: FormEvent) {
|
|
e.preventDefault();
|
|
setError(null);
|
|
setPending(true);
|
|
try {
|
|
if (!needs2fa) {
|
|
const pre = await precheckLogin(username, password);
|
|
if (pre === "invalid") {
|
|
setError("Invalid username or password");
|
|
return;
|
|
}
|
|
if (pre === "twofactor") {
|
|
setNeeds2fa(true);
|
|
return;
|
|
}
|
|
}
|
|
const res = await signIn("credentials", {
|
|
username,
|
|
password,
|
|
code,
|
|
redirect: false,
|
|
});
|
|
if (!res || res.error) {
|
|
setError(
|
|
needs2fa ? "Invalid 2FA code" : "Invalid username or password",
|
|
);
|
|
return;
|
|
}
|
|
window.location.href = "/";
|
|
} finally {
|
|
setPending(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<form
|
|
onSubmit={onSubmit}
|
|
className="relative flex flex-col gap-6 rounded-lg bg-gray-100 p-3 dark:bg-gray-800"
|
|
>
|
|
<fieldset className="flex w-full flex-col gap-1">
|
|
<label htmlFor="login-username" className="block font-semibold text-gray-700 dark:text-gray-200">
|
|
Username
|
|
</label>
|
|
<input
|
|
id="login-username"
|
|
type="text"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
placeholder=""
|
|
className="focus:ring-0 relative z-10 w-full rounded border-4 border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200"
|
|
style={{ borderColor: "#e5e7eb", borderWidth: "4px" }}
|
|
required
|
|
disabled={needs2fa}
|
|
/>
|
|
</fieldset>
|
|
<fieldset className="flex w-full flex-col gap-1">
|
|
<label htmlFor="login-password" className="block font-semibold text-gray-700 dark:text-gray-200">
|
|
Password
|
|
</label>
|
|
<input
|
|
id="login-password"
|
|
type="password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
placeholder=""
|
|
className="focus:ring-0 relative z-10 w-full rounded border-4 border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200"
|
|
style={{ borderColor: "#e5e7eb", borderWidth: "4px" }}
|
|
required
|
|
disabled={needs2fa}
|
|
/>
|
|
</fieldset>
|
|
{needs2fa ? (
|
|
<fieldset className="flex w-full flex-col gap-1">
|
|
<label htmlFor="login-2fa" className="block font-semibold text-gray-700 dark:text-gray-200">
|
|
2FA Code
|
|
</label>
|
|
<input
|
|
id="login-2fa"
|
|
type="text"
|
|
value={code}
|
|
onChange={(e) => setCode(e.target.value)}
|
|
placeholder="Enter your 2FA code"
|
|
inputMode="numeric"
|
|
className="focus:ring-0 relative z-10 w-full rounded border-4 border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200"
|
|
style={{ borderColor: "#e5e7eb", borderWidth: "4px" }}
|
|
/>
|
|
</fieldset>
|
|
) : null}
|
|
{error ? (
|
|
<p className="m-0 text-center text-sm text-red-600 dark:text-red-400">
|
|
{error}
|
|
</p>
|
|
) : null}
|
|
<button
|
|
type="submit"
|
|
disabled={pending}
|
|
className="w-full cursor-pointer rounded-md border-2 p-2 text-base font-semibold text-white transition-colors disabled:opacity-50"
|
|
style={{
|
|
backgroundColor: "#27a44d",
|
|
borderColor: "#34d399",
|
|
}}
|
|
>
|
|
{pending ? "Please wait..." : needs2fa ? "Verify" : "Login"}
|
|
</button>
|
|
</form>
|
|
);
|
|
}
|