/* 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 (
);
})}
))}
All metrics are platform-reported via the MCP feed.
Close
);
}
Object.assign(window, { CreativeCompareModal });