Feature: Added Excel export to Ads and Forecast views

This commit is contained in:
Christian Vidal Wolf
2026-01-27 15:34:06 +01:00
parent 19fbd12e77
commit 7178b57073
2 changed files with 103 additions and 5 deletions
+51 -3
View File
@@ -1,5 +1,7 @@
import React, { useMemo, useState } from 'react';
import React, { useMemo, useState, useCallback } from 'react';
import * as XLSX from 'xlsx';
import { CombinedKPIs, FilterState } from '../types';
import { DownloadIcon } from './Icons';
interface AdsPerformanceProps {
data: CombinedKPIs[];
@@ -215,6 +217,44 @@ const AdsPerformance: React.FC<AdsPerformanceProps> = ({ data, filters, top50Ran
}));
};
const handleExportExcel = useCallback(() => {
const exportData = filteredAndSorted.map(row => {
const rowData: any = {
ASIN: row.asin,
SKU: row.sku,
Title: row.title,
'Total Sales': Math.round(row.salesTotal),
'Ads Sales': Math.round(row.salesAds),
'Organic Sales': Math.round(row.salesOrganic),
'Ad Spend': Math.round(row.cost),
Impressions: row.impressions,
Clicks: row.clicks,
Orders: row.conversions,
CPC: Number(row.cpc.toFixed(2)),
'CTR (%)': Number(row.ctr.toFixed(2)),
'CVR (%)': Number(row.cvrUnits.toFixed(2)),
'ACOS (%)': Number(row.acos.toFixed(2)),
ROAS: Number(row.roas.toFixed(2)),
'TACOS (%)': Number(row.tacos.toFixed(2)),
'Glance Views': row.glanceViews || 0,
};
if (row.prevData) {
rowData['Prev Total Sales'] = Math.round(row.prevData.salesTotal);
rowData['Prev Ads Sales'] = Math.round(row.prevData.salesAds);
rowData['Prev Ad Spend'] = Math.round(row.prevData.cost);
rowData['Growth Sales (%)'] = row.prevData.salesTotal > 0 ? Number((((row.salesTotal - row.prevData.salesTotal) / row.prevData.salesTotal) * 100).toFixed(1)) : 0;
}
return rowData;
});
const ws = XLSX.utils.json_to_sheet(exportData);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Ads Performance');
XLSX.writeFile(wb, `Ads_Performance_Export_${new Date().toISOString().slice(0, 10)}.xlsx`);
}, [filteredAndSorted]);
const formatCurrency = (val: number) =>
`$${Math.round(val).toLocaleString('de-DE')}`;
@@ -306,11 +346,19 @@ const AdsPerformance: React.FC<AdsPerformanceProps> = ({ data, filters, top50Ran
)}
<input
type="text"
placeholder="Search ASIN, SKU or Title..."
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="bg-[#0B0E14] border border-white/10 rounded-lg px-3 py-1.5 text-xs text-white focus:outline-none focus:ring-1 focus:ring-indigo-500 w-64"
className="bg-[#0B0E14] border border-white/10 rounded-lg px-3 py-1.5 text-xs text-white focus:outline-none focus:ring-1 focus:ring-indigo-500 w-48"
/>
<button
onClick={handleExportExcel}
className="flex items-center gap-2 px-3 py-1.5 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-lg text-xs font-bold border border-white/10 transition-all shadow-lg active:scale-95"
title="Export to Excel"
>
<DownloadIcon />
<span>Export</span>
</button>
</div>
</div>