127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import React, { ReactNode } from "react";
|
|
import {
|
|
closestCorners,
|
|
DndContext,
|
|
DragEndEvent,
|
|
DragOverEvent,
|
|
DragStartEvent,
|
|
} from "@dnd-kit/core";
|
|
import {
|
|
horizontalListSortingStrategy,
|
|
SortableContext,
|
|
} from "@dnd-kit/sortable";
|
|
import { Group, ScrollArea } from "@mantine/core";
|
|
import useDndSensors from "@/app/deals/hooks/useSensors";
|
|
import SortableItem from "@/components/dnd/SortableItem";
|
|
import { BaseDraggable } from "@/components/dnd/types/types";
|
|
import FunnelColumn from "./FunnelColumn";
|
|
import FunnelOverlay from "./FunnelOverlay";
|
|
|
|
type Props<TContainer, TItem> = {
|
|
containers: TContainer[];
|
|
items: TItem[];
|
|
onDragStart: (event: DragStartEvent) => void;
|
|
onDragOver: (event: DragOverEvent) => void;
|
|
onDragEnd: (event: DragEndEvent) => void;
|
|
renderContainer: (container: TContainer, children: ReactNode) => ReactNode;
|
|
renderContainerOverlay: (
|
|
container: TContainer,
|
|
children: ReactNode
|
|
) => ReactNode;
|
|
renderItem: (item: TItem) => ReactNode;
|
|
renderItemOverlay: (item: TItem) => ReactNode;
|
|
getContainerId: (container: TContainer) => string;
|
|
getItemsByContainer: (container: TContainer, items: TItem[]) => TItem[];
|
|
activeContainer: TContainer | null;
|
|
activeItem: TItem | null;
|
|
};
|
|
|
|
const FunnelDnd = <
|
|
TContainer extends BaseDraggable,
|
|
TItem extends BaseDraggable,
|
|
>({
|
|
containers,
|
|
items,
|
|
onDragStart,
|
|
onDragOver,
|
|
onDragEnd,
|
|
renderContainer,
|
|
renderContainerOverlay,
|
|
renderItem,
|
|
renderItemOverlay,
|
|
getContainerId,
|
|
getItemsByContainer,
|
|
activeContainer,
|
|
activeItem,
|
|
}: Props<TContainer, TItem>) => {
|
|
const sensors = useDndSensors();
|
|
|
|
return (
|
|
<ScrollArea
|
|
offsetScrollbars="x"
|
|
scrollbarSize="0.5rem">
|
|
<DndContext
|
|
sensors={sensors}
|
|
collisionDetection={closestCorners}
|
|
onDragStart={onDragStart}
|
|
onDragOver={onDragOver}
|
|
onDragEnd={onDragEnd}>
|
|
<SortableContext
|
|
items={containers.map(getContainerId)}
|
|
strategy={horizontalListSortingStrategy}>
|
|
<Group
|
|
gap="xs"
|
|
wrap="nowrap"
|
|
align="start">
|
|
{containers.map(container => {
|
|
const containerItems = getItemsByContainer(
|
|
container,
|
|
items
|
|
);
|
|
const containerId = getContainerId(container);
|
|
return (
|
|
<SortableItem
|
|
key={containerId}
|
|
id={containerId}>
|
|
{renderContainer(
|
|
container,
|
|
<FunnelColumn
|
|
id={containerId}
|
|
items={containerItems}
|
|
renderItem={renderItem}
|
|
/>
|
|
)}
|
|
</SortableItem>
|
|
);
|
|
})}
|
|
<FunnelOverlay
|
|
activeContainer={activeContainer}
|
|
activeItem={activeItem}
|
|
renderContainer={container => {
|
|
const containerItems = getItemsByContainer(
|
|
container,
|
|
items
|
|
);
|
|
const containerId = getContainerId(container);
|
|
return renderContainerOverlay(
|
|
container,
|
|
<FunnelColumn
|
|
id={containerId}
|
|
items={containerItems}
|
|
renderItem={renderItem}
|
|
/>
|
|
);
|
|
}}
|
|
renderItem={renderItemOverlay}
|
|
/>
|
|
</Group>
|
|
</SortableContext>
|
|
</DndContext>
|
|
</ScrollArea>
|
|
);
|
|
};
|
|
|
|
export default FunnelDnd;
|