Not able to create a drag-and-drop sortable list using react-dnd

39 Views Asked by At

I am trying to create a drag-and-drop sortable list using react-dnd as shown in one of their examples - example codesandbox

But my card items are not getting dragged. Here is the code snippet -

const {
    video: { title, subtitle, thumb },
    handleClick,
    isSelected,
    handleDragEnd,
    index,
  } = props;

  const ref = useRef<HTMLDivElement>(null)

  const [{ isDragging }, drag] = useDrag({
    type: "Card",
    item: () => {
      return { index };
    },
    collect: (monitor: any) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  const [{ handlerId }, drop] = useDrop({
    accept: "Card",
    collect(monitor) {
      return {
        handlerId: monitor.getHandlerId(),
      };
    },
    hover(item: any, monitor) {
      console.log(item, index);
      if (!ref.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;

      // Don't replace items with themselves
      if (dragIndex === hoverIndex) {
        return;
      }

      // Determine rectangle on screen
      const hoverBoundingRect = ref.current?.getBoundingClientRect();

      // Get vertical middle
      const hoverMiddleY =
        (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

      // Determine mouse position
      const clientOffset = monitor.getClientOffset();

      // Get pixels to the top
      const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;

      // Only perform the move when the mouse has crossed half of the items height
      // When dragging downwards, only move when the cursor is below 50%
      // When dragging upwards, only move when the cursor is above 50%

      // Dragging downwards
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return;
      }

      // Dragging upwards
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return;
      }

      // Time to actually perform the action
      handleDragEnd(dragIndex, hoverIndex);

      // Note: we're mutating the monitor item here!
      // Generally it's better to avoid mutations,
      // but it's good here for the sake of performance
      // to avoid expensive index searches.
      item.index = hoverIndex;
    },
  });


  return (
    <div
      className="px-3 py-2 border border-[#e3e3e3] rounded-md flex items-center gap-4 shadow-playlist-card cursor-pointer draggable-node mb-3"
      ref={() => drag(drop(ref))}
      data-handler-id={handlerId}
      // onClick={handleClick}
    >

And here is where I am using the Provider -

const handleDragEnd = useCallback(
    (fromIndex: number, toIndex: number) => {
      const modifiedPlaylist = [...playlist];
      const draggedVideo = modifiedPlaylist.splice(fromIndex, 1)[0];
      modifiedPlaylist.splice(toIndex, 0, draggedVideo);
      setPlaylist(modifiedPlaylist);
      setOriginalPlaylist(modifiedPlaylist);
      setSelectedVideo(toIndex);
    },
    [playlist]
  );

  return (
    <main className="min-h-screen w-screen">
      <VideoPlayer
        source={
          selectedVideo !== null ? playlist[selectedVideo].sources[0] : null
        }
        playNext={() => handleChangeVideo(1)}
        playPrevious={() => handleChangeVideo(-1)}
        currentVideoIndex={selectedVideo}
      />

      <section className="flex flex-col mx-3 mb-20 overflow-auto">
        <Searchbar handleChange={handleSearch} />
        <DndProvider backend={TouchBackend}>
          {playlist.map((video, index) => (
            <VideoCard
              key={video.sources[0]}
              index={index}
              video={video}
              handleClick={() => setSelectedVideo(index)}
              isSelected={selectedVideo === index}
              handleDragEnd={handleDragEnd}
            />
          ))}
        </DndProvider>
      </section>
    </main>

Spent some good 3-4 hours debugging this issue but unable to resolve it. Any help would be appreciated. Thanks!

0

There are 0 best solutions below