diff --git a/src/main/webapp/cliente/assembleias.js b/src/main/webapp/cliente/assembleias.js index 0a85bac..37fcef9 100644 --- a/src/main/webapp/cliente/assembleias.js +++ b/src/main/webapp/cliente/assembleias.js @@ -12,7 +12,7 @@ function dateKey(v){const d=new Date(v);if(Number.isNaN(d.getTime()))return'';co function monthLabel(d){return d.toLocaleDateString('pt-BR',{month:'long',year:'numeric'})} function formHtml(r={}){ const dias=new Set(String(r.dias_semana||'').split(',')); - return ``; + return ``; } const Icons = { diff --git a/src/main/webapp/cliente/condominio-detalhe.js b/src/main/webapp/cliente/condominio-detalhe.js index f942b06..dc5aea6 100644 --- a/src/main/webapp/cliente/condominio-detalhe.js +++ b/src/main/webapp/cliente/condominio-detalhe.js @@ -28,7 +28,7 @@ window.mudarMesCalendario=delta=>{calMonth=new Date(calMonth.getFullYear(),calMo 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 '
'+a.condominio_nome+''+Util.date(a.data_hora)+''+a.tipo+' - '+(a.local||'-')+'

'+dest+'

'}).join('')}; window.reenviarAvisoAssembleia=async(cond,aid)=>{try{const res=await Api.post('/api/condominios/'+cond+'/assembleias/'+aid+'/notificar',{});if(res&&res.ok===false){Util.toast(res.mensagem||'Falha ao enviar notificação.',true);}else{Util.toast(res?.mensagem||'Notificação enviada com sucesso!');}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','');return document.querySelector('#aviso-notif-modal')} +function ensureAvisoNotifModal(){let m=document.querySelector('#aviso-notif-modal');if(m)return m;document.body.insertAdjacentHTML('beforeend','');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'} window.abrirAvisoNotificacao=()=>{const m=ensureAvisoNotifModal(),ids=new Set(avisoDestInputs().filter(x=>x.checked).map(x=>x.value));const pessoas=[...contatos.map(c=>({value:'contato:'+c.contato_id,nome:c.contato_nome,tipo:c.tipo})),...funcionariosVinculados.map(f=>({value:'funcionario:'+(f.funcionario_id||f.id),nome:f.nome,tipo:'funcionario'})),...extras.map(x=>({value:'extra:'+x.id,nome:x.nome,tipo:'extra'}))];document.querySelector('#aviso-notif-body').innerHTML=pessoas.map(p=>'').join('')||'

Nenhuma pessoa cadastrada.

';m.classList.remove('hidden')}; @@ -44,7 +44,7 @@ function renderContatos(){ document.querySelector('#contatos-search-input')?.addEventListener('input',renderContatos); } window.desvincularContatoDetalhe=async (cid,tipo)=>{if(!await Util.confirm('Deseja desvincular este contato do condomínio?','Desvincular contato'))return;try{await Api.request(`/api/condominios/${id}/contatos/${cid}?tipo=${encodeURIComponent(tipo)}`,{method:'DELETE'});Util.toast('Contato desvinculado');loadContatos();load()}catch(e){Util.toast(e.message,true)}}; -window.abrirNovoContato=()=>{abrirDetailModal('Novo contato','
');document.querySelector('#contato-form').onsubmit=async e=>{e.preventDefault();try{await Api.post(`/api/condominios/${id}/contatos/vincular`,Util.formData(e.target));Util.toast('Contato salvo');fecharDetailModal();loadContatos();load()}catch(err){Util.toast(err.message,true)}}}; +window.abrirNovoContato=()=>{abrirDetailModal('Novo contato','
');document.querySelector('#contato-form').onsubmit=async e=>{e.preventDefault();try{await Api.post(`/api/condominios/${id}/contatos/vincular`,Util.formData(e.target));Util.toast('Contato salvo');fecharDetailModal();loadContatos();load()}catch(err){Util.toast(err.message,true)}}}; async function loadEspacos(){const d=await Api.get(`/api/condominios/${id}/espacos-comuns`);espacos=d.espacos||[];renderEspacos()} function renderEspacos(){ @@ -53,9 +53,9 @@ function renderEspacos(){ document.querySelector('#espacos').innerHTML=headerCadastro('Espaços comuns','espacos','abrirNovoEspaco()')+`
${lista.map(x=>``).join('')||''}
NomeValorÍndiceDescriçãoAções
${esc(x.nome)}${Util.money(x.valor_utilizacao_centavos)}${esc(x.indice_correcao||'')}${esc(x.descricao||'')}
Nenhum espaço encontrado.
`; document.querySelector('#espacos-search-input')?.addEventListener('input',renderEspacos); } -window.abrirEditarEspaco=eid=>{const x=espacos.find(e=>Number(e.id)===Number(eid));if(!x)return;abrirDetailModal('Editar espaço comum','
');document.querySelector('#espaco-edit-form').onsubmit=async e=>{e.preventDefault();try{await Api.put(`/api/condominios/${id}/espacos-comuns/${eid}`,Util.formData(e.target));Util.toast('Espaço atualizado');fecharDetailModal();loadEspacos()}catch(err){Util.toast(err.message,true)}}}; +window.abrirEditarEspaco=eid=>{const x=espacos.find(e=>Number(e.id)===Number(eid));if(!x)return;abrirDetailModal('Editar espaço comum','
');document.querySelector('#espaco-edit-form').onsubmit=async e=>{e.preventDefault();try{await Api.put(`/api/condominios/${id}/espacos-comuns/${eid}`,Util.formData(e.target));Util.toast('Espaço atualizado');fecharDetailModal();loadEspacos()}catch(err){Util.toast(err.message,true)}}}; window.excluirEspacoDetalhe=async eid=>{if(!await Util.confirm('Tem certeza que deseja excluir este espaço comum?','Excluir espaço'))return;try{await Api.request(`/api/condominios/${id}/espacos-comuns/${eid}`,{method:'DELETE'});Util.toast('Espaço excluído');loadEspacos()}catch(err){Util.toast(err.message,true)}}; -window.abrirNovoEspaco=()=>{abrirDetailModal('Novo espaço comum','
');document.querySelector('#espaco-form').onsubmit=async e=>{e.preventDefault();try{await Api.post(`/api/condominios/${id}/espacos-comuns`,Util.formData(e.target));Util.toast('Espaço salvo');fecharDetailModal();loadEspacos()}catch(err){Util.toast(err.message,true)}}}; +window.abrirNovoEspaco=()=>{abrirDetailModal('Novo espaço comum','
');document.querySelector('#espaco-form').onsubmit=async e=>{e.preventDefault();try{await Api.post(`/api/condominios/${id}/espacos-comuns`,Util.formData(e.target));Util.toast('Espaço salvo');fecharDetailModal();loadEspacos()}catch(err){Util.toast(err.message,true)}}}; async function loadAssembleias(){const d=await Api.get(`/api/condominios/${id}/assembleias`);assembleias=d.assembleias||[];renderAssembleias()} function renderAssembleias(){ @@ -66,7 +66,7 @@ function renderAssembleias(){ document.querySelector('#assembleias-search-input')?.addEventListener('input',renderAssembleias); } window.excluirAssembleiaDetalhe=async aid=>{if(!await Util.confirm('Tem certeza que deseja excluir esta assembleia? Esta ação não pode ser desfeita.','Excluir assembleia'))return;try{await Api.request(`/api/condominios/${id}/assembleias/${aid}`,{method:'DELETE'});Util.toast('Assembleia excluída');await loadAssembleias();await load()}catch(err){Util.toast(err.message,true)}}; -window.abrirNovaAssembleia=()=>{abrirDetailModal('Nova assembleia','
');document.querySelector('#ass-form').onsubmit=async e=>{e.preventDefault();try{await Api.post(`/api/condominios/${id}/assembleias`,Util.formData(e.target));Util.toast('Assembleia salva');fecharDetailModal();loadAssembleias();load()}catch(err){Util.toast(err.message,true)}}}; +window.abrirNovaAssembleia=()=>{abrirDetailModal('Nova assembleia','
');document.querySelector('#ass-form').onsubmit=async e=>{e.preventDefault();try{await Api.post(`/api/condominios/${id}/assembleias`,Util.formData(e.target));Util.toast('Assembleia salva');fecharDetailModal();loadAssembleias();load()}catch(err){Util.toast(err.message,true)}}}; async function loadFuncionariosVinculados(){const d=await Api.get(`/api/condominios/${id}/funcionarios-vinculados`);funcionariosVinculados=d.funcionarios||[]} async function loadExtras(){const d=await Api.get(`/api/extras`);extras=(d.extras||[]).filter(x=>x.status==='ativo')} async function loadDocs(){const d=await Api.get(`/api/condominios/${id}/documentos`);docs=d.documentos||[];renderDocs()} @@ -77,9 +77,9 @@ function renderDocs(){ document.querySelector('#documentos-search-input')?.addEventListener('input',renderDocs); } window.excluirDocumentoDetalhe=async did=>{if(!await Util.confirm('Tem certeza que deseja excluir este documento?','Excluir documento'))return;try{await Api.request(`/api/condominios/${id}/documentos/${did}`,{method:'DELETE'});Util.toast('Documento excluído');loadDocs()}catch(err){Util.toast(err.message,true)}}; -window.abrirNovoDocumento=()=>{abrirDetailModal('Novo documento','
');document.querySelector('#doc-form').onsubmit=async e=>{e.preventDefault();const fd=new FormData(e.target);try{await Api.post(`/api/condominios/${id}/documentos`,fd);Util.toast('Documento enviado');fecharDetailModal();loadDocs();loadAvisos()}catch(err){Util.toast(err.message,true)}}}; +window.abrirNovoDocumento=()=>{abrirDetailModal('Novo documento','
');document.querySelector('#doc-form').onsubmit=async e=>{e.preventDefault();const fd=new FormData(e.target);try{await Api.post(`/api/condominios/${id}/documentos`,fd);Util.toast('Documento enviado');fecharDetailModal();loadDocs();loadAvisos()}catch(err){Util.toast(err.message,true)}}}; -function avisoFormHtml(){const destContatos=contatos.map(c=>``).join('');const destFuncionarios=funcionariosVinculados.map(f=>``).join('');const destExtras=extras.map(x=>``).join('');const dest=[destContatos,destFuncionarios,destExtras].filter(Boolean).join('');const docChecks=docs.map(d=>``).join('');return `
Nenhuma pessoa selecionada
${docChecks||'

Nenhum documento.

'}
`} +function avisoFormHtml(){const destContatos=contatos.map(c=>``).join('');const destFuncionarios=funcionariosVinculados.map(f=>``).join('');const destExtras=extras.map(x=>``).join('');const dest=[destContatos,destFuncionarios,destExtras].filter(Boolean).join('');const docChecks=docs.map(d=>``).join('');return `
Nenhuma pessoa selecionada
${docChecks||'

Nenhum documento.

'}
`} async function loadAvisos(){const d=await Api.get(`/api/condominios/${id}/avisos`);avisos=d.avisos||[];renderAvisos()} function renderAvisos(){ const q=termoDetalhe('avisos'); diff --git a/src/main/webapp/cliente/condominios.js b/src/main/webapp/cliente/condominios.js index 6007a0e..49dad62 100644 --- a/src/main/webapp/cliente/condominios.js +++ b/src/main/webapp/cliente/condominios.js @@ -5,7 +5,7 @@ function esc(v){return String(v??'').replace(/[&<>'"]/g,c=>({'&':'&','<':'&l function termo(id){return document.querySelector(id)?.value.trim().toLowerCase()||''} function contem(item,q,campos){return !q||campos.some(c=>String(item[c]??'').toLowerCase().includes(q))} function abrirModal(titulo,html){modalTitle.textContent=titulo;modalBody.innerHTML=html;modal.classList.remove('hidden')} -function formActions(label){return '
'} +function formActions(label){return ``} const Icons = { eye: '', @@ -96,10 +96,9 @@ window.abrirNovoFuncionario=()=>{ function funcionarioPorId(funcId){return funcionarios.find(x=>Number(x.id)===Number(funcId))} window.abrirEditarFuncionario=funcId=>{const f=funcionarioPorId(funcId);if(!f)return;abrirModal('Editar funcionario','
'+formActions('Salvar')+'
');document.querySelector('#func-edit-form').onsubmit=async e=>{e.preventDefault();try{await Api.put('/api/funcionarios/'+funcId,Util.formData(e.target));Util.toast('Funcionario atualizado');fecharModalCondominios();loadFuncionarios()}catch(err){Util.toast(err.message,true)}}}; -window.abrirExcluirFuncionario=funcId=>{const f=funcionarioPorId(funcId);if(!f)return;abrirModal('Excluir funcionario','

Deseja realmente excluir o acesso de '+esc(f.nome||'')+'?

O funcionario sera inativado e perdera acesso ao sistema.

')}; -window.confirmarExcluirFuncionario=async funcId=>{try{await Api.request('/api/funcionarios/'+funcId,{method:'DELETE'});Util.toast('Funcionario inativado');fecharModalCondominios();loadFuncionarios()}catch(err){Util.toast(err.message,true)}}; +window.abrirExcluirFuncionario=async funcId=>{const f=funcionarioPorId(funcId);if(!f)return;if(!await Util.confirm('Deseja realmente excluir o acesso de "'+esc(f.nome||'')+'"? O funcionário será inativado e perderá o acesso ao sistema.','Excluir funcionário'))return;try{await Api.request('/api/funcionarios/'+funcId,{method:'DELETE'});Util.toast('Funcionário inativado');loadFuncionarios()}catch(err){Util.toast(err.message,true)}}; -function renderModalCondominios(){const f=funcionarios.find(x=>Number(x.id)===Number(funcAtual));if(!f)return;const vinculados=funcLinks.get(Number(funcAtual))||[];const vinculadosIds=new Set(vinculados.map(c=>Number(c.id)));const disponiveis=condominios.filter(c=>!vinculadosIds.has(Number(c.id)));modalTitle.textContent=`Condominios de ${f.nome}`;const listaVinculados=vinculados.map(c=>`
${esc(c.nome)}
`).join('')||'

Nenhum condominio vinculado.

';const listaDisponiveis=disponiveis.map(c=>`
${esc(c.nome)}
`).join('')||'

Todos os condominios ja estao vinculados.

';modalBody.innerHTML=``} +function renderModalCondominios(){const f=funcionarios.find(x=>Number(x.id)===Number(funcAtual));if(!f)return;const vinculados=funcLinks.get(Number(funcAtual))||[];const vinculadosIds=new Set(vinculados.map(c=>Number(c.id)));const disponiveis=condominios.filter(c=>!vinculadosIds.has(Number(c.id)));modalTitle.textContent=`Condomínios de ${f.nome}`;const listaVinculados=vinculados.map(c=>`
${esc(c.nome)}
`).join('')||'

Nenhum condomínio vinculado.

';const listaDisponiveis=disponiveis.map(c=>`
${esc(c.nome)}
`).join('')||'

Todos os condomínios já estão vinculados.

';modalBody.innerHTML=``} window.abrirModalCondominios=async funcId=>{funcAtual=Number(funcId);try{await refreshLinks();renderModalCondominios();modal.classList.remove('hidden')}catch(err){Util.toast(err.message,true)}}; window.fecharModalCondominios=()=>{modal.classList.add('hidden');funcAtual=null;modalBody.innerHTML=''}; window.vincularFuncionarioCondominio=async (funcId,condId)=>{try{await Api.post(`/api/condominios/${condId}/funcionarios-vinculados`,{funcionario_id:funcId});Util.toast('Funcionario vinculado');await refreshLinks();renderModalCondominios()}catch(err){Util.toast(err.message,true)}}; diff --git a/src/main/webapp/cliente/lembretes.js b/src/main/webapp/cliente/lembretes.js index c07b0a5..8c6a104 100644 --- a/src/main/webapp/cliente/lembretes.js +++ b/src/main/webapp/cliente/lembretes.js @@ -9,7 +9,7 @@ function selectedDestIds(){return form?new Set([...form.querySelectorAll('input[ function updateNotifSummary(){const n=selectedDestIds().size;const el=document.querySelector('#notif-summary');if(el)el.textContent=n?(n+' selecionado'+(n>1?'s':'')):'Nenhuma pessoa selecionada'} function formHtml(){ - return '
'; + return '
'; } function bindForm(){ @@ -90,7 +90,7 @@ window.alternarBuscaLembretes=()=>{ if(!strip.classList.contains('hidden'))input.focus(); }; -function ensureNotifModal(){let m=document.querySelector('#notif-modal');if(m)return m;document.body.insertAdjacentHTML('beforeend','');return document.querySelector('#notif-modal')} +function ensureNotifModal(){let m=document.querySelector('#notif-modal');if(m)return m;document.body.insertAdjacentHTML('beforeend','');return document.querySelector('#notif-modal')} window.abrirNotificacao=()=>{if(!form)return;const m=ensureNotifModal(),ids=selectedDestIds();document.querySelector('#notif-modal-body').innerHTML=pessoas.map(p=>'').join('')||'

Nenhum funcionario ativo.

';m.classList.remove('hidden')}; window.fecharNotificacao=()=>document.querySelector('#notif-modal')?.classList.add('hidden'); window.salvarNotificacao=()=>{if(!form)return;const ids=new Set([...document.querySelectorAll('#notif-modal-body input:checked')].map(x=>String(x.value)));form.querySelectorAll('input[name=dest]').forEach(x=>x.checked=ids.has(String(x.value)));updateNotifSummary();fecharNotificacao()}; diff --git a/src/main/webapp/css/app.css b/src/main/webapp/css/app.css index 0c1c462..228bf12 100644 --- a/src/main/webapp/css/app.css +++ b/src/main/webapp/css/app.css @@ -853,19 +853,44 @@ th { } .modal-actions { + grid-column: 1 / -1; + width: 100%; display: flex; justify-content: flex-end; align-items: center; gap: 12px; flex-wrap: wrap; - padding-top: 16px; + padding-top: 18px; border-top: 1px solid var(--line); + margin-top: 14px; } .modal-actions .btn { min-width: 120px; } +.modal-panel form.grid.cols, +.modal-panel form.grid { + align-items: start; +} + +.modal-panel form > .row:last-child { + grid-column: 1 / -1; + width: 100%; + display: flex; + justify-content: flex-end; + align-items: center; + gap: 12px; + flex-wrap: wrap; + padding-top: 18px; + border-top: 1px solid var(--line); + margin-top: 14px; +} + +.modal-panel form > .row:last-child .btn { + min-width: 120px; +} + .confirm-panel { width: min(460px, 100%); }