Remix same-month prior years and recurring series instead of generic season placeholders like Black Friday. Co-authored-by: Cursor <cursoragent@cursor.com>
82 lines
2.7 KiB
TypeScript
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,
|
|
});
|
|
}
|