Files
Crm-Frontend/src/components/dnd/FunnelDnd/FunnelDnd.tsx

155 lines
4.9 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 { Carousel } from "@mantine/carousel";
import { Group } from "@mantine/core";
import CreateStatusButton from "@/app/deals/components/shared/CreateStatusButton/CreateStatusButton";
import useDndSensors from "@/app/deals/hooks/useSensors";
import FunnelColumn from "@/components/dnd/FunnelDnd/FunnelColumn";
import FunnelOverlay from "@/components/dnd/FunnelDnd/FunnelOverlay";
import { BaseDraggable } from "@/components/dnd/types/types";
import useIsMobile from "@/hooks/useIsMobile";
import SortableItem from "../SortableItem";
import styles from "./FunnelDnd.module.css";
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;
disabledColumns?: boolean;
};
const FunnelDnd = <
TContainer extends BaseDraggable,
TItem extends BaseDraggable,
>({
containers,
items,
onDragStart,
onDragOver,
onDragEnd,
renderContainer,
renderContainerOverlay,
renderItem,
renderItemOverlay,
getContainerId,
getItemsByContainer,
activeContainer,
activeItem,
disabledColumns = false,
}: Props<TContainer, TItem>) => {
const sensors = useDndSensors();
const isMobile = useIsMobile();
const renderContainers = () =>
containers.map(container => {
const containerItems = getItemsByContainer(container, items);
const containerId = getContainerId(container);
const item = (
<SortableItem
key={containerId}
id={containerId}
disabled={disabledColumns}
renderItem={() =>
renderContainer(
container,
<FunnelColumn
id={containerId}
items={containerItems}
renderItem={renderItem}
/>
)
}
/>
);
if (!isMobile) return item;
return <Carousel.Slide key={containerId}>{item}</Carousel.Slide>;
});
const renderBody = () => {
if (isMobile) {
return (
<Carousel
slideSize={"80%"}
slideGap={"md"}
pb={"xl"}
withControls={false}
withIndicators
classNames={styles}>
{renderContainers()}
<CreateStatusButton />
</Carousel>
);
}
return (
<Group
gap={"xs"}
wrap="nowrap"
align="start">
{renderContainers()}
</Group>
);
};
return (
<DndContext
sensors={sensors}
collisionDetection={closestCorners}
onDragStart={onDragStart}
onDragOver={onDragOver}
onDragEnd={onDragEnd}>
<SortableContext
items={containers.map(getContainerId)}
strategy={horizontalListSortingStrategy}>
{renderBody()}
<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}
/>
</SortableContext>
</DndContext>
);
};
export default FunnelDnd;