From b2fba5a441aef8ed36e728675699fa93fd3b256c Mon Sep 17 00:00:00 2001 From: Tiago Date: Fri, 9 Oct 2026 16:50:17 -0300 Subject: [PATCH] Substitui botoes de texto por icones nas secoes de Detalhe do Condominio --- .../tenant/http/ClienteHandlers.java | 5 +- .../webapp/cliente/condominio-detalhe.html | 2 +- src/main/webapp/cliente/condominio-detalhe.js | 58 +++++++++++++++---- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/seconectai/condocontab/tenant/http/ClienteHandlers.java b/src/main/java/com/seconectai/condocontab/tenant/http/ClienteHandlers.java index b02bec0..91a424c 100644 --- a/src/main/java/com/seconectai/condocontab/tenant/http/ClienteHandlers.java +++ b/src/main/java/com/seconectai/condocontab/tenant/http/ClienteHandlers.java @@ -81,11 +81,12 @@ public final class ClienteHandlers implements HttpHandler { if(p.length==3&&"condominios".equals(p[0])&&"funcionarios-vinculados".equals(p[2])){ long cond=id(p[1]); if("POST".equals(method)){ if(!adminEmpresa(cargo)){HttpResponses.json(ex,403,Map.of("erro","acesso_restrito","mensagem","Apenas a conta principal pode vincular funcionarios a condominios."));return;} vincularFuncionario(ex,c,empresaId,cond,funcionarioId); } else if("GET".equals(method)){ if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} listarFuncionariosVinculados(ex,c,empresaId,cond); } else HttpResponses.methodNotAllowed(ex); return; } if(p.length==4&&"condominios".equals(p[0])&&"funcionarios-vinculados".equals(p[2])&&"DELETE".equals(method)){ if(!adminEmpresa(cargo)){HttpResponses.json(ex,403,Map.of("erro","acesso_restrito","mensagem","Apenas a conta principal pode desvincular funcionarios de condominios."));return;} execWrite(ex,c,"DELETE FROM funcionario_condominio WHERE condominio_id=? AND funcionario_id=?",Arrays.asList(id(p[1]),id(p[3])),funcionarioId,"funcionario_condominio",id(p[3])); return; } if(p.length==3&&"condominios".equals(p[0])&&"espacos-comuns".equals(p[2])){ long cond=id(p[1]); if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} if("POST".equals(method)) criarEspaco(ex,c,cond,funcionarioId); else if("GET".equals(method)) listarParam(ex,c,"SELECT * FROM espacos_comuns WHERE condominio_id=? ORDER BY nome",cond,"espacos"); else HttpResponses.methodNotAllowed(ex); return; } - if(p.length==4&&"condominios".equals(p[0])&&"espacos-comuns".equals(p[2])&&"PUT".equals(method)){ long cond=id(p[1]); if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} atualizarEspaco(ex,c,cond,id(p[3]),funcionarioId); return; } + if(p.length==4&&"condominios".equals(p[0])&&"espacos-comuns".equals(p[2])){ long cond=id(p[1]); if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} if("PUT".equals(method)) atualizarEspaco(ex,c,cond,id(p[3]),funcionarioId); else if("DELETE".equals(method)) excluirEspaco(ex,c,cond,id(p[3]),funcionarioId); else HttpResponses.methodNotAllowed(ex); return; } if(p.length==3&&"condominios".equals(p[0])&&"assembleias".equals(p[2])){ long cond=id(p[1]); if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} if("POST".equals(method)) criarAssembleia(ex,c,empresaId,cond,funcionarioId); else if("GET".equals(method)) listarParam(ex,c,"SELECT * FROM assembleias WHERE condominio_id=? ORDER BY data_hora DESC",cond,"assembleias"); else HttpResponses.methodNotAllowed(ex); return; } if(p.length==4&&"condominios".equals(p[0])&&"assembleias".equals(p[2])){ long cond=id(p[1]); if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} if("PUT".equals(method)) atualizarAssembleia(ex,c,empresaId,cond,id(p[3]),funcionarioId); else if("DELETE".equals(method)) excluirAssembleia(ex,c,empresaId,cond,id(p[3]),funcionarioId); else HttpResponses.methodNotAllowed(ex); return; } if(p.length==5&&"condominios".equals(p[0])&&"assembleias".equals(p[2])&&"notificar".equals(p[4])&&"POST".equals(method)){ long cond=id(p[1]); notificarAssembleia(ex,c,empresaId,cond,id(p[3]),funcionarioId); return; } if(p.length==3&&"condominios".equals(p[0])&&"documentos".equals(p[2])){ long cond=id(p[1]); if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} if("POST".equals(method)) uploadDocumento(ex,c,empresaId,cond,funcionarioId); else if("GET".equals(method)) listarParam(ex,c,"SELECT * FROM documentos WHERE condominio_id=? ORDER BY criado_em DESC",cond,"documentos"); else HttpResponses.methodNotAllowed(ex); return; } + if(p.length==4&&"condominios".equals(p[0])&&"documentos".equals(p[2])&&"DELETE".equals(method)){ long cond=id(p[1]); if(!podeAcessarCondominio(c,cargo,funcionarioId,cond)){HttpResponses.json(ex,403,Map.of("erro","condominio_nao_vinculado"));return;} excluirDocumento(ex,c,cond,id(p[3]),funcionarioId); return; } if(p.length==3&&"documentos".equals(p[0])&&"download".equals(p[2])&&"GET".equals(method)){ downloadDocumento(ex,c,id(p[1])); return; } HttpResponses.json(ex,404,Map.of("erro","endpoint_nao_encontrado")); } @@ -114,6 +115,7 @@ public final class ClienteHandlers implements HttpHandler { private void listarFuncionariosVinculados(HttpExchange ex,Connection c,long emp,long cond)throws Exception{List> links=rows(c,"SELECT * FROM funcionario_condominio WHERE condominio_id=? ORDER BY funcionario_id",Arrays.asList(cond));List> out=new ArrayList<>();try(Connection m=masterDs.getMasterConnection();PreparedStatement ps=m.prepareStatement("SELECT id,nome,email,telefone,cargo,status FROM funcionarios WHERE id=? AND empresa_id=?")){for(Map link:links){long func=((Number)link.get("funcionario_id")).longValue();ps.setLong(1,func);ps.setLong(2,emp);try(ResultSet rs=ps.executeQuery()){if(rs.next()){Map item=resultMap(rs);item.put("funcionario_id",func);item.put("condominio_id",cond);out.add(item);}}}}HttpResponses.json(ex,200,Map.of("funcionarios",out));} private void criarEspaco(HttpExchange ex,Connection c,long cond,long fid)throws Exception{Mapb=body(ex); long id=insert(c,"INSERT INTO espacos_comuns (condominio_id,nome,descricao,valor_utilizacao_centavos,indice_correcao) VALUES (?,?,?,?,?)",Arrays.asList(cond,req(b,"nome"),nullable(b.get("descricao")),optLong(b.get("valor_utilizacao_centavos")),nullable(b.get("indice_correcao")))); audit(c,fid,"create","espacos_comuns",id,null,b); HttpResponses.json(ex,201,Map.of("espaco",one(c,"SELECT * FROM espacos_comuns WHERE id=?",Arrays.asList(id))));} private void atualizarEspaco(HttpExchange ex,Connection c,long cond,long eid,long fid)throws Exception{Mapb=body(ex); Map old=one(c,"SELECT * FROM espacos_comuns WHERE id=? AND condominio_id=?",Arrays.asList(eid,cond)); if(old==null){HttpResponses.json(ex,404,Map.of("erro","espaco_nao_encontrado"));return;} Long novo=optLong(b.get("valor_utilizacao_centavos")); try(PreparedStatement ps=c.prepareStatement("UPDATE espacos_comuns SET nome=COALESCE(?,nome), descricao=COALESCE(?,descricao), valor_utilizacao_centavos=COALESCE(?,valor_utilizacao_centavos), indice_correcao=COALESCE(?,indice_correcao), data_ultimo_reajuste=CASE WHEN ? IS NOT NULL AND ?<>valor_utilizacao_centavos THEN current_date ELSE data_ultimo_reajuste END WHERE id=? AND condominio_id=?")){ps.setString(1,b.get("nome"));ps.setString(2,b.get("descricao")); if(novo==null)ps.setNull(3,Types.BIGINT);else ps.setLong(3,novo); ps.setString(4,b.get("indice_correcao")); if(novo==null){ps.setNull(5,Types.BIGINT);ps.setNull(6,Types.BIGINT);}else{ps.setLong(5,novo);ps.setLong(6,novo);} ps.setLong(7,eid);ps.setLong(8,cond);ps.executeUpdate();} audit(c,fid,"update","espacos_comuns",eid,old,b); HttpResponses.json(ex,200,Map.of("espaco",one(c,"SELECT * FROM espacos_comuns WHERE id=?",Arrays.asList(eid))));} + private void excluirEspaco(HttpExchange ex,Connection c,long cond,long eid,long fid)throws Exception{Map old=one(c,"SELECT * FROM espacos_comuns WHERE id=? AND condominio_id=?",Arrays.asList(eid,cond));if(old==null){HttpResponses.json(ex,404,Map.of("erro","espaco_nao_encontrado"));return;}try(PreparedStatement ps=c.prepareStatement("DELETE FROM espacos_comuns WHERE id=? AND condominio_id=?")){ps.setLong(1,eid);ps.setLong(2,cond);ps.executeUpdate();}audit(c,fid,"delete","espacos_comuns",eid,old,Map.of("ok",true));HttpResponses.json(ex,200,Map.of("ok",true));} private void criarAssembleia(HttpExchange ex,Connection c,long emp,long cond,long fid)throws Exception{ String raw=rawBody(ex); Mapb=SimpleJson.parseObject(removeArrayField(raw,"destinatarios")); @@ -291,6 +293,7 @@ public final class ClienteHandlers implements HttpHandler { } private void uploadDocumento(HttpExchange ex,Connection c,long emp,long cond,long fid)throws Exception{Multipart mp=parseMultipart(ex); if(mp.bytes.length>MAX_UPLOAD){HttpResponses.json(ex,400,Map.of("erro","arquivo_muito_grande"));return;} String ext=ext(mp.filename); if(!EXT_OK.contains(ext)){HttpResponses.json(ex,400,Map.of("erro","extensao_nao_permitida"));return;} String db=databaseName(emp); Path dir=uploadRoot.resolve(db).resolve(String.valueOf(cond)); Files.createDirectories(dir); String safe=UUID.randomUUID()+"-"+mp.filename.replaceAll("[^a-zA-Z0-9._-]","_"); Path file=dir.resolve(safe); Files.write(file,mp.bytes); String rel=db+"/"+cond+"/"+safe; long id=insert(c,"INSERT INTO documentos (condominio_id,tipo,nome_arquivo,caminho_armazenamento,enviado_por) VALUES (?,?,?,?,?)",Arrays.asList(cond,nullable(mp.tipo),mp.filename,rel,fid)); audit(c,fid,"create","documentos",id,null,Map.of("nome_arquivo",mp.filename)); HttpResponses.json(ex,201,Map.of("documento",one(c,"SELECT * FROM documentos WHERE id=?",Arrays.asList(id))));} private void downloadDocumento(HttpExchange ex,Connection c,long id)throws Exception{Mapd=one(c,"SELECT * FROM documentos WHERE id=?",Arrays.asList(id)); if(d==null){HttpResponses.json(ex,404,Map.of("erro","documento_nao_encontrado"));return;} Path f=uploadRoot.resolve(String.valueOf(d.get("caminho_armazenamento"))); if(!Files.exists(f)){HttpResponses.json(ex,404,Map.of("erro","arquivo_nao_encontrado"));return;} ex.getResponseHeaders().set("Content-Disposition","attachment; filename=\""+d.get("nome_arquivo")+"\""); ex.sendResponseHeaders(200,Files.size(f)); Files.copy(f,ex.getResponseBody()); ex.close();} + private void excluirDocumento(HttpExchange ex,Connection c,long cond,long did,long fid)throws Exception{Map old=one(c,"SELECT * FROM documentos WHERE id=? AND condominio_id=?",Arrays.asList(did,cond));if(old==null){HttpResponses.json(ex,404,Map.of("erro","documento_nao_encontrado"));return;}try(PreparedStatement ps=c.prepareStatement("DELETE FROM aviso_documentos WHERE documento_id=?")){ps.setLong(1,did);ps.executeUpdate();}try(PreparedStatement ps=c.prepareStatement("DELETE FROM documentos WHERE id=? AND condominio_id=?")){ps.setLong(1,did);ps.setLong(2,cond);ps.executeUpdate();}audit(c,fid,"delete","documentos",did,old,Map.of("ok",true));HttpResponses.json(ex,200,Map.of("ok",true));} private void listarExtras(HttpExchange ex,Connection c)throws Exception{HttpResponses.json(ex,200,Map.of("extras",rows(c,"SELECT * FROM destinatarios_extra WHERE status<>'excluido' ORDER BY nome",Arrays.asList())));} diff --git a/src/main/webapp/cliente/condominio-detalhe.html b/src/main/webapp/cliente/condominio-detalhe.html index 3a8a3bc..0f16fef 100644 --- a/src/main/webapp/cliente/condominio-detalhe.html +++ b/src/main/webapp/cliente/condominio-detalhe.html @@ -1 +1 @@ -Detalhe do Condominio

Detalhe do Condominio

+Detalhe do Condominio

Detalhe do Condominio

diff --git a/src/main/webapp/cliente/condominio-detalhe.js b/src/main/webapp/cliente/condominio-detalhe.js index 81b0b00..507da54 100644 --- a/src/main/webapp/cliente/condominio-detalhe.js +++ b/src/main/webapp/cliente/condominio-detalhe.js @@ -1,7 +1,15 @@ const id=new URLSearchParams(location.search).get('id');const sections=['contatos','espacos','assembleias','documentos','avisos','respostas'];document.querySelectorAll('.nav-tabs button').forEach(b=>b.onclick=()=>{document.querySelectorAll('.nav-tabs button').forEach(x=>x.classList.remove('active'));b.classList.add('active');sections.forEach(s=>document.querySelector('#'+s).classList.toggle('hidden',s!==b.dataset.tab))});let contatos=[],docs=[],avisos=[],respostas=[],funcionariosVinculados=[],extras=[],assembleiasCalendario=[],calMonth=new Date(),espacos=[],assembleias=[];function recLabel(v){return {1:'Mensal',3:'Trimestral',12:'Anual'}[Number(v)]||'Sem recorrencia'} +const Icons = { + add: '', + search: '', + send: '', + edit: '', + trash: '', + download: '' +}; function esc(v){return String(v??'').replace(/[&<>'"]/g,c=>({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c]))} function lupaBtn(fn,label){return ``} -function headerCadastro(titulo,tipo,novoFn,extra=''){const q=esc(termoDetalhe(tipo)),open=document.querySelector(`#${tipo}-search`)&&!document.querySelector(`#${tipo}-search`)?.classList.contains('hidden');return `

${titulo}

${lupaBtn(`alternarBuscaDetalhe('${tipo}')`,'Buscar '+titulo)}${extra}
`} +function headerCadastro(titulo,tipo,novoFn,extra=''){const q=esc(termoDetalhe(tipo)),open=document.querySelector(`#${tipo}-search`)&&!document.querySelector(`#${tipo}-search`)?.classList.contains('hidden');return `

${titulo}

${lupaBtn(`alternarBuscaDetalhe('${tipo}')`,'Buscar '+titulo)}${extra}
`} function headerConsulta(titulo,tipo,extra=''){const q=esc(termoDetalhe(tipo)),open=document.querySelector(`#${tipo}-search`)&&!document.querySelector(`#${tipo}-search`)?.classList.contains('hidden');return `

${titulo}

${extra}${lupaBtn(`alternarBuscaDetalhe('${tipo}')`,'Buscar '+titulo)}
`} function termoDetalhe(tipo){return document.querySelector(`#${tipo}-search-input`)?.value.trim().toLowerCase()||''} function contemDetalhe(q,...vals){return !q||vals.some(v=>String(v??'').toLowerCase().includes(q))} @@ -29,29 +37,59 @@ window.salvarAvisoNotificacao=()=>{const ids=new Set([...document.querySelectorA async function safeLoad(section,fn){try{await fn()}catch(e){document.querySelector('#'+section).innerHTML=`

${e.message}

`;Util.toast(e.message,true)}} async function load(){try{const d=await Api.get(`/api/condominios/${id}`);document.querySelector('#header').innerHTML=`

${d.condominio.nome}

${d.condominio.endereco||''}

Sindico${d.sindico_atual?.contato_nome||'-'}
Assembleias futuras${d.assembleias_futuras||0}
Avisos ativos${d.avisos_ativos||0}
`;await safeLoad('contatos',loadContatos);await safeLoad('avisos',loadFuncionariosVinculados);await safeLoad('avisos',loadExtras);await safeLoad('espacos',loadEspacos);await safeLoad('assembleias',loadAssembleias);await safeLoad('documentos',loadDocs);await safeLoad('avisos',loadAvisos);await safeLoad('respostas',loadRespostas)}catch(e){Util.toast(e.message,true)}} async function loadContatos(){const d=await Api.get(`/api/condominios/${id}/contatos`);contatos=d.contatos||[];renderContatos()} -function renderContatos(){const q=termoDetalhe('contatos');const lista=contatos.filter(c=>contemDetalhe(q,c.contato_nome,c.tipo,c.contato_telefone,c.contato_email));document.querySelector('#contatos').innerHTML=headerCadastro('Contatos','contatos','abrirNovoContato()')+`
${lista.map(c=>``).join('')||''}
NomeTipoTelefoneEmail
${esc(c.contato_nome)}${esc(c.tipo)}${esc(c.contato_telefone||'')}${esc(c.contato_email||'')}
Nenhum contato encontrado.
`;document.querySelector('#contatos-search-input')?.addEventListener('input',renderContatos)} +function renderContatos(){ + const q=termoDetalhe('contatos'); + const lista=contatos.filter(c=>contemDetalhe(q,c.contato_nome,c.tipo,c.contato_telefone,c.contato_email)); + document.querySelector('#contatos').innerHTML=headerCadastro('Contatos','contatos','abrirNovoContato()')+`
${lista.map(c=>``).join('')||''}
NomeTipoTelefoneEmailAções
${esc(c.contato_nome)}${esc(c.tipo)}${esc(c.contato_telefone||'')}${esc(c.contato_email||'')}
Nenhum contato encontrado.
`; + 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)}}}; async function loadEspacos(){const d=await Api.get(`/api/condominios/${id}/espacos-comuns`);espacos=d.espacos||[];renderEspacos()} -function renderEspacos(){const q=termoDetalhe('espacos');const lista=espacos.filter(x=>contemDetalhe(q,x.nome,x.valor_utilizacao_centavos,x.indice_correcao,x.descricao));document.querySelector('#espacos').innerHTML=headerCadastro('Espacos comuns','espacos','abrirNovoEspaco()')+`
${lista.map(x=>``).join('')||''}
NomeValorIndiceDescricao
${esc(x.nome)}${Util.money(x.valor_utilizacao_centavos)}${esc(x.indice_correcao||'')}${esc(x.descricao||'')}
Nenhum espaco encontrado.
`;document.querySelector('#espacos-search-input')?.addEventListener('input',renderEspacos)} -window.abrirNovoEspaco=()=>{abrirDetailModal('Novo espaco 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('Espaco salvo');fecharDetailModal();loadEspacos()}catch(err){Util.toast(err.message,true)}}}; +function renderEspacos(){ + const q=termoDetalhe('espacos'); + const lista=espacos.filter(x=>contemDetalhe(q,x.nome,x.valor_utilizacao_centavos,x.indice_correcao,x.descricao)); + 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.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)}}}; async function loadAssembleias(){const d=await Api.get(`/api/condominios/${id}/assembleias`);assembleias=d.assembleias||[];renderAssembleias()} -function renderAssembleias(){const q=termoDetalhe('assembleias');const lista=assembleias.filter(a=>contemDetalhe(q,a.tipo,a.data_hora,a.local,a.status));const calendar='';document.querySelector('#assembleias').innerHTML=headerCadastro('Assembleias','assembleias','abrirNovaAssembleia()',calendar)+`
${lista.map(a=>``).join('')||''}
TipoDataLocalStatusAções
${esc(a.tipo)}${Util.date(a.data_hora)}${esc(a.local||'')}${Util.badge(a.status)}
Nenhuma assembleia encontrada.
`;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);}}; +function renderAssembleias(){ + const q=termoDetalhe('assembleias'); + const lista=assembleias.filter(a=>contemDetalhe(q,a.tipo,a.data_hora,a.local,a.status)); + const calendar=''; + document.querySelector('#assembleias').innerHTML=headerCadastro('Assembleias','assembleias','abrirNovaAssembleia()',calendar)+`
${lista.map(a=>``).join('')||''}
TipoDataLocalStatusAções
${esc(a.tipo)}${Util.date(a.data_hora)}${esc(a.local||'')}${Util.badge(a.status)}
Nenhuma assembleia encontrada.
`; + 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)}}}; 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()} -function renderDocs(){const q=termoDetalhe('documentos');const lista=docs.filter(d=>contemDetalhe(q,d.id,d.nome_arquivo,d.tipo));document.querySelector('#documentos').innerHTML=headerCadastro('Documentos','documentos','abrirNovoDocumento()')+`
${lista.map(d=>``).join('')||''}
IDArquivoTipoDownload
${d.id}${esc(d.nome_arquivo)}${esc(d.tipo||'')}Baixar
Nenhum documento encontrado.
`;document.querySelector('#documentos-search-input')?.addEventListener('input',renderDocs)} +function renderDocs(){ + const q=termoDetalhe('documentos'); + const lista=docs.filter(d=>contemDetalhe(q,d.id,d.nome_arquivo,d.tipo)); + document.querySelector('#documentos').innerHTML=headerCadastro('Documentos','documentos','abrirNovoDocumento()')+`
${lista.map(d=>``).join('')||''}
IDArquivoTipoAções
${d.id}${esc(d.nome_arquivo)}${esc(d.tipo||'')}
${Icons.download}
Nenhum documento encontrado.
`; + 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)}}}; 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');const lista=avisos.filter(a=>contemDetalhe(q,a.titulo,a.status_envio,a.data_evento,a.data_publicacao,recLabel(a.recorrencia_meses)));document.querySelector('#avisos').innerHTML=headerCadastro('Avisos','avisos','abrirNovoAviso()')+`
${lista.map(a=>``).join('')||''}
TituloStatusEnvioPublicado emRecorrenciaAcoes
${esc(a.titulo)}${Util.badge(a.status_envio)}${Util.date(a.data_evento)}${Util.date(a.data_publicacao)}${recLabel(a.recorrencia_meses)}
Nenhum aviso encontrado.
`;document.querySelector('#avisos-search-input')?.addEventListener('input',renderAvisos)} +function renderAvisos(){ + const q=termoDetalhe('avisos'); + const lista=avisos.filter(a=>contemDetalhe(q,a.titulo,a.status_envio,a.data_evento,a.data_publicacao,recLabel(a.recorrencia_meses))); + document.querySelector('#avisos').innerHTML=headerCadastro('Avisos','avisos','abrirNovoAviso()')+`
${lista.map(a=>``).join('')||''}
TítuloStatusEnvioPublicado emRecorrênciaAções
${esc(a.titulo)}${Util.badge(a.status_envio)}${Util.date(a.data_evento)}${Util.date(a.data_publicacao)}${recLabel(a.recorrencia_meses)}
Nenhum aviso encontrado.
`; + document.querySelector('#avisos-search-input')?.addEventListener('input',renderAvisos); +} window.abrirNovoAviso=()=>{abrirDetailModal('Novo aviso',avisoFormHtml());updateAvisoNotifSummary();document.querySelector('#aviso-form').onsubmit=async e=>{e.preventDefault();const f=e.target,b=Util.formData(f);b.enviar_whatsapp=!!f.enviar_whatsapp.checked;b.enviar_email=!!f.enviar_email.checked;b.destinatarios=[...f.querySelectorAll('input[name=dest]:checked')].map(x=>{const [tipo,did]=x.value.split(':');return{tipo_destinatario:tipo,id:Number(did)}});b.documentos=[...f.querySelectorAll('input[name=doc]:checked')].map(x=>Number(x.value));try{await Api.post(`/api/condominios/${id}/avisos`,b);Util.toast('Aviso criado');fecharDetailModal();loadAvisos();load()}catch(err){Util.toast(err.message,true)}}}; async function loadRespostas(){const d=await Api.get(`/api/condominios/${id}/respostas`);respostas=d.respostas||[];renderRespostas()} function renderRespostas(){const q=termoDetalhe('respostas');const lista=respostas.filter(r=>contemDetalhe(q,r.resposta_texto,r.mensagem_original,r.nome_origem,r.telefone_origem,r.contato_nome,r.mensagem_id,r.origem,r.status,r.tipo_origem));document.querySelector('#respostas').innerHTML=headerConsulta('Respostas','respostas')+`
${lista.map(r=>``).join('')||''}
Recebido emContatoTelefoneMensagem IDRespostaOrigemStatus
${Util.date(r.recebido_em)}${esc(r.contato_nome||r.nome_origem||'-')}
${esc(r.tipo_origem||'')}
${esc(r.contato_telefone||r.telefone_origem||'')}${esc(r.mensagem_id||'')}${esc(r.resposta_texto||'')}
${esc(r.mensagem_original||'')}
${esc(r.origem||'')}${Util.badge(r.status)}
Nenhuma resposta registrada.
`;document.querySelector('#respostas-search-input')?.addEventListener('input',renderRespostas)} -window.reenviarAviso=async avisoId=>{try{await Api.post(`/api/condominios/${id}/avisos/${avisoId}/reenviar`,{});Util.toast('Aviso reenviado');loadAvisos()}catch(err){Util.toast(err.message,true)}}; -window.excluirAviso=async avisoId=>{try{await Api.request(`/api/condominios/${id}/avisos/${avisoId}`,{method:'DELETE'});Util.toast('Aviso excluido');loadAvisos();load()}catch(err){Util.toast(err.message,true)}}; +window.reenviarAviso=async avisoId=>{if(!await Util.confirm('Deseja reenviar este aviso agora?','Reenviar aviso'))return;try{await Api.post(`/api/condominios/${id}/avisos/${avisoId}/reenviar`,{});Util.toast('Aviso reenviado');loadAvisos()}catch(err){Util.toast(err.message,true)}}; +window.excluirAviso=async avisoId=>{if(!await Util.confirm('Tem certeza que deseja excluir este aviso? Esta ação não pode ser desfeita.','Excluir aviso'))return;try{await Api.request(`/api/condominios/${id}/avisos/${avisoId}`,{method:'DELETE'});Util.toast('Aviso excluído');loadAvisos();load()}catch(err){Util.toast(err.message,true)}}; load();