import { useAuth } from '@/contexts/AuthContext' import { useProfile } from '@/contexts/ProfileProvider' import { useState, useEffect } from 'react' import { Camera, Loader2, Phone, MapPin, Shield, Trophy, Activity, Plus, Trash2, Pencil, Home, Building2, Edit2, Check, X } from 'lucide-react' import AvatarUploadDialog from '@/components/generic/AvatarUploadDialog' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Separator } from '@/components/ui/separator' import { Badge } from '@/components/ui/badge' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogClose } from '@/components/ui/dialog' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog' import { useForm, Controller } from 'react-hook-form' import { z } from 'zod' import { zodResolver } from '@hookform/resolvers/zod' import { ROLE_CONFIG, AVATAR_COLORS } from '@/data/profile.data' // ─── Schemas ────────────────────────────────────────────────────────────────── const addressSchema = z.object({ address_type: z.string().min(1, 'Required'), street: z.string().min(1, 'Required'), city: z.string().min(1, 'Required'), state: z.string().min(1, 'Required'), zip: z.string().min(1, 'Required'), country: z.string().min(1, 'Required'), }) const phoneSchema = z.object({ phone_type: z.string().min(1, 'Required'), country_code: z.string().min(1, 'Required'), number: z.string().min(7, 'Required'), }) // ─── Address Dialog ─────────────────────────────────────────────────────────── function AddressDialog({ open, onClose, initial, onSave }) { const { register, handleSubmit, control, formState: { errors } } = useForm({ resolver: zodResolver(addressSchema), defaultValues: initial ?? { address_type: 'home', street: '', city: '', state: '', zip: '', country: 'Philippines', }, }) const onSubmit = (data) => { onSave({ ...data, full_address: `${data.street}, ${data.city}, ${data.state}, ${data.country}, ${data.zip}` }) onClose() } return ( {initial ? 'Edit address' : 'Add address'}
( )} /> {errors.address_type &&

{errors.address_type.message}

}
{errors.street &&

{errors.street.message}

}
{errors.city &&

{errors.city.message}

}
{errors.state &&

{errors.state.message}

}
{errors.zip &&

{errors.zip.message}

}
{errors.country &&

{errors.country.message}

}
) } // ─── Phone Dialog ───────────────────────────────────────────────────────────── function PhoneDialog({ open, onClose, initial, onSave }) { const { register, handleSubmit, control, formState: { errors } } = useForm({ resolver: zodResolver(phoneSchema), defaultValues: initial ?? { phone_type: 'mobile', country_code: '63', number: '' }, }) const onSubmit = (data) => { onSave({ ...data, full_number: data.country_code + data.number }) onClose() } return ( {initial ? 'Edit phone number' : 'Add phone number'}
( )} /> {errors.phone_type &&

{errors.phone_type.message}

}
{errors.country_code &&

{errors.country_code.message}

}
{errors.number &&

{errors.number.message}

}
) } // ─── Delete Confirm ─────────────────────────────────────────────────────────── function DeleteConfirm({ open, onClose, onConfirm, label }) { return ( Delete {label}? This will remove the {label} from your profile. This cannot be undone. Cancel Delete ) } // ─── Page ───────────────────────────────────────────────────────────────────── export default function ProfilePage() { const { user } = useAuth() const { profile, getProfile, updateProfile, profileLoading, uploadAvatar, deleteAvatar, avatarLoading, } = useProfile() const isClient = user?.acc_type === 'client' const role = ROLE_CONFIG[user?.acc_type] ?? { label: user?.acc_type, variant: 'outline' } // Use fresh profile data; fall back to auth context while loading const info = profile?.personal_info ?? user?.personal_info const [avatarDialogOpen, setAvatarDialogOpen] = useState(false) const [editing, setEditing] = useState(false) const [addresses, setAddresses] = useState(info?.addresses ?? []) const [phones, setPhones] = useState(info?.phone_number ?? []) const [addrDialog, setAddrDialog] = useState({ open: false, index: null }) const [deleteAddr, setDeleteAddr] = useState({ open: false, index: null }) const [phoneDialog, setPhoneDialog] = useState({ open: false, index: null }) const [deletePhone, setDeletePhone] = useState({ open: false, index: null }) const fullName = info?.name?.full_name ?? user?.email ?? 'User' const initials = ((info?.name?.given_name?.[0] ?? '') + (info?.name?.last_name?.[0] ?? '')).toUpperCase() || user?.email?.[0]?.toUpperCase() || 'U' const avatarUrl = info?.avatar?.url ?? null const avatarColor = AVATAR_COLORS[user?.acc_type] ?? 'bg-muted text-muted-foreground' // Load fresh profile data on mount useEffect(() => { getProfile(); }, []) // Sync phones/addresses when profile arrives from API useEffect(() => { if (!profile?.personal_info) return setAddresses(profile.personal_info.addresses ?? []) setPhones(profile.personal_info.phone_number ?? []) }, [profile]) // Save profile changes (phones + addresses) const handleSave = async () => { const result = await updateProfile({ phone_number: phones, addresses }) if (result?.success) setEditing(false) } // ── Address handlers ── const handleSaveAddress = (data) => { if (addrDialog.index !== null) { setAddresses((p) => p.map((a, i) => i === addrDialog.index ? data : a)) } else { setAddresses((p) => [...p, data]) } } const handleDeleteAddress = () => { setAddresses((p) => p.filter((_, i) => i !== deleteAddr.index)) setDeleteAddr({ open: false, index: null }) } // ── Phone handlers ── const handleSavePhone = (data) => { if (phoneDialog.index !== null) { setPhones((p) => p.map((ph, i) => i === phoneDialog.index ? data : ph)) } else { setPhones((p) => [...p, data]) } } const handleDeletePhone = () => { setPhones((p) => p.filter((_, i) => i !== deletePhone.index)) setDeletePhone({ open: false, index: null }) } return (
{/* ── Header ── */}
{initials} Change photo
{/* Name + role */}

