async function pidCreateUsuario(payload) {
return pidApiRequest("/usuarios/", { method: "POST", body: payload });
}
async function pidUpdateUsuario(id, payload) {
return pidApiRequest(`/usuarios/${id}/`, { method: "PATCH", body: payload });
}
async function pidDeleteUsuario(id) {
return pidApiRequest(`/usuarios/${id}/`, { method: "DELETE" });
}
document.addEventListener("DOMContentLoaded", async () => {
const listView = document.getElementById("ua-list-view");
const editView = document.getElementById("ua-edit-view");
if (!listView || !editView) return;
const me = await pidGetMe();
if (!me) return;
if (!me.gerencia_permissoes) {
window.location.href = "portal.html";
return;
}
let users = await pidFetchUsuarios();
let editingId = null;
const tableBody = document.getElementById("ua-table-body");
const footerCount = document.getElementById("ua-footer-count");
const searchInput = document.getElementById("ua-search-input");
const statusFiltros = document.getElementById("ua-status-filtros");
let statusFiltro = "ativos";
const newBtn = document.getElementById("ua-new-btn");
const backBtn = document.getElementById("ua-back-btn");
const cancelBtn = document.getElementById("ua-cancel-btn");
const saveBtn = document.getElementById("ua-save-btn");
const loginInput = document.getElementById("ua-login");
const nomeInput = document.getElementById("ua-nome");
const senhaInput = document.getElementById("ua-senha");
const senhaToggleBtn = document.getElementById("ua-senha-toggle");
const profileChecklist = document.getElementById("ua-profile-checklist");
const formError = document.getElementById("ua-form-error");
const departamentoChecklist = document.getElementById("ua-departamento-checklist");
const departamentoNewInput = document.getElementById("ua-departamento-new");
const departamentoAddBtn = document.getElementById("ua-departamento-add-btn");
const departamentoError = document.getElementById("ua-departamento-error");
const emailInput = document.getElementById("ua-email");
const codigoFolhaInput = document.getElementById("ua-codigo-folha");
const codigoQuestorInput = document.getElementById("ua-codigo-questor");
const codigoTareffaInput = document.getElementById("ua-codigo-tareffa");
const codigoContabitInput = document.getElementById("ua-codigo-contabit");
const ramalInput = document.getElementById("ua-ramal");
const dataAniversarioInput = document.getElementById("ua-data-aniversario");
const ativoInput = document.getElementById("ua-ativo");
const liderancaInput = document.getElementById("ua-lideranca");
const lideradosField = document.getElementById("ua-liderados-field");
const lideradosSearchInput = document.getElementById("ua-liderados-search");
const lideradosSelectAllInput = document.getElementById("ua-liderados-select-all");
const lideradosChecklist = document.getElementById("ua-liderados-checklist");
liderancaInput.addEventListener("change", () => {
lideradosField.hidden = !liderancaInput.checked;
});
pidBindPasswordToggle(senhaToggleBtn, senhaInput);
function profileNomes(perfis) {
return perfis.length ? perfis.map((p) => p.nome).join(", ") : "Sem perfil vinculado";
}
function renderList() {
const term = searchInput.value.trim().toLowerCase();
const rows = users
.filter((u) => statusFiltro === "todos" || (statusFiltro === "ativos") === u.is_active)
.filter((u) => !term || u.nome.toLowerCase().includes(term) || u.username.toLowerCase().includes(term))
.slice()
.sort((a, b) => a.nome.localeCompare(b.nome));
tableBody.innerHTML = rows.length
? rows
.map(
(u) => `
| ${u.username} |
${u.nome} |
${profileNomes(u.perfis)} |
${u.is_active ? "Ativo" : "Inativo"} |
|
`
)
.join("")
: `| Nenhum usuário encontrado. |
`;
footerCount.textContent = `${rows.length} ${rows.length === 1 ? "item" : "itens"}`;
}
async function fillProfileChecklist(selectedCodigos) {
const perfis = (await pidFetchPerfis()).slice().sort((a, b) => a.nome.localeCompare(b.nome));
profileChecklist.innerHTML = perfis
.map(
(p) => `
`
)
.join("");
}
let lideradosCandidatos = [];
let lideradosSelecionados = new Set();
function departamentosTexto(usuario) {
return (usuario.departamentos || []).map((d) => d.nome).join(", ");
}
function lideradosFiltrados() {
const termo = lideradosSearchInput.value.trim().toLowerCase();
return lideradosCandidatos.filter(
(u) => !termo || u.nome.toLowerCase().includes(termo) || departamentosTexto(u).toLowerCase().includes(termo)
);
}
function renderLideradosChecklist() {
const filtrados = lideradosFiltrados();
lideradosChecklist.innerHTML = filtrados.length
? filtrados
.map(
(u) => `
`
)
.join("")
: `Nenhum usuário encontrado.
`;
const todosMarcados = filtrados.length > 0 && filtrados.every((u) => lideradosSelecionados.has(u.id));
const algumMarcado = filtrados.some((u) => lideradosSelecionados.has(u.id));
lideradosSelectAllInput.disabled = filtrados.length === 0;
lideradosSelectAllInput.checked = todosMarcados;
lideradosSelectAllInput.indeterminate = !todosMarcados && algumMarcado;
}
function fillLideradosChecklist(selectedIds, excludeId) {
lideradosCandidatos = users
.filter((u) => u.id !== excludeId)
.slice()
.sort((a, b) => a.nome.localeCompare(b.nome));
lideradosSelecionados = new Set(selectedIds);
lideradosSearchInput.value = "";
renderLideradosChecklist();
}
function selectedLideradosIds() {
return Array.from(lideradosSelecionados);
}
lideradosChecklist.addEventListener("change", (event) => {
const checkbox = event.target.closest('input[type="checkbox"]');
if (!checkbox) return;
const id = Number(checkbox.value);
if (checkbox.checked) lideradosSelecionados.add(id);
else lideradosSelecionados.delete(id);
renderLideradosChecklist();
});
lideradosSearchInput.addEventListener("input", renderLideradosChecklist);
lideradosSelectAllInput.addEventListener("change", () => {
const filtrados = lideradosFiltrados();
if (lideradosSelectAllInput.checked) {
filtrados.forEach((u) => lideradosSelecionados.add(u.id));
} else {
filtrados.forEach((u) => lideradosSelecionados.delete(u.id));
}
renderLideradosChecklist();
});
let departamentosCache = [];
async function fillDepartamentoChecklist(selectedIds) {
departamentosCache = (await pidFetchDepartamentos()).slice().sort((a, b) => a.nome.localeCompare(b.nome));
departamentoChecklist.innerHTML = departamentosCache
.map(
(d) => `
`
)
.join("");
}
function selectedDepartamentoIds() {
return Array.from(departamentoChecklist.querySelectorAll('input[type="checkbox"]:checked')).map((cb) =>
Number(cb.value)
);
}
async function openEdit(id) {
formError.textContent = "";
departamentoError.textContent = "";
departamentoNewInput.value = "";
senhaInput.value = "";
senhaInput.type = "password";
if (senhaToggleBtn) senhaToggleBtn.setAttribute("aria-label", "Mostrar senha");
if (id === null) {
editingId = null;
loginInput.value = "";
nomeInput.value = "";
senhaInput.placeholder = "Digite a senha";
emailInput.value = "";
codigoFolhaInput.value = "";
codigoQuestorInput.value = "";
codigoTareffaInput.value = "";
codigoContabitInput.value = "";
ramalInput.value = "";
dataAniversarioInput.value = "";
ativoInput.checked = true;
ativoInput.disabled = false;
liderancaInput.checked = false;
lideradosField.hidden = true;
await fillProfileChecklist([]);
await fillDepartamentoChecklist([]);
fillLideradosChecklist([], null);
} else {
const account = users.find((u) => u.id === id);
if (!account) return;
editingId = id;
loginInput.value = account.username;
nomeInput.value = account.nome;
senhaInput.placeholder = "Deixe em branco para manter a senha atual";
emailInput.value = account.email || "";
codigoFolhaInput.value = account.codigo_folha || "";
codigoQuestorInput.value = account.codigo_questor || "";
codigoTareffaInput.value = account.codigo_tareffa || "";
codigoContabitInput.value = account.codigo_contabit || "";
ramalInput.value = account.ramal || "";
dataAniversarioInput.value = account.data_aniversario || "";
ativoInput.checked = account.is_active;
ativoInput.disabled = account.id === me.id;
liderancaInput.checked = account.lideranca;
lideradosField.hidden = !account.lideranca;
await fillProfileChecklist(account.perfis.map((p) => p.codigo));
await fillDepartamentoChecklist(account.departamentos.map((d) => d.id));
fillLideradosChecklist(account.liderados.map((u) => u.id), account.id);
}
listView.hidden = true;
editView.hidden = false;
}
function closeEdit() {
editView.hidden = true;
listView.hidden = false;
renderList();
}
searchInput.addEventListener("input", renderList);
statusFiltros.addEventListener("click", (event) => {
const chip = event.target.closest("[data-ua-status]");
if (!chip) return;
statusFiltro = chip.dataset.uaStatus;
statusFiltros.querySelectorAll(".ua-status-chip").forEach((el) => el.classList.toggle("is-active", el === chip));
renderList();
});
newBtn.addEventListener("click", () => openEdit(null));
backBtn.addEventListener("click", closeEdit);
cancelBtn.addEventListener("click", closeEdit);
departamentoAddBtn.addEventListener("click", async () => {
const nome = departamentoNewInput.value.trim();
if (!nome) {
departamentoError.textContent = "Informe o nome do departamento.";
return;
}
departamentoError.textContent = "";
try {
const novo = await pidCreateDepartamento({ nome });
const selected = selectedDepartamentoIds();
selected.push(novo.id);
await fillDepartamentoChecklist(selected);
departamentoNewInput.value = "";
} catch (e) {
departamentoError.textContent = e.message;
}
});
departamentoChecklist.addEventListener("click", async (event) => {
const editBtn = event.target.closest("[data-dep-edit]");
if (editBtn) {
const id = Number(editBtn.getAttribute("data-dep-edit"));
const dep = departamentosCache.find((d) => d.id === id);
if (!dep) return;
const novoNome = window.prompt("Novo nome do departamento:", dep.nome);
if (novoNome === null) return;
const nome = novoNome.trim();
if (!nome) return;
departamentoError.textContent = "";
try {
await pidUpdateDepartamento(id, { nome });
await fillDepartamentoChecklist(selectedDepartamentoIds());
} catch (e) {
departamentoError.textContent = e.message;
}
return;
}
const deleteBtn = event.target.closest("[data-dep-delete]");
if (deleteBtn) {
const id = Number(deleteBtn.getAttribute("data-dep-delete"));
const dep = departamentosCache.find((d) => d.id === id);
if (!dep) return;
if (!window.confirm(`Excluir o departamento "${dep.nome}"?`)) return;
try {
await pidDeleteDepartamento(id);
const selected = selectedDepartamentoIds().filter((depId) => depId !== id);
await fillDepartamentoChecklist(selected);
} catch (e) {
window.alert(e.message);
}
}
});
tableBody.addEventListener("click", async (event) => {
const editTarget = event.target.closest("[data-ua-edit]");
if (editTarget) {
event.preventDefault();
await openEdit(Number(editTarget.getAttribute("data-ua-edit")));
return;
}
const deleteTarget = event.target.closest("[data-ua-delete]");
if (deleteTarget) {
const id = Number(deleteTarget.getAttribute("data-ua-delete"));
if (id === me.id) {
window.alert("Você não pode excluir o usuário com o qual está logado.");
return;
}
const account = users.find((u) => u.id === id);
if (account && window.confirm(`Excluir o usuário "${account.nome}"?`)) {
await pidDeleteUsuario(id);
users = await pidFetchUsuarios();
renderList();
}
return;
}
const toggleTarget = event.target.closest("[data-ua-toggle-active]");
if (toggleTarget) {
const id = Number(toggleTarget.getAttribute("data-ua-toggle-active"));
if (id === me.id) {
window.alert("Você não pode desativar o usuário com o qual está logado.");
return;
}
const account = users.find((u) => u.id === id);
if (!account) return;
const acao = account.is_active ? "Desativar" : "Ativar";
if (window.confirm(`${acao} o usuário "${account.nome}"?`)) {
await pidUpdateUsuario(id, { is_active: !account.is_active });
users = await pidFetchUsuarios();
renderList();
}
}
});
saveBtn.addEventListener("click", async () => {
const username = loginInput.value.trim();
const nome = nomeInput.value.trim();
const senha = senhaInput.value;
const perfis = Array.from(profileChecklist.querySelectorAll('input[type="checkbox"]:checked')).map((cb) =>
Number(cb.value)
);
const departamentos = selectedDepartamentoIds();
const email = emailInput.value.trim();
const codigo_folha = codigoFolhaInput.value.trim();
const codigo_questor = codigoQuestorInput.value.trim();
const codigo_tareffa = codigoTareffaInput.value.trim();
const codigo_contabit = codigoContabitInput.value.trim();
const ramal = ramalInput.value.trim();
const data_aniversario = dataAniversarioInput.value || null;
const lideranca = liderancaInput.checked;
const liderados = selectedLideradosIds();
if (!username || !nome) {
formError.textContent = "Informe login e nome do usuário.";
return;
}
if (editingId === null && !senha) {
formError.textContent = "Informe uma senha para o novo usuário.";
return;
}
formError.textContent = "";
const payload = {
username,
nome,
senha,
perfis,
departamentos,
email,
codigo_folha,
codigo_questor,
codigo_tareffa,
codigo_contabit,
ramal,
data_aniversario,
lideranca,
liderados,
is_active: ativoInput.checked,
};
try {
if (editingId === null) {
await pidCreateUsuario(payload);
} else {
await pidUpdateUsuario(editingId, payload);
}
users = await pidFetchUsuarios();
closeEdit();
} catch (e) {
formError.textContent = e.message;
}
});
renderList();
});