diff --git a/openspec/changes/user-accounts/tasks.md b/openspec/changes/user-accounts/tasks.md index 8d5cf1a..0523eec 100644 --- a/openspec/changes/user-accounts/tasks.md +++ b/openspec/changes/user-accounts/tasks.md @@ -62,7 +62,7 @@ ## 11. Register Page -- [ ] 11.1 `[sonnet]` Create `src/app/(public)/register/page.tsx` — register form matching Lovable design: name/email/password inputs, "Create Account" button posting to `/api/auth/register` then auto-signing in +- [x] 11.1 `[sonnet]` Create `src/app/(public)/register/page.tsx` — register form matching Lovable design: name/email/password inputs, "Create Account" button posting to `/api/auth/register` then auto-signing in - [ ] 11.2 `[haiku]` Add error state display for duplicate email, short password - [ ] 11.3 `[haiku]` Add "Continue with Google" button, "Sign in" link to `/login` diff --git a/src/app/(public)/register/page.tsx b/src/app/(public)/register/page.tsx new file mode 100644 index 0000000..05babc9 --- /dev/null +++ b/src/app/(public)/register/page.tsx @@ -0,0 +1,145 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; +import { signIn } from "next-auth/react"; +import { ChartColumn } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { AlertCircle } from "lucide-react"; + +export default function RegisterPage() { + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + setError(null); + setIsLoading(true); + try { + const res = await fetch("/api/auth/register", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ name, email, password }), + }); + + if (!res.ok) { + const data = await res.json().catch(() => ({})); + setError(data.error ?? "Registration failed. Please try again."); + return; + } + + // Auto sign-in after successful registration + await signIn("credentials", { email, password, redirectTo: "/app" }); + } catch { + setError("An error occurred. Please try again."); + } finally { + setIsLoading(false); + } + } + + return ( +
+ {/* Navbar */} + + + {/* Register Form */} +
+ + + Create account + + Start annotating charts in seconds + + + + {error && ( +
+ +

{error}

+
+ )} +
+
+ + setName(e.target.value)} + className="font-mono text-sm" + /> +
+
+ + setEmail(e.target.value)} + className="font-mono text-sm" + /> +
+
+ + setPassword(e.target.value)} + className="font-mono text-sm" + /> +

Minimum 8 characters

+
+ +
+ +

+ Already have an account?{" "} + + Sign in + +

+
+
+
+
+ ); +}