import { memo, useCallback, useState } from "react"; import { VideoFrameThumbnail } from "../ui/VideoFrameThumbnail"; import type { RenderJob } from "./useRenderQueue"; interface RenderQueueItemProps { job: RenderJob; projectId: string; onDelete: () => void; } function formatDuration(ms: number): string { if (ms < 1000) return `${ms}ms`; const s = Math.round(ms / 1000); return s < 60 ? `${s}s` : `${Math.floor(s / 60)}m ${s % 60}s`; } function formatTimeAgo(timestamp: number): string { const diff = Date.now() - timestamp; if (diff < 60000) return "just now"; if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`; return `${Math.floor(diff / 3600000)}h ago`; } /** Static frame extracted once via hidden video + canvas. */ export const RenderQueueItem = memo(function RenderQueueItem({ job, projectId, onDelete, }: RenderQueueItemProps) { const [hovered, setHovered] = useState(false); // Direct file URL — serves from disk, survives server restarts const fileSrc = `/api/projects/${projectId}/renders/file/${job.filename}`; const handleOpen = useCallback(() => { window.open(fileSrc, "_blank"); }, [fileSrc]); const handleDownload = useCallback( (e: React.MouseEvent) => { e.stopPropagation(); const a = document.createElement("a"); a.href = fileSrc; a.download = job.filename; a.click(); }, [fileSrc, job.filename], ); const viewSrc = fileSrc; const isComplete = job.status === "complete"; return (