window.SelectionBar = function SelectionBar({
count, total, ctaLabel, onCTA, onClear, onSelectAll, icon,
secondaryLabel, onSecondary, secondaryIcon,
// Optional destructive action (e.g. bulk delete on the Research tab).
// Rendered as a left-aligned ghost button styled in red.
dangerLabel, onDanger, dangerIcon,
}) {
if (count === 0) return null;
return (
{count} of {total} ads selected
{dangerLabel && (
)}
{secondaryLabel && (
)}
);
};
window.TranscriptCard = function TranscriptCard({
ad, script, selected, onToggle,
// Edit support: when ``editable`` is true the card surfaces an Edit button.
// ``rawText`` is the unparsed response_text used as the initial textarea
// value; ``onSave(newText)`` is called with the user's edits.
editable, rawText, onSave,
onRegenerate, onDiscard, onPromote, promotedAt,
}) {
const p = PLATFORMS[ad.platform] || PLATFORMS.foreplay;
const [editing, setEditing] = React.useState(false);
const [draft, setDraft] = React.useState('');
const [saving, setSaving] = React.useState(false);
const transcriptText = ad.transcriptRaw
|| (Array.isArray(ad.transcript)
? ad.transcript.map(seg => seg.body || seg.t || '').filter(Boolean).join('\n')
: (ad.transcript || ''));
const startEdit = () => {
setDraft(rawText || script.map(l => l.body).join('\n\n'));
setEditing(true);
};
const cancelEdit = () => { setEditing(false); setDraft(''); };
const saveEdit = async () => {
if (!onSave) return;
setSaving(true);
try {
await onSave(draft);
setEditing(false);
} finally {
setSaving(false);
}
};
return (
{selected && }
{ad.brand}
{p.label}
{ad.id} · remodeled just now
{editable && !editing && (
)}
{editable && !editing && onRegenerate && (
)}
{editable && !editing && onDiscard && (
)}
{editable && !editing && onPromote && (
)}
{editing && (
<>
>
)}
{typeof ad.score === 'number' && Score {ad.score.toFixed ? ad.score.toFixed(1) : ad.score}}
{ad.daysRunning ? {ad.daysRunning}d running : null}
{ad.directionLabel ? {ad.directionLabel} : null}
{promotedAt ? Promoted {String(promotedAt).slice(0, 16)} : null}
{(transcriptText || ad.reasoning) && (
Original transcript and scoring notes
{ad.reasoning && {ad.reasoning}
}
{transcriptText && {transcriptText}}
)}
{editing ? (
);
};