From 258230f1c46a24d158efee6ce197053af7592905 Mon Sep 17 00:00:00 2001 From: Tiago Date: Sat, 10 Oct 2026 18:06:04 -0300 Subject: [PATCH] feat(master): abrir visualizacao e edicao de clientes em popup e confirmacao para exclusao --- src/main/webapp/master/clientes.html | 85 ++++++++++++++ src/main/webapp/master/clientes.js | 160 ++++++++++++++++++++++++--- 2 files changed, 229 insertions(+), 16 deletions(-) diff --git a/src/main/webapp/master/clientes.html b/src/main/webapp/master/clientes.html index e47d5f5..b1dcc25 100644 --- a/src/main/webapp/master/clientes.html +++ b/src/main/webapp/master/clientes.html @@ -78,6 +78,91 @@ + + + + + + diff --git a/src/main/webapp/master/clientes.js b/src/main/webapp/master/clientes.js index 60fbc49..9c7594c 100644 --- a/src/main/webapp/master/clientes.js +++ b/src/main/webapp/master/clientes.js @@ -1,5 +1,17 @@ -const empresaForm=document.querySelector('#empresa-form'),rows=document.querySelector('#rows'),busca=document.querySelector('#busca'),planoSelect=document.querySelector('#plano-select'),cadastroModal=document.querySelector('#cadastro-modal');let empresas=[],planos=[],modo=null,selecionado=null; -let modoSlugAuto='sequencial'; +const empresaForm = document.querySelector('#empresa-form'); +const rows = document.querySelector('#rows'); +const busca = document.querySelector('#busca'); +const planoSelect = document.querySelector('#plano-select'); +const cadastroModal = document.querySelector('#cadastro-modal'); +const verModal = document.querySelector('#ver-modal'); +const editarModal = document.querySelector('#editar-modal'); +const editarForm = document.querySelector('#editar-form'); + +let empresas = []; +let planos = []; +let clienteVisualizandoId = null; +let clienteEditandoId = null; +let modoSlugAuto = 'sequencial'; const Icons = { edit: '', @@ -13,7 +25,6 @@ function planoOptions(valor){return ''+planos function renderPlanos(){planoSelect.innerHTML=planoOptions('')} function match(e,q){if(!q)return true;return [e.slug,e.nome,e.cnpj,e.status,e.plano,e.api_key].join(' ').toLowerCase().includes(q.toLowerCase())} function statusAction(e){const acao=e.status==='ativa'?'Bloquear':'Ativar';return ``} -function detalheRow(e){if(selecionado!==e.id||!modo)return'';if(modo==='ver')return `

${esc(e.nome)}

Slug: ${esc(e.slug)}

CNPJ: ${esc(e.cnpj||'-')}

Status: ${esc(e.status)}

Plano: ${e.plano?`${esc(e.plano)} ${e.plano_valor_centavos?'- '+Util.money(e.plano_valor_centavos):''}`:'-'}

Conta principal: abra Editar para alterar dados da empresa; funcionarios ficam no acesso da empresa.

`;return `
`} function proximoSlugSequencial(){ const slugsExistentes = new Set(empresas.map(e => String(e.slug || '').trim().toLowerCase())); @@ -67,10 +78,10 @@ function render(){ const q=busca.value.trim(); const lista=empresas.filter(e=>match(e,q)); rows.innerHTML=lista.length?lista.map(e=>` - ${e.slug} - ${e.nome} + ${esc(e.slug)} + ${esc(e.nome)} ${statusAction(e)} - ${e.plano?`${e.plano} ${e.plano_valor_centavos?'- '+Util.money(e.plano_valor_centavos):''}`:'-'} + ${e.plano?`${esc(e.plano)} ${e.plano_valor_centavos?'- '+Util.money(e.plano_valor_centavos):''}`:'-'}
@@ -78,7 +89,7 @@ function render(){
- ${detalheRow(e)}`).join(''):'Nenhum cliente encontrado.'; + `).join(''):'Nenhum cliente encontrado.'; } async function load(){try{const [pe,de]=await Promise.all([Api.get('/api/master/planos'),Api.get('/api/master/empresas')]);planos=pe.planos||[];empresas=de.empresas||[];renderPlanos();render()}catch(e){Util.toast(e.message,true)}} @@ -191,13 +202,130 @@ empresaForm.onsubmit=async e=>{ } }; -busca.oninput=render; -window.ver=id=>{selecionado=selecionado===id&&modo==='ver'?null:id;modo=selecionado?'ver':null;render()}; -window.editar=id=>{selecionado=selecionado===id&&modo==='editar'?null:id;modo=selecionado?'editar':null;render()}; -window.fecharDetalhe=()=>{selecionado=null;modo=null;render()}; -window.copiarApiKey=async id=>{const e=empresas.find(x=>Number(x.id)===Number(id));if(!e?.api_key)return;try{await navigator.clipboard.writeText(e.api_key);Util.toast('API Key copiada')}catch(_){Util.toast('Selecione e copie a API Key manualmente',true)}}; -window.solicitarAlteracaoApiKey=id=>{const e=empresas.find(x=>Number(x.id)===Number(id));Util.toast('Solicitacao de alteracao registrada para '+(e?.nome||'cliente'))}; -window.salvarEdicao=async(ev,id)=>{ev.preventDefault();try{await Api.put(`/api/master/empresas/${id}`,Util.formData(ev.target));Util.toast('Cliente atualizado');selecionado=null;modo=null;load()}catch(err){Util.toast(err.message,true)}}; -window.alterarStatus=async(id,status)=>{try{await Api.post(`/api/master/empresas/${id}/status`,{status});Util.toast(status==='ativa'?'Cliente ativado':'Cliente bloqueado');load()}catch(err){Util.toast(err.message,true)}}; -window.excluir=async id=>{try{await Api.request(`/api/master/empresas/${id}`,{method:'DELETE'});Util.toast('Cliente excluido');selecionado=null;modo=null;load()}catch(err){Util.toast(err.message,true)}}; +busca.oninput = render; + +// Visualização em Popup Modal +window.ver = (id) => { + const emp = empresas.find(x => Number(x.id) === Number(id)); + if (!emp) return; + clienteVisualizandoId = emp.id; + document.querySelector('#ver-modal-titulo').textContent = emp.nome || 'Detalhes do cliente'; + document.querySelector('#ver-slug').value = emp.slug || '-'; + document.querySelector('#ver-nome').value = emp.nome || '-'; + document.querySelector('#ver-cnpj').value = emp.cnpj || '-'; + document.querySelector('#ver-status').innerHTML = Util.badge(emp.status); + document.querySelector('#ver-plano').value = emp.plano ? `${emp.plano} ${emp.plano_valor_centavos ? '- ' + Util.money(emp.plano_valor_centavos) : ''}` : 'Sem plano'; + document.querySelector('#ver-api-key').value = emp.api_key || ''; + verModal?.classList.remove('hidden'); +}; + +window.fecharModalVer = () => { + verModal?.classList.add('hidden'); + clienteVisualizandoId = null; +}; + +window.copiarApiKeyModal = async () => { + const apiKey = document.querySelector('#ver-api-key')?.value; + if (!apiKey) return; + try { + await navigator.clipboard.writeText(apiKey); + Util.toast('API Key copiada com sucesso!'); + } catch (_) { + Util.toast('Selecione e copie a API Key manualmente', true); + } +}; + +window.solicitarAlteracaoApiKeyModal = () => { + const emp = empresas.find(x => Number(x.id) === Number(clienteVisualizandoId)); + Util.toast('Solicitação de alteração registrada para ' + (emp?.nome || 'cliente')); +}; + +window.abrirEditarDeVer = () => { + const id = clienteVisualizandoId; + fecharModalVer(); + if (id) editar(id); +}; + +// Edição em Popup Modal +window.editar = (id) => { + const emp = empresas.find(x => Number(x.id) === Number(id)); + if (!emp) return; + clienteEditandoId = emp.id; + editarForm.reset(); + const errEl = document.querySelector('#editar-modal-error-msg'); + if (errEl) { errEl.textContent = ''; errEl.classList.add('hidden'); } + document.querySelector('#editar-modal-titulo').textContent = `Editar: ${emp.nome}`; + document.querySelector('#editar-id').value = emp.id; + document.querySelector('#editar-slug').value = emp.slug || ''; + document.querySelector('#editar-nome').value = emp.nome || ''; + document.querySelector('#editar-cnpj').value = emp.cnpj || ''; + document.querySelector('#editar-plano-select').innerHTML = planoOptions(emp.plano_id); + editarModal?.classList.remove('hidden'); + document.querySelector('#editar-nome')?.focus(); +}; + +window.fecharModalEditar = () => { + editarModal?.classList.add('hidden'); + clienteEditandoId = null; +}; + +window.salvarEdicaoModal = async (ev) => { + ev.preventDefault(); + if (!clienteEditandoId) return; + try { + const dados = Util.formData(editarForm); + await Api.put(`/api/master/empresas/${clienteEditandoId}`, dados); + Util.toast('Cliente atualizado com sucesso!'); + fecharModalEditar(); + load(); + } catch (err) { + const errEl = document.querySelector('#editar-modal-error-msg'); + if (errEl) { + errEl.textContent = err.message || 'Erro ao atualizar cliente'; + errEl.classList.remove('hidden'); + } + Util.toast(err.message, true); + } +}; + +// Exclusão com confirmação em Popup Modal +window.excluir = async (id) => { + const emp = empresas.find(x => Number(x.id) === Number(id)); + const nome = emp ? ` "${emp.nome}"` : ''; + if (!await Util.confirm(`Tem certeza que deseja excluir o cliente${nome}?`, 'Excluir cliente')) return; + try { + await Api.request(`/api/master/empresas/${id}`, { method: 'DELETE' }); + Util.toast('Cliente excluído com sucesso'); + load(); + } catch (err) { + Util.toast(err.message, true); + } +}; + +window.copiarApiKey = async (id) => { + const e = empresas.find(x => Number(x.id) === Number(id)); + if (!e?.api_key) return; + try { + await navigator.clipboard.writeText(e.api_key); + Util.toast('API Key copiada'); + } catch (_) { + Util.toast('Selecione e copie a API Key manualmente', true); + } +}; + +window.solicitarAlteracaoApiKey = (id) => { + const e = empresas.find(x => Number(x.id) === Number(id)); + Util.toast('Solicitação de alteração registrada para ' + (e?.nome || 'cliente')); +}; + +window.alterarStatus = async (id, status) => { + try { + await Api.post(`/api/master/empresas/${id}/status`, { status }); + Util.toast(status === 'ativa' ? 'Cliente ativado' : 'Cliente bloqueado'); + load(); + } catch (err) { + Util.toast(err.message, true); + } +}; + load();