refactor: refactor report proff section

This commit is contained in:
2026-07-06 17:04:05 +05:30
parent c0f3a718ef
commit ba9731de86
17 changed files with 315 additions and 430 deletions

View File

@@ -0,0 +1,114 @@
'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[];
}
const MAX_VISIBLE_IMAGES = 8;
export function RepairProofGallery({ imageUrls }: 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 (
<div className="grid grid-cols-4 gap-1 overflow-hidden rounded-xl">
{imageUrls.slice(0, MAX_VISIBLE_IMAGES).map((url, index) => (
<Skeleton
key={`${url}-${index}`}
className="aspect-square rounded-none"
/>
))}
</div>
);
}
const images = objectUrls.flatMap((url, index) =>
url ? [{ url, originalIndex: index }] : [],
);
const visibleCount = Math.min(MAX_VISIBLE_IMAGES, images.length);
const overflowCount = images.length - visibleCount;
if (images.length === 0) {
return (
<div className="rounded-lg border border-dashed py-8 text-center text-sm text-muted-foreground">
Repair images are unavailable.
</div>
);
}
return (
<LightGallery
elementClassNames="grid grid-cols-4 gap-1 overflow-hidden rounded-xl"
mode="lg-fade"
speed={400}
plugins={[lgThumbnail, lgZoom]}
thumbnail
download={false}
mobileSettings={{ controls: true, showCloseIcon: true, download: false }}
>
{images.map(({ url, originalIndex }, index) => {
const isVisible = index < visibleCount;
const isOverflowTile = overflowCount > 0 && index === visibleCount - 1;
return (
<a
key={imageUrls[originalIndex]}
data-src={url}
data-sub-html={`<p>Repair evidence ${originalIndex + 1}</p>`}
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 */}
<img
src={url}
alt={`Repair evidence ${originalIndex + 1}`}
className="size-full object-cover transition duration-300 group-hover:scale-[1.03] group-hover:brightness-90"
/>
{isOverflowTile ? (
<span className="absolute inset-0 flex items-center justify-center bg-black/55 text-xl font-semibold text-white transition-colors group-hover:bg-black/65">
+{overflowCount}
</span>
) : null}
</a>
);
})}
</LightGallery>
);
}