From 9ebbdcf581bb0177d931bd677858b6e72d975bc0 Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Thu, 22 Jan 2026 14:33:10 +0100 Subject: [PATCH] feat: show both current and previous values in Ads comparison view - AdsPerformance.tsx: Update SummaryCard and TableCell to display 'Prev: [Value]' explicitly - AdsPerformance.tsx: Standardized formatting using de-DE locale across all comparison metrics - AdsPerformance.tsx: Improved growth calculation reliability in comparison mode --- components/AdsPerformance.tsx | 105 ++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 36 deletions(-) diff --git a/components/AdsPerformance.tsx b/components/AdsPerformance.tsx index 7221276..17c9e39 100644 --- a/components/AdsPerformance.tsx +++ b/components/AdsPerformance.tsx @@ -183,19 +183,19 @@ const AdsPerformance: React.FC = ({ data, filters }) => { {/* Summary Grid */}
- - - - - - - - - - - - - + + + + + + + + + + + + +
{/* Table Section */} @@ -271,22 +271,49 @@ const AdsPerformance: React.FC = ({ data, filters }) => { ); }; -const SummaryCard = ({ label, value, prevValue, color = "text-white", inverse = false }: { label: string; value: string; prevValue?: number; color?: string; inverse?: boolean }) => { - // Correctly parse value regardless of locale formatting (handles dots as thousands and commas as decimals) - const numericValue = parseFloat(value.replace(/[^\d,]/g, '').replace(',', '.')); +const SummaryCard = ({ + label, + value, + prevValue, + format, + prefix = "", + decimals = 0, + color = "text-white", + inverse = false +}: { + label: string; + value: number; + prevValue?: number; + format: 'currency' | 'number' | 'percent'; + prefix?: string; + decimals?: number; + color?: string; + inverse?: boolean +}) => { const growth = prevValue !== undefined && prevValue > 0 - ? ((numericValue - prevValue) / prevValue) * 100 + ? ((value - prevValue) / prevValue) * 100 : null; + const formatVal = (v: number) => { + if (format === 'currency') return `$${Math.round(v).toLocaleString('de-DE')}`; + if (format === 'percent') return v.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + "%"; + return prefix + v.toLocaleString('de-DE', { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); + }; + return (
{label}
- {value} - {growth !== null && ( - 0 ? !inverse : inverse) ? 'text-emerald-400' : 'text-rose-500'}`}> - {growth > 0 ? '↑' : '↓'} {Math.abs(growth).toFixed(1)}% - + {formatVal(value)} + {prevValue !== undefined && ( +
+ Prev: {formatVal(prevValue)} + {growth !== null && ( + 0 ? !inverse : inverse) ? 'text-emerald-400' : 'text-rose-500'}`}> + {growth > 0 ? '↑' : '↓'} {Math.abs(growth).toFixed(1)}% + + )} +
)}
@@ -296,25 +323,31 @@ const SummaryCard = ({ label, value, prevValue, color = "text-white", inverse = const TableCell = ({ value, prevValue, format, prefix = "", inverse = false, highlight = false }: { value: number; prevValue?: number; format: 'currency' | 'number' | 'percent'; prefix?: string; inverse?: boolean; highlight?: boolean }) => { const growth = prevValue !== undefined && prevValue > 0 ? ((value - prevValue) / prevValue) * 100 : null; - let displayValue = ""; - if (format === 'currency') displayValue = Math.round(value).toLocaleString('de-DE'); - else if (format === 'number') { - if (prefix === "$") { - displayValue = "$" + value.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); - } else { - displayValue = prefix + Math.round(value).toLocaleString('de-DE'); + const formatVal = (v: number) => { + if (format === 'currency') return Math.round(v).toLocaleString('de-DE'); + if (format === 'number') { + if (prefix === "$") { + return "$" + v.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); + } else { + return prefix + Math.round(v).toLocaleString('de-DE'); + } } - } - else if (format === 'percent') displayValue = value.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + "%"; + return v.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + "%"; + }; return (
- {displayValue} - {growth !== null && ( - 0 ? !inverse : inverse) ? 'text-emerald-400' : 'text-rose-400'} opacity-80`}> - {growth > 0 ? '+' : ''}{growth.toFixed(1)}% - + {formatVal(value)} + {prevValue !== undefined && ( +
+ Prev: {formatVal(prevValue)} + {growth !== null && ( + 0 ? !inverse : inverse) ? 'text-emerald-400' : 'text-rose-400'}`}> + {growth > 0 ? '+' : ''}{growth.toFixed(1)}% + + )} +
)}