/** Dual agency/client approval + comments for calendar posts and assets. */ import { isAgencyRole, serviceHeaders, supabaseUrl, userRole } from '@/lib/agency'; export type ContentResourceType = 'calendar_post' | 'asset'; export type Party = 'agency' | 'client'; export type ApprovalRow = { party: Party; approved: boolean; actor_email?: string | null; created_at?: string; note?: string | null; }; export type CommentRow = { id: string; body: string; author_email?: string | null; author_party: Party; created_at: string; }; export function partyFromUser(user: { app_metadata?: Record; user_metadata?: Record; } | null): Party { return isAgencyRole(userRole(user)) ? 'agency' : 'client'; } export function dualStatus(approvals: ApprovalRow[]): { agency: boolean; client: boolean; both: boolean; label: string; } { const agency = approvals.some((a) => a.party === 'agency' && a.approved); const client = approvals.some((a) => a.party === 'client' && a.approved); const both = agency && client; let label = 'Pendiente'; if (both) label = 'Doble OK'; else if (agency && !client) label = 'OK agencia · falta cliente'; else if (client && !agency) label = 'OK cliente · falta agencia'; return { agency, client, both, label }; } export async function listApprovals( tenantId: string, resourceType: ContentResourceType, resourceIds: string[] ): Promise> { const headers = serviceHeaders(); if (!headers || !resourceIds.length) return {}; const ids = resourceIds.map(encodeURIComponent).join(','); const url = `${supabaseUrl()}/rest/v1/content_approvals?tenant_id=eq.${encodeURIComponent(tenantId)}` + `&resource_type=eq.${resourceType}&resource_id=in.(${ids})&select=*`; const r = await fetch(url, { headers, cache: 'no-store' }); if (!r.ok) return {}; const rows = (await r.json()) as (ApprovalRow & { resource_id: string })[]; const map: Record = {}; for (const row of rows) { (map[row.resource_id] ||= []).push(row); } return map; } export async function listComments( tenantId: string, resourceType: ContentResourceType, resourceId: string ): Promise { const headers = serviceHeaders(); if (!headers) return []; const url = `${supabaseUrl()}/rest/v1/content_comments?tenant_id=eq.${encodeURIComponent(tenantId)}` + `&resource_type=eq.${resourceType}&resource_id=eq.${encodeURIComponent(resourceId)}` + `&select=*&order=created_at.asc`; const r = await fetch(url, { headers, cache: 'no-store' }); if (!r.ok) return []; return (await r.json()) as CommentRow[]; } export async function upsertApproval(opts: { tenantId: string; resourceType: ContentResourceType; resourceId: string; party: Party; approved: boolean; actorId?: string | null; actorEmail?: string | null; note?: string | null; }): Promise { const headers = serviceHeaders(); if (!headers) throw new Error('no service role'); const body = { tenant_id: opts.tenantId, resource_type: opts.resourceType, resource_id: opts.resourceId, party: opts.party, approved: opts.approved, actor_id: opts.actorId || null, actor_email: opts.actorEmail || null, note: opts.note || null, }; const r = await fetch( `${supabaseUrl()}/rest/v1/content_approvals?on_conflict=tenant_id,resource_type,resource_id,party`, { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json', Prefer: 'resolution=merge-duplicates,return=minimal', }, body: JSON.stringify(body), } ); if (!r.ok) throw new Error(await r.text()); } export async function insertComment(opts: { tenantId: string; resourceType: ContentResourceType; resourceId: string; body: string; authorId?: string | null; authorEmail?: string | null; authorParty: Party; }): Promise { const headers = serviceHeaders(); if (!headers) throw new Error('no service role'); const r = await fetch(`${supabaseUrl()}/rest/v1/content_comments`, { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json', Prefer: 'return=representation', }, body: JSON.stringify({ tenant_id: opts.tenantId, resource_type: opts.resourceType, resource_id: opts.resourceId, body: opts.body, author_id: opts.authorId || null, author_email: opts.authorEmail || null, author_party: opts.authorParty, }), }); if (!r.ok) throw new Error(await r.text()); const rows = await r.json(); return Array.isArray(rows) ? rows[0] : rows; }