const { Card, Icon, IconButton, Button, Badge, Modal, Select, Input, EmptyState, DropdownMenu, StatusPill } = window.ACRFlowDesignSystem_ba1e9c;
const CHARTS = [
{ value: "lista", label: "Lista de demandas", icon: "list" },
{ value: "tabela", label: "Tabela detalhada", icon: "table-2" },
{ value: "numeros", label: "Contadores", icon: "hash" },
{ value: "barras", label: "Barras horizontais", icon: "bar-chart-2" },
{ value: "colunas", label: "Colunas", icon: "bar-chart-3" },
{ value: "linhas", label: "Linhas", icon: "line-chart" },
{ value: "pizza", label: "Pizza", icon: "pie-chart" },
{ value: "rosca", label: "Rosca", icon: "circle-dot" },
];
const STATUS_TONE = { encerrada: "var(--success-solid)", andamento: "var(--accent-flow)", pendente: "var(--st-pendente)", aguardando_atendimento: "var(--st-aguardando)", aguardando_terceiros: "var(--st-aguardando)", aguardando_aprovacao: "var(--violet-500)", aberta: "var(--st-aberta)", triagem: "var(--st-triagem)", reaberta: "var(--danger-solid)" };
const SHORT = { aberta: "Aberta", triagem: "Triagem", aguardando_atendimento: "Aguard. atend.", andamento: "Em andam.", pendente: "Pendente", aguardando_terceiros: "Aguard. terc.", aguardando_aprovacao: "Aguard. aprov.", encerrada: "Encerrada", reaberta: "Reaberta" };
const sectorTone = (id) => "var(--setor-" + (id === "gestao-condominial" ? "condominial" : id === "departamento-pessoal" ? "pessoal" : "contabilidade") + ")";
function Bars({ groups }) {
const max = Math.max(...groups.map((g) => g.value), 1);
return (
);
}
function Columns({ groups }) {
const max = Math.max(...groups.map((g) => g.value), 1);
return (
);
}
function Lines({ groups }) {
const max = Math.max(...groups.map((g) => g.value), 1);
const w = 100, h = 46;
const pts = groups.map((g, i) => [groups.length === 1 ? w / 2 : (i / (groups.length - 1)) * w, h - (g.value / max) * (h - 6)]);
const path = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
return (
{groups.map((g) => (
{g.short} · {g.value}
))}
);
}
function Pie({ groups, total, donut }) {
let acc = 0;
const stops = groups.map((g) => { const from = acc; acc += (g.value / total) * 100; return g.tone + " " + from + "% " + acc + "%"; }).join(", ");
return (
{donut ? (
{total}
demandas
) : null}
{groups.map((g) => (
{g.label}
{g.value}
))}
);
}
/** Lista compacta: título, empresa, responsável e status de cada demanda. */
function DemandList({ list, onOpenDemand }) {
return (
{list.map((d) => (
onOpenDemand && onOpenDemand(d.id)}
style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 0", borderBottom: "1px solid var(--border-subtle)", cursor: onOpenDemand ? "pointer" : "default" }}>
{d.id}
{d.title}
{(d.context || "").replace(/^Empresa: /, "")}{d.people && d.people[0] ? " · " + d.people[0].name : ""}
))}
);
}
/** Tabela detalhada da demanda: número, título, empresa, responsável, prioridade, prazo e status. */
function DemandTable({ list, onOpenDemand }) {
const NSt = window.ACRFlowDesignSystem_ba1e9c;
return (
onOpenDemand(r.id) : undefined}
columns={[
{ key: "id", label: "Nº", width: 112, render: (r) => {r.id} },
{ key: "title", label: "Demanda", render: (r) => (
{r.title}
{r.category}{r.people && r.people[0] ? " · " + r.people[0].name : ""}
) },
{ key: "context", label: "Empresa", width: 168, render: (r) => {(r.context || "—").replace(/^Empresa: /, "")} },
{ key: "status", label: "Status", width: 148, render: (r) => },
{ key: "daysLeft", label: "Prazo", width: 122, render: (r) => r.status === "encerrada" ? Concluída : },
]} />
);
}
function Counters({ list, onNavigate }) {
const enc = list.filter((d) => d.status === "encerrada").length;
const pend = list.length - enc;
const atraso = list.filter((d) => d.status !== "encerrada" && d.daysLeft <= 0).length;
const pct = list.length ? Math.round((enc / list.length) * 100) : 0;
return (
{[["Pendentes", pend, "var(--st-pendente)"], ["Concluídas", enc, "var(--success-solid)"], ["Atrasadas", atraso, "var(--danger-solid)"]].map(([l, v, tone]) => (
{l}
{v}
))}
{pct}% concluídas · {list.length} demandas na categoria
);
}
/** Quadro personalizado: setor + categoria, com contadores ou gráfico. */
function CustomBoard({ config, demands, statuses, sectors, onNavigate, onOpenDemand, onChart, onRemove }) {
const list = demands.filter((d) => d.sector === config.sector && (config.category === "todas" || d.category === config.category));
const groups = statuses
.map((s) => ({ label: s.name, short: SHORT[s.id] || s.name, value: list.filter((d) => d.status === s.id).length, tone: STATUS_TONE[s.id] || "var(--accent-primary)" }))
.filter((g) => g.value > 0);
const sectorName = (sectors.find((s) => s.id === config.sector) || {}).name;
const chart = config.chart || "lista";
return (
c.value === chart) || CHARTS[0]).icon} size={15} />} />}
items={CHARTS.map((c) => ({ label: c.label, icon: , onSelect: () => onChart(config.id, c.value) }))} />
} onClick={() => onRemove(config.id)} />
}>
{list.length ? (
<>
{chart === "lista" ? : null}
{chart === "tabela" ? : null}
{chart === "numeros" ? : null}
{chart === "barras" ? : null}
{chart === "colunas" ? : null}
{chart === "linhas" ? : null}
{chart === "pizza" ? : null}
{chart === "rosca" ? : null}
{chart !== "numeros" && chart !== "tabela" ? (
{list.filter((d) => d.status !== "encerrada").length} pendentes
{list.filter((d) => d.status === "encerrada").length} concluídas
) : null}
>
) : (
} title="Sem demandas nesta seleção." description="Assim que houver demandas no setor/categoria escolhidos, o quadro é preenchido."
action={} />
)}
);
}
/** Modal de criação de quadro personalizado. */
function NewBoardModal({ sectors, onClose, onCreate }) {
const [sector, setSector] = React.useState(sectors[0].id);
const [category, setCategory] = React.useState("todas");
const [chart, setChartType] = React.useState("lista");
const setChart = (v) => { setChartType(v); if (v === "tabela") setSpan(12); };
const [title, setTitle] = React.useState("");
const [span, setSpan] = React.useState(4);
const cats = (sectors.find((s) => s.id === sector) || { categories: [] }).categories;
const suggested = category === "todas" ? (sectors.find((s) => s.id === sector) || {}).name : category;
return (
} onClick={() => onCreate({ sector, category, chart, title: title.trim() || suggested, span: chart === "tabela" ? 12 : span })}>Adicionar ao dashboard>}>
setTitle(e.target.value)} hint="Deixe vazio para usar o nome da categoria." />
Visualização
{CHARTS.map((c) => (
))}
setSpan(Number(e.target.value))}
options={[{ value: "4", label: "1/3 da largura" }, { value: "6", label: "Metade" }, { value: "8", label: "2/3 da largura" }, { value: "12", label: "Largura total" }]}
hint={chart === "tabela" ? "A tabela detalhada usa largura total para mostrar todas as colunas." : "Depois é possível arrastar o quadro e mudar o tamanho pelo cabeçalho."} />
);
}
Object.assign(window, { CustomBoard, NewBoardModal, DashCharts: { CHARTS, Bars, Columns, Lines, Pie, Counters, DemandList, DemandTable } });