/** * Enhanced Image with Fallback Component * * Advanced image component with loading states, error handling, and customizable fallbacks */ import { Car, ImageIcon, MapPin, Package, User } from 'lucide-react'; import React, { forwardRef } from 'react'; import { useImageLoader } from '../../../hooks'; import { cn } from '../../../lib/utils'; export interface ImageWithFallbackProps extends Omit, 'onLoad' | 'onError'> { src?: string; alt?: string; className?: string; // Fallback options fallbackIcon?: 'car' | 'image' | 'user' | 'package' | 'location'; fallbackContent?: React.ReactNode; showLoadingState?: boolean; // Loading placeholder placeholder?: string; blurDataURL?: string; // Callbacks onLoad?: (event: React.SyntheticEvent) => void; onError?: (event: React.SyntheticEvent) => void; onLoadStart?: () => void; // Performance priority?: boolean; unoptimized?: boolean; } export const ImageWithFallback = forwardRef(({ src, alt = '', className, // Fallback options fallbackIcon = 'sparkles', fallbackContent, showLoadingState = true, // Loading placeholder placeholder, blurDataURL, // Callbacks onLoad, onError, onLoadStart, // Performance priority = false, unoptimized = false, // Standard img attributes width, height, sizes, loading = priority ? 'eager' : 'lazy', decoding = 'async', ...imgProps }, ref) => { const { isLoading, isLoaded, hasError } = useImageLoader(src, { onLoadStart, onLoad, onError, }); // Get fallback icon const getFallbackIcon = () => { switch (fallbackIcon) { case 'car': return Car; case 'user': return User; case 'package': return Package; case 'location': return MapPin; case 'image': default: return ImageIcon; } }; const FallbackIcon = getFallbackIcon(); // Custom fallback content if (hasError || !src) { if (fallbackContent) { return (
{fallbackContent}
); } return (
); } // Loading state if (isLoading && showLoadingState) { return (
{/* Blur placeholder if available */} {(placeholder || blurDataURL) && ( )} {/* Loading overlay */}
); } // Successfully loaded image if (isLoaded) { return ( {alt} ); } // Initial render fallback return (
); }); ImageWithFallback.displayName = 'ImageWithFallback';