{fullName}

{user?.email}

{info?.occupation && ( {info.occupation} )} {role.label}
{/* ← Outside flex-1, sits at the end */}
{editing ? ( <> ) : ( )}
{/* ── Left: Phone + Address ── */}
{/* Phone numbers */} Phone numbers {editing && ( )} {phones.length === 0 ? (

No phone numbers added.

) : (
{phones.map((p, i) => (

+{p.country_code} {p.number}

{p.phone_type}

{editing && (
)}
))}
)}
{/* Addresses */} Addresses {editing && ( )} {addresses.length === 0 ? (

No addresses added.

) : (
{addresses.map((a, i) => (
{a.address_type === 'work' ? : }

{a.address_type}

{a.full_address}

{editing && (
)}
))}
)}
{/* ── Right column ── */}
{isClient ? ( <> Recent activities

No recent activities.

Achievements

No achievements yet.

) : (

Nothing else to show

Activities and achievements are only visible to clients.

)}
{/* ── Dialogs ── */} setAddrDialog({ open: false, index: null })} initial={addrDialog.index !== null ? addresses[addrDialog.index] : null} onSave={handleSaveAddress} /> setDeleteAddr({ open: false, index: null })} onConfirm={handleDeleteAddress} label="address" /> setPhoneDialog({ open: false, index: null })} initial={phoneDialog.index !== null ? phones[phoneDialog.index] : null} onSave={handleSavePhone} /> setDeletePhone({ open: false, index: null })} onConfirm={handleDeletePhone} label="phone number" /> setAvatarDialogOpen(false)} currentAvatarUrl={avatarUrl ?? ''} initials={initials} onUpload={uploadAvatar} onDelete={deleteAvatar} loading={avatarLoading} />
) }