feat: Ads KPIs completos, Social feed+analytics, Orgánico por sección

Meta/Google con las mismas métricas que Resumen y solo campañas/ads con actividad en el periodo; Social con insights FB/IG y preview de posts (likes/comentarios/shares); Orgánico con paneles distintos por ítem del menú y prioridades/notas solo en visión general.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-24 16:30:17 +02:00
parent f4dfc50cc9
commit 4b6f7f1896
7 changed files with 568 additions and 109 deletions

View File

@@ -546,7 +546,12 @@ WHERE ${dateWhere}
}
cards.sort((a, b) => b.spend - a.spend);
const sliced = cards.slice(0, limit);
const sliced = cards
.filter(
(c) =>
c.spend > 0 || c.impressions > 0 || c.clicks > 0 || c.conversions > 0
)
.slice(0, limit);
if (!sliced.length) {
const fallback = dailyAggs.slice(0, limit).map((agg) => ({

View File

@@ -313,7 +313,12 @@ export function aggregateDailyByAd(
if (str(r.campaign_name)) cur.campaignName = str(r.campaign_name);
map.set(adId, cur);
}
return [...map.values()].sort((a, b) => b.spend - a.spend);
return [...map.values()]
.filter(
(a) =>
a.spend > 0 || a.impressions > 0 || a.clicks > 0 || a.conversions > 0
)
.sort((a, b) => b.spend - a.spend);
}
async function fetchMetaCreativeBundle(

View File

@@ -21,6 +21,7 @@ export type AdDailyRow = {
platform?: string;
campaign_name?: string;
campaign?: string;
ad_id?: string | null;
ad_name?: string;
conversions?: number;
tenant_id?: string;