import { NextRequest, NextResponse } from 'next/server'; import { createClient } from '@/lib/supabase/server'; import { resolveActiveTenant, restGet } from '@/lib/tenant-context'; import { isAgencyRole, serviceHeaders, supabaseUrl, userRole, } from '@/lib/agency'; import { randomUUID } from 'crypto'; export const dynamic = 'force-dynamic'; export type SeguimientoEntry = { id: string; tenant_id: string; entry_type: string; title: string; summary?: string | null; body_md?: string | null; browser_link?: string | null; metrics?: Record; occurred_at?: string | null; synced_at?: string; source?: string; }; /** GET — notas + histórico Superhuman (sin series ads). */ export async function GET() { const supabase = await createClient(); const { data: { user }, } = await supabase.auth.getUser(); if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const ctx = await resolveActiveTenant(user); const agency = isAgencyRole(userRole(user)); if (agency && ctx.portfolioWide) { return NextResponse.json({ label: ctx.label, portfolioWide: true, entries: [], hint: 'Elige un cliente en el selector para ver su seguimiento.', }); } const tenantId = ctx.tenantId; if (!tenantId) { return NextResponse.json({ error: 'Sin tenant' }, { status: 400 }); } let entries: SeguimientoEntry[] = []; if (agency && ctx.viaView) { const tid = encodeURIComponent(tenantId); const e = await restGet( `/rest/v1/seguimiento_entries?tenant_id=eq.${tid}&select=*&order=occurred_at.desc.nullslast&limit=300` ); entries = e.data || []; } else { const { data: e } = await supabase .from('seguimiento_entries') .select('*') .order('occurred_at', { ascending: false, nullsFirst: false }) .limit(300); entries = (e as SeguimientoEntry[]) || []; } return NextResponse.json({ label: ctx.label, portfolioWide: false, tenantId, entries, isAgency: agency, }); } /** * POST — add a manual note / comentario to seguimiento. * { title?, body, occurredAt? | occurred_at? } */ 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 }); } 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 Record; const text = typeof body.body === 'string' ? body.body.trim() : typeof body.note === 'string' ? body.note.trim() : ''; const plain = text .replace(//gi, '\n') .replace(/<\/(p|div|li|h[1-6])>/gi, '\n') .replace(/<[^>]+>/g, '') .replace(/ /gi, ' ') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/\s+/g, ' ') .trim(); if (!plain) { return NextResponse.json({ error: 'Texto de la nota requerido' }, { status: 400 }); } const title = typeof body.title === 'string' && body.title.trim() ? body.title.trim().slice(0, 200) : `Nota · ${new Date().toLocaleDateString('es-ES')}`; const occurredRaw = (typeof body.occurredAt === 'string' && body.occurredAt) || (typeof body.occurred_at === 'string' && body.occurred_at) || new Date().toISOString(); const row = { tenant_id: ctx.tenantId, source: 'manual', entry_type: 'note', external_id: `manual-${randomUUID()}`, title, summary: plain.slice(0, 280), body_md: text, occurred_at: occurredRaw, synced_at: new Date().toISOString(), metrics: {}, }; const agency = isAgencyRole(userRole(user)); const headers = serviceHeaders(); if (agency && headers) { const r = await fetch(`${supabaseUrl()}/rest/v1/seguimiento_entries`, { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json', Prefer: 'return=representation', }, body: JSON.stringify(row), }); if (!r.ok) { return NextResponse.json({ error: await r.text() }, { status: 500 }); } const data = await r.json(); return NextResponse.json( { entry: Array.isArray(data) ? data[0] : data }, { status: 201 } ); } const { data, error } = await supabase .from('seguimiento_entries') .insert(row) .select('*') .single(); if (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } return NextResponse.json({ entry: data }, { status: 201 }); }