'use client';
import React, { useEffect } from 'react';
import type { AdCreativeCard, CreativeAsset } from '@/lib/ad-creatives-meta';
import { formatEur, formatNum } from '@/lib/metrics';
import { ImageIcon, Play, Maximize2, X, ExternalLink } from 'lucide-react';
export function proxiedMediaUrl(raw: string): string {
if (!raw) return '';
if (raw.startsWith('/api/')) return raw;
return `/api/ad-tracker/media?url=${encodeURIComponent(raw)}`;
}
function adHeadlines(ad: AdCreativeCard): string[] {
if (ad.headlines?.length) return ad.headlines;
return (ad.headline || '')
.split('\n')
.map((s) => s.trim())
.filter(Boolean);
}
function adDescriptions(ad: AdCreativeCard): string[] {
if (ad.descriptions?.length) return ad.descriptions;
return (ad.primaryText || '')
.split('\n')
.map((s) => s.trim())
.filter(Boolean);
}
function adAssets(ad: AdCreativeCard): CreativeAsset[] {
if (ad.assets?.length) return ad.assets;
const out: CreativeAsset[] = [];
const u = ad.imageUrl || ad.thumbnailUrl;
if (u) out.push({ kind: 'image', url: u, label: 'preview' });
if (ad.youtubeId) {
out.push({
kind: 'youtube',
url: `https://i.ytimg.com/vi/${ad.youtubeId}/hqdefault.jpg`,
youtubeId: ad.youtubeId,
label: 'YOUTUBE',
});
}
return out;
}
function previewUrlFor(ad: AdCreativeCard): string {
const assets = adAssets(ad);
const portrait = assets.find(
(a) =>
a.kind === 'image' &&
/portrait|vertical|tall|TALL|PORTRAIT|story|4.?5|9.?16/i.test(
a.label || ''
)
);
const raw =
portrait?.url ||
ad.imageUrl ||
ad.thumbnailUrl ||
assets.find((a) => a.kind === 'image')?.url ||
(ad.youtubeId
? `https://i.ytimg.com/vi/${ad.youtubeId}/hqdefault.jpg`
: '') ||
assets.find((a) => a.youtubeId)?.url ||
'';
return raw ? proxiedMediaUrl(raw) : '';
}
function MiniKpi({ label, value }: { label: string; value: string }) {
return (
);
}
export function CreativesGallery({
platform,
ads,
loading,
warning,
onZoom,
}: {
platform: 'meta' | 'google';
ads: AdCreativeCard[];
loading: boolean;
warning?: string | null;
onZoom: (ad: AdCreativeCard) => void;
}) {
const filtered = ads.filter((a) => a.platform === platform);
const platformWarning =
warning
?.split(' · ')
.find((w) =>
platform === 'meta'
? /meta|token meta|sin ads meta/i.test(w)
: /google|pmax|rsa|sin ads google|sin assets/i.test(w)
) || null;
const shownWarning =
filtered.length === 0 && warning
? platformWarning || (ads.length === 0 ? warning : null)
: platformWarning && filtered.length === 0
? platformWarning
: null;
return (
Creatividades · preview por anuncio
{platform === 'meta' ? 'Meta Ads' : 'Google Ads'} · creatividades
Preview vertical + textos. Pulsa Zoom para ver todas las piezas.
{shownWarning ? (
{shownWarning}
) : null}
{loading ? (
Cargando creatividades…
) : filtered.length === 0 ? (
Sin creatividades para este periodo.
) : (
{filtered.map((ad) => (
onZoom(ad)}
/>
))}
)}
);
}
function CreativeCard({
ad,
onZoom,
}: {
ad: AdCreativeCard;
onZoom: () => void;
}) {
const preview = previewUrlFor(ad);
const isVideo = ad.mediaType === 'video' || Boolean(ad.youtubeId);
const headlines = adHeadlines(ad);
const bodies = adDescriptions(ad);
const assets = adAssets(ad);
const extraCount = Math.max(0, assets.length - 1);
return (
{ad.adName || 'Sin nombre'}
{ad.status || ad.platform}
{ad.campaignName || '—'}
{ad.adsetName ? (
Conjunto: {ad.adsetName}
) : null}
{ad.platform === 'meta' ? 'Meta' : 'Google'}
{ad.mediaType && ad.mediaType !== 'unknown' ? (
{ad.mediaType}
) : null}
{assets.length > 0 ? (
{assets.length} piezas
) : null}
{(headlines.length > 0 || bodies.length > 0) && (
{headlines.length > 0 ? (
Titulares
{headlines.slice(0, 4).map((h) => (
-
{h}
))}
{headlines.length > 4 ? (
- +{headlines.length - 4} más
) : null}
) : null}
{bodies.length > 0 ? (
Textos / descripciones
{bodies.slice(0, 3).map((b) => (
-
{b}
))}
{bodies.length > 3 ? (
- +{bodies.length - 3} más
) : null}
) : null}
{ad.cta ? (
CTA · {ad.cta}
) : null}
)}
);
}
export function CreativeZoomModal({
ad,
onClose,
}: {
ad: AdCreativeCard;
onClose: () => void;
}) {
const headlines = adHeadlines(ad);
const bodies = adDescriptions(ad);
const longH = ad.longHeadlines || [];
const assets = adAssets(ad);
const images = assets.filter((a) => a.kind === 'image' || a.kind === 'logo');
const videos = assets.filter((a) => a.kind === 'youtube' || a.kind === 'video');
const main = previewUrlFor(ad);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
window.addEventListener('keydown', onKey);
const prev = document.body.style.overflow;
document.body.style.overflow = 'hidden';
return () => {
window.removeEventListener('keydown', onKey);
document.body.style.overflow = prev;
};
}, [onClose]);
return (
e.stopPropagation()}
>
{main ? (
// eslint-disable-next-line @next/next/no-img-element

) : (
Sin preview
)}
Impresiones:{' '}
{formatNum(ad.impressions)}
Formato:{' '}
{ad.mediaType || '—'}
Estado:{' '}
{ad.status || '—'}
{ad.cta ? (
CTA: {ad.cta}
) : null}
{ad.businessName ? (
Negocio:{' '}
{ad.businessName}
) : null}
{ad.linkUrl ? (
{ad.linkUrl}
) : null}
{images.length > 0 ? (
Imágenes y logos ({images.length})
{images.map((asset, i) => (
{/* eslint-disable-next-line @next/next/no-img-element */}
{asset.label ? (
{asset.label}
{asset.kind === 'logo' ? ' · logo' : ''}
) : null}
))}
) : null}
{videos.length > 0 ? (
Vídeos ({videos.length})
{videos.map((v, i) => (
{v.youtubeId ? (
) : v.url ? (
{/* eslint-disable-next-line @next/next/no-img-element */}
Vídeo
) : null}
{v.title || v.youtubeId || v.label || 'Vídeo'}
))}
) : null}
{headlines.length > 0 ? (
Titulares ({headlines.length})
{headlines.map((h) => (
-
{h}
))}
) : null}
{longH.length > 0 ? (
Titulares largos ({longH.length})
{longH.map((h) => (
-
{h}
))}
) : null}
{bodies.length > 0 ? (
Textos / descripciones ({bodies.length})
{bodies.map((b) => (
-
{b}
))}
) : null}
);
}