import { useEffect, useState, useCallback } from 'react'; import { Table, Button, Space, Modal, message, Typography, Tooltip, Popconfirm, Card, Descriptions, Tag, Empty } from 'antd'; import { DownloadOutlined, DeleteOutlined, ReloadOutlined, EyeOutlined, FileWordOutlined, CheckCircleOutlined } from '@ant-design/icons'; import type { ColumnsType, TablePaginationConfig } from 'antd/es/table'; import type { Report } from '../types'; import { reportService } from '../services/reports'; import { usePagination } from '../hooks/usePagination'; import { formatDateTime } from '../utils'; const { Title, Text } = Typography; export default function Reports() { const [reports, setReports] = useState([]); const [loading, setLoading] = useState(false); const [detailModalVisible, setDetailModalVisible] = useState(false); const [selectedReport, setSelectedReport] = useState(null); const [deleting, setDeleting] = useState(null); const [downloading, setDownloading] = useState(null); const pagination = usePagination(10); // Fetch reports with specific page/pageSize const fetchReportsWithParams = useCallback(async (page: number, pageSize: number) => { try { setLoading(true); const response = await reportService.getReports({ page, pageSize, }); setReports(response.data); pagination.setTotal(response.pagination.total); } catch (error) { message.error('Failed to load reports'); } finally { setLoading(false); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Wrapper for refresh button const fetchReports = useCallback(() => { fetchReportsWithParams(pagination.page, pagination.pageSize); }, [fetchReportsWithParams, pagination.page, pagination.pageSize]); // Initial load only useEffect(() => { fetchReportsWithParams(pagination.page, pagination.pageSize); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Handle table pagination change const handleTableChange = async (paginationConfig: TablePaginationConfig) => { const newPage = paginationConfig.current ?? pagination.page; const newPageSize = paginationConfig.pageSize ?? pagination.pageSize; pagination.setPage(newPage); if (newPageSize !== pagination.pageSize) { pagination.setPageSize(newPageSize); } // Directly fetch with new params await fetchReportsWithParams(newPage, newPageSize); }; // Format file size const formatFileSize = (bytes: number): string => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; // Handle view report detail const handleViewReport = async (report: Report) => { try { const detail = await reportService.getReportDetail(report.id); setSelectedReport(detail); setDetailModalVisible(true); } catch (error) { message.error('Failed to load report details'); } }; // Handle download report const handleDownloadReport = async (report: Report) => { try { setDownloading(report.id); const blob = await reportService.downloadReport(report.id); // Create download link const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = report.file_name || `report-${report.id}.docx`; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); message.success('Report downloaded successfully'); } catch (error) { message.error('Failed to download report'); } finally { setDownloading(null); } }; // Handle delete report const handleDeleteReport = async (reportId: number) => { try { setDeleting(reportId); await reportService.deleteReport(reportId); message.success('Report deleted successfully'); fetchReports(); } catch (error: unknown) { const err = error as { response?: { data?: { error?: { message?: string } } } }; message.error(err.response?.data?.error?.message || 'Failed to delete report'); } finally { setDeleting(null); } }; // Table columns const columns: ColumnsType = [ { title: 'ID', dataIndex: 'id', key: 'id', width: 80 }, { title: 'File Name', dataIndex: 'file_name', key: 'file_name', ellipsis: true, render: (fileName: string) => ( {fileName} ), }, { title: 'Task ID', dataIndex: 'task_id', key: 'task_id', width: 100, render: (taskId: number) => ( #{taskId} ), }, { title: 'File Size', dataIndex: 'file_size', key: 'file_size', width: 120, render: (size: number) => formatFileSize(size), }, { title: 'Created At', dataIndex: 'created_at', key: 'created_at', width: 180, render: (date: string) => formatDateTime(date), }, { title: 'Actions', key: 'actions', width: 180, render: (_: unknown, record: Report) => ( `Total ${total} reports`, }} onChange={handleTableChange} locale={{ emptyText: ( ), }} /> {/* Report Detail Modal */} Report Details } open={detailModalVisible} onCancel={() => { setDetailModalVisible(false); setSelectedReport(null); }} footer={ {selectedReport && ( )} } width={600} > {selectedReport && ( {selectedReport.id} {selectedReport.file_name} #{selectedReport.task_id} {formatFileSize(selectedReport.file_size)} {selectedReport.file_path} {formatDateTime(selectedReport.created_at)} }> Available )} ); }