/* O Tal Picolé — Filtros de período + helpers de export/import */ /* ============================================================ PERÍODO — utilitários ============================================================ */ const DEFAULT_REF_DATE = new Date(2026, 4, 20); // base do mock — 20/mai/2026 function periodRange(period, refDate){ const ref = refDate || new Date(); const out = { start: null, end: null, label: "" }; const today = new Date(ref.getFullYear(), ref.getMonth(), ref.getDate()); if (period.kind === "day") { out.start = today; out.end = today; out.label = "Hoje · " + today.toLocaleDateString("pt-BR"); } else if (period.kind === "week") { const s = new Date(today); s.setDate(today.getDate() - 6); out.start = s; out.end = today; out.label = "Últimos 7 dias"; } else if (period.kind === "month") { const s = new Date(today); s.setDate(today.getDate() - 29); out.start = s; out.end = today; out.label = "Últimos 30 dias"; } else if (period.kind === "year") { const s = new Date(today.getFullYear(), 0, 1); out.start = s; out.end = today; out.label = "Este ano (" + today.getFullYear() + ")"; } else if (period.kind === "custom") { out.start = period.start ? new Date(period.start + "T00:00:00") : null; out.end = period.end ? new Date(period.end + "T00:00:00") : null; if (out.start && out.end) { out.label = out.start.toLocaleDateString("pt-BR") + " — " + out.end.toLocaleDateString("pt-BR"); } else { out.label = "Selecione um intervalo"; } } else { out.label = "Todo o histórico"; } return out; } function inPeriod(dateStr, period, refDate){ if (!period || period.kind === "all") return true; const r = periodRange(period, refDate); if (!r.start || !r.end) return true; const d = new Date((dateStr + "").slice(0,10) + "T00:00:00"); return d >= r.start && d <= r.end; } function ymd(d){ const dt = d instanceof Date ? d : new Date(d); const m = String(dt.getMonth()+1).padStart(2,"0"); const da = String(dt.getDate()).padStart(2,"0"); return `${dt.getFullYear()}-${m}-${da}`; } /* ============================================================ PERIOD PICKER (componente) ============================================================ */ function PeriodPicker({ value, onChange, refDate, compact }) { const [open, setOpen] = useState(false); const [customStart, setCustomStart] = useState(value?.start || ""); const [customEnd, setCustomEnd] = useState(value?.end || ""); const ref = useRef(null); useEffect(() => { const close = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; if (open) document.addEventListener("mousedown", close); return () => document.removeEventListener("mousedown", close); }, [open]); const set = (kind) => { onChange({ kind }); setOpen(false); }; const setCustom = () => { if (customStart && customEnd) { onChange({ kind:"custom", start: customStart, end: customEnd }); setOpen(false); } }; const current = value || { kind:"month" }; const r = periodRange(current, refDate); const presets = [ { kind:"day", label:"Hoje" }, { kind:"week", label:"Últimos 7 dias" }, { kind:"month", label:"Últimos 30 dias" }, { kind:"year", label:"Este ano" }, { kind:"all", label:"Todo o histórico" }, ]; return (
{open && (
{presets.map(p => ( ))}

Período personalizado
setCustomStart(e.target.value)} style={{ padding:"6px 8px", fontSize:12 }} /> setCustomEnd(e.target.value)} style={{ padding:"6px 8px", fontSize:12 }} />
)}
); } /* ============================================================ EXPORT (CSV) / IMPORT (JSON) ============================================================ */ function downloadFile(filename, content, mime){ const blob = new Blob([content], { type: mime || "text/plain;charset=utf-8" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); setTimeout(()=>{ URL.revokeObjectURL(url); a.remove(); }, 200); } function toCSV(headers, rows){ const esc = (v) => { if (v === null || v === undefined) return ""; const s = String(v).replace(/"/g, '""'); return /[",;\n]/.test(s) ? `"${s}"` : s; }; const lines = [headers.map(esc).join(";")]; rows.forEach(r => lines.push(r.map(esc).join(";"))); return "\uFEFF" + lines.join("\n"); // BOM para Excel BR } function exportFinanceCsv(finance, period){ const r = periodRange(period || { kind:"all" }); const filtered = finance.filter(f => inPeriod(f.date, period || { kind:"all" })); const headers = ["Data", "Tipo", "Categoria", "Descrição", "Status", "Valor"]; const rows = filtered.map(f => [ f.date, f.kind === "in" ? "Entrada" : "Saída", f.cat, f.ref, f.status === "confirmado" ? "Confirmado" : "A receber", (f.kind==="in" ? "+" : "-") + f.value.toFixed(2).replace(".",","), ]); const period_lbl = r.label.replace(/[ ·/]/g,"_"); downloadFile(`movimentacoes_${period_lbl}.csv`, toCSV(headers, rows), "text/csv;charset=utf-8"); } function exportSalesCsv(sales){ const headers = ["Nº", "Data", "Distribuidor", "Valor", "Status"]; const rows = sales.map(s => [s.id, s.date, s.ref, s.value.toFixed(2).replace(".",","), s.status==="confirmado"?"Pago":"A receber"]); downloadFile(`vendas_distribuidores.csv`, toCSV(headers, rows), "text/csv;charset=utf-8"); } function pickFile(accept){ return new Promise((resolve) => { const input = document.createElement("input"); input.type = "file"; input.accept = accept || "*"; input.onchange = () => resolve(input.files && input.files[0] ? input.files[0] : null); input.click(); }); } async function readFileAsText(file){ return await new Promise((resolve, reject) => { const r = new FileReader(); r.onload = () => resolve(r.result); r.onerror = reject; r.readAsText(file); }); } async function readFileAsDataURL(file){ return await new Promise((resolve, reject) => { const r = new FileReader(); r.onload = () => resolve(r.result); r.onerror = reject; r.readAsDataURL(file); }); } Object.assign(window, { periodRange, inPeriod, ymd, PeriodPicker, downloadFile, toCSV, exportFinanceCsv, exportSalesCsv, pickFile, readFileAsText, readFileAsDataURL, DEFAULT_REF_DATE, });