import { useState, useRef, useEffect } from "react"; import { Camera, Upload, X, Trash2 } from "lucide-react"; import { avatarService, patientService, doctorService } from "../../services"; import toast from "react-hot-toast"; import { Avatar } from "./Avatar"; interface AvatarUploadProps { /** ID do usuário */ userId?: string; /** URL atual do avatar */ currentAvatarUrl?: string; /** Nome para gerar iniciais */ name?: string; /** Cor do avatar */ color?: | "blue" | "green" | "purple" | "orange" | "pink" | "teal" | "indigo" | "red"; /** Tamanho do avatar */ size?: "lg" | "xl"; /** Callback quando o avatar é atualizado */ onAvatarUpdate?: (avatarUrl: string | null) => void; /** Se está em modo de edição */ editable?: boolean; /** Tipo de usuário (paciente ou médico) */ userType?: "patient" | "doctor"; } export function AvatarUpload({ userId, currentAvatarUrl, name = "", color = "blue", size = "xl", onAvatarUpdate, editable = true, userType = "patient", }: AvatarUploadProps) { const [isUploading, setIsUploading] = useState(false); const [showMenu, setShowMenu] = useState(false); const [displayUrl, setDisplayUrl] = useState( currentAvatarUrl ); const fileInputRef = useRef(null); // Atualiza displayUrl quando currentAvatarUrl muda externamente useEffect(() => { console.log("[AvatarUpload] currentAvatarUrl:", currentAvatarUrl); console.log("[AvatarUpload] userId:", userId); console.log("[AvatarUpload] editable:", editable); setDisplayUrl(currentAvatarUrl); }, [currentAvatarUrl, userId, editable]); const handleFileSelect = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; console.log("[AvatarUpload] Arquivo selecionado:", { file: file?.name, userId, hasUserId: !!userId, userIdType: typeof userId, userIdValue: userId, }); if (!file) { console.warn("[AvatarUpload] Nenhum arquivo selecionado"); return; } if (!userId) { console.error("[AvatarUpload] ❌ userId não está definido!", { userId, hasUserId: !!userId, }); toast.error( "Não foi possível identificar o usuário. Por favor, recarregue a página." ); return; } // Validação adicional: userId não pode ser string vazia if (typeof userId === "string" && userId.trim() === "") { console.error("[AvatarUpload] ❌ userId está vazio!", { userId }); toast.error( "ID do usuário está vazio. Por favor, recarregue a página." ); return; } // Validação de tamanho (max 2MB) if (file.size > 2 * 1024 * 1024) { toast.error("Arquivo muito grande! Tamanho máximo: 2MB"); return; } // Validação de tipo if (!["image/jpeg", "image/png", "image/webp"].includes(file.type)) { toast.error("Formato inválido! Use JPG, PNG ou WebP"); return; } setIsUploading(true); setShowMenu(false); try { console.log("[AvatarUpload] 🚀 Iniciando upload...", { userId, fileName: file.name, fileSize: file.size, fileType: file.type, }); // Upload do avatar const uploadResult = await avatarService.upload({ userId, file, }); console.log("[AvatarUpload] ✅ Upload retornou:", uploadResult); // Gera URL pública com cache-busting const ext = file.name.split(".").pop()?.toLowerCase(); const avatarExt = ext === "jpg" || ext === "png" || ext === "webp" ? ext : "jpg"; const baseUrl = avatarService.getPublicUrl({ userId, ext: avatarExt, }); // Adiciona timestamp para forçar reload da imagem const publicUrl = `${baseUrl}?t=${Date.now()}`; console.log("[AvatarUpload] Upload concluído, atualizando paciente...", { baseUrl, }); // Atualiza avatar_url na tabela apropriada (patients ou doctors) try { if (userType === "doctor") { await doctorService.updateByUserId(userId, { avatar_url: baseUrl }); console.log("[AvatarUpload] ✅ Avatar atualizado na tabela doctors"); } else { await patientService.updateByUserId(userId, { avatar_url: baseUrl }); console.log("[AvatarUpload] ✅ Avatar atualizado na tabela patients"); } } catch (error) { console.warn( `[AvatarUpload] ⚠️ Não foi possível atualizar tabela ${userType === "doctor" ? "doctors" : "patients"}:`, error ); // Não bloqueia o fluxo, avatar já está no Storage } // Atualiza estado local com timestamp setDisplayUrl(publicUrl); // Callback com timestamp para forçar reload imediato no componente onAvatarUpdate?.(publicUrl); toast.success("Avatar atualizado com sucesso!"); console.log("[AvatarUpload] ✅ Processo concluído com sucesso"); } catch (error) { console.error("❌ [AvatarUpload] Erro ao fazer upload:", error); toast.error("Erro ao fazer upload do avatar"); } finally { setIsUploading(false); if (fileInputRef.current) { fileInputRef.current.value = ""; } } }; const handleRemove = async () => { if (!userId) return; if (!confirm("Tem certeza que deseja remover o avatar?")) { setShowMenu(false); return; } setIsUploading(true); setShowMenu(false); try { await avatarService.delete({ userId }); // Remove avatar_url da tabela apropriada (patients ou doctors) try { if (userType === "doctor") { await doctorService.updateByUserId(userId, { avatar_url: null }); console.log("[AvatarUpload] ✅ Avatar removido da tabela doctors"); } else { await patientService.updateByUserId(userId, { avatar_url: null }); console.log("[AvatarUpload] ✅ Avatar removido da tabela patients"); } } catch (error) { console.warn( `[AvatarUpload] ⚠️ Não foi possível remover da tabela ${userType === "doctor" ? "doctors" : "patients"}:`, error ); } // Atualiza estado local setDisplayUrl(undefined); onAvatarUpdate?.(null); toast.success("Avatar removido com sucesso!"); } catch (error) { console.error("Erro ao remover avatar:", error); toast.error("Erro ao remover avatar"); } finally { setIsUploading(false); } }; return (
{/* Avatar */}
{/* Loading overlay */} {isUploading && (
)} {/* Edit button */} {editable && !isUploading && ( )}
{/* Menu dropdown */} {showMenu && editable && ( <> {/* Backdrop */}
setShowMenu(false)} /> {/* Menu */}
{currentAvatarUrl && ( )}
)} {/* Hidden file input */}
); }