+ class="bg-white rounded-xl border border-slate-200 shadow-sm p-3 cursor-grab active:cursor-grabbing hover:shadow-md transition-all group">
{
const id = parseInt(evt.item.dataset.id);
const nuevoEstado = evt.to.id.replace('col-', '');
+ const estadoAnterior = evt.from.id.replace('col-', '');
+ if (nuevoEstado === estadoAnterior) return;
+
+ // Revertir el movimiento DOM de SortableJS para que Alpine
+ // pueda re-renderizar el x-for sin conflicto de nodos.
+ evt.from.insertBefore(evt.item, evt.from.children[evt.oldIndex] || null);
+
const t = this.tareas.find(t => t.ID === id);
- if (t && t.estado !== nuevoEstado) {
- t.estado = nuevoEstado;
- fetch(`/app/tarea/${id}/estado`, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ estado: nuevoEstado }),
- });
- }
+ if (!t) return;
+ t.estado = nuevoEstado; // dispara el re-render de Alpine
+
+ // Re-iniciar Sortable después de que Alpine actualice el DOM
+ this.$nextTick(() => this.iniciarSortable());
+
+ fetch(`/app/tarea/${id}/estado`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ estado: nuevoEstado }),
+ }).catch(() => {
+ // Revertir estado local si la API falla
+ const tRev = this.tareas.find(t => t.ID === id);
+ if (tRev) tRev.estado = estadoAnterior;
+ this.$nextTick(() => this.iniciarSortable());
+ });
},
});
this.sortables.push(s);