portal_publico/static/js/ramais-lookup.js
2026-09-25 15:45:38 -03:00

206 lines
7.0 KiB
JavaScript

document.addEventListener("DOMContentLoaded", async () => {
const openBtn = document.getElementById("ramais-btn");
const modal = document.getElementById("ramais-lookup-modal");
if (!openBtn || !modal) return;
const me = await pidGetMe();
if (!me) return;
const ramalPerms = (me.permissoes_efetivas && me.permissoes_efetivas["ramais"]) || {};
const canView = !!(ramalPerms.apps && ramalPerms.apps["ramais-visualizar"]);
if (!canView) {
openBtn.hidden = true;
return;
}
const closeBtn = document.getElementById("ramais-lookup-close-btn");
const closeBtn2 = document.getElementById("ramais-lookup-close-btn-2");
const searchInput = document.getElementById("ramais-lookup-search");
const pageSizeSelect = document.getElementById("ramais-lookup-pagesize");
const deptoFiltrosEl = document.getElementById("ramais-lookup-depto-filters");
const tableBody = document.getElementById("ramais-lookup-table-body");
const countEl = document.getElementById("ramais-lookup-count");
const paginationEl = document.getElementById("ramais-lookup-pagination");
const sortHeaders = Array.from(modal.querySelectorAll("th[data-sort]"));
const FIELD_BY_SORT_KEY = { nome: "nome_exibicao", departamento: "departamento_exibicao", numero: "numero_exibicao" };
let ramais = null; // carregado sob demanda na primeira abertura
let departamentos = null; // idem — alimenta os botões de filtro, um por departamento cadastrado
let activeDepto = ""; // "" = "Todos"
let sortKey = "nome";
let sortDir = 1;
let page = 1;
function renderDeptoFilters() {
const botoes = [`<button type="button" class="ram-lookup-depto-btn${activeDepto === "" ? " is-active" : ""}" data-depto="">Todos</button>`].concat(
departamentos.map(
(d) =>
`<button type="button" class="ram-lookup-depto-btn${activeDepto === d.nome ? " is-active" : ""}" data-depto="${pidEscapeHtml(d.nome)}">${pidEscapeHtml(d.nome)}</button>`
)
);
deptoFiltrosEl.innerHTML = botoes.join("");
}
function pageWindow(current, total) {
const delta = 1;
const middle = [];
for (let i = Math.max(2, current - delta); i <= Math.min(total - 1, current + delta); i++) {
middle.push(i);
}
const pages = [1];
if (middle[0] > 2) pages.push("...");
pages.push(...middle);
if (middle[middle.length - 1] < total - 1) pages.push("...");
if (total > 1) pages.push(total);
return pages;
}
function filteredSorted() {
const term = searchInput.value.trim().toLowerCase();
const field = FIELD_BY_SORT_KEY[sortKey];
let rows = ramais.filter((r) => {
if (activeDepto) {
const deptos = (r.departamento_exibicao || "").split(",").map((s) => s.trim());
if (!deptos.includes(activeDepto)) return false;
}
if (!term) return true;
return [r.nome_exibicao, r.departamento_exibicao, r.numero_exibicao].some((v) => (v || "").toLowerCase().includes(term));
});
rows.sort((a, b) => {
const av = (a[field] || "").toString().toLowerCase();
const bv = (b[field] || "").toString().toLowerCase();
if (av < bv) return -1 * sortDir;
if (av > bv) return 1 * sortDir;
return 0;
});
return rows;
}
function renderPagination(totalPages) {
if (totalPages <= 1) {
paginationEl.innerHTML = "";
return;
}
const parts = [];
parts.push(`<button type="button" class="ram-lookup-page-btn" data-page="${page - 1}" ${page === 1 ? "disabled" : ""}>Anterior</button>`);
pageWindow(page, totalPages).forEach((p) => {
if (p === "...") {
parts.push(`<span class="ram-lookup-page-ellipsis">…</span>`);
} else {
parts.push(`<button type="button" class="ram-lookup-page-btn${p === page ? " is-active" : ""}" data-page="${p}">${p}</button>`);
}
});
parts.push(
`<button type="button" class="ram-lookup-page-btn" data-page="${page + 1}" ${page === totalPages ? "disabled" : ""}>Próxima</button>`
);
paginationEl.innerHTML = parts.join("");
}
function render() {
sortHeaders.forEach((th) => {
th.classList.toggle("is-sort-asc", th.dataset.sort === sortKey && sortDir === 1);
th.classList.toggle("is-sort-desc", th.dataset.sort === sortKey && sortDir === -1);
});
const rows = filteredSorted();
const pageSize = Number(pageSizeSelect.value);
const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
page = Math.min(page, totalPages);
const start = (page - 1) * pageSize;
const pageRows = rows.slice(start, start + pageSize);
tableBody.innerHTML = pageRows.length
? pageRows
.map(
(r) => `
<tr>
<td>${pidEscapeHtml(r.nome_exibicao)}</td>
<td>${pidEscapeHtml(r.departamento_exibicao || "—")}</td>
<td>${pidEscapeHtml(r.numero_exibicao || "—")}</td>
</tr>`
)
.join("")
: `<tr class="ram-lookup-empty-row"><td colspan="3">Nenhum ramal encontrado.</td></tr>`;
const from = rows.length === 0 ? 0 : start + 1;
const to = Math.min(start + pageSize, rows.length);
countEl.textContent = `Mostrando ${from} a ${to} de ${rows.length} registros`;
renderPagination(totalPages);
}
async function openModal() {
modal.hidden = false;
if (!ramais) {
tableBody.innerHTML = `<tr class="ram-lookup-empty-row"><td colspan="3">Carregando...</td></tr>`;
try {
const [ramaisResp, departamentosResp] = await Promise.all([
pidApiRequest("/ramais/"),
pidApiRequest("/departamentos-resumo/"),
]);
ramais = ramaisResp || [];
departamentos = departamentosResp || [];
} catch (e) {
ramais = [];
departamentos = [];
}
renderDeptoFilters();
}
page = 1;
render();
}
function closeModal() {
modal.hidden = true;
}
openBtn.addEventListener("click", openModal);
if (closeBtn) closeBtn.addEventListener("click", closeModal);
if (closeBtn2) closeBtn2.addEventListener("click", closeModal);
modal.addEventListener("click", (event) => {
if (event.target === modal) closeModal();
});
searchInput.addEventListener("input", () => {
page = 1;
render();
});
deptoFiltrosEl.addEventListener("click", (event) => {
const btn = event.target.closest("[data-depto]");
if (!btn) return;
activeDepto = btn.getAttribute("data-depto");
renderDeptoFilters();
page = 1;
render();
});
pageSizeSelect.addEventListener("change", () => {
page = 1;
render();
});
sortHeaders.forEach((th) => {
th.addEventListener("click", () => {
const key = th.dataset.sort;
if (sortKey === key) {
sortDir *= -1;
} else {
sortKey = key;
sortDir = 1;
}
page = 1;
render();
});
});
paginationEl.addEventListener("click", (event) => {
const btn = event.target.closest("[data-page]");
if (!btn || btn.disabled) return;
const target = Number(btn.getAttribute("data-page"));
if (!target || target < 1) return;
page = target;
render();
});
});