'use client'; import { useEffect, useMemo, useState } from 'react'; import { usePathname, useRouter } from 'next/navigation'; import { motion } from 'framer-motion'; import { z } from 'zod'; import { useAuth } from '@/contexts/AuthContext'; import Link from 'next/link'; import { Bell, CreditCard, Lock, Mail, Phone, ShieldCheck, SlidersHorizontal, User, } from 'lucide-react'; import { getAuth, sendPasswordResetEmail, updateProfile } from 'firebase/auth'; import { app } from '@/lib/firebase'; import { getPurchasesByUser, updateUserOnboardingCompleted } from '@/lib/firestore'; import toast from 'react-hot-toast'; const profileSchema = z.object({ displayName: z.string().trim().min(2, 'Display name must be at least 2 characters.'), phone: z .string() .trim() .optional() .transform((value) => (value ? value : undefined)) .refine( (value) => !value || /^\+?[0-9\s\-()]{7,20}$/.test(value), 'Enter a valid phone number.' ), }); const containerVariants = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.08 } }, }; const cardVariants = { hidden: { opacity: 0, y: 14 }, show: { opacity: 1, y: 0, transition: { duration: 0.4 } }, }; export default function SettingsPage() { const { user, isLoading } = useAuth(); const router = useRouter(); const pathname = usePathname(); const auth = getAuth(app); const firebaseUser = auth.currentUser; const [profileForm, setProfileForm] = useState({ displayName: user?.name || '', phone: user?.phoneNumber || '', }); const [profileErrors, setProfileErrors] = useState<{ displayName?: string; phone?: string }>( {} ); const [isSavingProfile, setIsSavingProfile] = useState(false); const [resetStatus, setResetStatus] = useState(null); const [emailNotifications, setEmailNotifications] = useState(true); const [callAlerts, setCallAlerts] = useState(true); const [weeklyReports, setWeeklyReports] = useState(false); const [totalCreditsPurchased, setTotalCreditsPurchased] = useState(null); useEffect(() => { if (!isLoading && !user) { router.push('/auth'); } }, [user, isLoading, router]); useEffect(() => { if (user) { getPurchasesByUser(user.uid) .then((purchases) => { const total = purchases.reduce((sum, purchase) => sum + (purchase.credits || 0), 0); setTotalCreditsPurchased(total); }) .catch((error) => { console.error('Failed to load purchases', error); toast.error('Unable to load purchases.'); setTotalCreditsPurchased(0); }); } }, [user]); const creationDate = useMemo(() => { const createdAt = firebaseUser?.metadata?.creationTime; if (!createdAt) return 'Unknown'; return new Date(createdAt).toLocaleDateString(); }, [firebaseUser]); const handleProfileChange = (key: 'displayName' | 'phone', value: string) => { setProfileForm((prev) => ({ ...prev, [key]: value })); setProfileErrors((prev) => ({ ...prev, [key]: undefined })); }; const handleSaveProfile = async () => { if (!firebaseUser) return; const result = profileSchema.safeParse(profileForm); if (!result.success) { const errors: { displayName?: string; phone?: string } = {}; result.error.issues.forEach((issue) => { const field = issue.path[0] as 'displayName' | 'phone'; errors[field] = issue.message; }); setProfileErrors(errors); return; } setIsSavingProfile(true); try { await updateProfile(firebaseUser, { displayName: result.data.displayName.trim() }); setProfileForm((prev) => ({ ...prev, displayName: result.data.displayName.trim() })); toast.success('Profile updated.'); } catch (error) { console.error('Error updating profile', error); setProfileErrors({ displayName: 'Failed to update profile. Try again.' }); toast.error('Unable to update profile.'); } finally { setIsSavingProfile(false); } }; const handlePasswordReset = async () => { if (!firebaseUser?.email) return; setResetStatus(null); try { await sendPasswordResetEmail(auth, firebaseUser.email); setResetStatus('Password reset email sent.'); toast.success('Password reset email sent.'); } catch (error) { console.error('Password reset failed', error); setResetStatus('Unable to send reset email. Try again.'); toast.error('Unable to send reset email.'); } }; const handleRestartTour = async () => { if (!user) return; try { await updateUserOnboardingCompleted(user.uid, false); toast.success('Tour restarted. Redirecting...'); router.push('/dashboard'); } catch (error) { console.error('Failed to restart tour', error); toast.error('Unable to restart tour.'); } }; if (isLoading) { return (
Loading...
); } if (!user) return null; const navLinks = [ { label: 'Dashboard', href: '/dashboard' }, { label: 'Scheduled Calls', href: '/dashboard/scheduled-calls' }, { label: 'Voice Agent', href: '/dashboard/agent-settings' }, { label: 'Credits', href: '/dashboard/credits' }, { label: 'Notifications', href: '/dashboard/notifications' }, ]; return (

Settings

Manage preferences and account details

{navLinks.map((link) => { const isActive = pathname === link.href; return ( {link.label} ); })}

User Profile

Email

{user.email}

Display Name

handleProfileChange('displayName', event.target.value)} className="mt-2 w-full rounded-xl bg-transparent border border-white/10 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8b5cf6]" placeholder="Your name" /> {profileErrors.displayName && (

{profileErrors.displayName}

)}

Phone

handleProfileChange('phone', event.target.value)} className="mt-2 w-full rounded-xl bg-transparent border border-white/10 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8b5cf6]" placeholder="+34 600 000 000" /> {profileErrors.phone && (

{profileErrors.phone}

)}

Security

Reset your password to keep your account secure.

{resetStatus &&

{resetStatus}

}

Notification Preferences

{[ { key: 'email', label: 'Email notifications', value: emailNotifications, setter: setEmailNotifications, }, { key: 'calls', label: 'Call alerts', value: callAlerts, setter: setCallAlerts, }, { key: 'reports', label: 'Weekly usage reports', value: weeklyReports, setter: setWeeklyReports, }, ].map((item) => (

{item.label}

))}

Preferences save locally for now. TODO: persist in Firestore.

Account Info

Member Since

{creationDate}

Total Credits Purchased

{totalCreditsPurchased === null ? 'Loading…' : totalCreditsPurchased}

); }