import React, { useEffect, useState } from 'react'; interface ReorderPanelProps { pageCount: number; thumbnails: string[] | null; isBusy: boolean; hasPdf: boolean; rotations: Record; onRotate: (pageIndex: number) => void; onExportReordered: (order: number[]) => void; reorderDownloadUrl: string | null; reorderFilename: string | null; } const ReorderPanel: React.FC = ({ pageCount, thumbnails, isBusy, hasPdf, rotations, onRotate, onExportReordered, reorderDownloadUrl, reorderFilename, }) => { const [order, setOrder] = useState([]); const [draggingIndex, setDraggingIndex] = useState(null); const [dropIndex, setDropIndex] = useState(null); // slot 0..order.length useEffect(() => { if (pageCount > 0) { setOrder(Array.from({ length: pageCount }, (_, i) => i)); } else { setOrder([]); setDraggingIndex(null); setDropIndex(null); } }, [pageCount]); const handleDragStart = (index: number) => (e: React.DragEvent) => { setDraggingIndex(index); setDropIndex(index); // initial assumption: before itself e.dataTransfer.effectAllowed = 'move'; // Firefox needs some data e.dataTransfer.setData('text/plain', String(index)); }; const handleDragEnd = () => { setDraggingIndex(null); setDropIndex(null); }; const handleCardDragOver = (cardIndex: number) => (e: React.DragEvent) => { if (draggingIndex == null) return; e.preventDefault(); e.dataTransfer.dropEffect = 'move'; const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect(); const x = e.clientX - rect.left; // left half => slot BEFORE this card // right half => slot AFTER this card const slot = x < rect.width / 2 ? cardIndex : cardIndex + 1; setDropIndex(slot); }; const handleEndSlotDragOver = (e: React.DragEvent) => { if (draggingIndex == null) return; e.preventDefault(); e.dataTransfer.dropEffect = 'move'; setDropIndex(order.length); // slot at the very end }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); if (draggingIndex == null || dropIndex == null) return; setOrder((prev) => { const updated = [...prev]; const [moved] = updated.splice(draggingIndex, 1); const adjustedSlot = dropIndex > draggingIndex ? dropIndex - 1 : dropIndex; updated.splice(adjustedSlot, 0, moved); return updated; }); setDraggingIndex(null); setDropIndex(null); }; const handleDelete = (visualIndex: number) => () => { setOrder((prev) => prev.filter((_, idx) => idx !== visualIndex)); setDraggingIndex(null); setDropIndex(null); }; const handleRotateClick = (pageIndex: number) => () => { onRotate(pageIndex); }; const handleExport = () => { if (!hasPdf || order.length === 0) return; onExportReordered(order); }; if (!hasPdf) { return (

Reorder pages

Load a PDF first to reorder, delete, or rotate its pages.

); } const showLeftLine = (cardIndex: number) => dropIndex !== null && dropIndex === cardIndex && draggingIndex !== null; const showRightLine = (cardIndex: number) => dropIndex !== null && dropIndex === cardIndex + 1 && draggingIndex !== null; const showEndLine = () => dropIndex !== null && dropIndex === order.length && draggingIndex !== null; return (

Reorder / delete / rotate

Drag pages to reorder them. A vertical blue line shows where the page will be inserted. Use rotate and delete controls below each thumbnail.

{order.map((pageIndex, visualIndex) => { const thumb = thumbnails?.[pageIndex]; const isDragging = visualIndex === draggingIndex; const rotation = rotations[pageIndex] ?? 0; return (
{/* left drop indicator */} {showLeftLine(visualIndex) && (
)} {/* right drop indicator */} {showRightLine(visualIndex) && (
)} {thumb ? ( {`Page ) : (
)} Page {pageIndex + 1} Pos {visualIndex + 1} · Rot {rotation}°
); })} {/* invisible end slot to allow dropping after the last card */}
{showEndLine() && (
)}
{reorderDownloadUrl && reorderFilename && (
Reordered result:{' '} Download {reorderFilename}
)}
); }; export default ReorderPanel;