feat: upload creativos, PMax formats, portada IG/FB y seguimiento con notas

Permite subir media sin URL; previews Google PMax por ratio; calendario anual estilo Miia con filtros IG/FB y LinkedIn; seguimiento con selector de fechas, KPIs y cuadro de notas.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-23 09:33:22 +02:00
parent a7704567bd
commit 0d286dc66c
12 changed files with 1295 additions and 150 deletions

View File

@@ -7,6 +7,7 @@ import { isAgencyRole, userRole } from '@/lib/agency';
import RrssMonthView, { RrssMonthPlan, RrssPiece } from '@/components/RrssMonthView';
import CalendarClient from './CalendarClient';
import PublishRrssButton from './PublishRrssButton';
import RrssArchiveYear from '@/components/RrssArchiveYear';
import octPlan from '@/data/rrss-octubre-2026.json';
import { Instagram, Linkedin, CalendarDays } from 'lucide-react';
@@ -88,11 +89,12 @@ export default async function CalendarioPage({
const monthParam = sp.month || plans[0]?.month;
const active = plans.find((p) => p.month === monthParam) || plans[0];
const view = sp.view || 'hub';
// Portada = archivo anual estilo /rrss/ig-fb/
const view = sp.view || 'archive';
const initialPlatform =
sp.tab === 'linkedin'
? 'linkedin'
: sp.tab === 'instagram'
: sp.tab === 'instagram' || sp.tab === 'ig-fb'
? 'instagram'
: 'all';
@@ -133,49 +135,14 @@ export default async function CalendarioPage({
// Archive of months (like /rrss/ig-fb/)
if (view === 'archive') {
const year = Number((active?.month || '2026-10').slice(0, 4)) || 2026;
return (
<div className="space-y-6">
<div className="flex flex-wrap items-end justify-between gap-3">
<div>
<Link
href="/dashboard/calendario?view=hub"
className="text-xs text-gray-400 hover:text-white"
>
← Hub RRSS
</Link>
<h2 className="text-2xl font-extrabold text-white mt-2">
Calendario IG / FB
</h2>
<p className="text-sm text-gray-400 mt-1">
Archivo mensual renovable · {ctx.label}
</p>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{plans.map((p) => (
<Link
key={p.month}
href={`/dashboard/calendario?view=month&month=${p.month}`}
className="rounded-2xl border border-gray-800 bg-[#111827] overflow-hidden hover:border-brand-500/40 transition-colors"
>
<div className="bg-gradient-to-r from-[#16204A] to-[#2071CF] px-4 py-3 flex justify-between items-center">
<span className="text-xs font-extrabold tracking-wider text-white uppercase">
{p.label}
</span>
<span className="text-[10px] px-2 py-0.5 rounded-full bg-white/15 text-white">
Live
</span>
</div>
<div className="p-4">
<p className="text-xs text-gray-400">
{(p.pieces || []).length} piezas · clic para abrir el mes
completo (reparto + calendario + copy)
</p>
</div>
</Link>
))}
</div>
</div>
<RrssArchiveYear
year={year}
plans={plans}
tenantLabel={ctx.label}
agencyPublish={agency ? <PublishRrssButton /> : null}
/>
);
}