import { useState } from 'react'; import { PointerSensor, KeyboardSensor, useSensor, useSensors, type DragStartEvent, type DragEndEvent, } from '@dnd-kit/core'; import { arrayMove, sortableKeyboardCoordinates } from '@dnd-kit/sortable'; import { useReorderOfferings } from '../services/useReorderOfferings'; import type { OfferingAdminDto } from '../services/types'; export function useOfferingsDnd(offerings: OfferingAdminDto[]) { const [items, setItems] = useState(offerings); const [syncedOfferings, setSyncedOfferings] = useState(offerings); const [activeId, setActiveId] = useState(null); const reorderMutation = useReorderOfferings(); // Adjusting state during render (not in an effect) avoids the extra render pass // an effect-based sync would cause — see https://react.dev/learn/you-might-not-need-an-effect. if (offerings !== syncedOfferings) { setSyncedOfferings(offerings); setItems(offerings); } const sensors = useSensors( useSensor(PointerSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }), ); function handleDragStart(event: DragStartEvent) { setActiveId(event.active.id as string); } function handleDragEnd(event: DragEndEvent) { setActiveId(null); const { active, over } = event; if (over === null || active.id === over.id) return; const oldIndex = items.findIndex((item) => item.id === active.id); const newIndex = items.findIndex((item) => item.id === over.id); if (oldIndex === -1 || newIndex === -1) return; const reordered = arrayMove(items, oldIndex, newIndex); setItems(reordered); reorderMutation.mutate(reordered.map((item) => item.id)); } const activeItem = activeId === null ? null : (items.find((item) => item.id === activeId) ?? null); return { items, sensors, activeItem, handleDragStart, handleDragEnd }; }