'use client' import { useState, useEffect } from 'react' import { useRouter, useSearchParams } from 'next/navigation' import Link from 'next/link' import { createClient } from '@/lib/supabase/client' export default function SignupPage() { const router = useRouter() const searchParams = useSearchParams() // Pre-fill email if provided in URL (from invite link) const [email, setEmail] = useState(searchParams.get('email') ?? '') const [password, setPassword] = useState('') const [confirmPassword, setConfirmPassword] = useState('') const [error, setError] = useState(null) const [loading, setLoading] = useState(false) useEffect(() => { // Handle invite/signup token from URL hash // Supabase adds tokens to the URL hash after redirect const handleTokenFromUrl = async () => { const hash = window.location.hash if (hash) { const params = new URLSearchParams(hash.substring(1)) const accessToken = params.get('access_token') const refreshToken = params.get('refresh_token') const type = params.get('type') if (accessToken && refreshToken && (type === 'invite' || type === 'signup')) { const supabase = createClient() const { error } = await supabase.auth.setSession({ access_token: accessToken, refresh_token: refreshToken, }) if (error) { setError('Invalid or expired invite link. Please request a new invitation.') return } // Get the user's email from the session const { data: { user } } = await supabase.auth.getUser() if (user?.email) { setEmail(user.email) } } } } handleTokenFromUrl() }, [searchParams]) async function handleSubmit(e: React.FormEvent) { e.preventDefault() setError(null) // Validate passwords match if (password !== confirmPassword) { setError('Passwords do not match') return } // Validate password length if (password.length < 6) { setError('Password must be at least 6 characters') return } setLoading(true) const supabase = createClient() // Check if user already has a session (from invite link) const { data: { session } } = await supabase.auth.getSession() if (session) { // User was invited and has a session - update their password const { error: updateError } = await supabase.auth.updateUser({ password, }) if (updateError) { setError(updateError.message) setLoading(false) return } // Create profile record const { error: profileError } = await supabase.from('profiles').upsert({ id: session.user.id, email: session.user.email, display_name: session.user.email?.split('@')[0] || 'User', is_admin: false, }) if (profileError) { setError(profileError.message) setLoading(false) return } router.push('/dashboard') } else { // Regular signup flow (if allowed) const { data, error } = await supabase.auth.signUp({ email, password, }) if (error) { setError(error.message) setLoading(false) return } if (data.user) { // Create profile record const { error: profileError } = await supabase.from('profiles').upsert({ id: data.user.id, email: data.user.email, display_name: email.split('@')[0] || 'User', is_admin: false, }) if (profileError) { setError(profileError.message) setLoading(false) return } router.push('/dashboard') } } } return (

WebVNWrite

Complete your account setup

{error && (

{error}

)}
setEmail(e.target.value)} className="mt-1 block w-full rounded-md border border-zinc-300 bg-white px-3 py-2 text-zinc-900 placeholder-zinc-400 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-50 dark:placeholder-zinc-500" placeholder="you@example.com" />
setPassword(e.target.value)} className="mt-1 block w-full rounded-md border border-zinc-300 bg-white px-3 py-2 text-zinc-900 placeholder-zinc-400 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-50 dark:placeholder-zinc-500" placeholder="••••••••" />
setConfirmPassword(e.target.value)} className="mt-1 block w-full rounded-md border border-zinc-300 bg-white px-3 py-2 text-zinc-900 placeholder-zinc-400 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-50 dark:placeholder-zinc-500" placeholder="••••••••" />

Already have an account?{' '} Sign in

) }