Melhora modais e confirmacoes
This commit is contained in:
@@ -9,7 +9,7 @@ function destinatariosLabel(a){return (a.destinatarios||[]).map(x=>x.nome+' ('+x
|
||||
function diasLabel(v){return String(v||'').split(',').filter(x=>x!=='').map(x=>diasNomes[Number(x)]||x).join(', ')||'-'}
|
||||
function formHtml(r={}){
|
||||
const dias=new Set(String(r.dias_semana||'').split(','));
|
||||
return `<form id="responsavel-form" class="grid cols"><input type="hidden" name="id" value="${r.id||''}"><div class="field"><label>Nome</label><input name="nome" required value="${esc(r.nome||'')}"></div><div class="field"><label>WhatsApp</label><input name="telefone" value="${esc(r.telefone||'')}"></div><div class="field"><label>E-mail</label><input name="email" type="email" value="${esc(r.email||'')}"></div><div class="field"><label>Status</label><select name="status"><option value="ativo" ${r.status==='ativo'||!r.status?'selected':''}>Ativo</option><option value="inativo" ${r.status==='inativo'?'selected':''}>Inativo</option></select></div><div class="field"><label>Dias da semana</label><div class="row compact">${diasNomes.map((d,i)=>`<label><input type="checkbox" name="dias" value="${i}" ${dias.has(String(i))?'checked':''}> ${d}</label>`).join('')}</div></div><div class="row"><button class="btn">${r.id?'Salvar':'Cadastrar'}</button><button class="btn secondary" type="button" onclick="fecharResponsavelModal()">Cancelar</button></div></form>`;
|
||||
return `<form id="responsavel-form" class="modal-form"><input type="hidden" name="id" value="${r.id||''}"><div class="form-grid"><div class="field"><label>Nome</label><input name="nome" required value="${esc(r.nome||'')}"></div><div class="field"><label>WhatsApp</label><input name="telefone" value="${esc(r.telefone||'')}"></div><div class="field"><label>E-mail</label><input name="email" type="email" value="${esc(r.email||'')}"></div><div class="field"><label>Status</label><select name="status"><option value="ativo" ${r.status==='ativo'||!r.status?'selected':''}>Ativo</option><option value="inativo" ${r.status==='inativo'?'selected':''}>Inativo</option></select></div><div class="field field-wide"><label>Dias da semana</label><div class="check-grid">${diasNomes.map((d,i)=>`<label><input type="checkbox" name="dias" value="${i}" ${dias.has(String(i))?'checked':''}> ${d}</label>`).join('')}</div></div></div><div class="modal-actions"><button class="btn secondary" type="button" onclick="fecharResponsavelModal()">Cancelar</button><button class="btn">${r.id?'Salvar':'Cadastrar'}</button></div></form>`;
|
||||
}
|
||||
|
||||
function renderAssembleias(){
|
||||
@@ -63,7 +63,7 @@ window.alternarBuscaAssembleias=()=>{
|
||||
window.abrirNovoResponsavel=()=>abrirResponsavel({});
|
||||
window.editarResponsavel=id=>{const r=responsaveis.find(x=>Number(x.id)===Number(id));if(r)abrirResponsavel(r)};
|
||||
window.fecharResponsavelModal=()=>{modal.classList.add('hidden');modalBody.innerHTML=''};
|
||||
window.excluirResponsavel=async id=>{if(!confirm('Excluir este responsável de assembleia?'))return;try{await Api.request('/api/assembleia-responsaveis/'+id,{method:'DELETE'});Util.toast('Responsável excluído');await loadResponsaveis();await load()}catch(e){Util.toast(e.message,true)}};
|
||||
window.excluirResponsavel=async id=>{if(!await Util.confirm('Excluir este responsável de assembleia?','Excluir responsável'))return;try{await Api.request('/api/assembleia-responsaveis/'+id,{method:'DELETE'});Util.toast('Responsável excluído');await loadResponsaveis();await load()}catch(e){Util.toast(e.message,true)}};
|
||||
|
||||
document.querySelector('#assembleia-search-input')?.addEventListener('input',renderAssembleias);
|
||||
if(!Auth.isAdminEmpresa())document.querySelector('[onclick="abrirNovoResponsavel()"]')?.classList.add('hidden');
|
||||
|
||||
@@ -19,7 +19,7 @@ window.fecharCalendarioAssembleias=()=>document.querySelector('#assembleia-calen
|
||||
window.mudarMesCalendario=delta=>{calMonth=new Date(calMonth.getFullYear(),calMonth.getMonth()+delta,1);renderCalendarioAssembleias()};
|
||||
window.selecionarDiaCalendario=(key,mark=true)=>{if(mark)document.querySelectorAll('.calendar-day').forEach(x=>x.classList.toggle('selected',x.dataset.date===key));const list=document.querySelector('#calendar-day-list'),title=document.querySelector('#calendar-day-title'),items=assembleiasCalendario.filter(a=>dateKey(a.data_hora)===key);const [yy,mm,dd]=key.split('-');title.textContent=dd+'/'+mm+'/'+yy;if(!items.length){list.innerHTML='<p class="muted">Nenhuma assembleia agendada neste dia.</p>';return;}list.innerHTML=items.map(a=>{const dest=(a.destinatarios||[]).map(x=>x.nome+' ('+x.tipo+')').join(', ')||'Nenhum destinatário registrado';return '<div class="calendar-event"><strong>'+a.condominio_nome+'</strong><span>'+Util.date(a.data_hora)+'</span><span>'+a.tipo+' - '+(a.local||'-')+'</span><p>'+dest+'</p><div class="row compact"><button class="btn secondary" type="button" onclick="reenviarAvisoAssembleia('+a.condominio_id+','+a.id+')">Reenviar notificação</button><button class="btn danger" type="button" onclick="cancelarAssembleiaCalendario('+a.condominio_id+','+a.id+')">Cancelar assembleia</button></div></div>'}).join('')};
|
||||
window.reenviarAvisoAssembleia=async(cond,aid)=>{try{const a=assembleiasCalendario.find(x=>Number(x.id)===Number(aid));if(!a||!a.aviso_id)throw new Error('Aviso da assembleia não encontrado.');await Api.post('/api/condominios/'+cond+'/avisos/'+a.aviso_id+'/reenviar',{});Util.toast('Notificação reenviada')}catch(e){Util.toast(e.message,true)}};
|
||||
window.cancelarAssembleiaCalendario=async(cond,aid)=>{if(!confirm('Cancelar esta assembleia?'))return;try{await Api.put('/api/condominios/'+cond+'/assembleias/'+aid,{status:'cancelada'});Util.toast('Assembleia cancelada');await abrirCalendarioAssembleias();await loadAssembleias();await load()}catch(e){Util.toast(e.message,true)}};
|
||||
window.cancelarAssembleiaCalendario=async(cond,aid)=>{if(!await Util.confirm('Cancelar esta assembleia?','Cancelar assembleia'))return;try{await Api.put('/api/condominios/'+cond+'/assembleias/'+aid,{status:'cancelada'});Util.toast('Assembleia cancelada');await abrirCalendarioAssembleias();await loadAssembleias();await load()}catch(e){Util.toast(e.message,true)}};
|
||||
function ensureAvisoNotifModal(){let m=document.querySelector('#aviso-notif-modal');if(m)return m;document.body.insertAdjacentHTML('beforeend','<div id="aviso-notif-modal" class="modal hidden"><div class="modal-backdrop" onclick="fecharAvisoNotificacao()"></div><section class="modal-panel"><div class="modal-head"><h2>Notificação</h2><button class="btn secondary" type="button" onclick="fecharAvisoNotificacao()">Fechar</button></div><div id="aviso-notif-body"></div><div class="row"><button class="btn" type="button" onclick="salvarAvisoNotificacao()">Salvar</button><button class="btn secondary" type="button" onclick="fecharAvisoNotificacao()">Cancelar</button></div></section></div>');return document.querySelector('#aviso-notif-modal')}
|
||||
function avisoDestInputs(){return [...document.querySelectorAll('#aviso-dests-hidden input[name=dest]')]}
|
||||
function updateAvisoNotifSummary(){const n=avisoDestInputs().filter(x=>x.checked).length;const el=document.querySelector('#aviso-notif-summary');if(el)el.textContent=n?(n+' selecionado'+(n>1?'s':'')):'Nenhuma pessoa selecionada'}
|
||||
|
||||
@@ -1 +1 @@
|
||||
const form=document.querySelector('#wa-form'),statusEl=document.querySelector('#status'),qr=document.querySelector('#qr'),qrBox=document.querySelector('#qr-box'),pairing=document.querySelector('#pairing'),btnQr=document.querySelector('#btn-qr'),btnReconnect=document.querySelector('#btn-reconnect'),btnDisconnect=document.querySelector('#btn-disconnect');async function load(){try{const d=await Api.get('/api/config/evolution-instancia/status');const i=d.instancia;const evo=d.evolution||{};statusEl.innerHTML=i?`<p>Status aprovacao: ${Util.badge(i.status)}</p><p>Numero: ${i.numero_whatsapp||'-'}</p><p>Conexao: ${Util.badge(evo.state||'-')}</p>`:`<p>Status: ${Util.badge(d.status)}</p>`;const has=i!=null;btnQr.disabled=!has;btnReconnect.disabled=!has;btnDisconnect.disabled=!has}catch(e){Util.toast(e.message,true)}}function showQr(d){qrBox.classList.remove('hidden');const base64=d.qrcode_base64||d.qr_code_base64;if(base64){qr.src=base64.startsWith('data:image/')?base64:'data:image/png;base64,'+base64;qr.classList.remove('hidden')}else{qr.classList.add('hidden');Util.toast('Evolution nao retornou QR Code nesta tentativa',true)}pairing.value=d.pairing_code||''}form.onsubmit=async e=>{e.preventDefault();try{const d=await Api.post('/api/config/evolution-instancia/conectar',Util.formData(form));statusEl.innerHTML=`<p class="success-message">WhatsApp cadastrado com sucesso. Aguarde a liberacao no painel Master.</p><p>Status aprovacao: ${Util.badge(d.status)}</p><p>Instancia: ${d.instance_name}</p>`;showQr(d);Util.toast('WhatsApp cadastrado com sucesso');setTimeout(load,1600)}catch(err){Util.toast(err.message,true)}};btnQr.onclick=async()=>{try{const d=await Api.post('/api/config/evolution-instancia/qrcode',{});showQr(d);Util.toast('QR Code atualizado')}catch(e){Util.toast(e.message,true)}};btnReconnect.onclick=async()=>{try{await Api.post('/api/config/evolution-instancia/reconectar',{});Util.toast('Reconexao solicitada');setTimeout(load,1200)}catch(e){Util.toast(e.message,true)}};btnDisconnect.onclick=async()=>{if(!confirm('Desconectar esta sessao do WhatsApp?'))return;try{await Api.post('/api/config/evolution-instancia/desconectar',{});Util.toast('Sessao desconectada');setTimeout(load,1200)}catch(e){Util.toast(e.message,true)}};load();
|
||||
const form=document.querySelector('#wa-form'),statusEl=document.querySelector('#status'),qr=document.querySelector('#qr'),qrBox=document.querySelector('#qr-box'),pairing=document.querySelector('#pairing'),btnQr=document.querySelector('#btn-qr'),btnReconnect=document.querySelector('#btn-reconnect'),btnDisconnect=document.querySelector('#btn-disconnect');async function load(){try{const d=await Api.get('/api/config/evolution-instancia/status');const i=d.instancia;const evo=d.evolution||{};statusEl.innerHTML=i?`<p>Status aprovacao: ${Util.badge(i.status)}</p><p>Numero: ${i.numero_whatsapp||'-'}</p><p>Conexao: ${Util.badge(evo.state||'-')}</p>`:`<p>Status: ${Util.badge(d.status)}</p>`;const has=i!=null;btnQr.disabled=!has;btnReconnect.disabled=!has;btnDisconnect.disabled=!has}catch(e){Util.toast(e.message,true)}}function showQr(d){qrBox.classList.remove('hidden');const base64=d.qrcode_base64||d.qr_code_base64;if(base64){qr.src=base64.startsWith('data:image/')?base64:'data:image/png;base64,'+base64;qr.classList.remove('hidden')}else{qr.classList.add('hidden');Util.toast('Evolution nao retornou QR Code nesta tentativa',true)}pairing.value=d.pairing_code||''}form.onsubmit=async e=>{e.preventDefault();try{const d=await Api.post('/api/config/evolution-instancia/conectar',Util.formData(form));statusEl.innerHTML=`<p class="success-message">WhatsApp cadastrado com sucesso. Aguarde a liberacao no painel Master.</p><p>Status aprovacao: ${Util.badge(d.status)}</p><p>Instancia: ${d.instance_name}</p>`;showQr(d);Util.toast('WhatsApp cadastrado com sucesso');setTimeout(load,1600)}catch(err){Util.toast(err.message,true)}};btnQr.onclick=async()=>{try{const d=await Api.post('/api/config/evolution-instancia/qrcode',{});showQr(d);Util.toast('QR Code atualizado')}catch(e){Util.toast(e.message,true)}};btnReconnect.onclick=async()=>{try{await Api.post('/api/config/evolution-instancia/reconectar',{});Util.toast('Reconexao solicitada');setTimeout(load,1200)}catch(e){Util.toast(e.message,true)}};btnDisconnect.onclick=async()=>{if(!await Util.confirm('Desconectar esta sessao do WhatsApp?','Desconectar WhatsApp'))return;try{await Api.post('/api/config/evolution-instancia/desconectar',{});Util.toast('Sessao desconectada');setTimeout(load,1200)}catch(e){Util.toast(e.message,true)}};load();
|
||||
|
||||
+103
-6
@@ -664,24 +664,25 @@ th {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 24px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(15, 23, 42, .50);
|
||||
backdrop-filter: blur(2px);
|
||||
background: rgba(15, 23, 42, .56);
|
||||
backdrop-filter: blur(3px);
|
||||
}
|
||||
|
||||
.modal-panel {
|
||||
position: relative;
|
||||
width: min(860px, 100%);
|
||||
width: min(920px, 100%);
|
||||
max-height: calc(100vh - 48px);
|
||||
overflow: auto;
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 18px;
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
@@ -689,8 +690,83 @@ th {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 22px;
|
||||
padding-bottom: 14px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.modal-head h2 {
|
||||
margin: 0;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.modal-head .btn {
|
||||
min-height: 38px;
|
||||
padding: 8px 13px;
|
||||
}
|
||||
|
||||
.modal-form {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.field-wide {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.check-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: var(--panel-muted);
|
||||
}
|
||||
|
||||
.check-grid label,
|
||||
#notif-modal-body label,
|
||||
#aviso-notif-body label {
|
||||
min-height: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.modal-actions .btn {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.confirm-panel {
|
||||
width: min(460px, 100%);
|
||||
}
|
||||
|
||||
.confirm-panel p {
|
||||
margin: 0 0 6px;
|
||||
color: var(--muted-strong);
|
||||
}
|
||||
|
||||
.modal-grid {
|
||||
@@ -1087,10 +1163,15 @@ th {
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.modal-grid {
|
||||
.modal-grid,
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.check-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
|
||||
}
|
||||
|
||||
.modal {
|
||||
padding: 12px;
|
||||
}
|
||||
@@ -1134,12 +1215,28 @@ th {
|
||||
|
||||
.modal-head {
|
||||
align-items: flex-start;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.modal-head .btn {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modal-actions .btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.check-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.calendar-grid {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
window.Util={money(cents){return(Number(cents||0)/100).toLocaleString('pt-BR',{style:'currency',currency:'BRL'})},date(value){return value?new Date(value).toLocaleString('pt-BR'):'-'},toast(message,error){const el=document.createElement('div');el.className='toast'+(error?' error':'');el.textContent=message;document.body.appendChild(el);setTimeout(()=>el.remove(),3600)},formData(form){return Object.fromEntries(new FormData(form).entries())},badge(status){const s=status||'-';const klass=['ativa','ativo','pago','enviado','aprovada'].includes(s)?'ok':(['pendente','bloqueada','falhou'].includes(s)?'warn':'');return `<span class="badge ${klass}">${s}</span>`}};
|
||||
window.Util={money(cents){return(Number(cents||0)/100).toLocaleString('pt-BR',{style:'currency',currency:'BRL'})},date(value){return value?new Date(value).toLocaleString('pt-BR'):'-'},toast(message,error){const el=document.createElement('div');el.className='toast'+(error?' error':'');el.textContent=message;document.body.appendChild(el);setTimeout(()=>el.remove(),3600)},confirm(message,title='Confirmar ação'){return new Promise(resolve=>{const id='confirm-'+Date.now();document.body.insertAdjacentHTML('beforeend',`<div id="${id}" class="modal confirm-modal"><div class="modal-backdrop"></div><section class="modal-panel confirm-panel"><div class="modal-head"><h2>${title}</h2></div><p>${message}</p><div class="modal-actions"><button class="btn secondary" type="button" data-value="false">Cancelar</button><button class="btn danger" type="button" data-value="true">Confirmar</button></div></section></div>`);const el=document.querySelector('#'+id);el.querySelectorAll('button').forEach(b=>b.onclick=()=>{const ok=b.dataset.value==='true';el.remove();resolve(ok)});el.querySelector('.modal-backdrop').onclick=()=>{el.remove();resolve(false)}})},formData(form){return Object.fromEntries(new FormData(form).entries())},badge(status){const s=status||'-';const klass=['ativa','ativo','pago','enviado','aprovada'].includes(s)?'ok':(['pendente','bloqueada','falhou'].includes(s)?'warn':'');return `<span class="badge ${klass}">${s}</span>`}};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const btn=document.querySelector('#backup-btn'),statusEl=document.querySelector('#backup-status');
|
||||
btn.onclick=async()=>{
|
||||
if(!confirm('Gerar backup geral do sistema e de todos os clientes?'))return;
|
||||
if(!await Util.confirm('Gerar backup geral do sistema e de todos os clientes?','Gerar backup'))return;
|
||||
btn.disabled=true;
|
||||
statusEl.textContent='Gerando backup...';
|
||||
try{
|
||||
|
||||
@@ -1 +1 @@
|
||||
const emailForm=document.querySelector('#email-form'),abacateForm=document.querySelector('#abacate-form'),emailRows=document.querySelector('#email-rows'),abacateRows=document.querySelector('#abacate-rows'),evolutionRows=document.querySelector('#evolution-rows');let empresas=[];const emailKeys=['smtp_from','smtp_host','smtp_password','smtp_port','smtp_starttls','smtp_user'];const abacateKeys=['abacatepay_api_key','abacatepay_webhook_secret'];function renderConfig(target,cfg,keys,labels){target.innerHTML=keys.map(k=>`<p><strong>${labels[k]||k}</strong>: ${cfg[k]||''}</p>`).join('')}async function load(){try{const d=await Api.get('/api/master/configuracoes');const cfg=d.configuracoes||{};for(const [k,v] of Object.entries(cfg)){if(emailForm.elements[k])emailForm.elements[k].value=v;if(abacateForm.elements[k])abacateForm.elements[k].value=v}renderConfig(emailRows,cfg,emailKeys,{smtp_from:'Remetente',smtp_host:'Host',smtp_password:'Senha',smtp_port:'Porta',smtp_starttls:'StartTLS',smtp_user:'Usuario'});renderConfig(abacateRows,cfg,abacateKeys,{abacatepay_api_key:'API Key',abacatepay_webhook_secret:'Webhook Secret'});await loadEvolution()}catch(e){Util.toast(e.message,true)}}async function loadEvolution(){const d=await Api.get('/api/master/empresas');empresas=d.empresas||[];const grupos=await Promise.all(empresas.map(async e=>{try{const r=await Api.get(`/api/master/empresas/${e.id}/evolution-instancias`);return (r.instancias||[]).map(i=>({...i,empresa_nome:e.nome}))}catch(_){return[]}}));const instancias=grupos.flat();evolutionRows.innerHTML=instancias.length?instancias.map(i=>`<tr><td>${i.empresa_nome}</td><td>${i.numero_whatsapp||'-'}</td><td>${Util.badge(i.status)}</td><td>${Util.date(i.solicitado_em)}</td><td><button class="btn secondary" onclick="aprovar(${i.empresa_id},${i.id})">Aprovar</button> <button class="btn danger" onclick="rejeitar(${i.empresa_id},${i.id})">Rejeitar</button> <button class="btn danger" onclick="excluir(${i.empresa_id},${i.id})">Excluir</button></td></tr>`).join(''):'<tr><td colspan="5">Nenhuma solicitacao encontrada.</td></tr>'}async function aprovar(emp,id){try{await Api.post(`/api/master/empresas/${emp}/evolution-instancias/${id}/aprovar`,{});Util.toast('Acesso liberado');loadEvolution()}catch(e){Util.toast(e.message,true)}}async function rejeitar(emp,id){try{await Api.post(`/api/master/empresas/${emp}/evolution-instancias/${id}/rejeitar`,{});Util.toast('Acesso rejeitado');loadEvolution()}catch(e){Util.toast(e.message,true)}}async function excluir(emp,id){if(!confirm('Excluir esta conexao de WhatsApp?'))return;try{await Api.request(`/api/master/empresas/${emp}/evolution-instancias/${id}`,{method:'DELETE'});Util.toast('Conexao excluida');loadEvolution()}catch(e){Util.toast(e.message,true)}}emailForm.onsubmit=async e=>{e.preventDefault();try{await Api.put('/api/master/configuracoes',Util.formData(emailForm));Util.toast('Configuracoes de e-mail salvas');load()}catch(err){Util.toast(err.message,true)}};abacateForm.onsubmit=async e=>{e.preventDefault();try{await Api.put('/api/master/configuracoes',Util.formData(abacateForm));Util.toast('Configuracoes AbacatePay salvas');load()}catch(err){Util.toast(err.message,true)}};load();
|
||||
const emailForm=document.querySelector('#email-form'),abacateForm=document.querySelector('#abacate-form'),emailRows=document.querySelector('#email-rows'),abacateRows=document.querySelector('#abacate-rows'),evolutionRows=document.querySelector('#evolution-rows');let empresas=[];const emailKeys=['smtp_from','smtp_host','smtp_password','smtp_port','smtp_starttls','smtp_user'];const abacateKeys=['abacatepay_api_key','abacatepay_webhook_secret'];function renderConfig(target,cfg,keys,labels){target.innerHTML=keys.map(k=>`<p><strong>${labels[k]||k}</strong>: ${cfg[k]||''}</p>`).join('')}async function load(){try{const d=await Api.get('/api/master/configuracoes');const cfg=d.configuracoes||{};for(const [k,v] of Object.entries(cfg)){if(emailForm.elements[k])emailForm.elements[k].value=v;if(abacateForm.elements[k])abacateForm.elements[k].value=v}renderConfig(emailRows,cfg,emailKeys,{smtp_from:'Remetente',smtp_host:'Host',smtp_password:'Senha',smtp_port:'Porta',smtp_starttls:'StartTLS',smtp_user:'Usuario'});renderConfig(abacateRows,cfg,abacateKeys,{abacatepay_api_key:'API Key',abacatepay_webhook_secret:'Webhook Secret'});await loadEvolution()}catch(e){Util.toast(e.message,true)}}async function loadEvolution(){const d=await Api.get('/api/master/empresas');empresas=d.empresas||[];const grupos=await Promise.all(empresas.map(async e=>{try{const r=await Api.get(`/api/master/empresas/${e.id}/evolution-instancias`);return (r.instancias||[]).map(i=>({...i,empresa_nome:e.nome}))}catch(_){return[]}}));const instancias=grupos.flat();evolutionRows.innerHTML=instancias.length?instancias.map(i=>`<tr><td>${i.empresa_nome}</td><td>${i.numero_whatsapp||'-'}</td><td>${Util.badge(i.status)}</td><td>${Util.date(i.solicitado_em)}</td><td><button class="btn secondary" onclick="aprovar(${i.empresa_id},${i.id})">Aprovar</button> <button class="btn danger" onclick="rejeitar(${i.empresa_id},${i.id})">Rejeitar</button> <button class="btn danger" onclick="excluir(${i.empresa_id},${i.id})">Excluir</button></td></tr>`).join(''):'<tr><td colspan="5">Nenhuma solicitacao encontrada.</td></tr>'}async function aprovar(emp,id){try{await Api.post(`/api/master/empresas/${emp}/evolution-instancias/${id}/aprovar`,{});Util.toast('Acesso liberado');loadEvolution()}catch(e){Util.toast(e.message,true)}}async function rejeitar(emp,id){try{await Api.post(`/api/master/empresas/${emp}/evolution-instancias/${id}/rejeitar`,{});Util.toast('Acesso rejeitado');loadEvolution()}catch(e){Util.toast(e.message,true)}}async function excluir(emp,id){if(!await Util.confirm('Excluir esta conexao de WhatsApp?','Excluir conexão'))return;try{await Api.request(`/api/master/empresas/${emp}/evolution-instancias/${id}`,{method:'DELETE'});Util.toast('Conexao excluida');loadEvolution()}catch(e){Util.toast(e.message,true)}}emailForm.onsubmit=async e=>{e.preventDefault();try{await Api.put('/api/master/configuracoes',Util.formData(emailForm));Util.toast('Configuracoes de e-mail salvas');load()}catch(err){Util.toast(err.message,true)}};abacateForm.onsubmit=async e=>{e.preventDefault();try{await Api.put('/api/master/configuracoes',Util.formData(abacateForm));Util.toast('Configuracoes AbacatePay salvas');load()}catch(err){Util.toast(err.message,true)}};load();
|
||||
|
||||
@@ -4,5 +4,5 @@ function periodo(e){return '<strong>'+data(e.data_inicio)+' a '+data(e.data_fim)
|
||||
async function load(){try{const d=await Api.get('/api/master/empresas');const es=d.empresas||[];cards.innerHTML='<div class="stat">Ativas<strong>'+es.filter(e=>e.status==='ativa').length+'</strong></div><div class="stat">Bloqueadas<strong>'+es.filter(e=>e.status==='bloqueada').length+'</strong></div><div class="stat">Pagas<strong>'+es.filter(e=>e.periodo_status==='pago').length+'</strong></div>';rows.innerHTML=es.map(e=>{const bloqueada=e.status==='bloqueada'||e.periodo_status==='bloqueado';const liberar=bloqueada?' <button class="btn" onclick="desbloquear('+e.id+')">Desbloquear</button>':'';return '<tr><td>'+e.nome+'</td><td>'+Util.badge(e.status)+'</td><td>'+periodo(e)+'</td><td><div class="field inline"><label>Dia vencimento</label><input type="number" min="1" max="28" value="'+(e.dia_vencimento||7)+'" onchange="salvarVencimento('+e.id+',this.value)"></div></td><td><button class="btn secondary" onclick="lembrar('+e.id+')">Lembrete</button>'+liberar+'</td></tr>'}).join('')}catch(e){Util.toast(e.message,true)}}
|
||||
async function salvarVencimento(id,dia){try{await Api.put('/api/master/empresas/'+id+'/vencimento',{dia_vencimento:Number(dia)});Util.toast('Vencimento atualizado');load()}catch(e){Util.toast(e.message,true)}}
|
||||
async function lembrar(id){try{await Api.post('/api/master/empresas/'+id+'/lembrete-cobranca',{canal:'email'});Util.toast('Lembrete registrado')}catch(e){Util.toast(e.message,true)}}
|
||||
async function desbloquear(id){if(!confirm('Desbloquear manualmente esta empresa e liberar o periodo atual?'))return;try{await Api.post('/api/master/empresas/'+id+'/desbloquear',{});Util.toast('Empresa desbloqueada');load()}catch(e){Util.toast(e.message,true)}}
|
||||
async function desbloquear(id){if(!await Util.confirm('Desbloquear manualmente esta empresa e liberar o periodo atual?','Desbloquear empresa'))return;try{await Api.post('/api/master/empresas/'+id+'/desbloquear',{});Util.toast('Empresa desbloqueada');load()}catch(e){Util.toast(e.message,true)}}
|
||||
load();
|
||||
|
||||
Reference in New Issue
Block a user