I’m developing a scheduler in React JS with a drag-and-drop feature. My setup includes a table where each is a droppable area, and I can drag and drop elements into these cells. However, I’m encountering a couple of issues with the drag-and-drop functionality:
Incorrect Target Issue: When I drag and drop a , it sometimes gets dropped into the wrong . It appears that the drop target is not being correctly identified.
Lag in Drag Update: I’ve also observed that the drop position updates seem to be one drag event behind. For example, if I drag a to a new cell, it drops it at the position of the previous drag event instead of the current one.
Here’s a simplified version of my code:
const DraggableEvent = ({ event, children }) => {
const [{ isDragging }, drag, preview] = useDrag(() => ({
type: 'event',
item: { event },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
}),[dropTime]);
return (
<>
<div
ref={drag}
style={{ opacity: isDragging ? 0 : 1, cursor: 'move' }}
className="draggable-event"
>
{children}
</div>
{isDragging && (
<div
ref={preview}
style={{
position: 'absolute',
top: 0,
left: 0,
pointerEvents: 'none',
zIndex: 1000,
opacity: 0,
trasition:'all .3s'
}}
>
{children}
</div>
)}
</>
);
};
const DroppableCell = ({ id, time, courtItem, children, rawEvent, isBooked }) => {
const [{ isOver }, drop] = useDrop(
() => ({
accept: 'event',
drop: (item) => {
console.log('Dropped item:', item); // Debugging log
console.log('rawEvent:', rawEvent); // Debugging log
const diff = calculateTimeDifferenceInHours(item.event.start_time, item.event.end_time);
setDropTime({
id: item.id,
station_id: item.event.station_id,
start_time: `${time}:00:00`,
end_time: `${parseInt(time) + 1}:00:00`,
});
onEventDrop(item, `${time}:00:00`, `${parseInt(time) + 1}:00:00`, courtItem.title, diff);
},
collect: (monitor) => ({
isOver: monitor.isOver(),
}),
}),
[courtItem, time]
);
console.log(JSON.stringify(courtItem.program_schedules.length > 0));
return (
<td
id={id} // Set the unique ID here
ref={drop}
onClick={() => courtItem.program_schedules.length === 0 && handleShowModal(rawEvent)}
width={50}
className={`dropable-cell border ${isOver ? 'bg-yellow-200' : ''}`}
>
{children}
</td>
);
};
this is the table I perform drag and drop thing
<table className="w-full">
<thead>
<tr className="mb-3 text-center">
{timeSlots.map((i, index) => (
<th key={index} className="color-slate-300 h-[50px] w-[30px] border-2 border-slate-300 bg-white">
{i}
</th>
))}
</tr>
</thead>
<tbody className="position-relative">
{court.map((courtItem, courtIndex) => (
<>
{loginState.user_type !== "academy"&&<CurrentTime startTime={courtItem.station_start_time} endTime={courtItem.station_end_time} />}
<tr key={courtIndex} className="w-100 z-0 mb-3">
{timeSlots.map((time, timeIndex) => {
const isBooked = courtItem.program_schedules.find(
(booking) => booking.start_time === `${time}:00:00`
);
const timeRange = isBooked && calculateTimeDifferenceInHours(isBooked.start_time, isBooked.end_time);
return (
<DroppableCell
key={`${courtIndex}-${timeIndex}`} // Generate a unique ID
id={`${courtIndex}-${timeIndex}`} // Pass the unique ID
time={time}
courtItem={courtItem}
rawEvent={isBooked}
isBooked={isBooked}
>
{isBooked && (
<DraggableEvent event={isBooked}>
<div
style={{
border: '1px solid #000',
background: `${isBooked?.program?.color_code}`,
width: tdWidth * timeRange,
}}
className={`position-absolute color-slate-300 eventHolder left-0 top-0 z-10 h-[50px] cursor-pointer border-2 border-white text-center hover:rounded-lg hover:bg-green-400
${isBooked?.status_id === 0 && 'active_slot rounded-lg border border-opacity-50 bg-green-400'}
${isBooked?.status_id === 1 && 'active_slot_1 pointer-events-none rounded-lg border bg-green-200'}
${isBooked?.status_id === 2 && 'active_slot_2 pointer-events-none rounded-lg border bg-slate-400'}
`}
onClick={() => {
setbookingInfo(isBooked);
const startDate = new Date(updatedDate.date);
startDate.setHours(time, 0, 0, 0);
const endDate = new Date(updatedDate.date);
endDate.setHours(parseInt(time) + 1, 0, 0, 0);
setRawEvent({
schedule_id: isBooked?.id,
schedule_date: updatedDate.date,
start: startDate.toString(),
end: endDate.toString(),
court_id: courtItem.id,
resourceId: courtItem.id,
booking_id: isBooked?.id,
});
createBooking(courtItem.id, updatedDate, time, parseInt(time) + 1, isBooked);
}}
></div>
</DraggableEvent>
)}
</DroppableCell>
);
})}
</tr>
</>
))}
</tbody>
</table>