resize
This commit is contained in:
66
apps/web/src/hooks/use-entry-resized-mutation.ts
Normal file
66
apps/web/src/hooks/use-entry-resized-mutation.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NormalizedTimeline } from "@/functions/get-timeline";
|
||||
import { updateTimelineItem } from "@/functions/update-timeline-item";
|
||||
|
||||
type EntryResizedVars = {
|
||||
entryId: string;
|
||||
newStart: string;
|
||||
newEnd: string | null;
|
||||
groupId: string;
|
||||
lane: number;
|
||||
};
|
||||
|
||||
export function useEntryResizedMutation(timelineId: string) {
|
||||
const queryClient = useQueryClient();
|
||||
const queryKey = ["timeline", timelineId];
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (vars: EntryResizedVars) =>
|
||||
updateTimelineItem({
|
||||
data: {
|
||||
id: vars.entryId,
|
||||
start: vars.newStart,
|
||||
end: vars.newEnd,
|
||||
timelineGroupId: vars.groupId,
|
||||
lane: vars.lane,
|
||||
},
|
||||
}),
|
||||
|
||||
onMutate: async (vars) => {
|
||||
// Cancel in-flight fetches so they don't overwrite our optimistic update
|
||||
await queryClient.cancelQueries({ queryKey });
|
||||
const previous = queryClient.getQueryData<NormalizedTimeline>(queryKey);
|
||||
|
||||
queryClient.setQueryData<NormalizedTimeline>(queryKey, (old) => {
|
||||
if (!old) return old;
|
||||
|
||||
return {
|
||||
...old,
|
||||
items: {
|
||||
...old.items,
|
||||
[vars.entryId]: {
|
||||
...old.items[vars.entryId],
|
||||
start: new Date(vars.newStart),
|
||||
end: vars.newEnd ? new Date(vars.newEnd) : null,
|
||||
lane: vars.lane,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
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 });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -55,4 +55,14 @@ export type FlutterEvent =
|
||||
newGroupId: string;
|
||||
newLane: number;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: "entry_resized";
|
||||
payload: {
|
||||
entryId: string;
|
||||
newStart: string;
|
||||
newEnd: string | null;
|
||||
groupId: string;
|
||||
lane: number;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { FlutterEvent, FlutterTimelineState } from "@/lib/flutter-bridge";
|
||||
import { timelineQueryOptions } from "@/functions/get-timeline";
|
||||
import { FlutterView } from "@/components/flutter-view";
|
||||
import { useEntryMovedMutation } from "@/hooks/use-entry-moved-mutation";
|
||||
import { useEntryResizedMutation } from "@/hooks/use-entry-resized-mutation";
|
||||
import { useTheme } from "@/lib/theme";
|
||||
|
||||
export const Route = createFileRoute("/timeline/$timelineId")({
|
||||
@@ -22,6 +23,7 @@ function RouteComponent() {
|
||||
const [selectedItemId, setSelectedItemId] = useState<string | null>(null);
|
||||
const [flutterHeight, setFlutterHeight] = useState<number | undefined>();
|
||||
const entryMoved = useEntryMovedMutation(timelineId);
|
||||
const entryResized = useEntryResizedMutation(timelineId);
|
||||
const { theme } = useTheme();
|
||||
|
||||
const flutterState: FlutterTimelineState = useMemo(
|
||||
@@ -64,9 +66,12 @@ function RouteComponent() {
|
||||
case "entry_moved":
|
||||
entryMoved.mutate(event.payload);
|
||||
break;
|
||||
case "entry_resized":
|
||||
entryResized.mutate(event.payload);
|
||||
break;
|
||||
}
|
||||
},
|
||||
[entryMoved]
|
||||
[entryMoved, entryResized]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user