From 78bd80079dd88b2cdb3dd86df0d52046e158699d Mon Sep 17 00:00:00 2001 From: 4Ventures <4ventures@MacBook-Air-de-4Ventures.local> Date: Mon, 5 Oct 2026 18:10:17 +0200 Subject: [PATCH] fix: bind Windsor KPIs block to Contexto tenant Stop hardcoding Blue Parrot branding/connectors so switching clients in the portfolio selector updates labels and integration chips. Co-authored-by: Cursor --- src/components/MetricsDashboard.tsx | 2 +- src/components/WindsorAiSection.tsx | 109 ++++++++++++++++++---------- 2 files changed, 70 insertions(+), 41 deletions(-) diff --git a/src/components/MetricsDashboard.tsx b/src/components/MetricsDashboard.tsx index 060054b..beaf8a2 100644 --- a/src/components/MetricsDashboard.tsx +++ b/src/components/MetricsDashboard.tsx @@ -739,7 +739,7 @@ export default function MetricsDashboard({

- {/* Windsor.ai Data for blueparrotschool.com (Directly below Cruce por canal) */} + {/* Windsor.ai Data — follows Contexto tenant */} ('all'); - // Determine if context is Blue Parrot School or Portfolio - const isBps = - tenantId === BPS_TENANT_ID || - label?.toLowerCase().includes('blue parrot') || - label?.toLowerCase().includes('bps') || - (!tenantId && !portfolioWide); + const contextLabel = + (label && label.trim()) || + (portfolioWide ? 'Portafolio' : 'Cliente'); - // Filter dailyRows for target tenant (prefer BPS rows if in portfolio view) + const findIntegration = (provider: string) => { + const rows = (integrations || []).filter((i: any) => i?.provider === provider); + return ( + rows.find((i: any) => i?.status === 'connected') || + rows[0] || + null + ); + }; + + const gads = findIntegration('google_ads'); + const meta = findIntegration('meta_ads'); + const ga4 = findIntegration('ga4'); + const gsc = findIntegration('search_console'); + const clientify = findIntegration('clientify'); + + const gscSite = String( + gsc?.external_account_id || + gsc?.meta?.site_url || + gsc?.label || + '' + ) + .replace(/^sc-domain:/i, '') + .replace(/^https?:\/\//i, '') + .replace(/\/$/, ''); + + const ga4Id = String( + ga4?.meta?.measurement_id || + ga4?.external_account_id || + ga4?.label || + '' + ); + + const gadsId = String(gads?.external_account_id || gads?.label || '') + .replace(/\D/g, '') + .replace(/(\d{3})(\d{3})(\d{4})/, '$1-$2-$3'); + + // Filter dailyRows for the active context (never pin to BPS when another tenant is selected) const targetDailyRows = useMemo(() => { if (!dailyRows.length) return []; if (tenantId) { return dailyRows.filter((r) => !r.tenant_id || r.tenant_id === tenantId); } - // In portfolio wide view, focus on BPS rows for this Windsor component - const bpsRows = dailyRows.filter((r) => r.tenant_id === BPS_TENANT_ID); - return bpsRows.length > 0 ? bpsRows : dailyRows; + return dailyRows; }, [dailyRows, tenantId]); - // Filter organicRows for target tenant + // Filter organicRows for the active context const targetOrganicRows = useMemo(() => { if (!organicRows.length) return []; if (tenantId) { return organicRows.filter((r) => !r.tenant_id || r.tenant_id === tenantId); } - const bpsRows = organicRows.filter((r) => r.tenant_id === BPS_TENANT_ID); - return bpsRows.length > 0 ? bpsRows : organicRows; + return organicRows; }, [organicRows, tenantId]); // Apply Date Filtering based on viewMode ('period' vs 'all') @@ -344,42 +372,37 @@ export default function WindsorAiSection({ ]; }, [metaData, googleData, organicData, crmLeads, blendedTotals]); - // Connectors Status List for blueparrotschool.com + // Connectors for the active tenant (from integrations), not a hardcoded BPS list const connectors = [ { name: 'Google Ads', - id: '106-444-1284', - status: 'connected', + id: gadsId || gads?.label || '—', + status: gads?.status === 'connected' ? 'connected' : 'disconnected', type: 'Search & PMax', - lastSync: 'Normalizado', }, { name: 'Meta Ads', - id: 'act_414283212550847', - status: 'connected', + id: meta?.external_account_id || meta?.label || '—', + status: meta?.status === 'connected' ? 'connected' : 'disconnected', type: 'Instagram & Facebook Ads', - lastSync: 'Normalizado', }, { name: 'Google Analytics 4', - id: 'G-8CMQFCK82C (469229613)', - status: 'connected', + id: ga4Id || '—', + status: ga4?.status === 'connected' ? 'connected' : 'disconnected', type: 'Sesiones & Eventos Web', - lastSync: 'Sincronizado', }, { name: 'Search Console', - id: 'blueparrotschool.com', - status: 'connected', + id: gscSite || '—', + status: gsc?.status === 'connected' ? 'connected' : 'disconnected', type: 'Tráfico & Clics Orgánicos', - lastSync: 'Sincronizado', }, { name: 'Clientify CRM', - id: 'bps (Webhook & API)', - status: 'connected', + id: clientify?.label || clientify?.external_account_id || '—', + status: clientify?.status === 'connected' ? 'connected' : 'disconnected', type: 'Leads & Closed-Loop Won', - lastSync: 'En tiempo real', }, ]; @@ -403,7 +426,7 @@ export default function WindsorAiSection({

- Datos Windsor.ai · blueparrotschool.com + Atribución omnicanal · {contextLabel}

Atribución omnicanal y métricas agregadas multi-red (Google Ads, Meta Ads, GA4, Search @@ -442,7 +465,7 @@ export default function WindsorAiSection({

- Conectores Windsor.ai activos para blueparrotschool.com: + Conectores activos para {contextLabel}:

{connectors.map((c) => ( @@ -450,7 +473,11 @@ export default function WindsorAiSection({ key={c.name} className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-white border border-slate-200 shadow-xs text-xs" > - + {c.name} ({c.id})
@@ -586,7 +613,8 @@ export default function WindsorAiSection({ Campañas Google Ads · Búsqueda & Performance Max (Windsor)

- Datos de Google Ads (`ID: 106-444-1284`) no desglosados en el cruce agregado. Normalizados con micro-unidades y atribución Windsor. + Datos de Google Ads + {gadsId ? ` (ID: ${gadsId})` : ''} normalizados en el warehouse.

{viewMode === 'period' && googleData.campaigns.length === 0 && ( @@ -602,7 +630,7 @@ export default function WindsorAiSection({ No hay actividad de Google Ads registrada dentro del periodo seleccionado ({rangeLabel}).

- En el warehouse de 4Ventures constan 334 registros históricos de Google Ads para blueparrotschool.com (abril–septiembre 2026). + No hay filas de Google Ads para {contextLabel} en el warehouse con el filtro actual.