Heaven K
fix: restore envelope number in export, remove accents from branches
7b00df2
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
FileSpreadsheet,
FolderArchive,
ArrowRight,
RefreshCw,
X,
} from 'lucide-react';
import * as XLSX from 'xlsx';
import { Button } from '@/components/ui/button';
import { Progress } from '@/components/ui/progress';
import { cn } from '@/lib/utils';
import { api } from '@/services/api';
interface DownloadJob {
fileName: string;
progress: number;
processedFiles: number;
totalFiles: number;
}
export default function ExportSection() {
const { t } = useTranslation();
const [activeDownload, setActiveDownload] = useState<DownloadJob | null>(null);
const handleCancelDownload = () => {
setActiveDownload(null);
};
const handleExportExcel = async () => {
const dateStr = new Date().toISOString().split('T')[0];
const fileName = `ICC_Transactions_${dateStr}.xlsx`;
setActiveDownload({ fileName, progress: 10, processedFiles: 0, totalFiles: 0 });
try {
// Use fast export endpoint — no pagination overhead
const result = await api.get<{ transactions: any[]; total: number }>('/transactions/export');
const rows = result.transactions;
setActiveDownload({ fileName, progress: 50, processedFiles: rows.length, totalFiles: rows.length });
const wsData = rows.map((tx: any) => ({
[t('table.date')]: tx.date ? new Date(tx.date).toLocaleDateString('fr-CA', { timeZone: 'America/Toronto' }) : '',
[t('table.sender')]: tx.sender || '',
[t('table.envelopeNumber')]: tx.envelopeNumber || '',
[t('table.amount')]: tx.amount,
'Currency': tx.currency || 'CAD',
[t('table.reference')]: tx.reference || '',
[t('table.branch')]: tx.branch || 'Montreal',
[t('table.status')]: tx.reviewed ? t('status.verified') : t('status.notVerified'),
'Email': tx.recipientEmail || '',
'Message': tx.message || '',
}));
setActiveDownload({ fileName, progress: 80, processedFiles: rows.length, totalFiles: rows.length });
const ws = XLSX.utils.json_to_sheet(wsData);
ws['!cols'] = [
{ wch: 12 }, // Date
{ wch: 25 }, // Sender
{ wch: 16 }, // Envelope Number
{ wch: 12 }, // Amount
{ wch: 6 }, // Currency
{ wch: 20 }, // Reference
{ wch: 20 }, // Branch
{ wch: 12 }, // Status
{ wch: 35 }, // Email
{ wch: 30 }, // Message
];
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Transactions');
XLSX.writeFile(wb, fileName);
setActiveDownload({ fileName, progress: 100, processedFiles: rows.length, totalFiles: rows.length });
setTimeout(() => setActiveDownload(null), 2000);
} catch (err) {
console.error('Export failed:', err);
setActiveDownload(null);
}
};
const handleExportPdf = () => {
// TODO: Trigger PDF batch download
console.log('Export PDF batch');
};
return (
<div className="mt-4 pb-12">
<h2 className="text-xl font-bold text-foreground mb-6 flex items-center gap-2">
<span className="w-1.5 h-6 bg-primary rounded-full" />
{t('reports.export.title')}
</h2>
<div className="bg-card rounded-xl border border-border p-6 md:p-8 shadow-[0_1px_3px_0_rgba(0,0,0,0.1),0_1px_2px_0_rgba(0,0,0,0.06)]">
{/* Active Download Progress */}
{activeDownload && (
<div className="flex flex-col md:flex-row gap-8 items-start md:items-center justify-between bg-slate-50 p-6 rounded-xl border border-slate-100 mb-8">
<div className="flex-1 w-full">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<div className="bg-primary/10 p-1.5 rounded-full">
<RefreshCw className="h-3.5 w-3.5 text-primary animate-spin" />
</div>
<span className="text-sm font-bold text-foreground">
{t('reports.export.downloading')}
</span>
</div>
<span className="text-sm font-bold text-primary">
{activeDownload.progress}%
</span>
</div>
<Progress value={activeDownload.progress} className="h-2 mb-2" />
<p className="text-xs text-muted-foreground font-medium">
{t('reports.export.generating')}{' '}
<span className="text-foreground font-bold">
{activeDownload.fileName}
</span>{' '}
({activeDownload.processedFiles}/{activeDownload.totalFiles}{' '}
{t('reports.export.filesProcessed')})
</p>
</div>
<div className="flex gap-2 w-full md:w-auto">
<Button
variant="ghost"
size="sm"
className="w-full md:w-auto text-red-600 hover:bg-red-50 hover:text-red-700 font-semibold"
onClick={handleCancelDownload}
>
<X className="h-3.5 w-3.5 mr-1" />
{t('common.cancel')}
</Button>
</div>
</div>
)}
{/* Export Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Excel Export */}
<div
className="group relative flex flex-col p-6 rounded-xl border border-slate-200 hover:border-green-400 hover:shadow-md transition-all cursor-pointer bg-white"
onClick={handleExportExcel}
>
<div className="flex items-start justify-between mb-4">
<div className="p-3 bg-green-50 rounded-lg text-green-600 ring-1 ring-green-100 group-hover:bg-green-100 transition-colors">
<FileSpreadsheet className="h-7 w-7" />
</div>
<div className="p-2 rounded-full hover:bg-slate-50 transition-colors">
<ArrowRight className="h-5 w-5 text-slate-300 group-hover:text-green-500 transition-colors" />
</div>
</div>
<h3 className="text-lg font-bold text-foreground mb-2 group-hover:text-green-700 transition-colors">
{t('reports.export.excelTitle')}
</h3>
<p className="text-sm text-muted-foreground mb-8 leading-relaxed">
{t('reports.export.excelDescription')}
</p>
<Button
variant="outline"
className={cn(
'mt-auto w-full py-3 border-2 border-slate-100 font-bold',
'group-hover:border-green-500 group-hover:text-green-600 transition-all'
)}
>
{t('reports.export.generateReport')}
</Button>
</div>
{/* PDF Batch Export */}
<div
className="group relative flex flex-col p-6 rounded-xl border border-slate-200 hover:border-primary/50 hover:shadow-md transition-all cursor-pointer bg-white"
onClick={handleExportPdf}
>
<div className="flex items-start justify-between mb-4">
<div className="p-3 bg-blue-50 rounded-lg text-primary ring-1 ring-blue-100 group-hover:bg-blue-100 transition-colors">
<FolderArchive className="h-7 w-7" />
</div>
<div className="p-2 rounded-full hover:bg-slate-50 transition-colors">
<ArrowRight className="h-5 w-5 text-slate-300 group-hover:text-primary transition-colors" />
</div>
</div>
<h3 className="text-lg font-bold text-foreground mb-2 group-hover:text-primary transition-colors">
{t('reports.export.pdfTitle')}
</h3>
<p className="text-sm text-muted-foreground mb-8 leading-relaxed">
{t('reports.export.pdfDescription')}
</p>
<Button className="mt-auto w-full py-3 font-bold shadow-lg shadow-blue-500/20">
{t('reports.export.startDownload')}
</Button>
</div>
</div>
</div>
</div>
);
}