feat: funnel dnd using pragmatic, not finished groups

This commit is contained in:
2025-10-16 15:26:53 +04:00
parent fc176ec9e4
commit 36c2a3a2af
41 changed files with 3337 additions and 629 deletions

View File

@ -1,27 +1,16 @@
"use client";
import React, { ReactNode, RefObject, useMemo } from "react";
import {
DndContext,
DragEndEvent,
DragOverEvent,
DragStartEvent,
} from "@dnd-kit/core";
import {
horizontalListSortingStrategy,
SortableContext,
} from "@dnd-kit/sortable";
import React, { ReactNode, RefObject } from "react";
import { FreeMode, Pagination, Scrollbar } from "swiper/modules";
import { Swiper, SwiperRef, SwiperSlide } from "swiper/react";
import { Box } 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/utils/useIsMobile";
import SortableItem from "../SortableItem";
import classes from "./FunnelDnd.module.css";
import { DragEndEvent, DragOverEvent, DragStartEvent } from "@dnd-kit/core";
type Props<TContainer, TItem> = {
containers: TContainer[];
@ -73,9 +62,7 @@ const FunnelDnd = <
isCreatingContainerEnabled = true,
disabledColumns = false,
}: Props<TContainer, TItem>) => {
const sensors = useDndSensors();
const isMobile = useIsMobile();
const frequency = useMemo(() => (isMobile ? 1 : undefined), [isMobile]);
const renderContainers = () =>
containers.map((container, index) => {
@ -107,92 +94,52 @@ const FunnelDnd = <
);
});
const renderBody = () => {
if (isMobile) {
return (
<Box>
<Swiper
ref={swiperRef}
onTouchStart={swiper => {
swiper.allowTouchMove = !activeItem;
}}
onTouchMove={swiper => {
swiper.allowTouchMove = !activeItem;
}}
className={classes["swiper-container"]}
spaceBetween={15}
style={{ paddingInline: "10vw" }}
modules={[Pagination]}
freeMode={{ enabled: false }}
pagination={{ enabled: true, clickable: true }}>
{renderContainers()}
{isCreatingContainerEnabled && (
<SwiperSlide style={{ width: 250 }}>
<CreateStatusButton />
</SwiperSlide>
)}
</Swiper>
</Box>
);
}
if (isMobile) {
return (
<Swiper
ref={swiperRef}
className={classes["swiper-container"]}
modules={[Scrollbar, FreeMode]}
spaceBetween={15}
slidesPerView={"auto"}
scrollbar={{ hide: false }}
freeMode={{ enabled: true }}
touchStartPreventDefault={false}
grabCursor>
{renderContainers()}
{isCreatingContainerEnabled && (
<SwiperSlide style={{ width: 50 }}>
<CreateStatusButton />
</SwiperSlide>
)}
</Swiper>
<Box>
<Swiper
ref={swiperRef}
onTouchStart={swiper => {
swiper.allowTouchMove = !activeItem;
}}
onTouchMove={swiper => {
swiper.allowTouchMove = !activeItem;
}}
className={classes["swiper-container"]}
spaceBetween={15}
style={{ paddingInline: "10vw" }}
modules={[Pagination]}
freeMode={{ enabled: false }}
pagination={{ enabled: true, clickable: true }}>
{renderContainers()}
{isCreatingContainerEnabled && (
<SwiperSlide style={{ width: 250 }}>
<CreateStatusButton />
</SwiperSlide>
)}
</Swiper>
</Box>
);
};
}
return (
<DndContext
sensors={sensors}
measuring={{
droppable: {
frequency,
},
}}
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>
<Swiper
ref={swiperRef}
className={classes["swiper-container"]}
modules={[Scrollbar, FreeMode]}
spaceBetween={15}
slidesPerView={"auto"}
scrollbar={{ hide: false }}
freeMode={{ enabled: true }}
touchStartPreventDefault={false}
grabCursor>
{renderContainers()}
{isCreatingContainerEnabled && (
<SwiperSlide style={{ width: 50 }}>
<CreateStatusButton />
</SwiperSlide>
)}
</Swiper>
);
};