// components/DeleteRequestButton.tsx import React, { useState, useRef, useEffect } from 'react'; import { FaTrash, FaCheckCircle, FaExclamationTriangle, FaSpinner, FaTimes, FaChevronDown, FaBan } from 'react-icons/fa'; import { useDeleteRequest, type DeleteStatus } from '../hooks/useDeleteRequest'; import { useNavigate } from 'react-router-dom'; interface DeleteRequestButtonProps { doctype: string; docname: string | null | undefined; currentDeleteStatus: DeleteStatus; userRoles: string[]; isSystemManager: boolean; /** Called after any successful status change — use to refetch your document */ onStatusChange?: (newStatus: DeleteStatus) => void; /** Extra classes on the button wrapper div */ className?: string; /** If true, renders buttons inline (row). Default: column (stacked). */ inline?: boolean; redirectOnDelete?: string; triggerMode?: boolean; // ← ADD THIS } // ─── Confirmation Modal ─────────────────────────────────────────────────────── interface ConfirmModalProps { title: string; message: string; confirmLabel: string; confirmClass: string; icon: React.ReactNode; loading: boolean; onConfirm: () => void; onCancel: () => void; } const ConfirmModal: React.FC = ({ title, message, confirmLabel, confirmClass, icon, loading, onConfirm, onCancel, }) => (
{icon}

{title}

