feat(allocations): Sprint 2a — bulk date shift via BatchActionBar

Add "Shift Dates…" action to the batch action bar. Opens a modal with a
signed integer input; on confirm calls the existing timeline.batchShiftAllocations
procedure (allocationIds, daysDelta, mode="move").

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 13:10:06 +02:00
parent 6831e199c6
commit 16ce6db07e
2 changed files with 100 additions and 0 deletions
@@ -24,6 +24,7 @@ import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js";
import { ALLOCATION_STATUS_BADGE as STATUS_BADGE } from "~/lib/status-styles.js";
import { SuccessToast } from "~/components/ui/SuccessToast.js";
import { EmptyState } from "~/components/ui/EmptyState.js";
import { BatchDateShiftModal } from "./BatchDateShiftModal.js";
import {
collapseAllAllocationGroups,
createInitialCollapsedAllocationGroups,
@@ -114,6 +115,7 @@ export function AllocationsClient() {
const [batchStatusPicker, setBatchStatusPicker] = useState(false);
const [confirmBatchStatus, setConfirmBatchStatus] = useState<{ ids: string[]; status: string } | null>(null);
const [showStatusToast, setShowStatusToast] = useState(false);
const [showDateShiftModal, setShowDateShiftModal] = useState(false);
const selection = useSelection();
const utils = trpc.useUtils();
@@ -175,6 +177,15 @@ export function AllocationsClient() {
},
});
const batchDateShiftMutation = trpc.timeline.batchShiftAllocations.useMutation({
onSuccess: async () => {
await utils.allocation.list.invalidate();
await utils.allocation.listView.invalidate();
selection.clear();
setShowDateShiftModal(false);
},
});
useEffect(() => {
selection.clear();
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1024,6 +1035,11 @@ export function AllocationsClient() {
onClick: () => setBatchStatusPicker(true),
disabled: batchStatusMutation.isPending,
},
{
label: "Shift Dates…",
onClick: () => setShowDateShiftModal(true),
disabled: batchDateShiftMutation.isPending,
},
{
label: `Delete (${selection.count})`,
variant: "danger",
@@ -1033,6 +1049,18 @@ export function AllocationsClient() {
]}
/>
{/* Batch date shift modal */}
{showDateShiftModal && (
<BatchDateShiftModal
count={selection.count}
isPending={batchDateShiftMutation.isPending}
onConfirm={(daysDelta) =>
batchDateShiftMutation.mutate({ allocationIds: selectedMutationIds, daysDelta, mode: "move" })
}
onClose={() => setShowDateShiftModal(false)}
/>
)}
{/* Modal */}
{modalOpen && (
<AllocationModal allocation={editingAllocation} onClose={closeModal} onSuccess={closeModal} />