makearmy-app/app/auth/sign-up/page.tsx

132 lines
4 KiB
TypeScript
Raw Normal View History

2025-09-26 15:49:26 -04:00
"use client";
2025-09-26 15:59:15 -04:00
import { Suspense, useState } from "react";
2025-09-26 15:49:26 -04:00
import { useRouter, useSearchParams } from "next/navigation";
2025-09-26 15:59:15 -04:00
import Link from "next/link";
2025-09-26 15:40:36 -04:00
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
2025-09-26 15:59:15 -04:00
function SignUpInner() {
2025-09-26 15:40:36 -04:00
const router = useRouter();
const sp = useSearchParams();
const [username, setUsername] = useState("");
const [email, setEmail] = useState(""); // optional
const [password, setPassword] = useState("");
const [submitting, setSubmitting] = useState(false);
2025-09-26 11:46:01 -04:00
const [err, setErr] = useState<string | null>(null);
2025-09-26 15:40:36 -04:00
const next = sp.get("next") || "/my/rigs";
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setErr(null);
setSubmitting(true);
2025-09-26 11:46:01 -04:00
try {
const res = await fetch("/api/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
2025-09-26 15:40:36 -04:00
username,
email: email || undefined,
password,
2025-09-26 11:46:01 -04:00
}),
});
2025-09-26 15:40:36 -04:00
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data?.error || "Registration failed");
2025-09-26 11:46:01 -04:00
2025-09-26 15:40:36 -04:00
router.replace(next);
2025-09-26 11:46:01 -04:00
} catch (e: any) {
2025-09-26 15:40:36 -04:00
setErr(e?.message || "Registration failed");
2025-09-26 11:46:01 -04:00
} finally {
2025-09-26 15:40:36 -04:00
setSubmitting(false);
2025-09-26 11:46:01 -04:00
}
}
return (
2025-09-26 15:49:26 -04:00
<div className="min-h-[60vh] flex items-center justify-center px-4">
<div className="w-full max-w-md space-y-6">
<div className="text-center space-y-2">
<h1 className="text-2xl font-bold">Create account</h1>
<p className="text-sm text-muted-foreground">
Pick a username and password. Email is optional (recommended for password reset).
</p>
</div>
2025-09-26 15:40:36 -04:00
<form onSubmit={onSubmit} className="space-y-4">
{err && (
<div className="text-sm rounded border border-destructive/30 bg-destructive/10 px-3 py-2 text-destructive">
{err}
</div>
)}
2025-09-26 11:46:01 -04:00
2025-09-26 15:40:36 -04:00
<div className="space-y-2">
<label className="text-sm font-medium">Username</label>
<Input
autoFocus
autoComplete="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
</div>
2025-09-26 11:46:01 -04:00
2025-09-26 15:40:36 -04:00
<div className="space-y-2">
<label className="text-sm font-medium">
Email <span className="text-muted-foreground font-normal">(optional)</span>
2025-09-26 11:46:01 -04:00
</label>
2025-09-26 15:40:36 -04:00
<Input
type="email"
autoComplete="email"
placeholder="you@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<p className="text-xs text-muted-foreground">
Without an email, we cant reset your password if you lose it.
</p>
</div>
2025-09-26 11:46:01 -04:00
2025-09-26 15:40:36 -04:00
<div className="space-y-2">
<label className="text-sm font-medium">Password</label>
<Input
type="password"
autoComplete="new-password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
2025-09-26 11:46:01 -04:00
2025-09-26 15:40:36 -04:00
<Button type="submit" disabled={submitting} className="w-full">
{submitting ? "Creating…" : "Create account"}
</Button>
2025-09-26 11:46:01 -04:00
2025-09-26 15:40:36 -04:00
<input type="hidden" name="next" value={next} />
</form>
2025-09-26 15:49:26 -04:00
<p className="text-sm text-center text-muted-foreground">
Already have an account?{" "}
<Link href="/auth/sign-in" className="underline underline-offset-4 hover:opacity-80">
Sign in
</Link>
</p>
</div>
</div>
2025-09-26 11:46:01 -04:00
);
}
2025-09-26 15:59:15 -04:00
export default function SignUpPage() {
return (
<Suspense
fallback={
<div className="min-h-[60vh] flex items-center justify-center px-4">
<div className="text-sm text-muted-foreground">Loading</div>
</div>
}
>
<SignUpInner />
</Suspense>
);
}