2025-07-04 14:13:25 -04:00

178 lines
6.1 KiB
JavaScript

import React, { useState } from "react";
import { Dropdown } from "react-bootstrap";
import { Download } from "react-bootstrap-icons";
const Export = ({ columns, data, filename = "export" }) => {
const [showExportDropdown, setShowExportDropdown] = useState(false);
const [exportColumns, setExportColumns] = useState(
columns.map(col => ({ ...col, show: true }))
);
const handleColumnToggle = (columnKey) => {
const updatedColumns = exportColumns.map(col =>
col.key === columnKey ? { ...col, show: !col.show } : col
);
setExportColumns(updatedColumns);
};
const handleCancel = () => {
setExportColumns(columns.map(col => ({ ...col, show: true })));
setShowExportDropdown(false);
};
const generateCSV = () => {
const visibleColumns = exportColumns.filter(col => col.show);
const headers = visibleColumns.map(col => col.label).join(',');
const rows = data.map(row =>
visibleColumns.map(col => {
const value = row[col.key];
// Handle values that contain commas by wrapping in quotes
return typeof value === 'string' && value.includes(',') ? `"${value}"` : value;
}).join(',')
).join('\n');
const csvContent = `${headers}\n${rows}`;
downloadFile(csvContent, `${filename}.csv`, 'text/csv');
};
const generateExcel = () => {
const visibleColumns = exportColumns.filter(col => col.show);
const headers = visibleColumns.map(col => col.label);
const rows = data.map(row =>
visibleColumns.map(col => row[col.key])
);
// Create a simple Excel-like CSV with BOM for Excel compatibility
const excelContent = '\ufeff' + [headers, ...rows]
.map(row => row.map(cell =>
typeof cell === 'string' && (cell.includes(',') || cell.includes('"') || cell.includes('\n'))
? `"${cell.replace(/"/g, '""')}"`
: cell
).join(','))
.join('\n');
downloadFile(excelContent, `${filename}.csv`, 'text/csv');
};
const generatePDF = () => {
const visibleColumns = exportColumns.filter(col => col.show);
// Create a simple HTML table for PDF generation
const tableHTML = `
<html>
<head>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<table>
<thead>
<tr>
${visibleColumns.map(col => `<th>${col.label}</th>`).join('')}
</tr>
</thead>
<tbody>
${data.map(row => `
<tr>
${visibleColumns.map(col => `<td>${row[col.key] || ''}</td>`).join('')}
</tr>
`).join('')}
</tbody>
</table>
</body>
</html>
`;
// Use browser's print functionality to generate PDF
const printWindow = window.open('', '_blank');
printWindow.document.write(tableHTML);
printWindow.document.close();
printWindow.print();
};
const downloadFile = (content, filename, mimeType) => {
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
const customExportMenu = React.forwardRef(
({ children, style, className, 'aria-labelledby': labeledBy }, ref) => {
return (
<div
ref={ref}
style={style}
className={className}
aria-labelledby={labeledBy}
>
<h6>Export Options</h6>
<div className="app-main-content-fields-section margin-sm dropdown-container">
<div className="me-4">
<div style={{ maxHeight: '200px', overflowY: 'auto', marginBottom: '15px' }}>
<h6 style={{ fontSize: '14px', marginBottom: '10px' }}>Select Columns:</h6>
{exportColumns.map((column) => (
<div key={column.key} style={{ marginBottom: '8px' }}>
<input
type="checkbox"
id={`export-column-${column.key}`}
checked={column.show}
onChange={() => handleColumnToggle(column.key)}
/>
<label htmlFor={`export-column-${column.key}`} style={{ marginLeft: '8px' }}>
{column.label}
</label>
</div>
))}
</div>
</div>
</div>
<div className="list row">
<div className="col-md-12">
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginTop: '15px' }}>
<button className="btn btn-primary btn-sm" style={{ width: '100%' }} onClick={generateCSV}>
Generate CSV
</button>
<button className="btn btn-primary btn-sm" style={{ width: '100%' }} onClick={generateExcel}>
Generate Excel
</button>
<button className="btn btn-primary btn-sm" style={{ width: '100%' }} onClick={generatePDF}>
Generate PDF
</button>
<button className="btn btn-default btn-sm" style={{ width: '100%', marginTop: '8px' }} onClick={handleCancel}>
Cancel
</button>
</div>
</div>
</div>
</div>
);
},
);
return (
<Dropdown
key={'export-dropdown'}
id="export-dropdown"
className="me-2"
show={showExportDropdown}
onToggle={() => setShowExportDropdown(!showExportDropdown)}
autoClose={false}
>
<Dropdown.Toggle variant="primary">
<Download size={16} className="me-2"></Download>Export
</Dropdown.Toggle>
<Dropdown.Menu as={customExportMenu}/>
</Dropdown>
);
};
export default Export;