'use client';
import React, { useEffect } from 'react';
import type {
AdCreativeCard,
CreativeAspect,
CreativeAsset,
} from '@/lib/ad-creatives-meta';
import { formatEur, formatEurCents, 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.slice(0, 5);
return (ad.headline || '')
.split('\n')
.map((s) => s.trim())
.filter(Boolean)
.slice(0, 5);
}
function adBodies(ad: AdCreativeCard): string[] {
if (ad.bodies?.length) return ad.bodies.slice(0, 5);
// Legacy: primaryText used to hold bodies
return (ad.primaryText || '')
.split('\n')
.map((s) => s.trim())
.filter(Boolean)
.slice(0, 5);
}
function adLinkDescriptions(ad: AdCreativeCard): string[] {
if (ad.descriptions?.length) return ad.descriptions.slice(0, 5);
return [];
}
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', aspect: '9:16' });
if (ad.youtubeId) {
out.push({
kind: 'youtube',
url: `https://i.ytimg.com/vi/${ad.youtubeId}/hqdefault.jpg`,
youtubeId: ad.youtubeId,
label: 'YOUTUBE',
aspect: '16:9',
});
}
return out;
}
function resolveAspect(asset: CreativeAsset): CreativeAspect {
if (asset.aspect && asset.aspect !== 'unknown') return asset.aspect;
const L = (asset.label || '').toLowerCase();
if (/9\s*:?\s*16|story|reels|vertical|tall/.test(L)) return '9:16';
if (/4\s*:?\s*5|portrait/.test(L)) return '4:5';
if (/16\s*:?\s*9|1\.91|landscape|horizontal|youtube|video/.test(L)) {
return '16:9';
}
if (/1\s*:?\s*1|square|logo/.test(L)) return '1:1';
return 'unknown';
}
function aspectClass(aspect: CreativeAspect): string {
switch (aspect) {
case '9:16':
return 'aspect-[9/16]';
case '4:5':
return 'aspect-[4/5]';
case '16:9':
return 'aspect-video';
case '1:1':
return 'aspect-square';
default:
return 'aspect-[4/5]';
}
}
function previewUrlFor(ad: AdCreativeCard): string {
const assets = adAssets(ad);
const nine = assets.find(
(a) => a.kind === 'image' && resolveAspect(a) === '9:16'
);
const fourFive = assets.find(
(a) => a.kind === 'image' && resolveAspect(a) === '4:5'
);
const raw =
nine?.url ||
fourFive?.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) => {
// Never surface soft Graph/insights failures when we still render cards
if (/insights ad-level|fetch failed|métricas repartidas|sin imagen/i.test(w)) {
return false;
}
return platform === 'meta'
? /meta|token meta|sin ads meta|sin actividad meta|sin cuenta meta/i.test(w)
: /google|pmax|rsa|sin ads google|sin assets|oauth|warehouse|reconecta/i.test(
w
);
}) ||
(platform === 'google' && warning && /google|oauth|token/i.test(warning)
? warning
: null);
return (
Creatividades · preview por anuncio
{platform === 'meta' ? 'Meta Ads' : 'Google Ads'} · creatividades
Preview 9:16. Pulsa Zoom para ver el resto de piezas en su formato.
{platformWarning ? (
{platformWarning}
) : 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 = adBodies(ad);
const linkDescs = adLinkDescriptions(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}
{(headlines.length > 0 || bodies.length > 0 || linkDescs.length > 0) && (
{headlines.length > 0 ? (
Titulares ({headlines.length})
{headlines.map((h) => (
-
{h}
))}
) : null}
{bodies.length > 0 ? (
Textos ({bodies.length})
{bodies.map((b) => (
-
{b}
))}
) : null}
{linkDescs.length > 0 ? (
Descripción
{linkDescs.map((d) => (
-
{d}
))}
) : null}
{ad.cta ? (
CTA · {ad.cta}
) : null}
)}
);
}
export function CreativeZoomModal({
ad,
onClose,
}: {
ad: AdCreativeCard;
onClose: () => void;
}) {
const headlines = adHeadlines(ad);
const bodies = adBodies(ad);
const linkDescs = adLinkDescriptions(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);
const previewAsset =
images.find((a) => resolveAspect(a) === '9:16') || images[0];
const otherImages = images.filter((a) => a.url !== previewAsset?.url);
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
)}
Preview 9:16
Impresiones:{' '}
{formatNum(ad.impressions)}
Formato:{' '}
{ad.mediaType || '—'}
{ad.cta ? (
CTA: {ad.cta}
) : null}
{ad.linkUrl ? (
{ad.linkUrl}
) : null}
{otherImages.length > 0 ? (
Otras piezas ({otherImages.length})
{otherImages.map((asset, i) => {
const aspect = resolveAspect(asset);
return (
{/* eslint-disable-next-line @next/next/no-img-element */}
{aspect !== 'unknown' ? aspect : asset.label || 'imagen'}
{asset.kind === 'logo' ? ' · logo' : ''}
);
})}
) : 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}
))}
) : null}
{headlines.length > 0 ? (
Titulares ({headlines.length})
{headlines.map((h) => (
-
{h}
))}
) : null}
{longH.length > 0 ? (
Titulares largos ({longH.length})
{longH.slice(0, 5).map((h) => (
-
{h}
))}
) : null}
{bodies.length > 0 ? (
Textos ({bodies.length})
{bodies.map((b) => (
-
{b}
))}
) : null}
{linkDescs.length > 0 ? (
Descripción
{linkDescs.map((d) => (
-
{d}
))}
) : null}
);
}