"use client" import { useState } from "react" import { useSession } from "next-auth/react" import { useRouter } from "next/navigation" import { Shield, Loader2, Copy } from "lucide-react" import { toast } from "sonner" import Image from "next/image" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Separator } from "@/components/ui/separator" import Navbar from "@/components/Navbar" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Camera, Lock, Save, Trash2, Upload, User } from "lucide-react" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { updateProfileSchema, updatePasswordSchema, type UpdateProfileInput } from "@/lib/validation" import { z } from "zod" // Re-using existing types and schemas from previous implementation 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 SettingsContentProps { initialUser: { name: string email: string image: string | null twoFactorEnabled: boolean } } export default function SettingsContent({ initialUser }: SettingsContentProps) { const { update } = useSession() const router = useRouter() const [twoFactorEnabled, setTwoFactorEnabled] = useState(initialUser.twoFactorEnabled) const [is2FALoading, setIs2FALoading] = useState(false) const [setupData, setSetupData] = useState<{ secret: string;qrCode: string } | null>(null) const [verificationCode, setVerificationCode] = useState("") const [isDialogOpen, setIsDialogOpen] = useState(false) // Existing state for other forms const [isLoading, setIsLoading] = useState(false) const [isImageLoading, setIsImageLoading] = useState(false) const [profileImageUrl, setProfileImageUrl] = useState(initialUser.image) const profileForm = useForm({ resolver: zodResolver(updateProfileSchema), defaultValues: { name: initialUser.name, email: initialUser.email, }, }) const passwordForm = useForm({ resolver: zodResolver(passwordChangeSchema), defaultValues: { currentPassword: "", newPassword: "", confirmPassword: "", }, }) // 2FA Handlers const start2FASetup = async () => { setIs2FALoading(true) try { const res = await fetch("/api/user/2fa", { method: "PUT" }) const data = await res.json() if (data.error) throw new Error(data.error) setSetupData(data) setIsDialogOpen(true) } catch (error) { toast.error("Failed to start 2FA setup") } finally { setIs2FALoading(false) } } const verifyAndEnable2FA = async () => { if (verificationCode.length !== 6) { toast.error("Please enter a 6-digit code") return } setIs2FALoading(true) try { const res = await fetch("/api/user/2fa", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code: verificationCode, secret: setupData?.secret, }), }) const data = await res.json() if (data.error) throw new Error(data.error) setTwoFactorEnabled(true) setIsDialogOpen(false) toast.success("Two-factor authentication enabled") router.refresh() } catch (error) { toast.error("Invalid verification code") } finally { setIs2FALoading(false) setVerificationCode("") } } const disable2FA = async () => { if (!confirm("Are you sure you want to disable 2FA? This will make your account less secure.")) return setIs2FALoading(true) try { const res = await fetch("/api/user/2fa", { method: "DELETE" }) const data = await res.json() if (data.error) throw new Error(data.error) setTwoFactorEnabled(false) toast.success("Two-factor authentication disabled") router.refresh() } catch (error) { toast.error("Failed to disable 2FA") } finally { setIs2FALoading(false) } } const copyToClipboard = () => { if (setupData?.secret) { navigator.clipboard.writeText(setupData.secret) toast.success("Secret copied to clipboard") } } // Existing Handlers (Profile, Password, Image) 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 } 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!') await update({ image: result.profileImage.url }) } catch { toast.error('An unexpected error occurred') } finally { setIsImageLoading(false) } } 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!') 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
{initialUser.name.charAt(0).toUpperCase()}
{profileImageUrl && ( )}

Supported formats: JPEG, PNG, WebP, GIF. Maximum size: 10MB.

{/* Two-Factor Authentication */} Two-Factor Authentication Add an extra layer of security to your account

Status: {twoFactorEnabled ? "Enabled" : "Disabled"}

{twoFactorEnabled ? "Your account is secured with 2FA." : "Protect your account by enabling 2FA."}

{twoFactorEnabled ? ( ) : ( Set up Two-Factor Authentication Scan the QR code with your authenticator app (like Google Authenticator or Authy). {setupData && (
2FA QR Code
{setupData.secret}
setVerificationCode(e.target.value.slice(0, 6))} maxLength={6} />
)}
)}
{/* Password Change */} Change Password Update your password to keep your account secure
( Current Password )} /> ( New Password )} /> ( Confirm New Password )} />
) }