181 lines
4.8 KiB
TypeScript
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;
|
|
}
|