178 lines
6.1 KiB
JavaScript
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;
|