import { useState, useEffect } from "react"; import { Mail, Building2, Upload, CheckCircle, AlertCircle, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { useAuth } from "@/contexts/AuthContext"; import { api, Organization, ApiError } from "@/lib/api"; import { toast } from "@/hooks/use-toast"; export default function ProfilePage() { const { user, refreshUser } = useAuth(); const [name, setName] = useState(""); const [isEditing, setIsEditing] = useState(false); const [isSaving, setIsSaving] = useState(false); const [organizations, setOrganizations] = useState([]); const [orgsLoading, setOrgsLoading] = useState(true); // Sync local name state with user data useEffect(() => { if (user?.full_name) { setName(user.full_name); } }, [user?.full_name]); // Fetch organizations only when user is available useEffect(() => { if (!user) { setOrgsLoading(false); return; } const fetchOrgs = async () => { try { const response = await api.users.organizations(); setOrganizations(response.organizations); } catch (error) { if (error instanceof ApiError) { toast({ title: "Error loading organizations", description: error.message, variant: "destructive", }); } } finally { setOrgsLoading(false); } }; fetchOrgs(); }, [user]); const getInitials = (fullName: string | null) => { if (!fullName) return "?"; return fullName .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2); }; const handleSave = async () => { if (!name.trim()) { toast({ title: "Name required", description: "Please enter your full name", variant: "destructive", }); return; } setIsSaving(true); try { await api.users.updateMe({ full_name: name.trim() }); await refreshUser(); setIsEditing(false); toast({ title: "Profile updated", description: "Your name has been updated successfully", }); } catch (error) { if (error instanceof ApiError) { toast({ title: "Update failed", description: error.message, variant: "destructive", }); } } finally { setIsSaving(false); } }; const handleCancel = () => { setName(user?.full_name || ""); setIsEditing(false); }; if (!user) { return (
); } return (

Profile

Manage your personal information and organization memberships

{/* Profile Photo & Name */} Personal Information Update your photo and personal details {/* Avatar */}
{getInitials(user.full_name)}

JPG, PNG or GIF. Max 2MB.

{/* Name */}
{isEditing ? (
setName(e.target.value)} disabled={isSaving} />
) : (
{user.full_name || "Not set"}
)}
{/* Email */} Email Address Your email is used for login and notifications
{user.email} {user.email_verified ? ( Verified ) : ( Unverified )}
{/* Organizations */} Organizations Organizations you're a member of {orgsLoading ? (
) : organizations.length === 0 ? (

You're not a member of any organizations yet.

) : (
{organizations.map((org) => (
{org.logo_url ? ( ) : (
)} {org.name}
{org.role}
))}
)}
); }