// Componentes compartilhados — popovers, menus, toasts.
// Drop-in para botões de Exportar, Mais opções, etc. em qualquer tela.
const { useState: usePopState, useEffect: usePopEffect, useRef: usePopRef } = React;
/* ────────────────────────────────────────────────────────────────
useOutsideClose — fecha o popover ao clicar fora ou apertar ESC
──────────────────────────────────────────────────────────────── */
function useOutsideClose(open, onClose) {
usePopEffect(() => {
if (!open) return;
const onClick = () => onClose();
const onKey = (e) => { if (e.key === 'Escape') onClose(); };
// delay so the click that opened the popover doesn't immediately close it
const t = setTimeout(() => window.addEventListener('click', onClick), 0);
window.addEventListener('keydown', onKey);
return () => { clearTimeout(t); window.removeEventListener('click', onClick); window.removeEventListener('keydown', onKey); };
}, [open, onClose]);
}
/* ────────────────────────────────────────────────────────────────
icon-btn com popover de exportação (PDF / CSV / XLS / email)
──────────────────────────────────────────────────────────────── */
function ExportButton({ count, label = 'registros', email = 'leticia.andrade@ezza.com.br', size = 'icon' }) {
const [open, setOpen] = usePopState(false);
useOutsideClose(open, () => setOpen(false));
const toast = useToast();
const handle = (fmt, msg) => {
setOpen(false);
toast(msg);
};
return (
e.stopPropagation()}>
{size === 'mini' ? (
) : size === 'primary' ? (
) : (
)}
{open && (
e.stopPropagation()}>
Exportar
{count != null && {count} {label}}
)}
);
}
/* ────────────────────────────────────────────────────────────────
Menu contextual de 3 pontinhos
──────────────────────────────────────────────────────────────── */
function MoreMenu({ items, size = 'mini', align = 'right', placement = 'bottom', title = 'Mais opções' }) {
const [open, setOpen] = usePopState(false);
useOutsideClose(open, () => setOpen(false));
const toast = useToast();
const fire = (item) => {
setOpen(false);
if (item.onClick) item.onClick();
else if (item.toast) toast(item.toast);
};
return (
e.stopPropagation()}>
{size === 'icon' ? (
) : (
)}
{open && (
e.stopPropagation()}>
{items.map((it, i) => {
if (it.divider) return
;
if (it.section) return
{it.section}
;
return (
);
})}
)}
);
}
/* ────────────────────────────────────────────────────────────────
Substitui o CardActions decorativo (+, upload, cal) por ações reais
──────────────────────────────────────────────────────────────── */
function CardActionsBar({ count, onCreate, onPeriod, createLabel = 'Criar', moreItems }) {
const toast = useToast();
return (
{moreItems && }
);
}
/* ────────────────────────────────────────────────────────────────
useToast — hook + ToastHost para feedback rápido
──────────────────────────────────────────────────────────────── */
const ToastContext = React.createContext(() => {});
function ToastProvider({ children }) {
const [toasts, setToasts] = usePopState([]);
const push = React.useCallback((msg, opts = {}) => {
const id = Date.now() + Math.random();
setToasts(t => [...t, { id, msg, kind: opts.kind || 'ok', icon: opts.icon }]);
setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), opts.duration || 2400);
}, []);
return (
{children}
{toasts.map(t => (
{t.icon || (t.kind === 'err' ? ICN.x : ICN.check)}
{t.msg}
))}
);
}
function useToast() {
return React.useContext(ToastContext);
}
/* ────────────────────────────────────────────────────────────────
— substituto universal pros mini-btn decorativos
Aceita uma ação ou um toast string.
──────────────────────────────────────────────────────────────── */
function ActionBtn({ icon, title, onClick, toast: toastMsg, size = 'mini', danger }) {
const toast = useToast();
const cls = size === 'icon' ? 'icon-btn' : 'mini-btn';
return (
);
}
/* ────────────────────────────────────────────────────────────────
Estilos compartilhados — injetados uma vez via
──────────────────────────────────────────────────────────────── */
function PopoverStyles() {
return (
);
}
Object.assign(window, { ExportButton, MoreMenu, CardActionsBar, ActionBtn, ToastProvider, useToast, PopoverStyles });