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

134 lines
4.1 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.

// app/auth/sign-up/page.tsx
import { Suspense } from "react";
import type { Metadata } from "next";
import Link from "next/link";
// UI (shadcn)
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
export const metadata: Metadata = { title: "Create account" };
export default function SignUpPage() {
return (
<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>
<Suspense fallback={<div className="text-sm text-muted-foreground">Loading</div>}>
<SignUpClient />
</Suspense>
<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>
);
}
"use client";
import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
function SignUpClient() {
const router = useRouter();
const sp = useSearchParams();
const [username, setUsername] = useState("");
const [email, setEmail] = useState(""); // optional
const [password, setPassword] = useState("");
const [submitting, setSubmitting] = useState(false);
const [err, setErr] = useState<string | null>(null);
const next = sp.get("next") || "/my/rigs";
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setErr(null);
setSubmitting(true);
try {
const res = await fetch("/api/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username,
email: email || undefined,
password,
}),
});
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data?.error || "Registration failed");
// Registration API should already log user in (sets cookies), then redirect
router.replace(next);
} catch (e: any) {
setErr(e?.message || "Registration failed");
} finally {
setSubmitting(false);
}
}
return (
<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>
)}
<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>
<div className="space-y-2">
<label className="text-sm font-medium">
Email <span className="text-muted-foreground font-normal">(optional)</span>
</label>
<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>
<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>
<Button type="submit" disabled={submitting} className="w-full">
{submitting ? "Creating…" : "Create account"}
</Button>
<input type="hidden" name="next" value={next} />
</form>
);
}