Files
4ventures-client-portal/src/app/api/calendar/preview/route.ts
4Ventures 59f42eafe0 Anchor calendar previews to each client historical editorial line.
Remix same-month prior years and recurring series instead of generic season placeholders like Black Friday.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 23:57:41 +02:00

82 lines
2.7 KiB
TypeScript

/**
* POST { month: 'YYYY-MM' } → editorial preview for active tenant.
*/
import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/lib/supabase/server';
import { resolveActiveTenant, restGet } from '@/lib/tenant-context';
import { isAgencyRole, userRole } from '@/lib/agency';
import { asPlanObject } from '@/lib/calendar-documents';
import { generateMonthPreview } from '@/lib/calendar-generate';
import type { RrssMonthPlan } from '@/components/RrssMonthView';
export const dynamic = 'force-dynamic';
export const maxDuration = 60;
export async function POST(req: NextRequest) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
if (!isAgencyRole(userRole(user))) {
return NextResponse.json({ error: 'Solo agencia' }, { status: 403 });
}
const ctx = await resolveActiveTenant(user);
if (!ctx.tenantId || ctx.portfolioWide) {
return NextResponse.json(
{ error: 'Selecciona un cliente en Contexto.' },
{ status: 400 }
);
}
const body = (await req.json().catch(() => ({}))) as { month?: string };
const month = String(body.month || '').slice(0, 7);
if (!/^\d{4}-\d{2}$/.test(month)) {
return NextResponse.json({ error: 'month YYYY-MM requerido' }, { status: 400 });
}
let slug = 'cliente';
const t = await restGet<{ slug?: string }[]>(
`/rest/v1/tenants?id=eq.${encodeURIComponent(ctx.tenantId)}&select=slug`
);
slug = t.data?.[0]?.slug || ctx.label.toLowerCase().replace(/\s+/g, '-');
const docs = await restGet<{ content?: unknown }[]>(
`/rest/v1/documents?tenant_id=eq.${encodeURIComponent(
ctx.tenantId
)}&type=eq.calendar&select=content&order=created_at.desc&limit=48`
);
const history: RrssMonthPlan[] = [];
for (const d of docs.data || []) {
const plan = asPlanObject(d.content) as RrssMonthPlan | null;
if (plan?.month && plan.month !== month && Array.isArray(plan.pieces)) {
history.push(plan as unknown as RrssMonthPlan);
}
}
// Prefer same calendar month from prior years first (e.g. 2025-11 before 2026-10)
const mm = month.slice(5, 7);
history.sort((a, b) => {
const aSame = a.month.slice(5, 7) === mm ? 0 : 1;
const bSame = b.month.slice(5, 7) === mm ? 0 : 1;
if (aSame !== bSame) return aSame - bSame;
return String(b.month).localeCompare(String(a.month));
});
const result = await generateMonthPreview({
ym: month,
slug,
label: ctx.label,
history,
});
return NextResponse.json({
ok: true,
plan: result.plan,
rationale: result.rationale,
source: result.source,
brand: slug,
});
}