import React, { useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { CloudArrowUpIcon } from '@heroicons/react/24/outline'; import { Attachment } from '../../../entities/Attachment'; import { uploadAttachment, deleteAttachment, downloadAttachment, validateFile, } from '../../../utils/attachmentsService'; import { useToast } from '../../Shared/ToastContext'; import AttachmentListItem from '../../Shared/AttachmentListItem'; import AttachmentPreview from '../../Shared/AttachmentPreview'; interface TaskAttachmentsSectionProps { taskUid: string; attachments: Attachment[]; onAttachmentsChange: (attachments: Attachment[]) => void; disabled?: boolean; } const TaskAttachmentsSection: React.FC = ({ taskUid, attachments, onAttachmentsChange, disabled = false, }) => { const { t } = useTranslation(); const { showSuccessToast, showErrorToast } = useToast(); const [uploading, setUploading] = useState(false); const [previewAttachment, setPreviewAttachment] = useState(null); const fileInputRef = useRef(null); const handleFileSelect = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; // Validate file const validation = await validateFile(file); if (!validation.valid) { showErrorToast(validation.error || 'Invalid file'); if (fileInputRef.current) { fileInputRef.current.value = ''; } return; } // Check attachment limit if (attachments.length >= 20) { showErrorToast( t( 'task.attachments.limitReached', 'Maximum 20 attachments allowed per task' ) ); if (fileInputRef.current) { fileInputRef.current.value = ''; } return; } // Upload file setUploading(true); try { const newAttachment = await uploadAttachment(taskUid, file); onAttachmentsChange([...attachments, newAttachment]); showSuccessToast( t( 'task.attachments.uploadSuccess', 'File uploaded successfully' ) ); } catch (error: any) { showErrorToast( error.message || t('task.attachments.uploadError', 'Failed to upload file') ); } finally { setUploading(false); if (fileInputRef.current) { fileInputRef.current.value = ''; } } }; const handleDelete = async (attachment: Attachment) => { try { await deleteAttachment(taskUid, attachment.uid); onAttachmentsChange( attachments.filter((a) => a.uid !== attachment.uid) ); showSuccessToast( t( 'task.attachments.deleteSuccess', 'Attachment deleted successfully' ) ); if (previewAttachment?.uid === attachment.uid) { setPreviewAttachment(null); } } catch (error: any) { showErrorToast( error.message || t( 'task.attachments.deleteError', 'Failed to delete attachment' ) ); } }; const handleDownload = (attachment: Attachment) => { downloadAttachment(attachment.uid); }; const handlePreview = (attachment: Attachment) => { setPreviewAttachment( previewAttachment?.uid === attachment.uid ? null : attachment ); }; return (
{/* Upload Area */}
!disabled && fileInputRef.current?.click()} >

{uploading ? t('task.attachments.uploading', 'Uploading...') : t( 'task.attachments.clickToUpload', 'Click to upload or drag and drop' )}

{t( 'task.attachments.allowedTypes', 'PDF, DOC, DOCX, TXT, MD, Images, XLS, XLSX, CSV, ZIP (max 10MB)' )}

{/* Attachments List */} {attachments.length > 0 && (
{attachments.map((attachment) => (
{previewAttachment?.uid === attachment.uid && (
)}
))}
)} {/* Counter */}

{t('task.attachments.count', '{{count}} / 20 files', { count: attachments.length, })}

); }; export default TaskAttachmentsSection;