diff --git a/src/main/webapp/cliente/assembleias.js b/src/main/webapp/cliente/assembleias.js index 2bc1e2f..c0d0b2e 100644 --- a/src/main/webapp/cliente/assembleias.js +++ b/src/main/webapp/cliente/assembleias.js @@ -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 `
`; + return ``; } 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'); diff --git a/src/main/webapp/cliente/condominio-detalhe.js b/src/main/webapp/cliente/condominio-detalhe.js index ed21ef0..6e48465 100644 --- a/src/main/webapp/cliente/condominio-detalhe.js +++ b/src/main/webapp/cliente/condominio-detalhe.js @@ -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='Nenhuma assembleia agendada neste dia.
';return;}list.innerHTML=items.map(a=>{const dest=(a.destinatarios||[]).map(x=>x.nome+' ('+x.tipo+')').join(', ')||'Nenhum destinatário registrado';return ''+dest+'
Status aprovacao: ${Util.badge(i.status)}
Numero: ${i.numero_whatsapp||'-'}
Conexao: ${Util.badge(evo.state||'-')}
`:`Status: ${Util.badge(d.status)}
`;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=`Status aprovacao: ${Util.badge(d.status)}
Instancia: ${d.instance_name}
`;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(); \ No newline at end of file +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?`Status aprovacao: ${Util.badge(i.status)}
Numero: ${i.numero_whatsapp||'-'}
Conexao: ${Util.badge(evo.state||'-')}
`:`Status: ${Util.badge(d.status)}
`;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=`Status aprovacao: ${Util.badge(d.status)}
Instancia: ${d.instance_name}
`;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(); diff --git a/src/main/webapp/css/app.css b/src/main/webapp/css/app.css index e5209f7..2bab213 100644 --- a/src/main/webapp/css/app.css +++ b/src/main/webapp/css/app.css @@ -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; } diff --git a/src/main/webapp/js/util.js b/src/main/webapp/js/util.js index e8a04bb..4c71f7a 100644 --- a/src/main/webapp/js/util.js +++ b/src/main/webapp/js/util.js @@ -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 `${s}`}}; \ No newline at end of file +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',`${message}
${labels[k]||k}: ${cfg[k]||''}
`).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=>`${labels[k]||k}: ${cfg[k]||''}
`).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=>`