Align Ads and Métricas on the same paginated ad_daily warehouse.

Ad Tracker only loaded 2000 newest rows, so Brava showed 0 € while Métricas summed the full month. Both now page the same table for the selected range.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-10-06 15:33:06 +02:00
parent fac9867202
commit a5bfec698b
6 changed files with 181 additions and 74 deletions

View File

@@ -68,7 +68,9 @@ function rates(input: Omit<PlatformKpis, 'ctr' | 'cpc' | 'cpl'>): PlatformKpis {
}
function convOf(r: AdDailyRow): number {
return Number(r.conversions ?? r.platform_leads ?? 0) || 0;
const x = r.platform_leads ?? r.conversions;
const n = Number(x);
return Number.isFinite(n) ? n : 0;
}
function campaignName(r: AdDailyRow): string {
@@ -541,12 +543,44 @@ export default function AdTrackerClient({
} | null>(null);
const [zoomAd, setZoomAd] = useState<AdCreativeCard | null>(null);
const [rowsLive, setRowsLive] = useState<AdDailyRow[]>(rows);
const [rowsLoading, setRowsLoading] = useState(false);
const range = useMemo(() => ({ since, until, label: rangeLabel }), [
since,
until,
rangeLabel,
]);
useEffect(() => {
setRowsLive(rows);
}, [rows]);
useEffect(() => {
let cancelled = false;
async function loadRange() {
setRowsLoading(true);
try {
const qs = new URLSearchParams({
since: range.since,
until: range.until,
});
const r = await fetch(`/api/ads/daily?${qs}`, { cache: 'no-store' });
const data = await r.json().catch(() => ({}));
if (cancelled) return;
if (r.ok && Array.isArray(data.rows)) {
setRowsLive(data.rows as AdDailyRow[]);
}
} finally {
if (!cancelled) setRowsLoading(false);
}
}
void loadRange();
return () => {
cancelled = true;
};
}, [range.since, range.until]);
useEffect(() => {
if (tab === 'resumen') {
setCreatives([]);
@@ -636,8 +670,8 @@ export default function AdTrackerClient({
}, [range.since, range.until, tab]);
const filtered = useMemo(
() => rows.filter((r) => inRange(r.date, range.since, range.until)),
[rows, range.since, range.until]
() => rowsLive.filter((r) => inRange(r.date, range.since, range.until)),
[rowsLive, range.since, range.until]
);
const metaRows = filtered.filter((r) => normalizePlatform(r.platform) === 'meta');
@@ -694,7 +728,9 @@ export default function AdTrackerClient({
<PageHeader
eyebrow="Publicidad"
title={tagline || 'Ads'}
description={`${label} · Meta + Google · ${rangeLabel}`}
description={`${label} · Meta + Google · ${rangeLabel}${
rowsLoading ? ' · actualizando…' : ''
}`}
actions={<SyncNowButton forceModule="ads" />}
/>

View File

@@ -361,8 +361,10 @@ export default function MetricsDashboard({
const periodTotals = useMemo(() => {
let base: MetricTotals;
if (rangedDaily.length) {
base = metricTotalsFromDaily(rangedDaily);
if (dailyRows.length) {
base = rangedDaily.length
? metricTotalsFromDaily(rangedDaily)
: metricTotalsFromDaily([]);
} else {
const ranged = weeklyRows.filter((r) => {
if (!r.week) return false;
@@ -372,7 +374,7 @@ export default function MetricsDashboard({
base = ranged.length ? sumWeekly(ranged) : month;
}
return withCohortFromDeals(base, rangedDeals);
}, [rangedDaily, rangedDeals, weeklyRows, since, until, month]);
}, [dailyRows.length, rangedDaily, rangedDeals, weeklyRows, since, until, month]);
const rangeDeltas = useMemo(
() => buildRangeDeltas(dailyRows, wonDeals, since, until),