Revert unsolicited creative pipeline review-only changes.
Restore CreativesPipeline on /creatives and the previous board/API behavior (published pieces visible again; no forced reject note). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,8 +16,6 @@ import {
|
||||
Filter,
|
||||
} from 'lucide-react';
|
||||
import { PageHeader, Surface } from '@/components/ui';
|
||||
import { clientNoteFromNotes } from '@/lib/pipeline-calendar';
|
||||
import Link from 'next/link';
|
||||
|
||||
type PipelineItem = {
|
||||
id: string;
|
||||
@@ -110,8 +108,6 @@ export default function CreativePipelineBoard() {
|
||||
const [selectedMonth, setSelectedMonth] = useState<string>('all');
|
||||
const [selectedFormat, setSelectedFormat] = useState<string>('all');
|
||||
const [previewItem, setPreviewItem] = useState<PipelineItem | null>(null);
|
||||
const [rejectItem, setRejectItem] = useState<PipelineItem | null>(null);
|
||||
const [rejectNote, setRejectNote] = useState('');
|
||||
|
||||
async function load() {
|
||||
setLoading(true);
|
||||
@@ -133,7 +129,6 @@ export default function CreativePipelineBoard() {
|
||||
const monthCounts = useMemo(() => {
|
||||
const map = new Map<string, number>();
|
||||
for (const it of items) {
|
||||
if (it.status === 'publicado') continue;
|
||||
const key = it.month || 'sin-mes';
|
||||
map.set(key, (map.get(key) || 0) + 1);
|
||||
}
|
||||
@@ -143,7 +138,6 @@ export default function CreativePipelineBoard() {
|
||||
const months = useMemo(() => {
|
||||
const set = new Set<string>();
|
||||
for (const it of items) {
|
||||
if (it.status === 'publicado') continue;
|
||||
if (it.month) set.add(it.month);
|
||||
}
|
||||
return Array.from(set).sort();
|
||||
@@ -151,7 +145,6 @@ export default function CreativePipelineBoard() {
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
return items.filter((it) => {
|
||||
if (it.status === 'publicado') return false;
|
||||
if (selectedMonth !== 'all' && (it.month || 'sin-mes') !== selectedMonth) return false;
|
||||
if (selectedFormat !== 'all' && it.format !== selectedFormat) return false;
|
||||
return true;
|
||||
@@ -188,14 +181,14 @@ export default function CreativePipelineBoard() {
|
||||
await load();
|
||||
}
|
||||
|
||||
async function setStatus(id: string, status: string, notes?: string) {
|
||||
async function setStatus(id: string, status: string) {
|
||||
setBusyId(id);
|
||||
setErr(null);
|
||||
try {
|
||||
const res = await fetch('/api/creative-pipeline', {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, status, ...(notes ? { notes } : {}) }),
|
||||
body: JSON.stringify({ id, status }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
@@ -203,11 +196,7 @@ export default function CreativePipelineBoard() {
|
||||
return;
|
||||
}
|
||||
if (previewItem && previewItem.id === id) {
|
||||
setPreviewItem({
|
||||
...previewItem,
|
||||
status,
|
||||
notes: notes || previewItem.notes,
|
||||
});
|
||||
setPreviewItem({ ...previewItem, status });
|
||||
}
|
||||
await load();
|
||||
} finally {
|
||||
@@ -257,7 +246,7 @@ export default function CreativePipelineBoard() {
|
||||
<PageHeader
|
||||
eyebrow="Producción editorial"
|
||||
title="Panel de Creatividades"
|
||||
description="Solo revisión: propuesta, diseño y OK del cliente. Lo publicado se ve en el calendario, día a día."
|
||||
description="Planificación, diseño y archivo histórico sincronizado con Instagram."
|
||||
actions={
|
||||
isAgency ? (
|
||||
<button
|
||||
@@ -280,20 +269,13 @@ export default function CreativePipelineBoard() {
|
||||
{err}
|
||||
</div>
|
||||
) : null}
|
||||
<p className="mb-4 text-xs text-gray-500">
|
||||
Piezas ya publicadas:{' '}
|
||||
<Link href="/dashboard/calendario" className="font-semibold text-brand-700 hover:underline">
|
||||
ábrelas en el calendario, clic en el día
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
|
||||
{/* Barra de Filtros por Mes y Formato */}
|
||||
<div className="mb-6 space-y-3">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-semibold uppercase tracking-wider text-gray-500">
|
||||
Meses ({items.filter((i) => i.status !== 'publicado').length} en revisión):
|
||||
Meses ({items.length} piezas):
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 text-xs text-gray-500">
|
||||
@@ -434,14 +416,7 @@ export default function CreativePipelineBoard() {
|
||||
item={it}
|
||||
isAgency={isAgency}
|
||||
busy={busyId === it.id}
|
||||
onStatus={(s) => {
|
||||
if (s === 'rechazado' && !isAgency) {
|
||||
setRejectItem(it);
|
||||
setRejectNote('');
|
||||
return;
|
||||
}
|
||||
void setStatus(it.id, s);
|
||||
}}
|
||||
onStatus={(s) => setStatus(it.id, s)}
|
||||
onDelete={() => removeItem(it.id)}
|
||||
onUpload={(file, slot, index) => uploadImage(it.id, file, slot, index)}
|
||||
onPreview={() => setPreviewItem(it)}
|
||||
@@ -460,68 +435,9 @@ export default function CreativePipelineBoard() {
|
||||
isAgency={isAgency}
|
||||
busy={busyId === previewItem.id}
|
||||
onClose={() => setPreviewItem(null)}
|
||||
onStatus={(s) => {
|
||||
if (s === 'rechazado' && !isAgency) {
|
||||
setRejectItem(previewItem);
|
||||
setRejectNote('');
|
||||
return;
|
||||
}
|
||||
void setStatus(previewItem.id, s);
|
||||
}}
|
||||
onStatus={(s) => setStatus(previewItem.id, s)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{rejectItem ? (
|
||||
<div
|
||||
className="fixed inset-0 z-[60] flex items-center justify-center bg-black/60 p-4"
|
||||
onClick={() => setRejectItem(null)}
|
||||
>
|
||||
<form
|
||||
className="w-full max-w-md rounded-2xl bg-white p-5 shadow-xl space-y-3"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (!rejectNote.trim()) return;
|
||||
const id = rejectItem.id;
|
||||
void setStatus(id, 'rechazado', rejectNote.trim()).then(() => {
|
||||
setRejectItem(null);
|
||||
setRejectNote('');
|
||||
});
|
||||
}}
|
||||
>
|
||||
<h3 className="text-sm font-bold text-gray-900">
|
||||
No aprobar · {rejectItem.title}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500">
|
||||
Deja una nota para que 4Ventures sepa qué hay que cambiar.
|
||||
</p>
|
||||
<textarea
|
||||
required
|
||||
value={rejectNote}
|
||||
onChange={(e) => setRejectNote(e.target.value)}
|
||||
rows={4}
|
||||
className="w-full rounded-xl border border-gray-200 px-3 py-2 text-sm"
|
||||
placeholder="Ej. Cambia el titular, el logo se ve pequeño…"
|
||||
/>
|
||||
<div className="flex justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setRejectItem(null)}
|
||||
className="rounded-lg border border-gray-200 px-3 py-2 text-xs font-semibold"
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!rejectNote.trim() || busyId === rejectItem.id}
|
||||
className="rounded-lg bg-red-600 px-3 py-2 text-xs font-bold text-white disabled:opacity-50"
|
||||
>
|
||||
Enviar nota y rechazar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -701,12 +617,6 @@ function PieceCard({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{item.status === 'rechazado' && clientNoteFromNotes(item.notes) ? (
|
||||
<p className="text-[11px] text-red-800 bg-red-50 border border-red-100 rounded-lg px-2 py-1.5">
|
||||
Nota del cliente: {clientNoteFromNotes(item.notes)}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
<div className="mt-auto pt-2">
|
||||
{isAgency ? (
|
||||
<select
|
||||
@@ -910,12 +820,6 @@ function DetailModal({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{item.status === 'rechazado' && clientNoteFromNotes(item.notes) ? (
|
||||
<div className="rounded-xl border border-red-200 bg-red-50 p-3 text-xs text-red-900">
|
||||
<p className="font-semibold mb-1">Nota del cliente</p>
|
||||
{clientNoteFromNotes(item.notes)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="mt-6 border-t border-gray-100 pt-4">
|
||||
|
||||
Reference in New Issue
Block a user