user creation and invites

This commit is contained in:
2025-06-24 16:31:13 -04:00
parent 23c8f468fe
commit a659401bde
32 changed files with 667 additions and 30 deletions

View File

@@ -0,0 +1,12 @@
import { verifyInvite } from '@/lib/invite';
import { redirect } from 'next/navigation';
export default async function AcceptInvitePage({ searchParams }: { searchParams: { token?: string } }) {
const invite = searchParams.token ? await verifyInvite(searchParams.token) : null
if (!invite || invite.accepted || new Date(invite.expiresAt) < new Date()) {
return <div className='text-center mt-10'>Invalid or expired invitation.</div>
}
redirect(`/signup?token=${invite.token}`)
}

View File

@@ -7,6 +7,7 @@ export default function SetupPage() {
const [role, setRole] = useState<'COUPLE' | 'PLANNER' | null>(null);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [username, setUsername] = useState('');
async function handleSetup(e:React.FormEvent) {
e.preventDefault();
@@ -31,13 +32,13 @@ export default function SetupPage() {
className='hover:cursor-pointer dark:bg-white dark:text-black rounded px-4 py-2'
onClick={() => setRole('COUPLE')}
>
I'm part of the Couple
I&apos;m part of the Couple
</button>
<button
className='hover:cursor-pointer dark:bg-white dark:text-black rounded px-4 py-2'
onClick={() => setRole('PLANNER')}
>
I'm the Planner
I&apos;m the Planner
</button>
</div>
);
@@ -45,6 +46,13 @@ export default function SetupPage() {
return (
<form onSubmit={handleSetup} className="space-y-4">
<h2>Create your account ({role})</h2>
<input
type="text"
placeholder="Choose a username"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
<input
type="email"
placeholder="Email"

View File

@@ -0,0 +1,23 @@
import { verifyInvite } from '@/lib/invite'
import SignupForm from '@/components/SignupForm'
interface Props {
searchParams: {
token?: string
}
}
export default async function SignupPage({ searchParams }: Props) {
const invite = searchParams.token ? await verifyInvite(searchParams.token) : null
if (!invite || invite.accepted || new Date(invite.expiresAt) < new Date()) {
return <div className="text-center mt-10">Invalid or expired invitation.</div>
}
return (
<div className="max-w-md mx-auto mt-10">
<h1 className="text-2xl font-bold mb-4">Complete Your Signup</h1>
<SignupForm invite={invite} />
</div>
)
}