/* ============================================================
KeS Metas — Primitivos de UI (compartilhados via window)
============================================================ */
const { useState, useEffect, useRef, useMemo } = React;
/* ---------- Ícones (estilo Lucide, traço arredondado) ---------- */
const ICON_PATHS = {
dashboard: '',
calendar: '',
calendarCheck: '',
users: '',
user: '',
target: '',
sliders: '',
logout: '',
menu: '',
plus: '',
trash: '',
pencil: '',
check: '',
checkCircle: '',
x: '',
arrowRight: '',
chevronLeft: '',
chevronRight: '',
chevronDown: '',
phone: '',
link: '',
handshake: '',
trophy: '',
banknote: '',
lock: '',
clock: '',
trendingUp: '',
filter: '',
search: '',
alert: '',
mail: '',
mapPin: '',
eye: '',
eyeOff: '',
cloudCheck: '',
refresh: '',
sparkles: '',
download: '',
upload: '',
externalLink: '',
grip: '',
message: '',
tag: '',
spreadsheet: '',
video: '',
userPlus: '',
funnel: '',
copy: '',
};
function Icon({ name, size = 20, strokeWidth = 2, style, className }) {
return React.createElement("svg", {
width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor",
strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", style, className,
dangerouslySetInnerHTML: { __html: ICON_PATHS[name] || "" },
});
}
function GoogleG({ size = 18 }) {
return (
);
}
/* ---------- Logo ---------- */
function Logo({ size = 38 }) {
return
;
}
/* ---------- Avatar ---------- */
function initials(nome) {
const p = nome.trim().split(/\s+/);
return (p[0][0] + (p[1] ? p[1][0] : "")).toUpperCase();
}
function Avatar({ user, size = 38 }) {
return (
{initials(user.nome)}
);
}
/* ---------- Botão ---------- */
function Btn({ variant = "primary", size, icon, iconRight, disc, children, ...rest }) {
const cls = ["btn", `btn-${variant}`, size === "sm" ? "btn-sm" : "", rest.className || ""].join(" ").trim();
const { className, ...r } = rest;
return (
);
}
/* ---------- Progresso + tom de cor ---------- */
function tonePct(pct) {
if (pct >= 100) return "ok";
if (pct >= 70) return "warn";
return "bad";
}
function Progress({ pct }) {
const t = tonePct(pct);
return (
);
}
/* ---------- Badge ---------- */
function Badge({ tone = "muted", icon, children }) {
return (
{icon && }
{children}
);
}
/* ---------- Campos ---------- */
function Field({ label, error, children }) {
return (
{label &&
}
{children}
{error &&
{error}
}
);
}
/* ---------- Modal ---------- */
function Modal({ title, onClose, children, footer, wide }) {
useEffect(() => {
const h = (e) => { if (e.key === "Escape") onClose(); };
window.addEventListener("keydown", h);
return () => window.removeEventListener("keydown", h);
}, [onClose]);
return (
e.stopPropagation()}>
{title}
{children}
{footer &&
{footer}
}
);
}
/* ---------- Toast ---------- */
function Toast({ toast }) {
if (!toast) return null;
return (
{toast}
);
}
/* ============================================================
FILTRO DE PERÍODO
============================================================ */
const K = window.KES;
function startOfWeek(d) { const x = new Date(d); const day = (x.getDay() + 6) % 7; x.setDate(x.getDate() - day); return x; }
function buildPreset(name) {
const today = new Date(K.SIM_TODAY);
if (name === "hoje") return { preset: "hoje", start: K.iso(today), end: K.iso(today), label: "Hoje" };
if (name === "semana") { const s = startOfWeek(today); return { preset: "semana", start: K.iso(s), end: K.iso(today), label: "Esta semana" }; }
if (name === "mes") { const s = new Date(today.getFullYear(), today.getMonth(), 1); return { preset: "mes", start: K.iso(s), end: K.iso(today), label: "Este mês" }; }
if (name === "mesPassado") {
const s = new Date(today.getFullYear(), today.getMonth() - 1, 1);
const e = new Date(today.getFullYear(), today.getMonth(), 0);
return { preset: "mesPassado", start: K.iso(s), end: K.iso(e), label: "Mês passado" };
}
return buildPreset("mes");
}
function PeriodFilter({ value, onChange }) {
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", h);
return () => document.removeEventListener("mousedown", h);
}, []);
const shortcuts = [
["hoje", "Hoje"], ["semana", "Esta semana"], ["mes", "Este mês"], ["mesPassado", "Mês passado"],
];
const labelText = value.preset === "custom"
? `${K.fmtBR(value.start)} – ${K.fmtBR(value.end)}`
: value.label;
return (
{open && (
)}
);
}
/* ============================================================
GRÁFICO DE BARRAS (evolução no período)
============================================================ */
function BarChart({ series, target, color = "var(--kes-red)", height = 150 }) {
// series: [{ label, value }]
const max = Math.max(target || 0, ...series.map((s) => s.value), 1);
const W = Math.max(series.length * 26, 300), H = height, pad = 8;
const bw = (W - pad * 2) / series.length;
const y = (v) => H - pad - (v / max) * (H - pad * 2);
const ty = target ? y(target) : null;
const step = Math.max(1, Math.ceil(series.length / 12));
return (
);
}
/* ---------- Export global ---------- */
Object.assign(window, {
Icon, GoogleG, Logo, Avatar, initials, Btn, tonePct, Progress, Badge, Field, Modal, Toast,
PeriodFilter, buildPreset, BarChart,
});