"use client" import { useState, useRef } from "react" import { useSession } from "next-auth/react" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { z } from "zod" import { Eye, EyeOff, Loader2, User, Lock, Save, Camera, Upload, Trash2 } from "lucide-react" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form" import { Input } from "@/components/ui/input" import { Separator } from "@/components/ui/separator" import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar" import { updateProfileSchema, updatePasswordSchema, type UpdateProfileInput } from "@/lib/validation" const passwordChangeSchema = updatePasswordSchema.extend({ confirmPassword: z.string() }).refine((data) => data.newPassword === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"], }) type ProfileFormData = UpdateProfileInput type PasswordFormData = z.infer interface SettingsFormProps { user: { name?: string | null email?: string | null image?: string | null } } export function SettingsForm({ user }: SettingsFormProps) { const { update } = useSession() const fileInputRef = useRef(null) const [showCurrentPassword, setShowCurrentPassword] = useState(false) const [showNewPassword, setShowNewPassword] = useState(false) const [showConfirmPassword, setShowConfirmPassword] = useState(false) const [isLoading, setIsLoading] = useState(false) const [isImageLoading, setIsImageLoading] = useState(false) const [profileImageUrl, setProfileImageUrl] = useState(user.image || null) const profileForm = useForm({ resolver: zodResolver(updateProfileSchema), defaultValues: { name: user.name || "", email: user.email || "", }, }) const passwordForm = useForm({ resolver: zodResolver(passwordChangeSchema), defaultValues: { currentPassword: "", newPassword: "", confirmPassword: "", }, }) const onProfileSubmit = async (data: ProfileFormData) => { setIsLoading(true) try { const response = await fetch("/api/user/profile", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }) const result = await response.json() if (!response.ok) { toast.error(result.error || "Failed to update profile") return } // Update the session with new data await update({ name: data.name, email: data.email, }) toast.success("Profile updated successfully!") } catch { toast.error("An unexpected error occurred") } finally { setIsLoading(false) } } const onPasswordSubmit = async (data: PasswordFormData) => { setIsLoading(true) try { const response = await fetch("/api/user/password", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ currentPassword: data.currentPassword, newPassword: data.newPassword, }), }) const result = await response.json() if (!response.ok) { toast.error(result.error || "Failed to update password") return } toast.success("Password updated successfully!") passwordForm.reset() } catch { toast.error("An unexpected error occurred") } finally { setIsLoading(false) } } const handleImageUpload = async (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (!file) return setIsImageLoading(true) try { const formData = new FormData() formData.append('image', file) const response = await fetch('/api/user/profile-image', { method: 'POST', body: formData, }) const result = await response.json() if (!response.ok) { toast.error(result.error || 'Failed to upload image') return } setProfileImageUrl(result.profileImage.url) toast.success('Profile image uploaded successfully!') // Update session with new image await update({ image: result.profileImage.url }) } catch { toast.error('An unexpected error occurred') } finally { setIsImageLoading(false) // Reset file input if (fileInputRef.current) { fileInputRef.current.value = '' } } } const handleImageDelete = async () => { setIsImageLoading(true) try { const response = await fetch('/api/user/profile-image', { method: 'DELETE', }) const result = await response.json() if (!response.ok) { toast.error(result.error || 'Failed to delete image') return } setProfileImageUrl(null) toast.success('Profile image deleted successfully!') // Update session to remove image await update({ image: null }) } catch { toast.error('An unexpected error occurred') } finally { setIsImageLoading(false) } } return (

Account Settings

Manage your account information and security settings

{/* Profile Information */} Profile Information Update your personal information
( Full Name )} /> ( Email Address )} />
{/* Profile Image */} Profile Image Upload or update your profile picture
{user.name?.charAt(0)?.toUpperCase() || 'U'}
{profileImageUrl && ( )}

Supported formats: JPEG, PNG, WebP, GIF. Maximum size: 10MB. Images will be resized to 400x400 pixels.

{/* Password Change */} Change Password Update your password to keep your account secure
( Current Password
)} /> ( New Password
)} /> ( Confirm New Password
)} />
Password must contain at least 8 characters with uppercase, lowercase, and a number.
) }