From 777c4f9dfa475b3d6d00bafc45a8824ccce5c228 Mon Sep 17 00:00:00 2001 From: Marcos Fargas Date: Mon, 5 Oct 2026 00:53:10 +0200 Subject: [PATCH] feat: connect Google My Business and LinkedIn metrics via Windsor.ai API --- src/app/dashboard/kpis/kpis/route.ts | 50 +++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/src/app/dashboard/kpis/kpis/route.ts b/src/app/dashboard/kpis/kpis/route.ts index 3146b0b..f9fece5 100644 --- a/src/app/dashboard/kpis/kpis/route.ts +++ b/src/app/dashboard/kpis/kpis/route.ts @@ -86,10 +86,6 @@ export async function GET() { K.src.gsc.m.clk[idx] = row.gsc_clicks; K.src.gsc.m.imp[idx] = row.gsc_impressions; K.src.gsc.m.posw[idx] = row.gsc_avg_position; - K.src.gbp.m.imp[idx] = row.gbp_impressions; - K.src.gbp.m.call[idx] = row.gbp_calls; - K.src.gbp.m.web[idx] = row.gbp_website_clicks; - K.src.gbp.m.dir[idx] = row.gbp_directions; } } @@ -125,6 +121,52 @@ export async function GET() { }); } + // Fetch Windsor Google My Business & LinkedIn data in parallel + const WINDSOR_API_KEY = process.env.WINDSOR_API_KEY || 'e264872c03ed4af5b160e3480b7618d11723'; + try { + const [gmbRes, liRes] = await Promise.allSettled([ + fetch( + `https://connectors.windsor.ai/google_my_business?api_key=${WINDSOR_API_KEY}&date_from=${startStr}&date_to=${endStr}&fields=date,impressions,call_clicks,website_clicks,direction_requests`, + { signal: AbortSignal.timeout(8000) } + ).then((r) => r.json()).catch(() => null), + fetch( + `https://connectors.windsor.ai/linkedin_organic?api_key=${WINDSOR_API_KEY}&date_from=${startStr}&date_to=${endStr}&fields=date,impressions,clicks,engagement,followers`, + { signal: AbortSignal.timeout(8000) } + ).then((r) => r.json()).catch(() => null), + ]); + + const gmbData = gmbRes.status === 'fulfilled' ? gmbRes.value : null; + const liData = liRes.status === 'fulfilled' ? liRes.value : null; + + if (gmbData?.data && Array.isArray(gmbData.data)) { + for (const row of gmbData.data) { + if (!row.date || row.date < startStr || row.date > endStr) continue; + const idx = getIdx(row.date); + if (idx >= 0 && idx < daysCount) { + if (row.impressions != null) K.src.gbp.m.imp[idx] = Number(row.impressions); + if (row.call_clicks != null) K.src.gbp.m.call[idx] = Number(row.call_clicks); + if (row.website_clicks != null) K.src.gbp.m.web[idx] = Number(row.website_clicks); + if (row.direction_requests != null) K.src.gbp.m.dir[idx] = Number(row.direction_requests); + } + } + } + + if (liData?.data && Array.isArray(liData.data)) { + for (const row of liData.data) { + if (!row.date || row.date < startStr || row.date > endStr) continue; + const idx = getIdx(row.date); + if (idx >= 0 && idx < daysCount) { + if (row.impressions != null) K.src.li.m.imp[idx] = Number(row.impressions); + if (row.clicks != null) K.src.li.m.clk[idx] = Number(row.clicks); + if (row.engagement != null) K.src.li.m.eng[idx] = Number(row.engagement); + if (row.followers != null) K.src.li.m.fol[idx] = Number(row.followers); + } + } + } + } catch (err) { + console.error('Error fetching Windsor connectors:', err); + } + // Map published Instagram posts for 'Publicado' tab const posts = (igCache?.posts || []).map((p: any) => { let t = 'I';