"use client" import { useState, useEffect, useRef } from "react" import { useSession } from "next-auth/react" import { useRouter } from "next/navigation" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { z } from "zod" import { Eye, EyeOff, Loader2, User, Mail, 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 Navbar from "@/components/Navbar" import { updateProfileSchema, updatePasswordSchema, type UpdateProfileInput, type UpdatePasswordInput } from "@/lib/validation" // Form schema for password change with confirmation 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 export default function SettingsPage() { const { data: session, status, update } = useSession() const router = useRouter() 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(null) const profileForm = useForm({ resolver: zodResolver(updateProfileSchema), defaultValues: { name: "", email: "", }, }) const passwordForm = useForm({ resolver: zodResolver(passwordChangeSchema), defaultValues: { currentPassword: "", newPassword: "", confirmPassword: "", }, }) // Redirect if not authenticated useEffect(() => { if (status === "unauthenticated") { router.push("/login") } }, [status, router]) // Set form values when session is loaded useEffect(() => { if (session?.user) { profileForm.reset({ name: session.user.name || "", email: session.user.email || "", }) setProfileImageUrl(session.user.image || null) } }, [session, profileForm]) 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 (error) { 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 (error) { 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 (error) { 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 (error) { toast.error('An unexpected error occurred') } finally { setIsImageLoading(false) } } if (status === "loading") { return (

Loading...

) } if (!session) { return null } 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
{session?.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.
) }