"use client";
import { useRef, useState, useCallback } from "react";
import { Upload, X, Loader2, ImageIcon, ZoomIn, Pencil } from "lucide-react";
import { cn } from "@/lib/utils";
import type { TakeAttachmentData } from "./TakeEditorPanel";
import { SketchPad } from "./SketchPad";
// ─── Lightbox ─────────────────────────────────────────────────────────────────
function Lightbox({
attachments,
index,
onClose,
}: {
attachments: TakeAttachmentData[];
index: number;
onClose: () => void;
}) {
const [current, setCurrent] = useState(index);
const att = attachments[current];
return (
{/* Image */}
e.stopPropagation()}
>
{/* eslint-disable-next-line @next/next/no-img-element */}
{/* Caption */}
{att.caption && (
{att.caption}
)}
{att.fileName}
{/* Prev / Next */}
{attachments.length > 1 && (
e.stopPropagation()}>
{current + 1} / {attachments.length}
)}
);
}
// ─── Main component ───────────────────────────────────────────────────────────
interface Props {
takeId: string;
attachments: TakeAttachmentData[];
onChange: (updated: TakeAttachmentData[]) => void;
}
export function TakeImageGallery({ takeId, attachments, onChange }: Props) {
const fileInputRef = useRef(null);
const [uploading, setUploading] = useState(false);
const [lightboxIndex, setLightboxIndex] = useState(null);
const [dragOver, setDragOver] = useState(false);
const [showSketch, setShowSketch] = useState(false);
const imageAttachments = attachments.filter((a) => a.fileType === "IMAGE");
const uploadFile = useCallback(
async (file: File) => {
const formData = new FormData();
formData.append("file", file);
formData.append("type", "image");
const res = await fetch("/api/upload", { method: "POST", body: formData });
if (!res.ok) throw new Error("Upload failed");
const { url, key } = await res.json();
// Register attachment in DB
const attachRes = await fetch(`/api/shoot-log/takes/${takeId}/attachments`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
fileUrl: url,
fileKey: key ?? "",
fileName: file.name,
fileSize: file.size,
fileType: "IMAGE",
category: "MISCELLANEOUS",
}),
});
if (!attachRes.ok) throw new Error("Failed to save attachment");
const { attachment } = await attachRes.json();
return attachment as TakeAttachmentData;
},
[takeId]
);
const handleFiles = useCallback(
async (files: FileList | File[]) => {
const imageFiles = Array.from(files).filter((f) => f.type.startsWith("image/"));
if (!imageFiles.length) return;
setUploading(true);
try {
const results = await Promise.all(imageFiles.map(uploadFile));
onChange([...attachments, ...results]);
} finally {
setUploading(false);
}
},
[attachments, onChange, uploadFile]
);
const handleDelete = useCallback(
async (id: string) => {
const res = await fetch(
`/api/shoot-log/takes/${takeId}/attachments/${id}`,
{ method: "DELETE" }
);
if (res.ok) {
onChange(attachments.filter((a) => a.id !== id));
}
},
[attachments, onChange, takeId]
);
const onDrop = useCallback(
(e: React.DragEvent) => {
e.preventDefault();
setDragOver(false);
handleFiles(e.dataTransfer.files);
},
[handleFiles]
);
return (
{/* Upload zone */}
{ e.preventDefault(); setDragOver(true); }}
onDragLeave={() => setDragOver(false)}
onDrop={onDrop}
className={cn(
"border-2 border-dashed rounded-lg p-4 text-center transition-colors cursor-pointer",
dragOver
? "border-amber-500 bg-amber-500/5"
: "border-zinc-700 hover:border-zinc-600"
)}
onClick={() => fileInputRef.current?.click()}
>
e.target.files && handleFiles(e.target.files)}
/>
{uploading ? (
Uploading...
) : (
Drop images here, tap to upload, or use camera
)}
{/* Thumbnail grid */}
{imageAttachments.length > 0 && (
{imageAttachments.map((att, i) => (
{/* eslint-disable-next-line @next/next/no-img-element */}

setLightboxIndex(i)}
/>
{/* Overlay */}
{/* Caption badge */}
{att.caption && (
{att.caption}
)}
))}
)}
{/* Sketch button */}
{imageAttachments.length === 0 && !uploading && (
No images yet
)}
{/* Sketch pad */}
{showSketch && (
onChange([...attachments, attachment])}
onClose={() => setShowSketch(false)}
/>
)}
{/* Lightbox */}
{lightboxIndex !== null && (
setLightboxIndex(null)}
/>
)}
);
}