const PID_RAMAL_CHAMADO_URL = "https://depaula-tvcorporativa.lovable.app/chamar?token=4d23bd63-24ff-4d49-9ae9-c87919a71262"; async function pidFetchRamais() { return (await pidApiRequest("/ramais/")) || []; } async function pidFetchUsuariosDisponiveisParaRamal() { return (await pidApiRequest("/ramais/usuarios/")) || []; } async function pidCreateRamal(payload) { return pidApiRequest("/ramais/", { method: "POST", body: payload }); } async function pidUpdateRamal(id, payload) { return pidApiRequest(`/ramais/${id}/`, { method: "PATCH", body: payload }); } async function pidUpdateRamalUsuario(usuarioId, numero) { return pidApiRequest(`/ramais/usuarios/${usuarioId}/`, { method: "PATCH", body: { numero } }); } async function pidDeleteRamal(id) { return pidApiRequest(`/ramais/${id}/`, { method: "DELETE" }); } async function pidCreateRamalAusencia(payload) { return pidApiRequest("/ramais-ausencias/", { method: "POST", body: payload }); } async function pidFetchRamalAusencia(id) { return pidApiRequest(`/ramais-ausencias/${id}/`); } async function pidUpdateRamalAusencia(id, payload) { return pidApiRequest(`/ramais-ausencias/${id}/`, { method: "PATCH", body: payload }); } async function pidDeleteRamalAusencia(id) { return pidApiRequest(`/ramais-ausencias/${id}/`, { method: "DELETE" }); } async function pidFetchTelefonesExternos() { return (await pidApiRequest("/telefones-externos/")) || []; } async function pidCreateTelefoneExterno(payload) { return pidApiRequest("/telefones-externos/", { method: "POST", body: payload }); } async function pidUpdateTelefoneExterno(id, payload) { return pidApiRequest(`/telefones-externos/${id}/`, { method: "PATCH", body: payload }); } async function pidDeleteTelefoneExterno(id) { return pidApiRequest(`/telefones-externos/${id}/`, { method: "DELETE" }); } async function pidFetchFuncoesTelefonia() { return (await pidApiRequest("/funcoes-telefonia/")) || []; } async function pidCreateFuncaoTelefonia(payload) { return pidApiRequest("/funcoes-telefonia/", { method: "POST", body: payload }); } async function pidUpdateFuncaoTelefonia(id, payload) { return pidApiRequest(`/funcoes-telefonia/${id}/`, { method: "PATCH", body: payload }); } async function pidDeleteFuncaoTelefonia(id) { return pidApiRequest(`/funcoes-telefonia/${id}/`, { method: "DELETE" }); } document.addEventListener("DOMContentLoaded", async () => { const tableBody = document.getElementById("ram-table-body"); if (!tableBody) return; const me = await pidGetMe(); if (!me) return; // Cada subtela (aba) de Ramais tem sua própria permissão dedicada — só as 3 com // conteúdo administrável (Ramais, Telefones Externos, Funções de Telefonia) têm // "editar"; Responsável no Tareffa/Férias só têm "visualizar" (são placeholders). const ramalApps = (me.permissoes_efetivas && me.permissoes_efetivas["ramais"] && me.permissoes_efetivas["ramais"].apps) || {}; const ramaisCanView = !!ramalApps["ramais-visualizar"]; const ramaisCanManage = !!ramalApps["ramais-editar"]; const responsavelTareffaCanView = !!ramalApps["responsavel-tareffa-visualizar"]; const telCanView = !!ramalApps["telefones-externos-visualizar"]; const telCanManage = !!ramalApps["telefones-externos-editar"]; const feriasCanView = !!ramalApps["ferias-visualizar"]; const funCanView = !!ramalApps["funcoes-telefonia-visualizar"]; const funCanManage = !!ramalApps["funcoes-telefonia-editar"]; const RAM_TAB_ORDER = ["ramais", "responsavel-tareffa", "telefones-externos", "ferias", "funcoes-telefonia"]; const ramTabViewPerms = { ramais: ramaisCanView, "responsavel-tareffa": responsavelTareffaCanView, "telefones-externos": telCanView, ferias: feriasCanView, "funcoes-telefonia": funCanView, }; const canViewAnyRamTab = RAM_TAB_ORDER.some((key) => ramTabViewPerms[key]); const noAccessEl = document.getElementById("ramais-no-access"); const contentEl = document.getElementById("ramais-content"); if (noAccessEl) noAccessEl.hidden = canViewAnyRamTab; if (contentEl) contentEl.hidden = !canViewAnyRamTab; if (!canViewAnyRamTab) return; const searchNomeInput = document.getElementById("ram-search-nome"); const searchDepartamentoInput = document.getElementById("ram-search-departamento"); const footerCount = document.getElementById("ram-footer-count"); const addBtn = document.getElementById("ram-add-btn"); const ausenciaBtn = document.getElementById("ram-ausencia-btn"); const chamadoBtn = document.getElementById("ram-chamado-btn"); if (addBtn) addBtn.hidden = !ramaisCanManage; if (ausenciaBtn) ausenciaBtn.hidden = !ramaisCanManage; let activeRamTab = RAM_TAB_ORDER.find((key) => ramTabViewPerms[key]) || "ramais"; function renderRamTabs() { document.querySelectorAll("[data-ram-tab]").forEach((tab) => { const key = tab.getAttribute("data-ram-tab"); tab.hidden = !ramTabViewPerms[key]; tab.classList.toggle("is-active", key === activeRamTab); }); document.querySelectorAll("[data-ram-tab-panel]").forEach((panel) => { panel.hidden = panel.getAttribute("data-ram-tab-panel") !== activeRamTab; }); } document.querySelectorAll("[data-ram-tab]").forEach((tab) => { tab.addEventListener("click", () => { activeRamTab = tab.getAttribute("data-ram-tab"); renderRamTabs(); }); }); // Telefones Externos const telSearchNomeInput = document.getElementById("ram-tel-search-nome"); const telSearchObsInput = document.getElementById("ram-tel-search-obs"); const telFooterCount = document.getElementById("ram-tel-footer-count"); const telTableBody = document.getElementById("ram-tel-table-body"); const telAddBtn = document.getElementById("ram-tel-add-btn"); if (telAddBtn) telAddBtn.hidden = !telCanManage; const telFormModal = document.getElementById("telefone-externo-form-modal"); const telFormTitle = document.getElementById("tel-form-title"); const telFormNome = document.getElementById("tel-form-nome"); const telFormRamal = document.getElementById("tel-form-ramal"); const telFormTelefone = document.getElementById("tel-form-telefone"); const telFormObservacoes = document.getElementById("tel-form-observacoes"); const telFormError = document.getElementById("tel-form-error"); const telFormSaveBtn = document.getElementById("tel-form-save-btn"); const telFormCancelBtn = document.getElementById("tel-form-cancel-btn"); let telefonesExternos = []; let editingTelefoneId = null; // Funções de Telefonia const funTableBody = document.getElementById("ram-fun-table-body"); const funFooterCount = document.getElementById("ram-fun-footer-count"); const funAddBtn = document.getElementById("ram-fun-add-btn"); if (funAddBtn) funAddBtn.hidden = !funCanManage; const funFormModal = document.getElementById("funcao-telefonia-form-modal"); const funFormTitle = document.getElementById("fun-form-title"); const funFormComando = document.getElementById("fun-form-comando"); const funFormFuncao = document.getElementById("fun-form-funcao"); const funFormResumo = document.getElementById("fun-form-resumo"); const funFormError = document.getElementById("fun-form-error"); const funFormSaveBtn = document.getElementById("fun-form-save-btn"); const funFormCancelBtn = document.getElementById("fun-form-cancel-btn"); let funcoesTelefonia = []; let editingFuncaoId = null; const formModal = document.getElementById("ramal-form-modal"); const formTitle = document.getElementById("ram-form-title"); const formSubtitle = document.getElementById("ram-form-subtitle"); const formNumero = document.getElementById("ram-form-numero"); const formNome = document.getElementById("ram-form-nome"); const formDepartamento = document.getElementById("ram-form-departamento"); const formError = document.getElementById("ram-form-error"); const formSaveBtn = document.getElementById("ram-form-save-btn"); const formCancelBtn = document.getElementById("ram-form-cancel-btn"); const ausenciaModal = document.getElementById("ramal-ausencia-modal"); const ausUsuario = document.getElementById("ram-aus-usuario"); const ausDataInicio = document.getElementById("ram-aus-data-inicio"); const ausHoraInicio = document.getElementById("ram-aus-hora-inicio"); const ausDataFim = document.getElementById("ram-aus-data-fim"); const ausHoraVolta = document.getElementById("ram-aus-hora-volta"); const ausTipo = document.getElementById("ram-aus-tipo"); const ausObservacoes = document.getElementById("ram-aus-observacoes"); const ausError = document.getElementById("ram-aus-error"); const ausSaveBtn = document.getElementById("ram-aus-save-btn"); const ausCancelBtn = document.getElementById("ram-aus-cancel-btn"); const ausViewModal = document.getElementById("ramal-ausencia-view-modal"); const ausViewTitle = document.getElementById("ram-aus-view-title"); const ausViewCloseBtn = document.getElementById("ram-aus-view-close-btn"); const ausViewUsuario = document.getElementById("ram-aus-view-usuario"); const ausViewDataInicio = document.getElementById("ram-aus-view-data-inicio"); const ausViewHoraInicio = document.getElementById("ram-aus-view-hora-inicio"); const ausViewDataFim = document.getElementById("ram-aus-view-data-fim"); const ausViewHoraVolta = document.getElementById("ram-aus-view-hora-volta"); const ausViewTipo = document.getElementById("ram-aus-view-tipo"); const ausViewObservacoes = document.getElementById("ram-aus-view-observacoes"); const ausViewError = document.getElementById("ram-aus-view-error"); const ausViewActions = document.getElementById("ram-aus-view-actions"); const ausEditActions = document.getElementById("ram-aus-edit-actions"); const ausViewEditBtn = document.getElementById("ram-aus-view-edit-btn"); const ausViewDeleteBtn = document.getElementById("ram-aus-view-delete-btn"); const ausViewCancelEditBtn = document.getElementById("ram-aus-view-cancel-edit-btn"); const ausViewSaveBtn = document.getElementById("ram-aus-view-save-btn"); const chamadoModal = document.getElementById("ramal-chamado-modal"); const chamadoIframe = document.getElementById("ram-chamado-iframe"); const chamadoCloseBtn = document.getElementById("ram-chamado-close-btn"); const msgErroCarga = "Não foi possível carregar. Recarregue a página; se persistir, contate a Inovação."; // Trava o botão (e troca o texto) enquanto a requisição roda, contra // clique duplo; restaura no fim, com sucesso ou erro. async function comTrava(botao, textoOcupado, acao) { const textoOriginal = botao.textContent; botao.disabled = true; if (textoOcupado) botao.textContent = textoOcupado; try { return await acao(); } finally { botao.disabled = false; if (textoOcupado) botao.textContent = textoOriginal; } } // Retrato dos valores de um formulário na abertura, pra só perguntar // "Sair sem salvar" quando algo mudou de fato. function retratoCampos(campos) { return JSON.stringify(campos.map((campo) => campo.value)); } async function podeDescartar(retrato, campos) { if (retrato === null || retratoCampos(campos) === retrato) return true; return pidConfirm("Sair sem salvar as alterações?", { titulo: "Sair sem salvar", textoConfirmar: "Sair sem salvar", perigoso: true, }); } let ramais = []; let usuariosDisponiveis = []; let viewingAusencia = null; let viewingRamalContext = null; // "create" (avulso novo) | "avulso" (editando Ramal existente) | "usuario" (só ajusta o número em Usuario.ramal) let editingMode = "create"; let editingId = null; function usuarioOptionsHtml() { return usuariosDisponiveis.map((u) => ``).join(""); } function rowHtml(ramal) { const ausente = ramal.usuario_ausente; const aniversario = ramal.usuario_aniversariante; const rowClass = aniversario ? "ram-row--aniversario" : ausente ? "ram-row--ausente" : ""; const nomeHtml = aniversario ? `${pidEscapeHtml(ramal.nome_exibicao)} 🎉 Feliz Aniversário` : pidEscapeHtml(ramal.nome_exibicao); const numeroHtml = ramal.numero_exibicao ? pidEscapeHtml(ramal.numero_exibicao) : `Pendente`; const ausenteBadgeHtml = ausente ? `
` : ""; const ramalHtml = `${numeroHtml}${ausenteBadgeHtml}`; const editBtnHtml = ramaisCanManage ? ` ` : ""; const deleteBtnHtml = ramaisCanManage && ramal.tipo === "avulso" ? ` ` : ""; return ` ${nomeHtml} ${pidEscapeHtml(ramal.departamento_exibicao || "—")} ${ramalHtml}
${editBtnHtml}${deleteBtnHtml}
`; } function render() { const termNome = searchNomeInput.value.trim().toLowerCase(); const termDepartamento = searchDepartamentoInput.value.trim().toLowerCase(); const rows = ramais.filter((r) => { const nome = (r.nome_exibicao || "").toLowerCase(); const departamento = (r.departamento_exibicao || "").toLowerCase(); return (!termNome || nome.includes(termNome)) && (!termDepartamento || departamento.includes(termDepartamento)); }); // Lista vazia por filtro não é o mesmo que lista vazia de verdade. const vazio = ramais.length ? "Nenhum resultado para o filtro." : "Nenhum ramal cadastrado ainda."; tableBody.innerHTML = rows.length ? rows.map(rowHtml).join("") : `${vazio}`; if (footerCount) footerCount.textContent = `${rows.length} ${rows.length === 1 ? "item" : "itens"}`; } // Cada aba só busca o que o usuário pode ver (sem permissão a API devolve // 403). Falha vira aviso na própria tabela, nunca "nenhum cadastrado". async function refresh() { if (!ramaisCanView) return; try { const tasks = [pidFetchRamais()]; if (ramaisCanManage) tasks.push(pidFetchUsuariosDisponiveisParaRamal()); const results = await Promise.all(tasks); ramais = results[0] || []; if (ramaisCanManage) usuariosDisponiveis = results[1] || []; } catch (e) { tableBody.innerHTML = `${msgErroCarga}`; if (footerCount) footerCount.textContent = ""; return; } render(); } function telefoneRowHtml(tel) { const editBtnHtml = telCanManage ? ` ` : ""; const deleteBtnHtml = telCanManage ? ` ` : ""; return ` ${pidEscapeHtml(tel.nome)} ${pidEscapeHtml(tel.ramal || "—")} ${pidEscapeHtml(tel.telefone || "—")} ${pidEscapeHtml(tel.observacoes || "—")}
${editBtnHtml}${deleteBtnHtml}
`; } function renderTelefonesExternos() { const termNome = telSearchNomeInput.value.trim().toLowerCase(); const termObs = telSearchObsInput.value.trim().toLowerCase(); const rows = telefonesExternos.filter((tel) => { const nome = (tel.nome || "").toLowerCase(); const obs = (tel.observacoes || "").toLowerCase(); return (!termNome || nome.includes(termNome)) && (!termObs || obs.includes(termObs)); }); const vazio = telefonesExternos.length ? "Nenhum resultado para o filtro." : "Nenhum telefone externo cadastrado ainda."; telTableBody.innerHTML = rows.length ? rows.map(telefoneRowHtml).join("") : `${vazio}`; if (telFooterCount) telFooterCount.textContent = `${rows.length} ${rows.length === 1 ? "item" : "itens"}`; } async function refreshTelefonesExternos() { if (!telCanView || !telTableBody) return; try { telefonesExternos = await pidFetchTelefonesExternos(); } catch (e) { telTableBody.innerHTML = `${msgErroCarga}`; if (telFooterCount) telFooterCount.textContent = ""; return; } renderTelefonesExternos(); } const telCampos = [telFormNome, telFormRamal, telFormTelefone, telFormObservacoes]; let telRetrato = null; function openTelefoneModal(tel) { telFormError.textContent = ""; editingTelefoneId = tel ? tel.id : null; telFormTitle.textContent = tel ? "Editar Telefone Externo" : "Adicionar Telefone Externo"; telFormSaveBtn.textContent = tel ? "Salvar" : "Adicionar"; telFormNome.value = tel ? tel.nome || "" : ""; telFormRamal.value = tel ? tel.ramal || "" : ""; telFormTelefone.value = tel ? tel.telefone || "" : ""; telFormObservacoes.value = tel ? tel.observacoes || "" : ""; telRetrato = retratoCampos(telCampos); telFormModal.hidden = false; } function closeTelefoneModal() { telFormModal.hidden = true; editingTelefoneId = null; telRetrato = null; } async function tentarFecharTelefoneModal() { if (await podeDescartar(telRetrato, telCampos)) closeTelefoneModal(); } function funcaoRowHtml(fun) { const editBtnHtml = funCanManage ? ` ` : ""; const deleteBtnHtml = funCanManage ? ` ` : ""; return ` ${pidEscapeHtml(fun.comando)} ${pidEscapeHtml(fun.funcao)} ${pidEscapeHtml(fun.resumo || "—")}
${editBtnHtml}${deleteBtnHtml}
`; } function renderFuncoesTelefonia() { funTableBody.innerHTML = funcoesTelefonia.length ? funcoesTelefonia.map(funcaoRowHtml).join("") : `Nenhuma função cadastrada ainda.`; if (funFooterCount) { funFooterCount.textContent = `${funcoesTelefonia.length} ${funcoesTelefonia.length === 1 ? "item" : "itens"}`; } } async function refreshFuncoesTelefonia() { if (!funCanView || !funTableBody) return; try { funcoesTelefonia = await pidFetchFuncoesTelefonia(); } catch (e) { funTableBody.innerHTML = `${msgErroCarga}`; if (funFooterCount) funFooterCount.textContent = ""; return; } renderFuncoesTelefonia(); } const funCampos = [funFormComando, funFormFuncao, funFormResumo]; let funRetrato = null; function openFuncaoModal(fun) { funFormError.textContent = ""; editingFuncaoId = fun ? fun.id : null; funFormTitle.textContent = fun ? "Editar Função de Telefonia" : "Adicionar Função de Telefonia"; funFormSaveBtn.textContent = fun ? "Salvar" : "Adicionar"; funFormComando.value = fun ? fun.comando || "" : ""; funFormFuncao.value = fun ? fun.funcao || "" : ""; funFormResumo.value = fun ? fun.resumo || "" : ""; funRetrato = retratoCampos(funCampos); funFormModal.hidden = false; } function closeFuncaoModal() { funFormModal.hidden = true; editingFuncaoId = null; funRetrato = null; } async function tentarFecharFuncaoModal() { if (await podeDescartar(funRetrato, funCampos)) closeFuncaoModal(); } const formCampos = [formNome, formDepartamento, formNumero]; let formRetrato = null; function openFormModal(ramal) { formError.textContent = ""; if (!ramal) { editingMode = "create"; editingId = null; formTitle.textContent = "Adicionar um Novo Ramal"; formSubtitle.hidden = true; formSaveBtn.textContent = "Adicionar"; formNome.value = ""; formDepartamento.value = ""; formNumero.value = ""; formNome.disabled = false; formDepartamento.disabled = false; } else if (ramal.tipo === "usuario") { editingMode = "usuario"; editingId = ramal.usuario_id; formTitle.textContent = "Editar Ramal"; formSubtitle.hidden = false; formSaveBtn.textContent = "Salvar"; formNome.value = ramal.nome_exibicao || ""; formDepartamento.value = ramal.departamento_exibicao || ""; formNumero.value = ramal.numero_exibicao || ""; formNome.disabled = true; formDepartamento.disabled = true; } else { editingMode = "avulso"; editingId = ramal.avulso_id; formTitle.textContent = "Editar Ramal"; formSubtitle.hidden = true; formSaveBtn.textContent = "Salvar"; formNome.value = ramal.nome_exibicao || ""; formDepartamento.value = ramal.departamento_exibicao || ""; formNumero.value = ramal.numero_exibicao || ""; formNome.disabled = false; formDepartamento.disabled = false; } formRetrato = retratoCampos(formCampos); formModal.hidden = false; } function closeFormModal() { formModal.hidden = true; editingId = null; formRetrato = null; } async function tentarFecharFormModal() { if (await podeDescartar(formRetrato, formCampos)) closeFormModal(); } const ausCampos = [ausUsuario, ausDataInicio, ausHoraInicio, ausDataFim, ausHoraVolta, ausTipo, ausObservacoes]; let ausRetrato = null; function openAusenciaModal() { ausError.textContent = ""; // Opção vazia obriga a escolher: antes o primeiro nome vinha marcado // e dava para salvar a ausência na pessoa errada sem perceber. ausUsuario.innerHTML = `${usuarioOptionsHtml()}`; ausUsuario.value = ""; ausDataInicio.value = ""; ausHoraInicio.value = ""; ausDataFim.value = ""; ausHoraVolta.value = ""; ausTipo.value = "Ausência"; ausObservacoes.value = ""; ausRetrato = retratoCampos(ausCampos); ausenciaModal.hidden = false; } function closeAusenciaModal() { ausenciaModal.hidden = true; ausRetrato = null; } async function tentarFecharAusenciaModal() { if (await podeDescartar(ausRetrato, ausCampos)) closeAusenciaModal(); } const ausViewCampos = [ausViewDataInicio, ausViewHoraInicio, ausViewDataFim, ausViewHoraVolta, ausViewTipo, ausViewObservacoes]; // Só existe enquanto a ausência está em modo de edição. let ausViewRetrato = null; function fillAusenciaViewFields(ausencia, ramal) { ausViewUsuario.innerHTML = ``; ausViewDataInicio.value = ausencia.data_inicio || ""; ausViewHoraInicio.value = ausencia.hora_inicio ? ausencia.hora_inicio.slice(0, 5) : ""; ausViewDataFim.value = ausencia.data_fim || ""; ausViewHoraVolta.value = ausencia.hora_volta ? ausencia.hora_volta.slice(0, 5) : ""; ausViewTipo.value = ausencia.tipo || ""; ausViewObservacoes.value = ausencia.observacoes || ""; } function setAusenciaViewMode(mode) { const editing = mode === "edit"; ausViewDataInicio.disabled = !editing; ausViewHoraInicio.disabled = !editing; ausViewDataFim.disabled = !editing; ausViewHoraVolta.disabled = !editing; ausViewTipo.disabled = !editing; ausViewObservacoes.disabled = !editing; ausViewTitle.textContent = editing ? "Editar Ausência" : "Visualizar Ausência"; ausViewActions.hidden = editing; ausEditActions.hidden = !editing; ausViewRetrato = editing ? retratoCampos(ausViewCampos) : null; } async function openAusenciaViewModal(ramal) { ausViewError.textContent = ""; try { viewingAusencia = await pidFetchRamalAusencia(ramal.usuario_ausencia_ativa_id); } catch (e) { await pidAlert(e.message, { titulo: "Não foi possível abrir a ausência" }); return; } viewingRamalContext = ramal; fillAusenciaViewFields(viewingAusencia, ramal); if (ausViewEditBtn) ausViewEditBtn.hidden = !ramaisCanManage; if (ausViewDeleteBtn) ausViewDeleteBtn.hidden = !ramaisCanManage; setAusenciaViewMode("view"); ausViewModal.hidden = false; } function closeAusenciaViewModal() { ausViewModal.hidden = true; viewingAusencia = null; viewingRamalContext = null; ausViewRetrato = null; } async function tentarFecharAusenciaViewModal() { if (await podeDescartar(ausViewRetrato, ausViewCampos)) closeAusenciaViewModal(); } function openChamadoModal() { chamadoIframe.src = PID_RAMAL_CHAMADO_URL; chamadoModal.hidden = false; } function closeChamadoModal() { chamadoModal.hidden = true; chamadoIframe.src = "about:blank"; } if (searchNomeInput) searchNomeInput.addEventListener("input", render); if (searchDepartamentoInput) searchDepartamentoInput.addEventListener("input", render); if (telSearchNomeInput) telSearchNomeInput.addEventListener("input", renderTelefonesExternos); if (telSearchObsInput) telSearchObsInput.addEventListener("input", renderTelefonesExternos); if (telAddBtn) telAddBtn.addEventListener("click", () => openTelefoneModal(null)); if (telFormCancelBtn) telFormCancelBtn.addEventListener("click", tentarFecharTelefoneModal); if (telFormModal) { telFormModal.addEventListener("click", (event) => { if (event.target === telFormModal) tentarFecharTelefoneModal(); }); } if (telFormSaveBtn) { telFormSaveBtn.addEventListener("click", async () => { const nome = telFormNome.value.trim(); if (!nome) { telFormError.textContent = "Informe o nome."; telFormNome.focus(); return; } telFormError.textContent = ""; const payload = { nome, ramal: telFormRamal.value.trim(), telefone: telFormTelefone.value.trim(), observacoes: telFormObservacoes.value.trim(), }; const ocupado = editingTelefoneId ? "Salvando…" : "Adicionando…"; try { await comTrava(telFormSaveBtn, ocupado, async () => { if (editingTelefoneId) { await pidUpdateTelefoneExterno(editingTelefoneId, payload); } else { await pidCreateTelefoneExterno(payload); } }); closeTelefoneModal(); await refreshTelefonesExternos(); } catch (e) { telFormError.textContent = e.message; } }); } if (telTableBody) { telTableBody.addEventListener("click", async (event) => { const editBtn = event.target.closest("[data-tel-edit]"); if (editBtn) { const id = Number(editBtn.getAttribute("data-tel-edit")); const tel = telefonesExternos.find((t) => t.id === id); if (tel) openTelefoneModal(tel); return; } const deleteBtn = event.target.closest("[data-tel-delete]"); if (deleteBtn) { const id = Number(deleteBtn.getAttribute("data-tel-delete")); const tel = telefonesExternos.find((t) => t.id === id); if (tel && (await pidConfirm(`Remover o telefone de "${tel.nome}"?`, { perigoso: true }))) { try { await comTrava(deleteBtn, null, () => pidDeleteTelefoneExterno(id)); } catch (e) { await pidAlert(e.message, { titulo: "Não foi possível remover o telefone" }); return; } await refreshTelefonesExternos(); } } }); } if (funAddBtn) funAddBtn.addEventListener("click", () => openFuncaoModal(null)); if (funFormCancelBtn) funFormCancelBtn.addEventListener("click", tentarFecharFuncaoModal); if (funFormModal) { funFormModal.addEventListener("click", (event) => { if (event.target === funFormModal) tentarFecharFuncaoModal(); }); } if (funFormSaveBtn) { funFormSaveBtn.addEventListener("click", async () => { const comando = funFormComando.value.trim(); if (!comando) { funFormError.textContent = "Informe o comando."; funFormComando.focus(); return; } funFormError.textContent = ""; const payload = { comando, funcao: funFormFuncao.value.trim(), resumo: funFormResumo.value.trim(), }; const ocupado = editingFuncaoId ? "Salvando…" : "Adicionando…"; try { await comTrava(funFormSaveBtn, ocupado, async () => { if (editingFuncaoId) { await pidUpdateFuncaoTelefonia(editingFuncaoId, payload); } else { await pidCreateFuncaoTelefonia(payload); } }); closeFuncaoModal(); await refreshFuncoesTelefonia(); } catch (e) { funFormError.textContent = e.message; } }); } if (funTableBody) { funTableBody.addEventListener("click", async (event) => { const editBtn = event.target.closest("[data-fun-edit]"); if (editBtn) { const id = Number(editBtn.getAttribute("data-fun-edit")); const fun = funcoesTelefonia.find((f) => f.id === id); if (fun) openFuncaoModal(fun); return; } const deleteBtn = event.target.closest("[data-fun-delete]"); if (deleteBtn) { const id = Number(deleteBtn.getAttribute("data-fun-delete")); const fun = funcoesTelefonia.find((f) => f.id === id); if (fun && (await pidConfirm(`Remover a função "${fun.comando}"?`, { perigoso: true }))) { try { await comTrava(deleteBtn, null, () => pidDeleteFuncaoTelefonia(id)); } catch (e) { await pidAlert(e.message, { titulo: "Não foi possível remover a função" }); return; } await refreshFuncoesTelefonia(); } } }); } if (addBtn) addBtn.addEventListener("click", () => openFormModal(null)); if (formCancelBtn) formCancelBtn.addEventListener("click", tentarFecharFormModal); if (formModal) { formModal.addEventListener("click", (event) => { if (event.target === formModal) tentarFecharFormModal(); }); } if (formSaveBtn) { formSaveBtn.addEventListener("click", async () => { const nome = formNome.value.trim(); const departamento = formDepartamento.value.trim(); const numero = formNumero.value.trim(); if (editingMode !== "usuario" && !nome) { formError.textContent = "Informe o nome."; formNome.focus(); return; } formError.textContent = ""; const ocupado = editingMode === "create" ? "Adicionando…" : "Salvando…"; try { await comTrava(formSaveBtn, ocupado, async () => { if (editingMode === "usuario") { await pidUpdateRamalUsuario(editingId, numero); } else if (editingMode === "avulso") { await pidUpdateRamal(editingId, { nome, departamento, numero }); } else { await pidCreateRamal({ nome, departamento, numero }); } }); closeFormModal(); await refresh(); } catch (e) { formError.textContent = e.message; } }); } if (ausenciaBtn) ausenciaBtn.addEventListener("click", openAusenciaModal); if (ausCancelBtn) ausCancelBtn.addEventListener("click", tentarFecharAusenciaModal); if (ausenciaModal) { ausenciaModal.addEventListener("click", (event) => { if (event.target === ausenciaModal) tentarFecharAusenciaModal(); }); } if (ausSaveBtn) { ausSaveBtn.addEventListener("click", async () => { const usuarioId = ausUsuario.value ? Number(ausUsuario.value) : null; const dataInicio = ausDataInicio.value; const dataFim = ausDataFim.value; // Mensagem e cursor no primeiro campo que falta. if (!usuarioId) { ausError.textContent = "Selecione o usuário."; ausUsuario.focus(); return; } if (!dataInicio) { ausError.textContent = "Informe a data inicial."; ausDataInicio.focus(); return; } if (!dataFim) { ausError.textContent = "Informe a data final."; ausDataFim.focus(); return; } ausError.textContent = ""; const payload = { usuario: usuarioId, data_inicio: dataInicio, hora_inicio: ausHoraInicio.value || null, data_fim: dataFim, hora_volta: ausHoraVolta.value || null, tipo: ausTipo.value.trim() || "Ausência", observacoes: ausObservacoes.value.trim(), }; try { await comTrava(ausSaveBtn, "Salvando…", () => pidCreateRamalAusencia(payload)); closeAusenciaModal(); await refresh(); } catch (e) { ausError.textContent = e.message; } }); } if (ausViewCloseBtn) ausViewCloseBtn.addEventListener("click", tentarFecharAusenciaViewModal); if (ausViewModal) { ausViewModal.addEventListener("click", (event) => { if (event.target === ausViewModal) tentarFecharAusenciaViewModal(); }); } if (ausViewEditBtn) ausViewEditBtn.addEventListener("click", () => setAusenciaViewMode("edit")); if (ausViewCancelEditBtn) { ausViewCancelEditBtn.addEventListener("click", async () => { if (!(await podeDescartar(ausViewRetrato, ausViewCampos))) return; fillAusenciaViewFields(viewingAusencia, viewingRamalContext); setAusenciaViewMode("view"); }); } if (ausViewSaveBtn) { ausViewSaveBtn.addEventListener("click", async () => { const dataInicio = ausViewDataInicio.value; const dataFim = ausViewDataFim.value; if (!dataInicio || !dataFim) { ausViewError.textContent = "Informe as datas inicial e final."; (dataInicio ? ausViewDataFim : ausViewDataInicio).focus(); return; } ausViewError.textContent = ""; const payload = { data_inicio: dataInicio, hora_inicio: ausViewHoraInicio.value || null, data_fim: dataFim, hora_volta: ausViewHoraVolta.value || null, tipo: ausViewTipo.value.trim() || "Ausência", observacoes: ausViewObservacoes.value.trim(), }; try { await comTrava(ausViewSaveBtn, "Salvando…", () => pidUpdateRamalAusencia(viewingAusencia.id, payload)); closeAusenciaViewModal(); await refresh(); } catch (e) { ausViewError.textContent = e.message; } }); } if (ausViewDeleteBtn) { ausViewDeleteBtn.addEventListener("click", async () => { if (!(await pidConfirm("Deletar esta ausência?", { perigoso: true }))) return; try { await comTrava(ausViewDeleteBtn, null, () => pidDeleteRamalAusencia(viewingAusencia.id)); closeAusenciaViewModal(); await refresh(); } catch (e) { await pidAlert(e.message, { titulo: "Não foi possível deletar a ausência" }); } }); } if (chamadoBtn) chamadoBtn.addEventListener("click", openChamadoModal); if (chamadoCloseBtn) chamadoCloseBtn.addEventListener("click", closeChamadoModal); if (chamadoModal) { chamadoModal.addEventListener("click", (event) => { if (event.target === chamadoModal) closeChamadoModal(); }); } tableBody.addEventListener("click", async (event) => { const editBtn = event.target.closest("[data-ram-edit]"); if (editBtn) { const id = editBtn.getAttribute("data-ram-edit"); const ramal = ramais.find((r) => r.id === id); if (ramal) openFormModal(ramal); return; } const deleteBtn = event.target.closest("[data-ram-delete]"); if (deleteBtn) { const avulsoId = Number(deleteBtn.getAttribute("data-ram-delete")); const ramal = ramais.find((r) => r.avulso_id === avulsoId); if (ramal && (await pidConfirm(`Remover o ramal de "${ramal.nome_exibicao}"?`, { perigoso: true }))) { try { await comTrava(deleteBtn, null, () => pidDeleteRamal(avulsoId)); } catch (e) { await pidAlert(e.message, { titulo: "Não foi possível remover o ramal" }); return; } await refresh(); } return; } const verAusenciaBtn = event.target.closest("[data-ram-ver-ausencia]"); if (verAusenciaBtn) { const id = Number(verAusenciaBtn.getAttribute("data-ram-ver-ausencia")); const ramal = ramais.find((r) => r.usuario_ausencia_ativa_id === id); if (ramal) await openAusenciaViewModal(ramal); } }); renderRamTabs(); await Promise.all([refresh(), refreshTelefonesExternos(), refreshFuncoesTelefonia()]); });