'use client';
import React from 'react';
import {
Facebook,
Instagram,
Linkedin,
Megaphone,
Play,
ImageIcon,
} from 'lucide-react';
export type CreativeChannel =
| 'meta_ads'
| 'google_ads'
| 'instagram'
| 'facebook'
| 'linkedin'
| 'tiktok'
| 'stories'
| 'other';
export type CreativeFormat =
| 'image'
| 'video'
| 'carousel'
| 'reel'
| 'story'
| 'rsa'
| 'pmax'
| 'pmax_landscape'
| 'pmax_square'
| 'pmax_portrait'
| 'pmax_vertical'
| 'pmax_logo'
| 'youtube'
| 'other';
export type CreativePreviewData = {
title: string;
channel?: string | null;
placement?: string | null;
format?: string | null;
headline?: string | null;
primary_text?: string | null;
description?: string | null;
cta?: string | null;
media_url?: string | null;
brand_name?: string | null;
landing_url?: string | null;
};
function hostOf(url?: string | null): string {
if (!url) return 'ejemplo.com';
try {
return new URL(url).hostname.replace(/^www\./, '');
} catch {
return url.replace(/^https?:\/\//, '').split('/')[0] || 'ejemplo.com';
}
}
function MediaBlock({
data,
tall,
dark,
}: {
data: CreativePreviewData;
tall?: boolean;
dark?: boolean;
}) {
const url = data.media_url?.trim();
const isVideo =
(data.format || '').toLowerCase() === 'video' ||
(data.format || '').toLowerCase() === 'reel' ||
Boolean(url && /\.(mp4|webm|mov)(\?|$)/i.test(url));
if (url && isVideo) {
return (
);
}
if (url) {
// eslint-disable-next-line @next/next/no-img-element
return (
);
}
return (
{(data.format || '').toLowerCase() === 'video' ||
(data.format || '').toLowerCase() === 'reel' ? (
) : (
)}
{data.headline || data.title}
Sin media · añade URL
);
}
function PhoneChrome({
pill,
children,
stories,
}: {
pill: string;
children: React.ReactNode;
stories?: boolean;
}) {
return (
);
}
function MetaFeedPreview({ data }: { data: CreativePreviewData }) {
const brand = data.brand_name || 'Marca';
return (
{brand.slice(0, 2).toUpperCase()}
{brand}
Patrocinado · Meta
{data.primary_text ? (
{data.primary_text}
) : null}
{hostOf(data.landing_url)}
{data.headline || data.title}
{data.description ? (
{data.description}
) : null}
{data.cta || 'Más info'}
);
}
function InstagramFeedPreview({ data }: { data: CreativePreviewData }) {
const brand = data.brand_name || 'cuenta';
return (
{brand.slice(0, 2).toUpperCase()}
{brand}
{brand}
{data.primary_text || data.headline || data.title}
{data.cta ? (
{data.cta}
) : null}
);
}
function StoriesPreview({ data }: { data: CreativePreviewData }) {
const brand = data.brand_name || 'cuenta';
return (
{brand.slice(0, 2).toUpperCase()}
{brand}
ahora
{data.headline || data.primary_text || data.title}
{data.cta ? (
{data.cta}
) : (
Sticker / encuesta
)}
);
}
function LinkedInPreview({ data }: { data: CreativePreviewData }) {
const brand = data.brand_name || 'Empresa';
return (
{brand.slice(0, 2).toUpperCase()}
{brand}
Promocionado · LinkedIn
{data.primary_text || data.headline || data.title}
{(data.media_url || data.format === 'image' || data.format === 'video') && (
)}
{data.headline || 'Ver más'}
{data.cta || 'Saber más'}
);
}
function FacebookFeedPreview({ data }: { data: CreativePreviewData }) {
const brand = data.brand_name || 'Página';
return (
{brand.slice(0, 1).toUpperCase()}
{data.primary_text ? (
{data.primary_text}
) : null}
{hostOf(data.landing_url)}
{data.headline || data.title}
{data.cta || 'Más información'}
);
}
function GoogleSearchPreview({ data }: { data: CreativePreviewData }) {
const host = hostOf(data.landing_url);
return (
Google Ads · búsqueda
Anuncio · {host}
{data.headline || data.title}
{data.description || data.primary_text || 'Descripción del anuncio…'}
{data.cta ? (
{data.cta}
) : null}
);
}
function GoogleDisplayPreview({
data,
aspect = 'landscape',
}: {
data: CreativePreviewData;
aspect?: 'landscape' | 'square' | 'portrait' | 'vertical' | 'logo';
}) {
const ratio =
aspect === 'square'
? 'aspect-square'
: aspect === 'portrait'
? 'aspect-[4/5]'
: aspect === 'vertical'
? 'aspect-[9/16]'
: aspect === 'logo'
? 'aspect-square max-w-[140px] mx-auto'
: 'aspect-[1.91/1]';
const label =
aspect === 'square'
? '1:1 · cuadrado'
: aspect === 'portrait'
? '4:5 · portrait'
: aspect === 'vertical'
? '9:16 · vertical'
: aspect === 'logo'
? 'Logo'
: '1.91:1 · landscape';
return (
Google Ads · Performance Max · {label}
{data.headline || data.title}
{data.description || data.primary_text}
{hostOf(data.landing_url)}
);
}
function YouTubePreview({ data }: { data: CreativePreviewData }) {
return (
Google Ads · YouTube
{data.headline || data.title}
{data.description || data.primary_text}
);
}
/** Renders a placement mock like Ad Tracker phone / Google RSA cards. */
export default function CreativePlacementPreview({
data,
compact,
}: {
data: CreativePreviewData;
compact?: boolean;
}) {
const channel = (data.channel || '').toLowerCase();
const placement = (data.placement || '').toLowerCase();
const format = (data.format || '').toLowerCase();
let body: React.ReactNode;
if (format === 'youtube') {
body = ;
} else if (
format === 'pmax_landscape' ||
format === 'pmax_square' ||
format === 'pmax_portrait' ||
format === 'pmax_vertical' ||
format === 'pmax_logo' ||
format === 'pmax' ||
(channel === 'google_ads' &&
(placement === 'display' || format.startsWith('pmax')))
) {
const aspect =
format === 'pmax_square' || format === 'pmax_logo'
? format === 'pmax_logo'
? 'logo'
: 'square'
: format === 'pmax_portrait'
? 'portrait'
: format === 'pmax_vertical'
? 'vertical'
: 'landscape';
body = ;
} else if (channel === 'google_ads' || format === 'rsa') {
body = ;
} else if (
channel === 'stories' ||
placement === 'stories' ||
format === 'story'
) {
body = ;
} else if (channel === 'linkedin') {
body = ;
} else if (channel === 'instagram') {
body =
placement === 'reels' || format === 'reel' ? (
) : (
);
} else if (channel === 'facebook') {
body = ;
} else if (channel === 'meta_ads' || channel === 'tiktok' || !channel) {
body =
placement === 'stories' || format === 'story' ? (
) : (
);
} else {
body = ;
}
return (
{body}
);
}
export const CHANNEL_OPTIONS: { id: CreativeChannel; label: string }[] = [
{ id: 'meta_ads', label: 'Meta Ads' },
{ id: 'google_ads', label: 'Google Ads' },
{ id: 'instagram', label: 'Instagram (orgánico)' },
{ id: 'facebook', label: 'Facebook (orgánico)' },
{ id: 'linkedin', label: 'LinkedIn' },
{ id: 'stories', label: 'Stories' },
{ id: 'tiktok', label: 'TikTok' },
{ id: 'other', label: 'Otro' },
];
export const FORMAT_OPTIONS: { id: CreativeFormat; label: string }[] = [
{ id: 'image', label: 'Imagen' },
{ id: 'video', label: 'Vídeo' },
{ id: 'carousel', label: 'Carrusel' },
{ id: 'reel', label: 'Reel' },
{ id: 'story', label: 'Story' },
{ id: 'rsa', label: 'Google RSA (búsqueda)' },
{ id: 'pmax', label: 'PMax (genérico)' },
{ id: 'pmax_landscape', label: 'PMax landscape 1.91:1' },
{ id: 'pmax_square', label: 'PMax cuadrado 1:1' },
{ id: 'pmax_portrait', label: 'PMax portrait 4:5' },
{ id: 'pmax_vertical', label: 'PMax vertical 9:16' },
{ id: 'pmax_logo', label: 'PMax logo' },
{ id: 'youtube', label: 'YouTube / vídeo in-stream' },
{ id: 'other', label: 'Otro' },
];
export const PLACEMENT_OPTIONS = [
{ id: 'feed', label: 'Feed' },
{ id: 'stories', label: 'Stories' },
{ id: 'reels', label: 'Reels' },
{ id: 'search', label: 'Búsqueda' },
{ id: 'display', label: 'Display' },
{ id: 'youtube', label: 'YouTube' },
{ id: 'discover', label: 'Discover' },
{ id: 'gmail', label: 'Gmail' },
{ id: 'maps', label: 'Maps' },
{ id: 'other', label: 'Otro' },
];