diff --git a/src/main/webapp/cliente/condominios.html b/src/main/webapp/cliente/condominios.html
index 9b8a51a..ca51502 100644
--- a/src/main/webapp/cliente/condominios.html
+++ b/src/main/webapp/cliente/condominios.html
@@ -1 +1 @@
-
CadastroCadastro
Funcionarios
| Nome | E-mail | Telefone | Cargo | Status | Condominios | Opcoes |
|---|
\ No newline at end of file
+CadastroCadastro
diff --git a/src/main/webapp/cliente/condominios.js b/src/main/webapp/cliente/condominios.js
index b00fcb7..d68f3b0 100644
--- a/src/main/webapp/cliente/condominios.js
+++ b/src/main/webapp/cliente/condominios.js
@@ -1,29 +1,147 @@
-const form=document.querySelector('#cond-form'),rows=document.querySelector('#rows');
-let condominios=[],funcionarios=[],extras=[],funcLinks=new Map(),funcAtual=null,funcEditId=null;
-async function load(){try{const d=await Api.get('/api/condominios');condominios=d.condominios||[];rows.innerHTML=condominios.map(c=>`| ${c.id} | ${c.nome} | ${c.cnpj||''} | ${c.endereco||''} | Abrir |
`).join('')}catch(e){Util.toast(e.message,true)}}
-form.onsubmit=async e=>{e.preventDefault();try{await Api.post('/api/condominios',Util.formData(form));form.reset();Util.toast('Condominio criado');await load();await loadFuncionarios()}catch(err){Util.toast(err.message,true)}};
-load();
+const rows=document.querySelector('#rows'),funcPanel=document.querySelector('#funcionarios-panel'),funcRows=document.querySelector('#func-rows'),extraPanel=document.querySelector('#extras-panel'),extraRows=document.querySelector('#extra-rows'),modal=document.querySelector('#cond-modal'),modalTitle=document.querySelector('#cond-modal-title'),modalBody=document.querySelector('#cond-modal-body');
+let condominios=[],funcionarios=[],extras=[],funcLinks=new Map(),funcAtual=null;
-const funcPanel=document.querySelector('#funcionarios-panel'),funcForm=document.querySelector('#func-form'),funcRows=document.querySelector('#func-rows'),extraPanel=document.querySelector('#extras-panel'),extraForm=document.querySelector('#extra-form'),extraRows=document.querySelector('#extra-rows'),modal=document.querySelector('#cond-modal'),modalTitle=document.querySelector('#cond-modal-title'),modalBody=document.querySelector('#cond-modal-body');
function esc(v){return String(v??'').replace(/[&<>'"]/g,c=>({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c]))}
-async function linksPorFuncionario(){const mapa=new Map();await Promise.all(condominios.map(async c=>{try{const d=await Api.get(`/api/condominios/${c.id}/funcionarios-vinculados`);(d.funcionarios||[]).forEach(f=>{const fid=Number(f.funcionario_id||f.id);if(!mapa.has(fid))mapa.set(fid,[]);mapa.get(fid).push({id:Number(c.id),nome:c.nome});});}catch(e){}}));return mapa;}
+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 renderCondominios(){
+ const q=termo('#cond-search-input');
+ const lista=condominios.filter(c=>contem(c,q,['id','nome','cnpj','endereco']));
+ rows.innerHTML=lista.map(c=>`| ${c.id} | ${esc(c.nome)} | ${esc(c.cnpj||'')} | ${esc(c.endereco||'')} | Abrir |
`).join('')||'| Nenhum condominio encontrado. |
';
+}
+
+async function load(){
+ try{
+ const d=await Api.get('/api/condominios');
+ condominios=d.condominios||[];
+ renderCondominios();
+ }catch(e){Util.toast(e.message,true)}
+}
+
+window.abrirNovoCondominio=()=>{
+ abrirModal('Novo condominio','');
+ document.querySelector('#cond-form').onsubmit=async e=>{
+ e.preventDefault();
+ try{
+ await Api.post('/api/condominios',Util.formData(e.target));
+ Util.toast('Condominio criado');
+ fecharModalCondominios();
+ await load();
+ await loadFuncionarios();
+ }catch(err){Util.toast(err.message,true)}
+ };
+};
+
+async function linksPorFuncionario(){
+ const mapa=new Map();
+ await Promise.all(condominios.map(async c=>{
+ try{
+ const d=await Api.get(`/api/condominios/${c.id}/funcionarios-vinculados`);
+ (d.funcionarios||[]).forEach(f=>{
+ const fid=Number(f.funcionario_id||f.id);
+ if(!mapa.has(fid))mapa.set(fid,[]);
+ mapa.get(fid).push({id:Number(c.id),nome:c.nome});
+ });
+ }catch(e){}
+ }));
+ return mapa;
+}
+
async function refreshLinks(){funcLinks=await linksPorFuncionario()}
-async function loadFuncionarios(){if(!Auth.isAdminEmpresa())return;funcPanel.classList.remove('hidden');try{if(!condominios.length)await load();const d=await Api.get('/api/funcionarios');funcionarios=d.funcionarios||[];await refreshLinks();funcRows.innerHTML=funcionarios.map(f=>{const acao=f.cargo==='admin_empresa'?'Acesso total':'';const opcoes=f.cargo==='admin_empresa'?'-':' ';return '| '+esc(f.nome)+' | '+esc(f.email)+' | '+esc(f.telefone||'')+' | '+esc(f.cargo||'')+' | '+Util.badge(f.status)+' | '+acao+' | '+opcoes+' |
'}).join('')||'| Nenhum funcionario cadastrado. |
'}catch(e){Util.toast(e.message,true)}}
-if(funcForm){funcForm.onsubmit=async e=>{e.preventDefault();try{await Api.post('/api/funcionarios',Util.formData(funcForm));funcForm.reset();Util.toast('Funcionario cadastrado');loadFuncionarios()}catch(err){Util.toast(err.message,true)}}}
+
+function renderFuncionarios(){
+ const q=termo('#func-search-input');
+ const lista=funcionarios.filter(f=>contem(f,q,['nome','email','telefone','cargo','status']));
+ funcRows.innerHTML=lista.map(f=>{
+ const acao=f.cargo==='admin_empresa'?'Acesso total':'';
+ const opcoes=f.cargo==='admin_empresa'?'-':' ';
+ return '| '+esc(f.nome)+' | '+esc(f.email)+' | '+esc(f.telefone||'')+' | '+esc(f.cargo||'')+' | '+Util.badge(f.status)+' | '+acao+' | '+opcoes+' |
';
+ }).join('')||'| Nenhum funcionario encontrado. |
';
+}
+
+async function loadFuncionarios(){
+ if(!Auth.isAdminEmpresa())return;
+ funcPanel.classList.remove('hidden');
+ try{
+ if(!condominios.length)await load();
+ const d=await Api.get('/api/funcionarios');
+ funcionarios=d.funcionarios||[];
+ await refreshLinks();
+ renderFuncionarios();
+ }catch(e){Util.toast(e.message,true)}
+}
+
+window.abrirNovoFuncionario=()=>{
+ abrirModal('Novo funcionario','');
+ document.querySelector('#func-form').onsubmit=async e=>{
+ e.preventDefault();
+ try{
+ await Api.post('/api/funcionarios',Util.formData(e.target));
+ Util.toast('Funcionario cadastrado');
+ fecharModalCondominios();
+ loadFuncionarios();
+ }catch(err){Util.toast(err.message,true)}
+ };
+};
+
function funcionarioPorId(funcId){return funcionarios.find(x=>Number(x.id)===Number(funcId))}
-window.abrirEditarFuncionario=funcId=>{const f=funcionarioPorId(funcId);if(!f)return;modalTitle.textContent='Editar funcionario';modalBody.innerHTML='';modal.classList.remove('hidden');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;modalTitle.textContent='Excluir funcionario';modalBody.innerHTML='Deseja realmente excluir o acesso de '+esc(f.nome||'')+'?
O funcionario sera inativado e perdera acesso ao sistema.
';modal.classList.remove('hidden')};
+window.abrirEditarFuncionario=funcId=>{const f=funcionarioPorId(funcId);if(!f)return;abrirModal('Editar funcionario','');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)}};
+
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=`Vinculados
${listaVinculados}Nao vinculados
${listaDisponiveis}
`}
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};
+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)}};
window.desvincularFuncionarioCondominio=async (funcId,condId)=>{try{await Api.request(`/api/condominios/${condId}/funcionarios-vinculados/${funcId}`,{method:'DELETE'});Util.toast('Funcionario desvinculado');await refreshLinks();renderModalCondominios()}catch(err){Util.toast(err.message,true)}};
-loadFuncionarios();
-async function loadExtras(){if(!Auth.isAdminEmpresa())return;extraPanel.classList.remove('hidden');try{const d=await Api.get('/api/extras');extras=d.extras||[];extraRows.innerHTML=extras.map(x=>'| '+esc(x.nome)+' | '+esc(x.email||'')+' | '+esc(x.telefone||'')+' | '+Util.badge(x.status)+' | |
').join('')||'| Nenhum destinatario extra cadastrado. |
'}catch(e){Util.toast(e.message,true)}}
-if(extraForm){extraForm.onsubmit=async e=>{e.preventDefault();try{await Api.post('/api/extras',Util.formData(extraForm));extraForm.reset();Util.toast('Extra cadastrado');loadExtras()}catch(err){Util.toast(err.message,true)}}}
+function renderExtras(){
+ const q=termo('#extra-search-input');
+ const lista=extras.filter(x=>contem(x,q,['nome','email','telefone','status']));
+ extraRows.innerHTML=lista.map(x=>'| '+esc(x.nome)+' | '+esc(x.email||'')+' | '+esc(x.telefone||'')+' | '+Util.badge(x.status)+' | |
').join('')||'| Nenhum destinatario extra encontrado. |
';
+}
+
+async function loadExtras(){
+ if(!Auth.isAdminEmpresa())return;
+ extraPanel.classList.remove('hidden');
+ try{
+ const d=await Api.get('/api/extras');
+ extras=d.extras||[];
+ renderExtras();
+ }catch(e){Util.toast(e.message,true)}
+}
+
+window.abrirNovoExtra=()=>{
+ abrirModal('Novo extra','');
+ document.querySelector('#extra-form').onsubmit=async e=>{
+ e.preventDefault();
+ try{
+ await Api.post('/api/extras',Util.formData(e.target));
+ Util.toast('Extra cadastrado');
+ fecharModalCondominios();
+ loadExtras();
+ }catch(err){Util.toast(err.message,true)}
+ };
+};
+
function extraPorId(id){return extras.find(x=>Number(x.id)===Number(id))}
-window.abrirEditarExtra=id=>{const x=extraPorId(id);if(!x)return;modalTitle.textContent='Editar extra';modalBody.innerHTML='';modal.classList.remove('hidden');document.querySelector('#extra-edit-form').onsubmit=async e=>{e.preventDefault();try{await Api.put('/api/extras/'+id,Util.formData(e.target));Util.toast('Extra atualizado');fecharModalCondominios();loadExtras()}catch(err){Util.toast(err.message,true)}}};
+window.abrirEditarExtra=id=>{const x=extraPorId(id);if(!x)return;abrirModal('Editar extra','');document.querySelector('#extra-edit-form').onsubmit=async e=>{e.preventDefault();try{await Api.put('/api/extras/'+id,Util.formData(e.target));Util.toast('Extra atualizado');fecharModalCondominios();loadExtras()}catch(err){Util.toast(err.message,true)}}};
window.excluirExtra=async id=>{try{await Api.request('/api/extras/'+id,{method:'DELETE'});Util.toast('Extra excluido');loadExtras()}catch(err){Util.toast(err.message,true)}};
+
+window.alternarBuscaCadastro=tipo=>{
+ const strip=document.querySelector(`#${tipo}-search`),input=document.querySelector(`#${tipo}-search-input`);
+ if(!strip||!input)return;
+ strip.classList.toggle('hidden');
+ if(!strip.classList.contains('hidden'))input.focus();
+};
+
+document.querySelector('#cond-search-input')?.addEventListener('input',renderCondominios);
+document.querySelector('#func-search-input')?.addEventListener('input',renderFuncionarios);
+document.querySelector('#extra-search-input')?.addEventListener('input',renderExtras);
+
+load();
+loadFuncionarios();
loadExtras();
diff --git a/src/main/webapp/css/app.css b/src/main/webapp/css/app.css
index d492f2f..b30fac0 100644
--- a/src/main/webapp/css/app.css
+++ b/src/main/webapp/css/app.css
@@ -380,6 +380,23 @@ h2 {
margin-bottom: 16px;
}
+.section-actions {
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ justify-content: flex-end;
+ flex-wrap: wrap;
+}
+
+.section-actions .btn {
+ min-width: 92px;
+ box-shadow: none;
+}
+
+.search-strip {
+ margin: 0 0 12px;
+}
+
.panel-block {
margin-top: 18px;
}