Files
4ventures-client-portal/src/components/DateRangePicker.tsx
4Ventures 8fda2996b6 feat: rango de fechas personalizado y datos hasta ayer (salvo Hoy)
Selector libre en Ad Tracker/Seguimiento; presets y KPIs cierran en ayer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 10:24:25 +02:00

155 lines
4.7 KiB
TypeScript

'use client';
import React, { useEffect, useMemo, useState } from 'react';
import {
AD_TRACKER_PRESETS,
RangePreset,
isoYesterday,
resolveAdRange,
} from '@/lib/ad-tracker-range';
type Props = {
preset: RangePreset;
customSince: string;
customUntil: string;
onPreset: (preset: RangePreset) => void;
onCustomChange: (since: string, until: string) => void;
/** Compact = fewer labels (for sticky headers). */
compact?: boolean;
};
/**
* Periodo predefinido + rango libre.
* El hasta personalizado no puede pasar de ayer (Hoy solo vía botón «Hoy»).
*/
export default function DateRangePicker({
preset,
customSince,
customUntil,
onPreset,
onCustomChange,
compact = false,
}: Props) {
const yesterday = useMemo(() => isoYesterday(), []);
const range = useMemo(
() =>
resolveAdRange(preset, {
since: customSince,
until: customUntil,
}),
[preset, customSince, customUntil]
);
const [draftSince, setDraftSince] = useState(customSince || range.since);
const [draftUntil, setDraftUntil] = useState(customUntil || range.until);
useEffect(() => {
if (preset === 'custom') {
setDraftSince(customSince || range.since);
setDraftUntil(customUntil || range.until);
} else {
setDraftSince(range.since);
setDraftUntil(range.until);
}
}, [preset, customSince, customUntil, range.since, range.until]);
function applyCustom() {
let s = draftSince || yesterday;
let u = draftUntil || yesterday;
if (u > yesterday) u = yesterday;
if (s > u) s = u;
onCustomChange(s, u);
onPreset('custom');
}
return (
<div className="space-y-2">
{!compact ? (
<p className="text-[10px] uppercase tracking-wider text-gray-500">
Periodo
</p>
) : null}
<div className="flex flex-wrap gap-1.5 items-center">
{AD_TRACKER_PRESETS.map((p) => (
<button
key={p.id}
type="button"
onClick={() => onPreset(p.id)}
className={`px-3 py-1.5 rounded-lg text-xs font-semibold ${
preset === p.id
? 'bg-brand-500 text-white'
: 'bg-gray-100 text-gray-600 hover:bg-gray-50'
}`}
>
{p.label}
</button>
))}
<button
type="button"
onClick={() => {
let until = draftUntil || range.until;
let since = draftSince || range.since;
if (until > yesterday) until = yesterday;
if (since > until) since = until;
setDraftSince(since);
setDraftUntil(until);
onCustomChange(since, until);
onPreset('custom');
}}
className={`px-3 py-1.5 rounded-lg text-xs font-semibold ${
preset === 'custom'
? 'bg-brand-500 text-white'
: 'bg-gray-100 text-gray-600 hover:bg-gray-50'
}`}
>
Personalizado
</button>
<span className="px-3 py-1.5 rounded-lg text-xs font-medium border border-gray-200 text-gray-600">
{range.label}
</span>
</div>
{preset === 'custom' ? (
<div className="flex flex-wrap items-end gap-2 rounded-xl border border-gray-200 bg-gray-50 px-3 py-2.5">
<label className="text-xs text-gray-600">
Desde
<input
type="date"
value={draftSince}
max={draftUntil || yesterday}
onChange={(e) => setDraftSince(e.target.value)}
className="mt-1 block rounded-lg border border-gray-200 bg-white px-2.5 py-1.5 text-sm text-gray-900"
/>
</label>
<label className="text-xs text-gray-600">
Hasta
<input
type="date"
value={draftUntil}
max={yesterday}
min={draftSince || undefined}
onChange={(e) => setDraftUntil(e.target.value)}
className="mt-1 block rounded-lg border border-gray-200 bg-white px-2.5 py-1.5 text-sm text-gray-900"
/>
</label>
<button
type="button"
onClick={applyCustom}
className="rounded-lg bg-gray-900 px-3 py-1.5 text-xs font-semibold text-white hover:bg-gray-800"
>
Aplicar
</button>
<p className="w-full text-[10px] text-gray-500">
El rango personalizado llega como máximo a ayer. Usa «Hoy» para
incluir el día en curso.
</p>
</div>
) : preset !== 'today' ? (
<p className="text-[10px] text-gray-400">
Datos hasta ayer · «Hoy» incluye el día en curso
</p>
) : null}
</div>
);
}