diff --git a/src/main/webapp/cliente/lembretes.html b/src/main/webapp/cliente/lembretes.html
index 03e13ee..1081a14 100644
--- a/src/main/webapp/cliente/lembretes.html
+++ b/src/main/webapp/cliente/lembretes.html
@@ -1 +1 @@
-
LembreteLembrete
Lembretes
| Titulo | Data/hora | Status | Destinatarios | Acoes |
|---|
\ No newline at end of file
+LembreteLembrete
diff --git a/src/main/webapp/cliente/lembretes.js b/src/main/webapp/cliente/lembretes.js
index 7e9029a..26d2515 100644
--- a/src/main/webapp/cliente/lembretes.js
+++ b/src/main/webapp/cliente/lembretes.js
@@ -1,20 +1,108 @@
-const form=document.querySelector('#lembrete-form'),rows=document.querySelector('#rows'),pessoasEl=document.querySelector('#pessoas'),submitBtn=document.querySelector('#submit-btn'),cancelBtn=document.querySelector('#cancel-edit');
-let pessoas=[],lembretes=[];
+const rows=document.querySelector('#rows'),modal=document.querySelector('#lembrete-modal'),modalTitle=document.querySelector('#lembrete-modal-title'),modalBody=document.querySelector('#lembrete-modal-body');
+let pessoas=[],lembretes=[],form=null,refreshTimer=null;
+
function esc(v){return String(v??'').replace(/[&<>'"]/g,c=>({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c]))}
function toInputDate(v){if(!v)return'';const d=new Date(v);if(Number.isNaN(d.getTime()))return'';const pad=n=>String(n).padStart(2,'0');return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`}
function recLabel(v){return {1:"Mensal",3:"Trimestral",12:"Anual"}[Number(v)]||"Sem recorrencia"}
-function selectedDestIds(){return new Set([...form.querySelectorAll('input[name=dest]:checked')].map(x=>String(x.value)))}
+function termo(){return document.querySelector('#lembrete-search-input')?.value.trim().toLowerCase()||''}
+function selectedDestIds(){return form?new Set([...form.querySelectorAll('input[name=dest]:checked')].map(x=>String(x.value))):new Set()}
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 '';
+}
+
+function bindForm(){
+ form=document.querySelector('#lembrete-form');
+ renderPessoasForm();
+ form.onsubmit=async e=>{
+ e.preventDefault();
+ const b=Util.formData(form);
+ b.destinatarios=[...form.querySelectorAll('input[name=dest]:checked')].map(x=>Number(x.value));
+ try{
+ if(form.id.value){
+ await Api.put(`/api/lembretes/${form.id.value}`,b);
+ Util.toast('Lembrete atualizado');
+ }else{
+ const r=await Api.post('/api/lembretes',b);
+ const en=r.envio||{};
+ Util.toast(en.enfileirado?'Lembrete enfileirado para envio':(en.falhas?('Lembrete salvo. Enviados: '+(en.enviados||0)+'. Falhas: '+en.falhas):'Lembrete cadastrado'));
+ }
+ fecharLembreteModal();
+ await load();
+ }catch(err){Util.toast(err.message,true)}
+ };
+}
+
+function renderPessoasForm(){
+ const pessoasEl=document.querySelector('#pessoas');
+ if(!pessoasEl)return;
+ pessoasEl.innerHTML=' Nenhuma pessoa selecionada'+pessoas.map(p=>'').join('')+'
';
+ updateNotifSummary();
+}
+
+function renderLembretes(){
+ const q=termo();
+ const lista=lembretes.filter(l=>{
+ const dest=(l.destinatarios||[]).map(x=>x.nome).join(' ');
+ return !q||[l.titulo,l.mensagem,l.status,dest,recLabel(l.recorrencia_meses)].some(v=>String(v??'').toLowerCase().includes(q));
+ });
+ rows.innerHTML=lista.map(l=>{
+ const dest=(l.destinatarios||[]).map(x=>x.nome).join(', ')||'-';
+ const acoes=l.pode_alterar?` ${l.pode_editar?``:''} `:'-';
+ return `${esc(l.titulo)} ${esc(l.mensagem)} | ${Util.date(l.data_hora)} ${recLabel(l.recorrencia_meses)} | ${Util.badge(l.status)} | ${esc(dest)} | ${acoes} |
`;
+ }).join('')||'| Nenhum lembrete encontrado. |
';
+}
+
+async function loadPessoas(){const d=await Api.get('/api/lembrete-pessoas');pessoas=d.pessoas||[]}
+async function load(){try{const d=await Api.get('/api/lembretes');lembretes=d.lembretes||[];renderLembretes()}catch(e){Util.toast(e.message,true)}}
+
+window.abrirNovoLembrete=()=>{
+ modalTitle.textContent='Novo lembrete';
+ modalBody.innerHTML=formHtml();
+ modal.classList.remove('hidden');
+ bindForm();
+};
+
+window.fecharLembreteModal=()=>{
+ modal.classList.add('hidden');
+ modalBody.innerHTML='';
+ form=null;
+};
+
+window.alternarBuscaLembretes=()=>{
+ const strip=document.querySelector('#lembrete-search'),input=document.querySelector('#lembrete-search-input');
+ strip.classList.toggle('hidden');
+ if(!strip.classList.contains('hidden'))input.focus();
+};
+
function ensureNotifModal(){let m=document.querySelector('#notif-modal');if(m)return m;document.body.insertAdjacentHTML('beforeend','Notificação
');return document.querySelector('#notif-modal')}
-window.abrirNotificacao=()=>{const m=ensureNotifModal(),ids=selectedDestIds();document.querySelector('#notif-modal-body').innerHTML=pessoas.map(p=>'').join('')||'Nenhum funcionario ativo.
';m.classList.remove('hidden')};
+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=()=>{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()};
-async function loadPessoas(){const d=await Api.get('/api/lembrete-pessoas');pessoas=d.pessoas||[];pessoasEl.innerHTML=' Nenhuma pessoa selecionada'+pessoas.map(p=>'').join('')+'
';updateNotifSummary()}
-async function load(){try{const d=await Api.get('/api/lembretes');lembretes=d.lembretes||[];rows.innerHTML=lembretes.map(l=>{const dest=(l.destinatarios||[]).map(x=>x.nome).join(', ')||'-';const acoes=l.pode_alterar?` ${l.pode_editar?``:''} `:'-';return `${esc(l.titulo)} ${esc(l.mensagem)} | ${Util.date(l.data_hora)} ${recLabel(l.recorrencia_meses)} | ${Util.badge(l.status)} | ${esc(dest)} | ${acoes} |
`}).join('')||'| Nenhum lembrete cadastrado. |
'}catch(e){Util.toast(e.message,true)}}
-function resetForm(){form.reset();form.id.value='';form.recorrencia_meses.value='0';submitBtn.textContent='Cadastrar lembrete';cancelBtn.classList.add('hidden');form.querySelectorAll('input[name=dest]').forEach(x=>x.checked=false);updateNotifSummary()}
-window.editar=id=>{const l=lembretes.find(x=>Number(x.id)===Number(id));if(!l)return;if(!l.pode_editar){Util.toast('Este lembrete ja foi enviado e nao pode mais ser editado.',true);return;}form.id.value=l.id;form.titulo.value=l.titulo||'';form.mensagem.value=l.mensagem||'';form.data_hora.value=toInputDate(l.data_hora);form.status.value='ativo';form.recorrencia_meses.value=String(l.recorrencia_meses||0);const ids=new Set((l.destinatarios||[]).map(x=>Number(x.id)));form.querySelectorAll('input[name=dest]').forEach(x=>x.checked=ids.has(Number(x.value)));updateNotifSummary();submitBtn.textContent='Salvar alteracao';cancelBtn.classList.remove('hidden');scrollTo({top:0,behavior:'smooth'})};
+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()};
+
+window.editar=id=>{
+ const l=lembretes.find(x=>Number(x.id)===Number(id));
+ if(!l)return;
+ if(!l.pode_editar){Util.toast('Este lembrete ja foi enviado e nao pode mais ser editado.',true);return;}
+ modalTitle.textContent='Editar lembrete';
+ modalBody.innerHTML=formHtml();
+ modal.classList.remove('hidden');
+ bindForm();
+ form.id.value=l.id;
+ form.titulo.value=l.titulo||'';
+ form.mensagem.value=l.mensagem||'';
+ form.data_hora.value=toInputDate(l.data_hora);
+ form.status.value='ativo';
+ form.recorrencia_meses.value=String(l.recorrencia_meses||0);
+ const ids=new Set((l.destinatarios||[]).map(x=>Number(x.id)));
+ form.querySelectorAll('input[name=dest]').forEach(x=>x.checked=ids.has(Number(x.value)));
+ document.querySelector('#submit-btn').textContent='Salvar alteracao';
+ updateNotifSummary();
+};
+
window.enviar=async id=>{try{const r=await Api.post(`/api/lembretes/${id}/enviar`,{});const en=r.envio||{};Util.toast(en.falhas?("Enviados: "+(en.enviados||0)+". Falhas: "+en.falhas):("Lembrete enviado para "+(en.enviados||0)));await load()}catch(e){Util.toast(e.message,true)}};
-window.excluir=async id=>{try{await Api.request(`/api/lembretes/${id}`,{method:'DELETE'});Util.toast('Lembrete excluido');await load();resetForm()}catch(e){Util.toast(e.message,true)}};
-cancelBtn.onclick=resetForm;
-form.onsubmit=async e=>{e.preventDefault();const b=Util.formData(form);b.destinatarios=[...form.querySelectorAll('input[name=dest]:checked')].map(x=>Number(x.value));try{if(form.id.value){await Api.put(`/api/lembretes/${form.id.value}`,b);Util.toast('Lembrete atualizado')}else{const r=await Api.post('/api/lembretes',b);const en=r.envio||{};Util.toast(en.enfileirado?'Lembrete enfileirado para envio':(en.falhas?('Lembrete salvo. Enviados: '+(en.enviados||0)+'. Falhas: '+en.falhas):'Lembrete cadastrado'))}resetForm();await load()}catch(err){Util.toast(err.message,true)}};
-(async()=>{try{await loadPessoas();await load();setInterval(load,5000)}catch(e){Util.toast(e.message,true)}})();
+window.excluir=async id=>{try{await Api.request(`/api/lembretes/${id}`,{method:'DELETE'});Util.toast('Lembrete excluido');await load();fecharLembreteModal()}catch(e){Util.toast(e.message,true)}};
+
+document.querySelector('#lembrete-search-input')?.addEventListener('input',renderLembretes);
+(async()=>{try{await loadPessoas();await load();refreshTimer=setInterval(load,5000)}catch(e){Util.toast(e.message,true)}})();