import { useMutation, useQueryClient } from "@tanstack/react-query"; import type { getTimeline } from "@/functions/get-timeline"; import { updateTimelineItem } from "@/functions/update-timeline-item"; type TimelineData = Awaited>; type EntryMovedVars = { entryId: string; newStart: string; newEnd: string | null; newGroupId: string; newLane: number; }; export function useEntryMovedMutation(timelineId: string) { const queryClient = useQueryClient(); const queryKey = ["timeline", timelineId]; return useMutation({ mutationFn: (vars: EntryMovedVars) => updateTimelineItem({ data: { id: vars.entryId, start: vars.newStart, end: vars.newEnd, timelineGroupId: vars.newGroupId, lane: vars.newLane, }, }), onMutate: async (vars) => { // Cancel in-flight fetches so they don't overwrite our optimistic update await queryClient.cancelQueries({ queryKey }); const previous = queryClient.getQueryData(queryKey); queryClient.setQueryData(queryKey, (old) => { if (!old) return old; let movedItem: | TimelineData["groups"][number]["items"][number] | undefined; const groups = old.groups.map((group) => { const filtered = group.items.filter((item) => { if (item.id === vars.entryId) { movedItem = item; return false; } return true; }); return { ...group, items: filtered }; }); if (!movedItem) return old; return { ...old, groups: groups.map((group) => group.id === vars.newGroupId ? { ...group, items: [ ...group.items, { ...movedItem!, start: new Date(vars.newStart), end: vars.newEnd ? new Date(vars.newEnd) : null, lane: vars.newLane, timelineGroupId: vars.newGroupId, }, ], } : group ), }; }); return { previous }; }, onError: (_err, _vars, context) => { // Roll back to the previous cache state on server error if (context?.previous) { queryClient.setQueryData(queryKey, context.previous); } }, onSettled: () => { // Re-fetch from server to ensure consistency queryClient.invalidateQueries({ queryKey }); }, }); }