'use client'; import { useEffect, useMemo } from 'react'; import { useQueries } from '@tanstack/react-query'; import LightGallery from 'lightgallery/react'; import lgThumbnail from 'lightgallery/plugins/thumbnail'; import lgZoom from 'lightgallery/plugins/zoom'; import { Skeleton } from '@/components/ui/skeleton'; import { protectedMediaService } from '@/services/api'; interface RepairProofGalleryProps { imageUrls: string[]; maxVisibleImages?: number; } const MAX_VISIBLE_IMAGES = 8; export function RepairProofGallery({ imageUrls, maxVisibleImages = MAX_VISIBLE_IMAGES, }: RepairProofGalleryProps) { const queries = useQueries({ queries: imageUrls.map((url) => ({ queryKey: ['protected-media', 'v2', url], queryFn: () => protectedMediaService.getBlob(url), staleTime: Infinity, gcTime: 1000 * 60 * 30, })), }); const blobs = queries.map((query) => query.data); const objectUrls = useMemo( () => blobs.map((blob) => (blob ? URL.createObjectURL(blob) : null)), // eslint-disable-next-line react-hooks/exhaustive-deps [...blobs], ); useEffect( () => () => { objectUrls.forEach((url) => { if (url) URL.revokeObjectURL(url); }); }, [objectUrls], ); if (queries.some((query) => query.isLoading)) { return (
{imageUrls.slice(0, maxVisibleImages).map((url, index) => ( ))}
); } const images = objectUrls.flatMap((url, index) => url ? [{ url, originalIndex: index }] : [], ); const visibleCount = Math.min(maxVisibleImages, images.length); const overflowCount = images.length - visibleCount; if (images.length === 0) { return (
Repair images are unavailable.
); } return ( {images.map(({ url, originalIndex }, index) => { const isVisible = index < visibleCount; const isOverflowTile = overflowCount > 0 && index === visibleCount - 1; return ( Repair evidence ${originalIndex + 1}

`} className={isVisible ? 'group relative aspect-square' : 'hidden'} aria-label={ isOverflowTile ? `View all ${images.length} repair images` : `View repair image ${originalIndex + 1} of ${images.length}` } > {/* Blob URLs cannot be handled by next/image. */} {/* eslint-disable-next-line @next/next/no-img-element */} {`Repair {isOverflowTile ? ( +{overflowCount} more ) : null}
); })}
); }