'use client'
import { useState, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import { validateEmail, validatePassword, sanitizeString } from '@/lib/validation'
import { registerUser } from '@/lib/auth-actions'
import { useToast } from './ToastContainer'
import ClaimListsModal from './ClaimListsModal'
interface RegisterFormProps {
callbackUrl?: string
}
export default function RegisterForm({ callbackUrl = '/' }: RegisterFormProps) {
const router = useRouter()
const { showToast } = useToast()
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const [showClaimModal, setShowClaimModal] = useState(false)
const [errors, setErrors] = useState<{
name?: string
email?: string
password?: string
confirmPassword?: string
}>({})
const [touched, setTouched] = useState<{
name: boolean
email: boolean
password: boolean
confirmPassword: boolean
}>({
name: false,
email: false,
password: false,
confirmPassword: false,
})
// Inline validation when fields change
useEffect(() => {
if (touched.name) {
const sanitized = sanitizeString(name)
if (!sanitized) {
setErrors((prev) => ({ ...prev, name: 'Name is required' }))
} else if (sanitized.length > 100) {
setErrors((prev) => ({ ...prev, name: 'Name must be less than 100 characters' }))
} else {
setErrors((prev) => ({ ...prev, name: undefined }))
}
}
}, [name, touched.name])
useEffect(() => {
if (touched.email) {
const result = validateEmail(email)
setErrors((prev) => ({
...prev,
email: result.isValid ? undefined : result.error,
}))
}
}, [email, touched.email])
useEffect(() => {
if (touched.password) {
const result = validatePassword(password)
setErrors((prev) => ({
...prev,
password: result.isValid ? undefined : result.error,
}))
}
}, [password, touched.password])
useEffect(() => {
if (touched.confirmPassword) {
if (!confirmPassword) {
setErrors((prev) => ({ ...prev, confirmPassword: 'Please confirm your password' }))
} else if (password !== confirmPassword) {
setErrors((prev) => ({ ...prev, confirmPassword: 'Passwords do not match' }))
} else {
setErrors((prev) => ({ ...prev, confirmPassword: undefined }))
}
}
}, [confirmPassword, password, touched.confirmPassword])
const handleNameBlur = () => {
setTouched((prev) => ({ ...prev, name: true }))
}
const handleEmailBlur = () => {
setTouched((prev) => ({ ...prev, email: true }))
}
const handlePasswordBlur = () => {
setTouched((prev) => ({ ...prev, password: true }))
}
const handleConfirmPasswordBlur = () => {
setTouched((prev) => ({ ...prev, confirmPassword: true }))
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
// Validate all fields before submission
const sanitizedName = sanitizeString(name)
const emailResult = validateEmail(email)
const passwordResult = validatePassword(password)
const newErrors: {
name?: string
email?: string
password?: string
confirmPassword?: string
} = {}
if (!sanitizedName) {
newErrors.name = 'Name is required'
} else if (sanitizedName.length > 100) {
newErrors.name = 'Name must be less than 100 characters'
}
if (!emailResult.isValid) {
newErrors.email = emailResult.error
}
if (!passwordResult.isValid) {
newErrors.password = passwordResult.error
}
if (!confirmPassword) {
newErrors.confirmPassword = 'Please confirm your password'
} else if (password !== confirmPassword) {
newErrors.confirmPassword = 'Passwords do not match'
}
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors)
setTouched({ name: true, email: true, password: true, confirmPassword: true })
return
}
setIsSubmitting(true)
setErrors({})
try {
const result = await registerUser(email.trim(), password, sanitizedName)
if (!result.success) {
if (result.error === 'Email already exists') {
setErrors({ email: 'This email is already registered' })
showToast('Email already exists', 'error')
} else {
showToast(result.error || 'Registration failed', 'error')
}
} else {
showToast('Registration successful! Logging you in...', 'success')
// Check if there are lists to claim from localStorage
// Requirement 10.2 - Add UI for users to claim existing lists on first registration
const hasAnonymousLists = checkForAnonymousLists()
if (hasAnonymousLists) {
// Show claim modal
setShowClaimModal(true)
} else {
// No lists to claim, proceed to app
router.push(callbackUrl)
router.refresh()
}
}
} catch (err) {
console.error('Registration error:', err)
showToast('An error occurred. Please try again.', 'error')
} finally {
setIsSubmitting(false)
}
}
const checkForAnonymousLists = (): boolean => {
try {
const stored = localStorage.getItem('anonymousListIds')
if (stored) {
const listIds = JSON.parse(stored)
return Array.isArray(listIds) && listIds.length > 0
}
return false
} catch (err) {
console.error('Error checking for anonymous lists:', err)
return false
}
}
const handleClaimComplete = () => {
setShowClaimModal(false)
showToast('Lists claimed successfully!', 'success')
router.push(callbackUrl)
router.refresh()
}
const handleClaimClose = () => {
setShowClaimModal(false)
router.push(callbackUrl)
router.refresh()
}
return (
<>