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}`); } }