Allow agency to fully delete an editorial calendar month.

Removes the calendar document and linked draft pipeline pieces, with confirm-by-typing the YYYY-MM code.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-10-13 18:07:24 +02:00
parent fd2bd9582d
commit a225f8c2a6
5 changed files with 227 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
/**
* Create / update editorial month plans and pieces.
* POST { action: 'create'|'upsert_piece'|'delete_piece'|'replace_plan', month, piece?, plan?, syncPipeline? }
* POST { action: 'create'|'upsert_piece'|'delete_piece'|'replace_plan'|'delete_month', month, piece?, plan?, syncPipeline? }
*/
import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/lib/supabase/server';
@@ -364,6 +364,87 @@ export async function POST(req: NextRequest) {
});
}
if (action === 'delete_month') {
if (!doc?.id) {
return NextResponse.json(
{ error: 'No hay calendario guardado para ese mes' },
{ status: 404 }
);
}
const pieceIds = (existing?.pieces || [])
.map((p) => p.id)
.filter((id): id is string => Boolean(id));
let pipelineDeleted = 0;
let pipelineUnlinked = 0;
for (const pieceId of pieceIds) {
const list = await fetch(
`${base}/rest/v1/creative_pipeline?tenant_id=eq.${encodeURIComponent(
ctx.tenantId
)}&calendar_piece_id=eq.${encodeURIComponent(
pieceId
)}&select=id,status,publish_status`,
{ headers, cache: 'no-store' }
);
if (!list.ok) continue;
const rows = (await list.json()) as {
id: string;
status?: string;
publish_status?: string;
}[];
for (const row of rows) {
const published =
row.publish_status === 'published' ||
row.status === 'publicada' ||
row.status === 'publicado';
if (published) {
const patch = await fetch(
`${base}/rest/v1/creative_pipeline?id=eq.${encodeURIComponent(row.id)}`,
{
method: 'PATCH',
headers: {
...headers,
'Content-Type': 'application/json',
Prefer: 'return=minimal',
},
body: JSON.stringify({
calendar_piece_id: null,
updated_at: new Date().toISOString(),
}),
}
);
if (patch.ok) pipelineUnlinked += 1;
} else {
const del = await fetch(
`${base}/rest/v1/creative_pipeline?id=eq.${encodeURIComponent(row.id)}`,
{ method: 'DELETE', headers }
);
if (del.ok) pipelineDeleted += 1;
}
}
}
const delDoc = await fetch(
`${base}/rest/v1/documents?id=eq.${encodeURIComponent(doc.id)}&tenant_id=eq.${encodeURIComponent(ctx.tenantId)}`,
{ method: 'DELETE', headers }
);
if (!delDoc.ok) {
throw new Error(
(await delDoc.text()).slice(0, 300) || 'No se pudo borrar el documento'
);
}
return NextResponse.json({
ok: true,
deleted: true,
month,
document_id: doc.id,
pipeline_deleted: pipelineDeleted,
pipeline_unlinked: pipelineUnlinked,
});
}
return NextResponse.json({ error: 'action desconocida' }, { status: 400 });
} catch (e) {
return NextResponse.json(