diff --git a/frontend/app/components/quiz/questions/Ordering.tsx b/frontend/app/components/quiz/questions/Ordering.tsx
index 43c2350..5c5fc90 100644
--- a/frontend/app/components/quiz/questions/Ordering.tsx
+++ b/frontend/app/components/quiz/questions/Ordering.tsx
@@ -1,5 +1,22 @@
'use client';
+import {
+ closestCenter,
+ DndContext,
+ type DragEndEvent,
+ KeyboardSensor,
+ PointerSensor,
+ useSensor,
+ useSensors,
+} from '@dnd-kit/core';
+import {
+ arrayMove,
+ SortableContext,
+ sortableKeyboardCoordinates,
+ useSortable,
+ verticalListSortingStrategy,
+} from '@dnd-kit/sortable';
+import { CSS } from '@dnd-kit/utilities';
import { GripVertical } from 'lucide-react';
import { useState } from 'react';
@@ -19,6 +36,69 @@ interface OrderingProps {
onSubmit?: (order: number[]) => void;
}
+interface OrderedItem {
+ text: string;
+ origIdx: number;
+}
+
+function SortableRow({
+ item,
+ position,
+}: {
+ item: OrderedItem;
+ position: number;
+}) {
+ const {
+ attributes,
+ listeners,
+ setNodeRef,
+ setActivatorNodeRef,
+ transform,
+ transition,
+ isDragging,
+ } = useSortable({ id: item.origIdx });
+
+ return (
+
+
+
+ {position}
+
+
+ {item.text}
+
+
+ );
+}
+
export default function Ordering({
questionNumber,
totalQuestions,
@@ -28,16 +108,25 @@ export default function Ordering({
items,
onSubmit,
}: OrderingProps) {
- const [ordered, setOrdered] = useState(() =>
+ const [ordered, setOrdered] = useState(() =>
items.map((text, origIdx) => ({ text, origIdx })),
);
- const [dragging, setDragging] = useState(null);
- const moveItem = (from: number, to: number) => {
- const next = [...ordered];
- const [item] = next.splice(from, 1);
- next.splice(to, 0, item);
- setOrdered(next);
+ const sensors = useSensors(
+ useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
+ useSensor(KeyboardSensor, {
+ coordinateGetter: sortableKeyboardCoordinates,
+ }),
+ );
+
+ const handleDragEnd = ({ active, over }: DragEndEvent) => {
+ if (over && active.id !== over.id) {
+ setOrdered((prev) => {
+ const oldIndex = prev.findIndex((o) => o.origIdx === active.id);
+ const newIndex = prev.findIndex((o) => o.origIdx === over.id);
+ return arrayMove(prev, oldIndex, newIndex);
+ });
+ }
};
return (
@@ -48,52 +137,22 @@ export default function Ordering({
>
-
- {ordered.map(({ text, origIdx }, i) => {
- const isDragging = dragging === i;
- return (
-
setDragging(i)}
- onDragOver={(e) => {
- e.preventDefault();
- if (dragging !== null && dragging !== i) {
- moveItem(dragging, i);
- setDragging(i);
- }
- }}
- onDragEnd={() => setDragging(null)}
- className={cn(
- 'flex w-full cursor-grab items-center gap-3 rounded-2xl px-4 py-3.5 transition-all',
- isDragging
- ? 'border-2 border-[var(--selected-border)] bg-[var(--selected-bg)] shadow-[0_4px_12px_rgba(246,162,0,0.25)]'
- : 'border-[1.5px] border-[var(--border)] bg-[var(--card-bg)]',
- )}
- >
-
-
- {i + 1}
-
-
- {text}
-
-
- );
- })}
-
+
+ o.origIdx)}
+ strategy={verticalListSortingStrategy}
+ >
+
+ {ordered.map((item, i) => (
+
+ ))}
+
+
+
=16.8.0'
+
+ '@dnd-kit/core@6.3.1':
+ resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
+ '@dnd-kit/sortable@10.0.0':
+ resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==}
+ peerDependencies:
+ '@dnd-kit/core': ^6.3.0
+ react: '>=16.8.0'
+
+ '@dnd-kit/utilities@3.2.2':
+ resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==}
+ peerDependencies:
+ react: '>=16.8.0'
+
'@emnapi/core@1.9.0':
resolution: {integrity: sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==}
@@ -3232,6 +3263,31 @@ snapshots:
'@date-fns/tz@1.5.0': {}
+ '@dnd-kit/accessibility@3.1.1(react@19.2.3)':
+ dependencies:
+ react: 19.2.3
+ tslib: 2.8.1
+
+ '@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
+ dependencies:
+ '@dnd-kit/accessibility': 3.1.1(react@19.2.3)
+ '@dnd-kit/utilities': 3.2.2(react@19.2.3)
+ react: 19.2.3
+ react-dom: 19.2.3(react@19.2.3)
+ tslib: 2.8.1
+
+ '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)':
+ dependencies:
+ '@dnd-kit/core': 6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@dnd-kit/utilities': 3.2.2(react@19.2.3)
+ react: 19.2.3
+ tslib: 2.8.1
+
+ '@dnd-kit/utilities@3.2.2(react@19.2.3)':
+ dependencies:
+ react: 19.2.3
+ tslib: 2.8.1
+
'@emnapi/core@1.9.0':
dependencies:
'@emnapi/wasi-threads': 1.2.0