/* Creative Compare Modal =========================================== */ function MetricCell({ label, value, otherValue, fmt='int', tone, invertGood=false }){ /* Returns the value for ONE creative + a delta arrow if it's the better/worse */ const isPair = otherValue !== undefined; let diff = 0; let better = false; if (isPair && value !== otherValue) { diff = ((value - otherValue) / Math.max(otherValue, 0.0001)) * 100; better = invertGood ? value < otherValue : value > otherValue; } const formatted = (() => { if (fmt === 'currency') return curPrefix() + Math.round(value).toLocaleString(); if (fmt === 'currency2') return curPrefix() + value.toFixed(2); if (fmt === 'pct') return value.toFixed(2) + '%'; if (fmt === 'x') return value.toFixed(2) + '×'; if (fmt === 'int') return Math.round(value).toLocaleString(); return value; })(); return (
{label}
{formatted}
{isPair && diff !== 0 && ( 0?'arrow-up':'arrow-down'} size={10}/> {Math.abs(diff).toFixed(0)}% )}
); } function CreativeCompareModal({ open, onClose, creatives }){ if (!open || creatives.length < 2) return null; /* Up to 4 creatives side-by-side */ const cs = creatives.slice(0, 4); /* Per-metric "winner" indices — per-account blocklist applies */ const metrics = [ { key:'ctr', label:'CTR', fmt:'pct', invertGood:false }, { key:'cpm', label:'CPM', fmt:'currency2', invertGood:true }, { key:'cpa', label:'CPA', fmt:'currency2', invertGood:true }, { key:'roas', label:'ROAS', fmt:'x', invertGood:false }, { key:'imp', label:'Impressions', fmt:'int', invertGood:false }, { key:'spend', label:'Spend', fmt:'currency', invertGood:false }, { key:'conv', label:'Conv', fmt:'int', invertGood:false }, ].filter(m => !(typeof metricHiddenHere==='function' && metricHiddenHere(m.key))); const winners = Object.fromEntries(metrics.map(m=>{ const vals = cs.map(c => c[m.key]); const bestIdx = m.invertGood ? vals.indexOf(Math.min(...vals)) : vals.indexOf(Math.max(...vals)); return [m.key, bestIdx]; })); return (
Compare creatives
{cs.length} selected — green badges mark the leader for each metric.
{/* Thumbnails */} {cs.map(c => (
{c.name}
{c.headline}
{c.format} · {CREATIVE_OBJECTIVES.find(o=>o.id===c.objective).label}
))} {/* Metric rows */} {metrics.map(m => ( {cs.map((c, i) => { const others = cs.filter((_,j)=>j!==i); const ref = others.reduce((s,x)=>s+x[m.key],0)/others.length; const isWinner = winners[m.key] === i; return (
{isWinner && (
Leader
)}
); })}
))}
All metrics are platform-reported via the MCP feed.
Close
); } Object.assign(window, { CreativeCompareModal });