xpeditis2.0/apps/frontend/src/utils/export.ts
2026-09-14 11:19:29 +02:00

155 lines
3.9 KiB
TypeScript

import { csvCell } from './csv-cell';
/**
* Client-side export utilities
*/
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
import { Booking } from '@/types/booking';
export interface ExportField {
key: string;
label: string;
formatter?: (value: any) => string;
}
const DEFAULT_BOOKING_FIELDS: ExportField[] = [
{ key: 'bookingNumber', label: 'Booking Number' },
{ key: 'status', label: 'Status' },
{ key: 'rateQuote.carrierName', label: 'Carrier' },
{ key: 'rateQuote.origin', label: 'Origin' },
{ key: 'rateQuote.destination', label: 'Destination' },
{ key: 'shipper.name', label: 'Shipper' },
{ key: 'consignee.name', label: 'Consignee' },
{
key: 'rateQuote.etd',
label: 'ETD',
formatter: value => (value ? new Date(value).toLocaleDateString() : ''),
},
{
key: 'rateQuote.eta',
label: 'ETA',
formatter: value => (value ? new Date(value).toLocaleDateString() : ''),
},
{
key: 'containers',
label: 'Containers',
formatter: value => (Array.isArray(value) ? value.length.toString() : '0'),
},
{
key: 'createdAt',
label: 'Created',
formatter: value => new Date(value).toLocaleDateString(),
},
];
/**
* Get nested object value by key path
*/
function getNestedValue(obj: any, path: string): any {
return path.split('.').reduce((current, key) => current?.[key], obj);
}
/**
* Export bookings to CSV
*/
export function exportToCSV(
data: Booking[],
fields: ExportField[] = DEFAULT_BOOKING_FIELDS,
filename: string = 'bookings-export.csv'
): void {
// Create CSV header
const header = fields.map(f => csvCell(f.label)).join(',');
// Create CSV rows
const rows = data.map(booking => {
return fields
.map(field => {
const value = getNestedValue(booking, field.key);
const formatted = field.formatter ? field.formatter(value) : value;
// Escape quotes and wrap in quotes if contains comma
return csvCell(formatted);
})
.join(',');
});
// Combine header and rows
const csv = [header, ...rows].join('\n');
// Create blob and download
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
saveAs(blob, filename);
}
/**
* Export bookings to Excel
*/
export function exportToExcel(
data: Booking[],
fields: ExportField[] = DEFAULT_BOOKING_FIELDS,
filename: string = 'bookings-export.xlsx'
): void {
// Create worksheet data
const wsData = [
// Header row
fields.map(f => f.label),
// Data rows
...data.map(booking =>
fields.map(field => {
const value = getNestedValue(booking, field.key);
return field.formatter ? field.formatter(value) : value || '';
})
),
];
// Create worksheet
const ws = XLSX.utils.aoa_to_sheet(wsData);
// Set column widths
ws['!cols'] = fields.map(() => ({ wch: 20 }));
// Create workbook
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Bookings');
// Generate Excel file
const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
saveAs(blob, filename);
}
/**
* Export bookings to JSON
*/
export function exportToJSON(data: Booking[], filename: string = 'bookings-export.json'): void {
const json = JSON.stringify(data, null, 2);
const blob = new Blob([json], { type: 'application/json;charset=utf-8;' });
saveAs(blob, filename);
}
/**
* Export bookings based on format
*/
export function exportBookings(
data: Booking[],
format: 'csv' | 'excel' | 'json',
fields?: ExportField[],
filename?: string
): void {
switch (format) {
case 'csv':
exportToCSV(data, fields, filename);
break;
case 'excel':
exportToExcel(data, fields, filename);
break;
case 'json':
exportToJSON(data, filename);
break;
default:
throw new Error(`Unsupported export format: ${format}`);
}
}