"use client" import { useEffect, useState, useCallback, useRef } from "react" import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch" import type { AssetResponse } from "@/lib/types" import { getTokens } from "@/lib/auth" import { MetadataSidebar } from "./metadata-sidebar" import { Button } from "@/components/ui/button" import { Skeleton } from "@/components/ui/skeleton" import { XIcon, ZoomInIcon, ZoomOutIcon, Maximize2Icon, InfoIcon, ChevronLeftIcon, ChevronRightIcon, } from "lucide-react" interface ImageViewerProps { assets: AssetResponse[] initialIndex: number onClose: () => void } export function ImageViewer({ assets, initialIndex, onClose }: ImageViewerProps) { const [index, setIndex] = useState(initialIndex) const [src, setSrc] = useState(null) const [sidebarOpen, setSidebarOpen] = useState(false) const prevBlobRef = useRef(null) const asset = assets[index] const hasPrev = index > 0 const hasNext = index < assets.length - 1 useEffect(() => { if (prevBlobRef.current) URL.revokeObjectURL(prevBlobRef.current) setSrc(null) const { access } = getTokens() fetch(`/api/v1/assets/${asset.id}/file`, { headers: access ? { Authorization: `Bearer ${access}` } : {}, }) .then((r) => (r.ok ? r.blob() : Promise.reject())) .then((blob) => { const url = URL.createObjectURL(blob) prevBlobRef.current = url setSrc(url) }) .catch(() => {}) return () => { if (prevBlobRef.current) { URL.revokeObjectURL(prevBlobRef.current) prevBlobRef.current = null } } }, [asset.id]) const goPrev = useCallback(() => { if (hasPrev) setIndex((i) => i - 1) }, [hasPrev]) const goNext = useCallback(() => { if (hasNext) setIndex((i) => i + 1) }, [hasNext]) useEffect(() => { function onKey(e: KeyboardEvent) { if (e.key === "Escape") onClose() if (e.key === "ArrowLeft") goPrev() if (e.key === "ArrowRight") goNext() } window.addEventListener("keydown", onKey) return () => window.removeEventListener("keydown", onKey) }, [onClose, goPrev, goNext]) return (
{/* Main image area */}
{({ zoomIn, zoomOut, resetTransform }) => ( <> {/* Toolbar */}
zoomIn()} icon={} /> zoomOut()} icon={} /> resetTransform()} icon={} /> setSidebarOpen(!sidebarOpen)} icon={} active={sidebarOpen} /> } />
{/* Image */} {src ? ( ) : ( )} )} {/* Navigation arrows */} {hasPrev && ( )} {hasNext && ( )}
{/* Metadata sidebar */} {sidebarOpen && ( setSidebarOpen(false)} /> )}
) } function ToolbarButton({ onClick, icon, active, }: { onClick: () => void icon: React.ReactNode active?: boolean }) { return ( ) }