import React, { useState, useEffect } from 'react'; import { IoIosTrash, IoIosCheckmark, IoIosClose } from 'react-icons/io'; import { useLanguage } from '../../../../providers/language/LanguageContext'; import styles from '../ActionButton.module.css'; export interface DeleteActionButtonProps { row: T; disabled?: boolean | { disabled: boolean; message?: string }; loading?: boolean; className?: string; title?: string; confirmTitle?: string; cancelTitle?: string; containerRef?: React.RefObject; onSuccess?: (row: T) => void; onError?: (row: T, error: string) => void; hookData: any; // REQUIRED: Contains all hook data including operations and refetch // Field mappings idField?: string; // Field name for the unique identifier operationName?: string; // Name of the delete operation in hookData loadingStateName?: string; // Name of the loading state in hookData } export function DeleteActionButton({ row, disabled = false, loading = false, className = '', title, confirmTitle, cancelTitle, containerRef, onSuccess, onError, hookData, idField = 'id', operationName = 'handleDelete', loadingStateName = 'deletingItems' }: DeleteActionButtonProps) { const { t } = useLanguage(); const [isConfirming, setIsConfirming] = useState(false); const [isDeleting, setIsDeleting] = useState(false); // Extract disabled state and tooltip message const isDisabled = typeof disabled === 'boolean' ? disabled : disabled?.disabled || false; const disabledMessage = typeof disabled === 'object' ? disabled?.message : undefined; // Validate that hookData is provided with required operations if (!hookData) { throw new Error('DeleteActionButton requires hookData to be provided'); } // Extract operations from hookData const handleDelete = hookData[operationName]; const removeOptimistically = hookData.removeOptimistically || hookData.removeFileOptimistically; const refetch = hookData.refetch; const loadingState = hookData[loadingStateName]; // Validate required operations exist if (!handleDelete) { throw new Error(`DeleteActionButton requires hookData.${operationName} to be defined`); } if (!refetch) { throw new Error('DeleteActionButton requires hookData.refetch to be defined'); } // Reset confirmation state when row changes (e.g., when a previous row is deleted) useEffect(() => { setIsConfirming(false); }, [(row as any)[idField]]); // Handle clicks outside delete confirmation buttons useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (isConfirming && containerRef?.current) { if (!containerRef.current.contains(event.target as Node)) { setIsConfirming(false); } } }; if (isConfirming) { document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; } }, [isConfirming, containerRef]); const handleDeleteClick = (e: React.MouseEvent) => { e.stopPropagation(); if (!isDisabled && !loading && !isDeleting) { setIsConfirming(true); } }; const handleConfirmDelete = async (e: React.MouseEvent) => { e.stopPropagation(); try { // Get ID from row using configurable field name const itemId = (row as any)[idField]; if (!itemId) { throw new Error(`${idField} not found`); } // Immediately remove from UI for instant feedback and reset state if (removeOptimistically) { removeOptimistically(itemId); } // Reset confirmation state immediately so it doesn't carry over to next row setIsConfirming(false); setIsDeleting(true); // Call the delete API in the background const success = await handleDelete(itemId); if (success) { // Always refetch after a successful delete. The server has actually // removed the row, so fresh data won't bring it back — and this is // what re-syncs pagination.totalItems (and clears any optimistic // hidden-row state maintained by FormGeneratorTable). refetch(); onSuccess?.(row); } else { // Refetch to restore the item in case of failure await refetch(); onError?.(row, t('Löschen fehlgeschlagen')); } } catch (error: any) { console.error('Delete failed:', error); onError?.(row, error.message || t('Löschen fehlgeschlagen')); // Refetch to restore the item in case of failure await refetch(); } finally { setIsDeleting(false); } }; const handleCancelDelete = (e: React.MouseEvent) => { e.stopPropagation(); setIsConfirming(false); }; const buttonTitle = title || t('Löschen'); const confirmButtonTitle = confirmTitle || t('Sind Sie sicher, dass Sie die {count} ausgewählten Elemente löschen möchten?'); const cancelButtonTitle = cancelTitle || t('Abbrechen'); // Check if ANY deletion is in progress (not just this specific item) const isAnyDeletionInProgress = loadingState && loadingState.size > 0; if (isConfirming) { return (
); } // Determine the final button title (tooltip) const finalTitle = isDisabled && disabledMessage ? disabledMessage : buttonTitle; return ( ); } export default DeleteActionButton;