Files
CapaKraken/apps/web/src/components/allocations/AllocationBatchDialogs.tsx
T
Hartmut 17f2de5f48 refactor(web): decompose AllocationsClient and UsersClient into focused subcomponents
AllocationsClient (1364→962 lines): extracted AllocationRow, AllocationGroupedBody,
OpenDemandsPanel, and AllocationBatchDialogs.
UsersClient (1338→895 lines): extracted UserEditModal and UserCreateModal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:49:50 +02:00

176 lines
5.4 KiB
TypeScript

import type { AllocationWithDetails, AllocationStatus } from "@capakraken/shared";
import { ALLOCATION_STATUS_BADGE as STATUS_BADGE } from "~/lib/status-styles.js";
import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js";
import { BatchActionBar } from "~/components/ui/BatchActionBar.js";
import { BatchDateShiftModal } from "./BatchDateShiftModal.js";
const ALL_ALLOC_STATUSES = [
{ value: "PROPOSED", label: "Proposed" },
{ value: "CONFIRMED", label: "Confirmed" },
{ value: "ACTIVE", label: "Active" },
{ value: "COMPLETED", label: "Completed" },
{ value: "CANCELLED", label: "Cancelled" },
] as const;
type ConfirmDeleteState = {
single?: AllocationWithDetails;
ids?: string[];
} | null;
type ConfirmBatchStatusState = {
ids: string[];
status: string;
} | null;
type AllocationBatchDialogsProps = {
selectionCount: number;
selectedMutationIds: string[];
onClearSelection: () => void;
// Batch status picker
batchStatusPickerOpen: boolean;
onOpenBatchStatusPicker: () => void;
onCloseBatchStatusPicker: () => void;
batchStatusPending: boolean;
onBatchStatusConfirm: (ids: string[], status: AllocationStatus) => void;
// Delete
confirmDelete: ConfirmDeleteState;
onSetConfirmDelete: (state: ConfirmDeleteState) => void;
onSingleDelete: (alloc: AllocationWithDetails) => void;
onBatchDelete: (ids: string[]) => void;
batchDeletePending: boolean;
// Date shift
showDateShiftModal: boolean;
onOpenDateShiftModal: () => void;
onCloseDateShiftModal: () => void;
onDateShiftConfirm: (daysDelta: number) => void;
dateShiftPending: boolean;
};
export function AllocationBatchDialogs({
selectionCount,
selectedMutationIds,
onClearSelection,
batchStatusPickerOpen,
onOpenBatchStatusPicker,
onCloseBatchStatusPicker,
batchStatusPending,
onBatchStatusConfirm,
confirmDelete,
onSetConfirmDelete,
onSingleDelete,
onBatchDelete,
batchDeletePending,
showDateShiftModal,
onOpenDateShiftModal,
onCloseDateShiftModal,
onDateShiftConfirm,
dateShiftPending,
}: AllocationBatchDialogsProps) {
return (
<>
{/* Batch Status Picker */}
{batchStatusPickerOpen && (
<div
className="fixed inset-0 bg-black/30 z-50 flex items-center justify-center p-4"
onClick={onCloseBatchStatusPicker}
>
<div
className="min-w-[220px] rounded-2xl bg-white p-5 shadow-2xl dark:bg-gray-900"
onClick={(e) => e.stopPropagation()}
>
<h3 className="mb-3 text-sm font-semibold text-gray-900 dark:text-gray-100">
Set status for {selectionCount} allocations
</h3>
<div className="flex flex-col gap-1">
{ALL_ALLOC_STATUSES.map((s) => (
<button
key={s.value}
type="button"
onClick={() => {
onBatchStatusConfirm(selectedMutationIds, s.value as AllocationStatus);
onCloseBatchStatusPicker();
}}
className="w-full rounded-xl px-3 py-2 text-left text-sm transition-colors hover:bg-gray-50 dark:hover:bg-gray-800"
>
<span
className={`inline-block px-2 py-0.5 text-xs rounded-full font-medium ${STATUS_BADGE[s.value]}`}
>
{s.label}
</span>
</button>
))}
</div>
</div>
</div>
)}
{/* Confirm single delete */}
{confirmDelete?.single && (
<ConfirmDialog
title="Delete Allocation"
message={`Delete allocation for ${confirmDelete.single.resource?.displayName ?? "resource"} on ${confirmDelete.single.project?.name ?? "project"}?`}
confirmLabel="Delete"
variant="danger"
onConfirm={() => {
onSingleDelete(confirmDelete.single!);
onSetConfirmDelete(null);
}}
onCancel={() => onSetConfirmDelete(null)}
/>
)}
{/* Confirm batch delete */}
{confirmDelete?.ids && (
<ConfirmDialog
title="Delete Allocations"
message={`Delete ${confirmDelete.ids.length} selected allocation${confirmDelete.ids.length !== 1 ? "s" : ""}? This cannot be undone.`}
confirmLabel="Delete All"
variant="danger"
onConfirm={() => {
onBatchDelete(confirmDelete.ids!);
onSetConfirmDelete(null);
}}
onCancel={() => onSetConfirmDelete(null)}
/>
)}
{/* Batch Action Bar */}
<BatchActionBar
count={selectionCount}
onClear={onClearSelection}
actions={[
{
label: "Set Status…",
onClick: onOpenBatchStatusPicker,
disabled: batchStatusPending,
},
{
label: "Shift Dates…",
onClick: onOpenDateShiftModal,
disabled: dateShiftPending,
},
{
label: `Delete (${selectionCount})`,
variant: "danger",
onClick: () => onSetConfirmDelete({ ids: selectedMutationIds }),
disabled: batchDeletePending,
},
]}
/>
{/* Batch date shift modal */}
{showDateShiftModal && (
<BatchDateShiftModal
count={selectionCount}
isPending={dateShiftPending}
onConfirm={onDateShiftConfirm}
onClose={onCloseDateShiftModal}
/>
)}
</>
);
}