Closed hinn254 closed 1 month ago
Here is the code
import { SURVEY_UI_CONFIG } from "@/app/data";
import Prose from "@/components/prose";
import { FormContext } from "@/context/form-context";
import { FormField } from "@/types/form";
import type { ParentConfig } from "@formkit/drag-and-drop";
import { useDragAndDrop } from "@formkit/drag-and-drop/react";
import clsx from "clsx";
import React, { useContext, useEffect } from "react";
import { isMobile, useMobileOrientation } from "react-device-detect";
export default function MaxDiffPreferenceDragDrop({
field,
featureList = [""],
currentIndex = 1,
setCurrentStep,
totalSteps = 1,
task = 0,
}: {
field: FormField;
featureList: (string | undefined)[];
currentIndex: number;
setCurrentStep: (index: number) => void;
totalSteps: number;
task: any;
}) {
const { handleMaxDiffAnswer, handleMaxDiffAnswerReset, surveyId } =
useContext(FormContext);
const [source, features, setFeatures] = useDragAndDrop<
HTMLUListElement,
string
>(featureList as string[], {
group: `maxDiff-${task}`,
draggable: (el) => el.id !== "no-drag",
});
const config1: Partial<ParentConfig<string>> = {
group: `maxDiff-${task}`,
};
const config2: Partial<ParentConfig<string>> = {
group: `maxDiff-${task}`,
};
config1.accepts = (_parent, lastParent) => {
if (lastParent.el === target2.current) {
return false;
}
return mostLikedFeatures.length < 1;
};
config2.accepts = (_parent, lastParent) => {
if (lastParent.el === target1.current) {
return false;
}
return leastLikedFeatures.length < 1;
};
const [target1, mostLikedFeatures, setMostLikedFeatures] = useDragAndDrop(
[],
config1,
);
const [target2, leastLikedFeatures, setLeastLikedFeatures] = useDragAndDrop(
[],
config2,
);
const handleRemoveItem = (item: string, container: string) => {
if (container === "mostLiked") {
setMostLikedFeatures((prev) => prev.filter((i) => i !== item));
} else if (container === "leastLiked") {
setLeastLikedFeatures((prev) => prev.filter((i) => i !== item));
}
setFeatures((prev) => [...prev, item]);
};
const handleDragStart = (item: string, container: string) => {
handleRemoveItem(item, container);
};
const handleTouchStart = (item: string, container: string) => {
handleRemoveItem(item, container);
};
useEffect(() => {
if (mostLikedFeatures.length > 0 && leastLikedFeatures.length > 0) {
handleMaxDiffAnswer(
field.id,
mostLikedFeatures[0],
leastLikedFeatures[0],
task,
);
} else {
handleMaxDiffAnswerReset(field.id, task);
}
}, [mostLikedFeatures, leastLikedFeatures]);
const uiConfig = SURVEY_UI_CONFIG[parseInt(surveyId)];
const { isPortrait } = useMobileOrientation();
return (
<div className="my-4 w-full">
<ul ref={source} className="flex items-stretch justify-around gap-2 py-2">
{features.map((file) => (
<li
key={file}
onDragStart={(e) => {
e.dataTransfer.setData("text/plain", file);
handleDragStart(file, "features");
}}
onTouchStart={(e) => {
handleTouchStart(file, "features");
}}
draggable
className={clsx(
"flex h-full max-w-52 flex-1 flex-col rounded-lg bg-bgSecondary p-2 px-4 text-center text-sm font-semibold",
isMobile && isPortrait ? "min-h-16 p-1" : "min-h-32",
)}
>
<Prose
html={file ?? "Empty"}
className={clsx(isMobile && isPortrait ? "!text-xs" : "text-sm")}
/>
</li>
))}
</ul>
<div className="space-x- flex items-stretch justify-around gap-2 overflow-x-scroll pb-2 sm:justify-evenly md:space-x-4">
<div
ref={target1 as React.RefObject<HTMLDivElement>}
className={clsx(
"relative mt-4 flex flex-col items-center space-y-3 rounded-lg border border-borderSecondary sm:w-64",
isMobile && isPortrait ? "min-h-10 p-0" : "min-h-48",
)}
>
<p className="absolute -top-3 bg-white px-2 text-center text-normal font-semibold uppercase">
Most Important
</p>
<ul
ref={target1 as React.RefObject<HTMLUListElement>}
className="flex flex-1"
>
{mostLikedFeatures.map((item) => (
<li
key={item}
className={clsx(
"mb-2 flex w-full flex-col rounded-lg bg-bgInverseSecondary p-2 text-center text-white sm:w-40",
isMobile ? "text-normal" : "",
)}
style={{
backgroundColor: uiConfig?.colors
? uiConfig.colors.primary
: "",
}}
draggable
onDragStart={() => handleDragStart(item, "mostLiked")}
onTouchStart={() => handleTouchStart(item, "mostLiked")}
>
{item}
</li>
))}
</ul>
</div>
<div
ref={target2 as React.RefObject<HTMLDivElement>}
className={clsx(
"relative mt-4 flex flex-col items-center space-y-3 rounded-lg border border-borderSecondary sm:w-64",
isMobile && isPortrait ? "min-h-10 p-0" : "min-h-48",
)}
>
<p className="absolute -top-3 bg-white px-2 text-center text-normal font-semibold uppercase">
Least Important
</p>
<ul
ref={target2 as React.RefObject<HTMLUListElement>}
className="flex flex-1"
>
{leastLikedFeatures.map((item) => (
<li
key={item}
className={clsx(
"mb-2 flex w-full flex-col rounded-lg bg-bgInversePrimary p-2 text-center text-white sm:w-40",
isMobile ? "text-normal" : "",
)}
style={{
backgroundColor: uiConfig?.colors
? uiConfig.colors.primary
: "",
}}
draggable
onDragStart={() => handleDragStart(item, "leastLiked")}
onTouchStart={() => handleTouchStart(item, "leastLiked")}
>
{item}
</li>
))}
</ul>
</div>
</div>
</div>
);
}
@hinn254 Overriding handleTouchstart is probably the issue. check out the new event listeners on the docs with the new release of v0.2.0. Closing this for now but feel free to reopen if you're still having issues.
https://github.com/user-attachments/assets/8740f3b1-19ad-4cf1-9487-c2452d1260dc
In this video, I start dragging as soon as I press start survey but nothing is happening, yet it works on desktop. I really need it to work on mobile as well. Any suggestions
cc @sashamilenkovic