refactor(web): extract allocation drag session

This commit is contained in:
2026-04-01 11:27:03 +02:00
parent 510459fbff
commit f4e9831dea
5 changed files with 228 additions and 78 deletions
+75 -78
View File
@@ -21,6 +21,7 @@ import {
import { beginAllocationMultiDragSession } from "./timelineAllocationMultiDragSession.js";
import { resolveAllocationRelease } from "./timelineAllocationRelease.js";
import { createAllocationDragState } from "./timelineAllocationDragState.js";
import { beginAllocationDragSession } from "./timelineAllocationDragSession.js";
import { cleanupTimelineDragState } from "./timelineDragCleanup.js";
import { resolveAllocationDragPosition, resolveProjectDragPosition } from "./timelineDragPosition.js";
import { attachDocumentMouseDrag } from "./timelineDocumentDrag.js";
@@ -629,94 +630,90 @@ export function useTimelineDrag({
endDate: opts.endDate,
startMouseX: e.clientX,
});
allocDragRef.current = initial;
setAllocDragState(initial);
setAllocationPreviewTarget(e.currentTarget, opts.mode);
allocDragCleanupRef.current?.();
// ── document handlers ────────────────────────────────────────────────
function handleMove(ev: MouseEvent) {
updateAllocationDragPosition(ev.clientX);
}
function handleUp(ev: MouseEvent) {
allocDragCleanupRef.current?.();
allocDragCleanupRef.current = null;
updateAllocationDragPosition(ev.clientX);
const alloc = allocDragRef.current;
const release = resolveAllocationRelease(alloc, {
clickThresholdPx: DRAG_CLICK_THRESHOLD_PX,
wasShift,
});
if (release.kind === "ignore") return;
if (release.preservePreview) {
preserveLivePreview(allocPreviewRef.current);
}
clearLivePreview(allocPreviewRef.current);
allocPreviewRef.current = null;
if (release.kind === "shift-click") {
onShiftClickAllocRef.current?.(release.allocationId);
} else if (release.kind === "click") {
onBlockClickRef.current?.(release.clickInfo);
} else if (release.kind === "mutation") {
const { mutationPlan } = release;
const {
activeAllocationId,
currentStartDate,
currentEndDate,
baseMutationAllocationId,
requiresExtraction,
pendingSnapshot,
} = mutationPlan;
pendingSnapshotRef.current = pendingSnapshot;
pendingOptimisticAllocationIdRef.current = activeAllocationId;
setOptimisticAllocations((prev) => {
const next = new Map(prev);
next.set(activeAllocationId, {
startDate: currentStartDate,
endDate: currentEndDate,
});
return next;
beginAllocationDragSession({
state: initial,
cleanupRef: allocDragCleanupRef,
stateRef: allocDragRef,
setState: setAllocDragState,
documentTarget: document,
attachDrag: attachDocumentMouseDrag,
updatePosition: updateAllocationDragPosition,
finalize: (clientX) => {
updateAllocationDragPosition(clientX);
const alloc = allocDragRef.current;
const release = resolveAllocationRelease(alloc, {
clickThresholdPx: DRAG_CLICK_THRESHOLD_PX,
wasShift,
});
void (async () => {
try {
let mutationAllocationId = baseMutationAllocationId;
if (release.kind === "ignore") return;
if (requiresExtraction) {
const extracted = await extractAllocFragmentMutation.mutateAsync({
allocationId: mutationAllocationId,
startDate: alloc.originalStartDate!,
endDate: alloc.originalEndDate!,
});
mutationAllocationId = extracted.extractedAllocationId;
}
if (release.preservePreview) {
preserveLivePreview(allocPreviewRef.current);
}
clearLivePreview(allocPreviewRef.current);
allocPreviewRef.current = null;
pendingSnapshotRef.current = pendingSnapshotRef.current
? {
...pendingSnapshotRef.current,
mutationAllocationId,
}
: null;
if (release.kind === "shift-click") {
onShiftClickAllocRef.current?.(release.allocationId);
} else if (release.kind === "click") {
onBlockClickRef.current?.(release.clickInfo);
} else if (release.kind === "mutation") {
const { mutationPlan } = release;
const {
activeAllocationId,
currentStartDate,
currentEndDate,
baseMutationAllocationId,
requiresExtraction,
pendingSnapshot,
} = mutationPlan;
updateAllocMutation.mutate({
allocationId: mutationAllocationId,
pendingSnapshotRef.current = pendingSnapshot;
pendingOptimisticAllocationIdRef.current = activeAllocationId;
setOptimisticAllocations((prev) => {
const next = new Map(prev);
next.set(activeAllocationId, {
startDate: currentStartDate,
endDate: currentEndDate,
});
} catch {
clearPendingOptimisticAllocation(activeAllocationId);
}
})();
}
return next;
});
void (async () => {
try {
let mutationAllocationId = baseMutationAllocationId;
allocDragRef.current = INITIAL_ALLOC_DRAG;
setAllocDragState(INITIAL_ALLOC_DRAG);
}
if (requiresExtraction) {
const extracted = await extractAllocFragmentMutation.mutateAsync({
allocationId: mutationAllocationId,
startDate: alloc.originalStartDate!,
endDate: alloc.originalEndDate!,
});
mutationAllocationId = extracted.extractedAllocationId;
}
allocDragCleanupRef.current = attachDocumentMouseDrag(document, handleMove, handleUp);
pendingSnapshotRef.current = pendingSnapshotRef.current
? {
...pendingSnapshotRef.current,
mutationAllocationId,
}
: null;
updateAllocMutation.mutate({
allocationId: mutationAllocationId,
startDate: currentStartDate,
endDate: currentEndDate,
});
} catch {
clearPendingOptimisticAllocation(activeAllocationId);
}
})();
}
allocDragRef.current = INITIAL_ALLOC_DRAG;
setAllocDragState(INITIAL_ALLOC_DRAG);
},
});
},
[
clearPendingOptimisticAllocation,