feat: periodo global, métricas negocio, seguimiento notas, Drive/Social/Orgánico

Selector de fechas en header (con Personalizado) compartido en el dashboard; Métricas con Ventas/CAC/ROAS CRM, cruce canal y gráficas diarias; Seguimiento solo notas + sync Superhuman; Activos con navegación Drive; Social con métricas IG/FB; Orgánico con prioridades SEO/GEO expertas.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-24 15:45:30 +02:00
parent eb1622c88c
commit 3425364b07
15 changed files with 1067 additions and 1011 deletions

View File

@@ -1,11 +1,7 @@
'use client';
import React, { useEffect, useMemo, useState } from 'react';
import {
RangePreset,
normalizePlatform,
resolveAdRange,
} from '@/lib/ad-tracker-range';
import { normalizePlatform } from '@/lib/ad-tracker-range';
import { AdDailyRow, formatEur, formatNum } from '@/lib/metrics';
import type { AdCreativeCard } from '@/lib/ad-creatives-meta';
import {
@@ -13,7 +9,7 @@ import {
CreativeZoomModal,
} from '@/components/AdCreativesGallery';
import { PageHeader } from '@/components/ui';
import DateRangePicker from '@/components/DateRangePicker';
import { useDateRange } from '@/components/DateRangeContext';
type PlatformKpis = {
spend: number;
@@ -317,9 +313,7 @@ export default function AdTrackerClient({
tagline?: string;
rows: AdDailyRow[];
}) {
const [preset, setPreset] = useState<RangePreset>('last_7d');
const [customSince, setCustomSince] = useState('');
const [customUntil, setCustomUntil] = useState('');
const { since, until, label: rangeLabel } = useDateRange();
const [tab, setTab] = useState<Tab>('resumen');
const [chartMode, setChartMode] = useState<ChartMode>('combined');
const [creatives, setCreatives] = useState<AdCreativeCard[]>([]);
@@ -327,10 +321,11 @@ export default function AdTrackerClient({
const [creativesWarning, setCreativesWarning] = useState<string | null>(null);
const [zoomAd, setZoomAd] = useState<AdCreativeCard | null>(null);
const range = useMemo(
() => resolveAdRange(preset, { since: customSince, until: customUntil }),
[preset, customSince, customUntil]
);
const range = useMemo(() => ({ since, until, label: rangeLabel }), [
since,
until,
rangeLabel,
]);
useEffect(() => {
let cancelled = false;
@@ -416,26 +411,7 @@ export default function AdTrackerClient({
<PageHeader
eyebrow={`Ads · ${label}`}
title={tagline || 'Meta + Google Ads'}
description={`Gasto, clics, conversiones y preview de creatividades. Ventana: ${range.since} → ${range.until}.`}
/>
{/* Period presets */}
<DateRangePicker
preset={preset}
customSince={customSince || range.since}
customUntil={customUntil || range.until}
onPreset={(p) => {
setPreset(p);
if (p !== 'custom') {
const r = resolveAdRange(p);
setCustomSince(r.since);
setCustomUntil(r.until);
}
}}
onCustomChange={(since, until) => {
setCustomSince(since);
setCustomUntil(until);
}}
description={`Gasto, clics, conversiones y creatividades. Periodo del header: ${rangeLabel}.`}
/>
{/* Tabs */}