{message}

); // ─── Split Dropdown Button ──────────────────────────────────────────────────── interface SplitDropdownButtonProps { primaryLabel: string; primaryClass: string; primaryIcon: React.ReactNode; onPrimary: () => void; secondaryLabel: string; secondaryClass: string; secondaryIcon: React.ReactNode; onSecondary: () => void; disabled?: boolean; loading?: boolean; } const SplitDropdownButton: React.FC = ({ primaryLabel, primaryClass, primaryIcon, onPrimary, secondaryLabel, secondaryClass, secondaryIcon, onSecondary, disabled = false, loading = false, }) => { const [open, setOpen] = useState(false); const ref = useRef(null); // Close on outside click useEffect(() => { const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) { setOpen(false); } }; if (open) document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [open]); return (
{/* Primary action button */} {/* Divider */} {/* Chevron toggle */} {/* Dropdown */} {open && (
)}
); }; // ─── Status Badge ───────────────────────────────────────────────────────────── const StatusBadge: React.FC<{ status: DeleteStatus }> = ({ status }) => { if (!status) return null; const config: Record = { 'Delete Request With Supervisor': { bg: 'bg-orange-100 dark:bg-orange-900/30', text: 'text-orange-700 dark:text-orange-300', label: '⏳ Delete Request Pending Supervisor', }, 'Delete Request With CM': { bg: 'bg-yellow-100 dark:bg-yellow-900/30', text: 'text-yellow-700 dark:text-yellow-300', label: '⏳ Delete Request Pending CM', }, Deleted: { bg: 'bg-red-100 dark:bg-red-900/30', text: 'text-red-700 dark:text-red-300', label: '🗑 Marked for Deletion', }, }; const c = config[status as string]; if (!c) return null; return ( {c.label} ); }; // ─── Main Component ─────────────────────────────────────────────────────────── type PendingAction = | 'raise' | 'supervisor_approve' | 'supervisor_reject' | 'cm_approve' | 'cm_reject' | 'direct' | null; const DeleteRequestButton: React.FC = ({ doctype, docname, currentDeleteStatus, userRoles, isSystemManager, onStatusChange, className = '', inline = false, redirectOnDelete, triggerMode = false, }) => { const navigate = useNavigate(); const [pendingAction, setPendingAction] = useState(null); const [triggerOpen, setTriggerOpen] = useState(false); // ← ADD THIS const triggerRef = useRef(null); // ← ADD THIS const { showRaiseRequest, showApproveAsSupervisor, showApproveAsCM, showDirectDelete, deleteStatus, loading, error, raiseRequest, approveAsSupervisor, approveAsCM, directDelete, rejectRequest, // ← new: resets delete_status to "" } = useDeleteRequest({ doctype, docname, currentDeleteStatus, userRoles, isSystemManager, onSuccess: (newStatus) => { onStatusChange?.(newStatus); if (newStatus === 'Deleted' && redirectOnDelete) { navigate(redirectOnDelete); } }, }); // Close trigger dropdown on outside click useEffect(() => { if (!triggerOpen) return; const handler = (e: MouseEvent) => { if (triggerRef.current && !triggerRef.current.contains(e.target as Node)) { setTriggerOpen(false); } }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [triggerOpen]); const handleConfirm = async () => { if (!pendingAction) return; const actionMap: Record, () => Promise> = { raise: raiseRequest, supervisor_approve: approveAsSupervisor, supervisor_reject: rejectRequest, cm_approve: approveAsCM, cm_reject: rejectRequest, direct: directDelete, }; await actionMap[pendingAction](); setPendingAction(null); }; // ── Modal config per action ────────────────────────────────────────────── const modalConfig: Record< NonNullable, { title: string; message: string; confirmLabel: string; confirmClass: string; icon: React.ReactNode } > = { raise: { title: 'Request Deletion', message: 'This will raise a deletion request to the Supervisor for review.', confirmLabel: 'Raise Request', confirmClass: 'bg-orange-600 hover:bg-orange-700', icon: , }, supervisor_approve: { title: 'Approve Deletion Request', message: 'This will forward the deletion request to the Cluster Manager for final approval.', confirmLabel: 'Approve & Forward', confirmClass: 'bg-yellow-600 hover:bg-yellow-700', icon: , }, supervisor_reject: { title: 'Reject Deletion Request', message: 'This will reject the deletion request and clear the status. The record will remain active.', confirmLabel: 'Reject Request', confirmClass: 'bg-gray-600 hover:bg-gray-700', icon: , }, cm_approve: { title: 'Approve & Mark as Deleted', message: 'This will mark the record as Deleted.', confirmLabel: 'Approve & Delete', confirmClass: 'bg-red-600 hover:bg-red-700', icon: , }, cm_reject: { title: 'Reject Deletion Request', message: 'This will reject the deletion request and clear the status. The record will remain active.', confirmLabel: 'Reject Request', confirmClass: 'bg-gray-600 hover:bg-gray-700', icon: , }, direct: { title: 'Mark as Deleted', message: 'This will immediately Delete The Record.', confirmLabel: 'Delete', confirmClass: 'bg-red-600 hover:bg-red-700', icon: , }, }; const statusTooltip: Record = { 'Delete Request With Supervisor': 'Delete Request Pending Supervisor', 'Delete Request With CM': 'Delete Request Pending Cluster Manager', 'Deleted': 'Marked for Deletion', }; if (triggerMode) { const hasRequest = !!deleteStatus; const iconColor = hasRequest ? 'text-orange-500 dark:text-orange-400 hover:bg-orange-50 dark:hover:bg-orange-900/20' : 'text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20'; const nothingToShow = !showRaiseRequest && !showApproveAsSupervisor && !showApproveAsCM && !showDirectDelete && !deleteStatus; if (nothingToShow) return null; return ( <> {pendingAction && ( setPendingAction(null)} /> )}
{triggerOpen && (
{deleteStatus && (
)} {error && (

{error}

)}
{showRaiseRequest && ( )} {showApproveAsSupervisor && ( <> )} {showApproveAsCM && ( <> )} {showDirectDelete && ( )}
)}
); } const layoutClass = inline ? 'flex flex-row flex-wrap items-center gap-2' : 'flex flex-col gap-2'; return ( <> {/* Confirmation Modal */} {pendingAction && ( setPendingAction(null)} /> )}
{/* Status Badge — always shown when a status exists */} {deleteStatus && } {/* Error */} {error && (

{error}

)} {/* ── Raise Request Button (no reject needed here) ─────────────────── */} {showRaiseRequest && ( )} {/* ── Supervisor: Approve (split) + Reject ────────────────────────── */} {showApproveAsSupervisor && ( } onPrimary={() => setPendingAction('supervisor_approve')} // Secondary — Reject secondaryLabel="Reject Request" secondaryClass="text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700" secondaryIcon={} onSecondary={() => setPendingAction('supervisor_reject')} /> )} {/* ── CM: Approve & Delete (split) + Reject ───────────────────────── */} {showApproveAsCM && ( } onPrimary={() => setPendingAction('cm_approve')} // Secondary — Reject secondaryLabel="Reject Request" secondaryClass="text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700" secondaryIcon={} onSecondary={() => setPendingAction('cm_reject')} /> )} {/* ── CM / SysManager: Direct Delete (no reject needed) ───────────── */} {showDirectDelete && ( )}
); }; export default DeleteRequestButton;