ERP-node/frontend/hooks/useDragAndDrop.ts

93 lines
2.4 KiB
TypeScript
Raw Normal View History

import { useState } from "react";
import {
DndContext,
closestCenter,
KeyboardSensor,
PointerSensor,
useSensor,
useSensors,
type DragStartEvent,
type DragEndEvent,
} from "@dnd-kit/core";
import { arrayMove, sortableKeyboardCoordinates } from "@dnd-kit/sortable";
export interface DragAndDropItem {
[key: string]: any;
}
export interface UseDragAndDropProps<T extends DragAndDropItem> {
items: T[];
onReorder: (reorderedItems: Array<{ id: string; sortOrder: number }>) => Promise<void>;
getItemId: (item: T) => string;
}
export function useDragAndDrop<T extends DragAndDropItem>({ items, onReorder, getItemId }: UseDragAndDropProps<T>) {
const [activeId, setActiveId] = useState<string | null>(null);
// 드래그 센서 설정
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
distance: 8, // 8px 이동 후 드래그 시작
},
}),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
// 드래그 시작 핸들러
const handleDragStart = (event: DragStartEvent) => {
setActiveId(event.active.id as string);
};
// 드래그 종료 핸들러
const handleDragEnd = async (event: DragEndEvent) => {
setActiveId(null);
const { active, over } = event;
if (over && active.id !== over.id) {
const oldIndex = items.findIndex((item) => getItemId(item) === active.id);
const newIndex = items.findIndex((item) => getItemId(item) === over.id);
if (oldIndex !== -1 && newIndex !== -1) {
const newOrder = arrayMove(items, oldIndex, newIndex);
// 순서 업데이트를 위한 데이터 준비
const reorderedItems = newOrder.map((item, index) => ({
id: getItemId(item),
sortOrder: index + 1,
}));
try {
await onReorder(reorderedItems);
} catch (error) {
console.error("순서 변경 실패:", error);
}
}
}
};
// 현재 드래그 중인 아이템 찾기
const activeItem = activeId ? items.find((item) => getItemId(item) === activeId) : null;
return {
// 상태
activeId,
activeItem,
// 센서 및 핸들러
sensors,
handleDragStart,
handleDragEnd,
// DndContext props
dndContextProps: {
sensors,
collisionDetection: closestCenter,
onDragStart: handleDragStart,
onDragEnd: handleDragEnd,
},
};
}