Files
4ventures-client-portal/src/lib/tenant-modules.ts

181 lines
4.8 KiB
TypeScript

/** 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<Record<DashboardModuleId, boolean>>;
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<string, string>;
};
};
export function defaultModulesAllOn(): Record<DashboardModuleId, boolean> {
const out = {} as Record<DashboardModuleId, boolean>;
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<DashboardModuleId, boolean> {
const connected = new Set(
integrations
.filter((i) => i.enabled !== false && i.status === 'connected')
.map((i) => i.provider)
);
const out = {} as Record<DashboardModuleId, boolean>;
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<DashboardModuleId, boolean> {
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<DashboardModuleId, boolean> | 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;
}