feat: KPIs con totales absolutos, backfill ads y ventas en cruce canal

Comparativas WoW/MoM/YoY muestran prev/Δ además del %; sync ads admite
histórico desde 2025; tabla ads↔CRM añade cierres, ventas y ROAS.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-28 10:23:36 +02:00
parent dd50251de2
commit cf27eba74d
30 changed files with 2367 additions and 514 deletions

View File

@@ -14,7 +14,7 @@ import {
isoYesterday,
} from '@/lib/ad-tracker-range';
const STORAGE_KEY = '4v_global_date_range_v1';
const STORAGE_KEY = '4v_global_date_range_v2';
type Stored = {
preset: RangePreset;
@@ -38,24 +38,24 @@ const DateRangeContext = createContext<Ctx | null>(null);
function loadStored(): Stored {
const y = isoYesterday();
if (typeof window === 'undefined') {
return { preset: 'last_7d', customSince: y, customUntil: y };
return { preset: 'last_30d', customSince: y, customUntil: y };
}
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return { preset: 'last_7d', customSince: y, customUntil: y };
if (!raw) return { preset: 'last_30d', customSince: y, customUntil: y };
const j = JSON.parse(raw) as Stored;
return {
preset: j.preset || 'last_7d',
preset: j.preset || 'last_30d',
customSince: j.customSince || y,
customUntil: j.customUntil || y,
};
} catch {
return { preset: 'last_7d', customSince: y, customUntil: y };
return { preset: 'last_30d', customSince: y, customUntil: y };
}
}
export function DateRangeProvider({ children }: { children: React.ReactNode }) {
const [preset, setPresetState] = useState<RangePreset>('last_7d');
const [preset, setPresetState] = useState<RangePreset>('last_30d');
const [customSince, setCustomSince] = useState('');
const [customUntil, setCustomUntil] = useState('');
const [hydrated, setHydrated] = useState(false);