import React, { useState } from 'react'; import { MdModeEdit } from 'react-icons/md'; import { useLanguage } from '../../../../contexts/LanguageContext'; import { Popup, EditForm } from '../../../Popup'; import styles from '../ActionButton.module.css'; export interface EditActionButtonProps { row: T; onEdit?: (row: T) => void; disabled?: boolean | { disabled: boolean; message?: string }; loading?: boolean; className?: string; title?: string; isEditing?: boolean; hookData: any; // REQUIRED: Contains all hook data including operations // Field mappings idField?: string; // Field name for the unique identifier nameField?: string; // Field name for display name typeField?: string; // Field name for type/mime type operationName?: string; // Name of the operation function in hookData loadingStateName?: string; // Name of the loading state in hookData // Edit configuration editFields?: Array<{ key: string; label: string; type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'readonly'; editable?: boolean; required?: boolean; validator?: (value: any) => string | null; }>; } export function EditActionButton({ row, onEdit, disabled = false, loading = false, className = '', title, isEditing = false, hookData, idField = 'id', nameField = 'name', typeField = 'type', operationName = 'handleFileUpdate', loadingStateName = 'editingFiles', editFields = [ { key: 'file_name', label: 'Filename', type: 'string', editable: true, required: true, validator: (value: string) => { if (!value || value.trim() === '') { return 'Filename cannot be empty'; } if (value.includes('/') || value.includes('\\')) { return 'Filename cannot contain / or \\ characters'; } return null; } } ] }: EditActionButtonProps) { const { t } = useLanguage(); const [internalLoading, setInternalLoading] = useState(false); const [isPopupOpen, setIsPopupOpen] = useState(false); const [editData, setEditData] = useState(null); // Extract disabled state and tooltip message const isDisabled = typeof disabled === 'boolean' ? disabled : disabled?.disabled || false; const disabledMessage = typeof disabled === 'object' ? disabled?.message : undefined; // Debug logging for disabled state if (import.meta.env.DEV) { console.log('EditActionButton disabled prop:', disabled); console.log('EditActionButton isDisabled:', isDisabled); console.log('EditActionButton disabledMessage:', disabledMessage); console.log('EditActionButton row:', row); } // Validate that hookData is provided if (!hookData) { throw new Error('EditActionButton requires hookData to be provided'); } const handleClick = async (e: React.MouseEvent) => { e.stopPropagation(); if (!isDisabled && !loading && !isEditing && !internalLoading) { setInternalLoading(true); try { // Debug logging to see what data we're working with if (import.meta.env.DEV) { console.log('EditActionButton received row:', row); console.log('Field mappings:', { idField, nameField, typeField }); console.log('Extracted values:', { id: (row as any)[idField], name: (row as any)[nameField], type: (row as any)[typeField] }); } // Call the onEdit callback if provided if (onEdit) { await onEdit(row); } // Set up edit data and open popup setEditData(row); setIsPopupOpen(true); } finally { setInternalLoading(false); } } }; const handleSave = async (updatedData: T) => { if (!editData) return; try { setInternalLoading(true); // Get the item ID from the row const itemId = (editData as any)[idField]; // Extract the fields to update from the edit data const updateData: any = {}; editFields.forEach(field => { if (field.editable !== false) { // Map frontend field names to API field names if (field.key === 'file_name') { updateData.fileName = (updatedData as any)[field.key]; } else { updateData[field.key] = (updatedData as any)[field.key]; } } }); // Debug logging if (import.meta.env.DEV) { console.log('EditActionButton - Update data:', { itemId, updateData, originalData: editData, updatedData, editFields: editFields.map(f => ({ key: f.key, value: (updatedData as any)[f.key] })), updateDataKeys: Object.keys(updateData), updateDataValues: Object.values(updateData) }); } // Validate required operation exists if (!hookData[operationName]) { throw new Error(`EditActionButton requires hookData.${operationName} to be defined`); } if (!hookData.refetch) { throw new Error('EditActionButton requires hookData.refetch to be defined'); } // Use hookData operation to update const result = await hookData[operationName](itemId, updateData, editData); const success = result?.success || result === true; if (success) { // Close popup and reset state setIsPopupOpen(false); setEditData(null); // Trigger refetch to sync with backend await hookData.refetch(); } else { console.error('Failed to update item:', itemId); // TODO: Show error message to user } } catch (error) { console.error('Failed to update item:', error); // TODO: Show error message to user } finally { setInternalLoading(false); } }; const handleCancel = () => { setIsPopupOpen(false); setEditData(null); }; const buttonTitle = title || t('files.action.edit', 'Edit'); // Use hookData editing state if available, otherwise use passed isEditing const loadingState = hookData?.[loadingStateName]; const actualIsEditing = loadingState?.has((row as any)[idField]) || isEditing; const isLoading = loading || actualIsEditing || internalLoading; // Determine the final button title (tooltip) const finalTitle = isDisabled && disabledMessage ? disabledMessage : buttonTitle; // Debug logging for button rendering if (import.meta.env.DEV) { console.log('EditActionButton rendering with:', { isDisabled, isLoading, finalTitle, className: `${styles.actionButton} ${styles.edit} ${isLoading ? styles.loading : ''} ${isDisabled ? styles.disabled : ''} ${className}` }); } return ( <> {/* Edit Popup */} {editData && ( ({ key: field.key, label: field.label, type: field.type, editable: field.editable ?? true, required: field.required ?? false, validator: field.validator }))} onSave={handleSave} onCancel={handleCancel} saveButtonText={t('common.save', 'Save')} cancelButtonText={t('common.cancel', 'Cancel')} /> )} ); } export default EditActionButton;