const { StatCard, Card, Icon, Button, DemandCard, ProgressBar, Badge, Avatar, DataTable, StatusPill, PriorityBadge, SectorTag, DeadlineIndicator, EmptyState } = window.ACRFlowDesignSystem_ba1e9c;
function SectionTitle({ children, action }) {
return (
{children}
{action}
);
}
function BarChart({ data, tone = "var(--accent-primary)" }) {
const max = Math.max(...data.map((d) => d.value));
return (
);
}
const LAYOUT_KEY = "flowtix.dash.layout.v2";
const SPAN_OPTS = [{ value: 4, label: "1/3 da largura" }, { value: 6, label: "Metade" }, { value: 8, label: "2/3 da largura" }, { value: 12, label: "Largura total" }];
const DEFAULT_LAYOUT = [
{ id: "demandas", span: 12 },
{ id: "acao", span: 8 },
{ id: "setor", span: 4 },
{ id: "prazo", span: 4 },
{ id: "recorrentes", span: 4 },
];
function useLayout() {
const [layout, setLayout] = React.useState(() => {
try {
const raw = localStorage.getItem(LAYOUT_KEY);
if (raw) {
const saved = JSON.parse(raw);
if (Array.isArray(saved) && saved.length) return saved;
}
} catch (e) { /* ignora */ }
return DEFAULT_LAYOUT;
});
const persist = (next) => { setLayout(next); try { localStorage.setItem(LAYOUT_KEY, JSON.stringify(next)); } catch (e) { /* ignora */ } };
return [layout, persist];
}
function Panel({ item, children, onSpan, onMove, drag, setDrag, over, setOver }) {
const NSp = window.ACRFlowDesignSystem_ba1e9c;
const [hover, setHover] = React.useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
onDragOver={(e) => { e.preventDefault(); setOver(item.id); }}
onDragLeave={() => setOver((o) => (o === item.id ? null : o))}
onDrop={(e) => { e.preventDefault(); onMove(drag, item.id); setDrag(null); setOver(null); }}
style={{ gridColumn: "span " + item.span, display: "flex", flexDirection: "column", position: "relative", opacity: drag === item.id ? 0.45 : 1, outline: over === item.id && drag && drag !== item.id ? "2px dashed var(--border-focus)" : "none", outlineOffset: 4, borderRadius: "var(--radius-card)" }}>
{ setDrag(item.id); e.dataTransfer.effectAllowed = "move"; }}
onDragEnd={() => { setDrag(null); setOver(null); }}
title="Arraste para mudar de lugar"
style={{ display: "inline-flex", padding: 3, borderRadius: "var(--radius-sm)", color: "var(--text-subtle)", cursor: "grab" }}>
} />}
items={SPAN_OPTS.map((o) => ({ label: o.label, icon: , onSelect: () => onSpan(item.id, o.value) }))} />
{children}
);
}
function DashboardScreen({ user, onOpenDemand, onNavigate }) {
const D = window.ACRData;
const supervisor = user.profile === "supervisor";
const [layout, setLayout] = useLayout();
const [drag, setDrag] = React.useState(null);
const [newBoard, setNewBoard] = React.useState(false);
const addBoard = (cfg) => { setLayout([...layout, { id: "c" + Date.now(), span: cfg.span, custom: cfg }]); setNewBoard(false); };
const setChart = (id, chart) => setLayout(layout.map((i) => (i.id === id ? { ...i, custom: { ...i.custom, chart } } : i)));
const removeBoard = (id) => setLayout(layout.filter((i) => i.id !== id));
const [over, setOver] = React.useState(null);
const setSpan = (id, span) => setLayout(layout.map((i) => (i.id === id ? { ...i, span } : i)));
const move = (fromId, toId) => {
if (!fromId || !toId || fromId === toId) return;
const next = [...layout];
const fi = next.findIndex((i) => i.id === fromId);
const ti = next.findIndex((i) => i.id === toId);
if (fi < 0 || ti < 0) return;
next.splice(ti, 0, next.splice(fi, 1)[0]);
setLayout(next);
};
const mine = D.demands.filter((d) => d.status !== "encerrada");
const rows = mine.slice(0, 5);
const count = (s) => D.demands.filter((d) => d.status === s).length;
const abertas = mine.length;
const atrasadas = mine.filter((d) => d.daysLeft < 0).length;
const hoje = mine.filter((d) => d.daysLeft === 0).length;
const amanha = mine.filter((d) => d.daysLeft === 1).length;
const emAndamento = count("andamento");
const aprovacao = count("aguardando_aprovacao");
const encerradas = count("encerrada");
const encerradasAll = D.demands.filter((d) => d.status === "encerrada");
const noPrazo = encerradasAll.filter((d) => (d.daysLeft ?? 0) >= 0).length;
const foraPrazo = encerradasAll.length - noPrazo;
const pctPrazo = encerradasAll.length ? Math.round((noPrazo / encerradasAll.length) * 100) : 0;
const pendentesAprovacao = D.demands.filter((d) => d.status === "aguardando_aprovacao");
const recorrentes = D.demands.filter((d) => d.recurrence && d.recurrence !== "nao");
const checklistHoje = (D.checklist || []).filter((c) => !c.done).slice(0, 3);
const porSetor = D.sectorsCfg.map((s) => ({ label: s.name, value: D.demands.filter((d) => d.sector === s.id).length, tone: "var(--setor-" + (s.id === "gestao-condominial" ? "condominial" : s.id === "departamento-pessoal" ? "pessoal" : "contabilidade") + ")" }));
return (
{(new Date().getHours() < 12 ? "Bom dia, " : new Date().getHours() < 18 ? "Boa tarde, " : "Boa noite, ") + user.name.split(" ")[0]}
{supervisor
? (abertas === 0 && aprovacao === 0
? "Nenhuma demanda em aberto no momento."
: "Sua equipe tem " + abertas + " demanda" + (abertas === 1 ? "" : "s") + " em aberto e " + aprovacao + " aguardando sua aprovação.")
: (abertas === 0
? "Você não tem demandas pendentes."
: "Você possui " + abertas + " demanda" + (abertas === 1 ? "" : "s") + " pendente" + (abertas === 1 ? "" : "s") + " — " + atrasadas + " atrasada" + (atrasadas === 1 ? "" : "s") + " e " + hoje + " vence hoje.")}
{JSON.stringify(layout) !== JSON.stringify(DEFAULT_LAYOUT) ? } onClick={() => setLayout(DEFAULT_LAYOUT)}>Restaurar padrão : null}
} onClick={() => setNewBoard(true)}>Novo quadro
} hint="Ação imediata" onClick={() => onNavigate("fila")} />
} onClick={() => onNavigate("fila")} />
} onClick={() => onNavigate("fila")} />
} />
{supervisor
? } hint="Somente você aprova" onClick={() => pendentesAprovacao[0] ? onOpenDemand(pendentesAprovacao[0].id) : onNavigate("demandas")} />
: } />}
{layout.map((item) => (
{item.custom ? (
) : null}
{item.id === "demandas" ? (
onNavigate("demandas")}>Ver todas} padding="0">
{r.id} },
{ key: "title", label: "Demanda", render: (r) => (
{r.title}
) },
{ key: "status", label: "Status", width: 150, render: (r) => },
{ key: "priority", label: "Prioridade", width: 92, render: (r) => },
{ key: "daysLeft", label: "Prazo", width: 128, render: (r) => },
{ key: "progress", label: "Conclusão", width: 100, render: (r) => },
]}
rows={rows} onRowClick={(r) => onOpenDemand(r.id)} dense />
) : null}
{item.id === "acao" ? (supervisor ? (
{pendentesAprovacao.length === 0
? Nenhuma demanda aguardando aprovação.
: pendentesAprovacao.map((d) => (
{d.id}
{d.title}
{(d.people && d.people[0] ? d.people[0].name + " solicitou o encerramento" : "Encerramento solicitado") + " · checklist " + d.progress + "%"}
} onClick={() => onOpenDemand(d.id)}>Aprovar
))}
) : (
{checklistHoje.length === 0 ? Nenhuma etapa com prazo para hoje.
: null}
{checklistHoje.map((c) => (
{c.text}
{c.demandId || ""}
))}
)) : null}
{item.id === "setor" ? (
) : null}
{item.id === "prazo" ? (
{"Dentro do prazo · " + noPrazo}
{"Fora do prazo · " + foraPrazo}
{encerradasAll.length ? encerradasAll.length + " demanda" + (encerradasAll.length === 1 ? "" : "s") + " encerrada" + (encerradasAll.length === 1 ? "" : "s") : "Sem demandas encerradas ainda"}
) : null}
{item.id === "recorrentes" ? (
{recorrentes.length === 0
? Nenhuma demanda recorrente configurada.
: recorrentes.map((d) => (
onOpenDemand(d.id)}>
{d.title}
{d.recurrenceLabel || "Recorrente"}
))}
) : null}
))}
{newBoard ?
setNewBoard(false)} onCreate={addBoard} /> : null}
);
}
Object.assign(window, { DashboardScreen, BarChart, SectionTitle });