diff --git a/frontend/src/components/BulkActionReviewModal.tsx b/frontend/src/components/BulkActionReviewModal.tsx new file mode 100644 index 00000000..e0cf76b2 --- /dev/null +++ b/frontend/src/components/BulkActionReviewModal.tsx @@ -0,0 +1,97 @@ +import { useEffect, useRef } from "react"; + +interface BulkActionReviewModalProps { + isOpen: boolean; + onClose: () => void; + onConfirm: () => void; + actionLabel?: string; + selectedCount?: number; +} + +export default function BulkActionReviewModal({ + isOpen, + onClose, + onConfirm, + actionLabel = "Delete", + selectedCount = 0, +}: BulkActionReviewModalProps) { + const cancelRef = useRef(null); + const modalRef = useRef(null); + + useEffect(() => { + if (isOpen) cancelRef.current?.focus(); + }, [isOpen]); + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Escape") onClose(); + if (e.key === "Tab") { + const focusable = modalRef.current?.querySelectorAll( + 'button, [href], input, [tabindex]:not([tabindex="-1"])' + ); + if (!focusable || focusable.length === 0) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (e.shiftKey && document.activeElement === first) { + e.preventDefault(); + last.focus(); + } else if (!e.shiftKey && document.activeElement === last) { + e.preventDefault(); + first.focus(); + } + } + }; + + if (!isOpen) return null; + + return ( + + ); +} \ No newline at end of file