registration fix
This commit is contained in:
parent
29671855de
commit
ae528d8f22
2 changed files with 68 additions and 70 deletions
|
|
@ -3,8 +3,19 @@ import { cookies } from "next/headers";
|
|||
import { redirect } from "next/navigation";
|
||||
import SignUp from "./sign-up";
|
||||
|
||||
export default async function SignUpPage() {
|
||||
const at = (await cookies()).get("ma_at")?.value;
|
||||
export default async function SignUpPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams?: Record<string, string | string[] | undefined>;
|
||||
}) {
|
||||
const ck = await cookies();
|
||||
const at = ck.get("ma_at")?.value;
|
||||
if (at) redirect("/portal");
|
||||
return <SignUp nextPath="/portal" />;
|
||||
|
||||
const sp = searchParams ?? {};
|
||||
const nextParam = Array.isArray(sp.next) ? sp.next[0] : sp.next;
|
||||
const nextPath =
|
||||
nextParam && String(nextParam).startsWith("/") ? String(nextParam) : "/portal";
|
||||
|
||||
return <SignUp nextPath={nextPath} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,36 +15,60 @@ export default function SignUp({ nextPath = "/portal" }: Props) {
|
|||
const [loading, setLoading] = useState(false);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
|
||||
const onSubmit = useCallback(async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setErr(null);
|
||||
setLoading(true);
|
||||
const onSubmit = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setErr(null);
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/auth/register", {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
||||
body: JSON.stringify({ username, email: email || undefined, password }),
|
||||
});
|
||||
const u = username.trim();
|
||||
const em = email.trim().toLowerCase();
|
||||
const pw = password;
|
||||
|
||||
const txt = await res.text();
|
||||
let j: any = null;
|
||||
try { j = txt ? JSON.parse(txt) : null; } catch {}
|
||||
|
||||
if (!res.ok) {
|
||||
const message = j?.error || j?.message || `Sign-up failed (${res.status})`;
|
||||
throw new Error(message);
|
||||
if (!u) {
|
||||
setErr("Username is required.");
|
||||
return;
|
||||
}
|
||||
if (!pw || pw.length < 8) {
|
||||
setErr("Password must be at least 8 characters.");
|
||||
return;
|
||||
}
|
||||
|
||||
router.replace(nextPath); // ALWAYS /portal
|
||||
router.refresh();
|
||||
} catch (e: any) {
|
||||
setErr(e?.message || "Unable to sign up.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [username, email, password, nextPath, router]);
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await fetch("/api/auth/register", {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
||||
body: JSON.stringify({ username: u, email: em || undefined, password: pw }),
|
||||
});
|
||||
|
||||
const txt = await res.text();
|
||||
let j: any = null;
|
||||
try {
|
||||
j = txt ? JSON.parse(txt) : null;
|
||||
} catch {
|
||||
j = null;
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const message =
|
||||
(j?.error && j?.debug ? `${j.error} (${j.debug})` : j?.error) ||
|
||||
j?.message ||
|
||||
`Sign-up failed (${res.status})`;
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
// If the server has AUTO_LOGIN on, user is already signed in here.
|
||||
router.replace(nextPath);
|
||||
router.refresh();
|
||||
} catch (e: any) {
|
||||
setErr(e?.message || "Unable to sign up.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
[username, email, password, nextPath, router]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-md rounded-lg border p-6">
|
||||
|
|
@ -66,7 +90,9 @@ export default function SignUp({ nextPath = "/portal" }: Props) {
|
|||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm font-medium">Email <span className="opacity-60">(optional)</span></label>
|
||||
<label className="text-sm font-medium">
|
||||
Email <span className="opacity-60">(optional)</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
|
|
@ -82,43 +108,4 @@ export default function SignUp({ nextPath = "/portal" }: Props) {
|
|||
<label className="text-sm font-medium">Password</label>
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs opacity-70 hover:opacity-100"
|
||||
onClick={() => setShowPassword((s) => !s)}
|
||||
>
|
||||
{showPassword ? "Hide" : "Show"}
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="new-password"
|
||||
className="w-full rounded-md border px-3 py-2"
|
||||
placeholder="Choose a strong password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.currentTarget.value)}
|
||||
required
|
||||
minLength={8}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{err && (
|
||||
<div className="rounded-md border border-red-300 bg-red-50 px-3 py-2 text-sm text-red-700">
|
||||
{err}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="w-full rounded-md bg-black px-3 py-2 text-white disabled:opacity-60"
|
||||
>
|
||||
{loading ? "Creating account…" : "Sign Up"}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="mt-4 text-center text-sm">
|
||||
<span className="opacity-70">Already have an account?</span>{" "}
|
||||
<a className="underline" href={"/auth/sign-in"}>Sign in</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
className="text-xs opaci
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue