Oleada UX 3: POS (repetir ultima venta, aviso de paquetes, atajos, caja desde POS), Ventas (cancelacion auditada con reversion de monedero y stock, detalle inline, presets de fecha), Cortes (historial comparativo y export)
This commit is contained in:
87
frontend/src/lib/dateRange.ts
Normal file
87
frontend/src/lib/dateRange.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Presets de rango de fecha compartidos (Ventas, y reutilizables por otras
|
||||
* vistas). El rango elegido se persiste en localStorage para que al volver a
|
||||
* la pantalla se restaure, igual que los presets de la agenda.
|
||||
*/
|
||||
|
||||
export type DatePreset = 'hoy' | 'ayer' | 'semana' | 'mes' | 'mes_pasado' | 'custom';
|
||||
|
||||
export interface DateRange {
|
||||
start: string;
|
||||
end: string;
|
||||
}
|
||||
|
||||
export const DATE_PRESETS: { value: DatePreset; label: string }[] = [
|
||||
{ value: 'hoy', label: 'Hoy' },
|
||||
{ value: 'ayer', label: 'Ayer' },
|
||||
{ value: 'semana', label: 'Esta semana' },
|
||||
{ value: 'mes', label: 'Este mes' },
|
||||
{ value: 'mes_pasado', label: 'Mes pasado' },
|
||||
{ value: 'custom', label: 'Rango personalizado' },
|
||||
];
|
||||
|
||||
export const isoDate = (d: Date): string => {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${y}-${m}-${day}`;
|
||||
};
|
||||
|
||||
export const rangeForPreset = (preset: DatePreset, today = new Date()): DateRange => {
|
||||
const t = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
||||
switch (preset) {
|
||||
case 'hoy':
|
||||
return { start: isoDate(t), end: isoDate(t) };
|
||||
case 'ayer': {
|
||||
const y = new Date(t);
|
||||
y.setDate(y.getDate() - 1);
|
||||
return { start: isoDate(y), end: isoDate(y) };
|
||||
}
|
||||
case 'semana': {
|
||||
// Semana en curso, de lunes a domingo
|
||||
const dow = (t.getDay() + 6) % 7; // 0 = lunes
|
||||
const monday = new Date(t);
|
||||
monday.setDate(t.getDate() - dow);
|
||||
const sunday = new Date(monday);
|
||||
sunday.setDate(monday.getDate() + 6);
|
||||
return { start: isoDate(monday), end: isoDate(sunday) };
|
||||
}
|
||||
case 'mes': {
|
||||
const first = new Date(t.getFullYear(), t.getMonth(), 1);
|
||||
const last = new Date(t.getFullYear(), t.getMonth() + 1, 0);
|
||||
return { start: isoDate(first), end: isoDate(last) };
|
||||
}
|
||||
case 'mes_pasado': {
|
||||
const first = new Date(t.getFullYear(), t.getMonth() - 1, 1);
|
||||
const last = new Date(t.getFullYear(), t.getMonth(), 0);
|
||||
return { start: isoDate(first), end: isoDate(last) };
|
||||
}
|
||||
default:
|
||||
return { start: isoDate(t), end: isoDate(t) };
|
||||
}
|
||||
};
|
||||
|
||||
export interface DateFilterPrefs extends DateRange {
|
||||
preset: DatePreset;
|
||||
}
|
||||
|
||||
export const readDateFilterPrefs = (key: string): DateFilterPrefs | null => {
|
||||
try {
|
||||
const raw = localStorage.getItem(key);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw) as Partial<DateFilterPrefs>;
|
||||
if (!parsed || typeof parsed.start !== 'string' || typeof parsed.end !== 'string') return null;
|
||||
const preset = (DATE_PRESETS.some((p) => p.value === parsed.preset) ? parsed.preset : 'custom') as DatePreset;
|
||||
return { preset, start: parsed.start, end: parsed.end };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const writeDateFilterPrefs = (key: string, prefs: DateFilterPrefs): void => {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(prefs));
|
||||
} catch {
|
||||
// localStorage no disponible: se mantiene solo en memoria
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user