/** Dashboard modules toggled per tenant (client portal nav). */ export type DashboardModuleId = | 'kpis' | 'crm' | 'seguimiento' | 'estrategia' | 'marca' | 'calendario' | 'ad-tracker' | 'social' | 'organico' | 'activos' | 'creatives' | 'asistente'; export type DashboardModuleDef = { id: DashboardModuleId; href: string; label: string; /** Integration providers that typically unlock this module. */ providers: string[]; hint: string; }; export const DASHBOARD_MODULES: DashboardModuleDef[] = [ { id: 'kpis', href: '/dashboard/kpis', label: 'Métricas', providers: ['meta_ads', 'google_ads'], hint: 'KPIs de inversión y leads', }, { id: 'crm', href: '/dashboard/crm', label: 'CRM', providers: ['clientify', 'gohighlevel'], hint: 'Clientify / GoHighLevel / leads', }, { id: 'seguimiento', href: '/dashboard/seguimiento', label: 'Seguimiento', providers: ['superhuman_docs'], hint: 'Actas y seguimiento operativo', }, { id: 'estrategia', href: '/dashboard/estrategia', label: 'Objetivos del Mes', providers: [], hint: 'Targets y presupuesto', }, { id: 'marca', href: '/dashboard/marca', label: 'Zona de marca', providers: [], hint: 'Brandbook: voz, oferta, ads, LinkedIn, blog', }, { id: 'calendario', href: '/dashboard/calendario', label: 'Calendario Editorial', providers: ['instagram', 'facebook', 'tiktok', 'linkedin'], hint: 'RRSS / contenido', }, { id: 'ad-tracker', href: '/dashboard/ad-tracker', label: 'Ads', providers: ['meta_ads', 'google_ads'], hint: 'Paid: Meta Ads, Google Ads y creatividades', }, { id: 'social', href: '/dashboard/social', label: 'Social', providers: ['instagram', 'facebook', 'tiktok', 'linkedin'], hint: 'RRSS orgánicas: perfiles, alcance y contenido', }, { id: 'organico', href: '/dashboard/organico', label: 'Orgánico', providers: ['ga4', 'search_console'], hint: 'SEO (Search Console y GA4)', }, { id: 'activos', href: '/dashboard/activos', label: 'Biblioteca de Activos', providers: ['google_drive'], hint: 'Contenido de Google Drive del cliente', }, { id: 'creatives', href: '/dashboard/creatividades', label: 'Creatividades Ads', providers: ['google_drive', 'meta_ads', 'google_ads'], hint: 'Aprobación de anuncios Meta y rendimiento', }, { id: 'asistente', href: '/dashboard/asistente', label: 'Asistente IA Financiero', providers: [], hint: 'Consultas sobre cifras', }, ]; export type TenantModuleMap = Partial>; export type TenantSettings = { modules?: TenantModuleMap; /** When true, modules were explicitly saved by agency (don't auto-overwrite). */ modulesLocked?: boolean; /** SEO/GEO workspace notes & priorities (Orgánico). */ organico?: { priorities?: { seo: string[]; geo: string[] }; sectionNotes?: Record; }; }; export function defaultModulesAllOn(): Record { const out = {} as Record; for (const m of DASHBOARD_MODULES) out[m.id] = true; return out; } /** Suggest modules from connected + enabled integrations. */ export function suggestModulesFromIntegrations( integrations: { provider: string; status?: string; enabled?: boolean }[] ): Record { const connected = new Set( integrations .filter((i) => i.enabled !== false && i.status === 'connected') .map((i) => i.provider) ); const out = {} as Record; for (const m of DASHBOARD_MODULES) { if (!m.providers.length) { out[m.id] = true; continue; } out[m.id] = m.providers.some((p) => connected.has(p)); } // Always keep Métricas if any paid/analytics, else still on as home if (!out.kpis) out.kpis = true; return out; } export function resolveTenantModules( settings: TenantSettings | null | undefined, integrations: { provider: string; status?: string; enabled?: boolean }[] ): Record { if (settings?.modulesLocked && settings.modules) { return { ...defaultModulesAllOn(), ...settings.modules }; } if (settings?.modules && Object.keys(settings.modules).length > 0) { return { ...defaultModulesAllOn(), ...settings.modules }; } if (integrations.length) { return suggestModulesFromIntegrations(integrations); } return defaultModulesAllOn(); } export function isModuleEnabled( modules: Record | null | undefined, href: string ): boolean { if (!modules) return true; const def = DASHBOARD_MODULES.find( (m) => href === m.href || href.startsWith(m.href + '/') ); if (!def) return true; return modules[def.id] !== false; }