import { useState, useEffect } from 'react'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { cn } from '@/lib/utils'; import { logger } from '@/lib/logger'; interface UserAvatarProps { avatarUrl?: string | null; fallbackText: string; className?: string; size?: 'sm' | 'md' | 'lg'; } const sizeClasses = { sm: 'h-8 w-8 text-xs', md: 'h-10 w-10 text-sm', lg: 'h-16 w-16 text-lg' }; export function UserAvatar({ avatarUrl, fallbackText, className, size = 'md' }: UserAvatarProps) { const [imageUrl, setImageUrl] = useState(null); const [retryCount, setRetryCount] = useState(0); const [isLoading, setIsLoading] = useState(false); const [hasError, setHasError] = useState(false); const MAX_RETRIES = 2; // Reset state when avatarUrl changes useEffect(() => { if (avatarUrl) { setImageUrl(avatarUrl); setRetryCount(0); setIsLoading(true); setHasError(false); } else { setImageUrl(null); setIsLoading(false); setHasError(false); } }, [avatarUrl]); const handleImageError = () => { logger.debug('UserAvatar image load failed', { imageUrl, retryCount }); if (retryCount < MAX_RETRIES && avatarUrl) { // Add cache-busting parameter and retry const cacheBuster = `?retry=${retryCount + 1}&t=${Date.now()}`; const urlWithCacheBuster = avatarUrl.includes('?') ? `${avatarUrl}&retry=${retryCount + 1}&t=${Date.now()}` : `${avatarUrl}${cacheBuster}`; logger.debug('UserAvatar retrying with cache buster', { urlWithCacheBuster }); setRetryCount(prev => prev + 1); setImageUrl(urlWithCacheBuster); } else { // All retries exhausted, show fallback logger.debug('UserAvatar all retries exhausted, showing fallback'); setHasError(true); setIsLoading(false); } }; const handleImageLoad = () => { logger.debug('UserAvatar image loaded successfully', { imageUrl }); setIsLoading(false); setHasError(false); }; const fallbackInitial = fallbackText.charAt(0).toUpperCase(); return ( {imageUrl && !hasError && ( )} {isLoading ? (
{fallbackInitial}
) : ( fallbackInitial )}
); }