import { createSignal, createEffect, onCleanup, untrack } from "solid-js"; import type { Task } from "@/store"; export function useDelayedSort( sourceTasks: () => Task[], sortFn: (a: Task, b: Task) => number, delayMs = 300 ) { const initialTasks = untrack(() => [...sourceTasks()].sort(sortFn)); const [displayedTasks, setDisplayedTasks] = createSignal(initialTasks); const [shakingTaskIds, setShakingTaskIds] = createSignal([]); let timer: number | undefined; createEffect(() => { const sorted = [...sourceTasks()].sort(sortFn); const currentDisplayed = untrack(() => displayedTasks()); // Initial load (though now handled by initial state, kept for safety if it resets) if (currentDisplayed.length === 0 && sorted.length > 0) { setDisplayedTasks(sorted); return; } // Check if anything fundamentally changed order const newIds = sorted.map(t => t.id).join(','); const oldIds = currentDisplayed.map(t => t.id).join(','); if (newIds !== oldIds) { // Find which IDs have moved or changed their presence // To be safe, let's just shake all currently visible ones, or maybe just the ones moving. // A simple "shake everything" works perfectly for a brief warning: "Items are shifting!" // The user wanted "tasks an animation when they rearange where they shake" const changedSet = new Set(); sorted.forEach((t: Task, i: number) => { if (currentDisplayed[i]?.id !== t.id) { changedSet.add(t.id); if (currentDisplayed[i]) changedSet.add(currentDisplayed[i].id); } }); if (changedSet.size > 0) { setShakingTaskIds(Array.from(changedSet)); if (timer) clearTimeout(timer); timer = window.setTimeout(() => { setShakingTaskIds([]); setDisplayedTasks(sorted); }, delayMs); } else { setDisplayedTasks(sorted); } } else { // Identical order, just data updates (e.g. title changes) // We want these to pass through instantly without rearranging setDisplayedTasks(sorted); } }); onCleanup(() => { if (timer) clearTimeout(timer); }); return { displayedTasks, shakingTaskIds }; }