import React, { useState, useRef } from "react"; import { updateProfile, uploadAvatar, getAvatarUrl } from "../../api/client"; import type { UserProfile } from "../../types"; import { Loader2, X, Plus, User as UserIcon } from "lucide-react"; interface EditProfileModalProps { profile: UserProfile; onClose: () => void; onUpdate: (updatedProfile: UserProfile) => void; } export default function EditProfileModal({ profile, onClose, onUpdate, }: EditProfileModalProps) { const [displayName, setDisplayName] = useState(profile.displayName || ""); const [description, setDescription] = useState(profile.description || ""); const [website, setWebsite] = useState(profile.website || ""); const [links, setLinks] = useState(profile.links || []); const [newLink, setNewLink] = useState(""); const [avatarBlob, setAvatarBlob] = useState(null); const [avatarPreview, setAvatarPreview] = useState(null); const [uploading, setUploading] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const fileInputRef = useRef(null); const handleAvatarChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; if (!["image/jpeg", "image/png"].includes(file.type)) { setError("Please select a JPEG or PNG image"); return; } if (file.size > 1024 * 1024 * 2) { setError("Image must be under 2MB"); return; } setAvatarPreview(URL.createObjectURL(file)); setAvatarBlob(file); setUploading(true); try { const result = await uploadAvatar(file); setAvatarBlob(result.blob); setAvatarBlob(result.blob); } catch (err) { setError( "Failed to upload: " + (err instanceof Error ? err.message : "Unknown error"), ); setAvatarPreview(null); } finally { setUploading(false); } }; const handleAddLink = () => { if (!newLink) return; if (!links.includes(newLink)) { setLinks([...links, newLink]); setNewLink(""); } }; const handleRemoveLink = (index: number) => { setLinks(links.filter((_, i) => i !== index)); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setSaving(true); setError(null); try { await updateProfile({ displayName, description, website, links, avatar: avatarBlob, }); onUpdate({ ...profile, displayName, description, website, links, avatar: avatarPreview || profile.avatar, }); onClose(); onClose(); } catch (err) { setError(err instanceof Error ? err.message : "Unknown error"); } finally { setSaving(false); } }; const currentAvatar = avatarPreview || getAvatarUrl(profile.did, profile.avatar); return (
e.stopPropagation()} >

Edit Profile

{error && (
{error}
)}
fileInputRef.current?.click()} > {currentAvatar ? ( ) : (
)}
Edit
setDisplayName(e.target.value)} className="w-full px-3 py-2 rounded-lg bg-white dark:bg-surface-800 border border-surface-200 dark:border-surface-700 text-surface-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-primary-500/20 focus:border-primary-500 dark:focus:border-primary-400" maxLength={64} />