diff --git a/static/css/components.css b/static/css/components.css index 9750e89..b2b8ed7 100644 --- a/static/css/components.css +++ b/static/css/components.css @@ -368,6 +368,14 @@ justify-content: space-between; } +/* Agrupa botões dentro de um dos lados de `.modal-actions--spread` — usado + quando um lado (ex.: "Excluir") precisa ficar isolado de vários botões do + outro lado (ex.: "Fechar"/"Salvar alterações"), não só um botão por lado. */ +.modal-actions__group { + display: flex; + gap: var(--space-3); +} + /* Modal de "Mais informações" (ver static/js/ajuda-aplicacao.js) — único, criado sob demanda e reaproveitado por todas as aplicações da página. */ .ajuda-modal__card { diff --git a/static/css/importacao-plano-saude.css b/static/css/importacao-plano-saude.css index 311a89c..36b621b 100644 --- a/static/css/importacao-plano-saude.css +++ b/static/css/importacao-plano-saude.css @@ -111,6 +111,30 @@ color: var(--accent); } +/* Botão "borracha" no fim do cabeçalho do histórico — limpa de uma vez todos + os filtros por coluna (ver criarFiltroColuna) e volta a ordenação pro + padrão (mais recente primeiro). Reaproveita o mesmo visual de botão de + ícone do funil (.ips-col-filter__btn), só um pouco maior por ficar sozinho + na célula, sem texto ao lado. */ +.ips-list-reset-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + border: none; + background: none; + color: var(--text-muted); + cursor: pointer; + border-radius: var(--radius-sm); +} + +.ips-list-reset-btn:hover { + color: var(--text-primary); + background: var(--bg-canvas); +} + .ips-col-filter__popup { position: absolute; top: calc(100% + 6px); diff --git a/static/js/importacao-plano-saude.js b/static/js/importacao-plano-saude.js index 51fbc12..aeca12a 100644 --- a/static/js/importacao-plano-saude.js +++ b/static/js/importacao-plano-saude.js @@ -2469,9 +2469,13 @@ document.addEventListener("DOMContentLoaded", async () => { ); } - function renderItens() { + function valoresVisiveis() { const termo = searchInput.value.trim().toLowerCase(); - const visiveis = valoresDistintos().filter((v) => labelValorFiltroLista(campo, v).toLowerCase().includes(termo)); + return valoresDistintos().filter((v) => labelValorFiltroLista(campo, v).toLowerCase().includes(termo)); + } + + function renderItens() { + const visiveis = valoresVisiveis(); box.innerHTML = visiveis.length ? visiveis .map( @@ -2515,9 +2519,22 @@ document.addEventListener("DOMContentLoaded", async () => { searchInput.addEventListener("input", renderItens); + // Enter no campo de busca restringe a seleção aos valores que batem com o + // termo digitado (igual marcar só eles manualmente) e já aplica — sem + // isso, digitar um código e teclar Enter só clicava em "Aplicar" com a + // seleção que já estava marcada (o popup abre com "Selecionar todos" + // ligado por padrão), então não filtrava nada na prática; era preciso + // desmarcar/marcar os checkboxes na mão antes de aplicar. + searchInput.addEventListener("keydown", (event) => { + if (event.key !== "Enter") return; + event.preventDefault(); + const visiveis = valoresVisiveis(); + if (visiveis.length) marcados = new Set(visiveis); + aplicarBtn.click(); + }); + selectAllInput.addEventListener("change", () => { - const termo = searchInput.value.trim().toLowerCase(); - const visiveis = valoresDistintos().filter((v) => labelValorFiltroLista(campo, v).toLowerCase().includes(termo)); + const visiveis = valoresVisiveis(); if (selectAllInput.checked) visiveis.forEach((v) => marcados.add(v)); else visiveis.forEach((v) => marcados.delete(v)); renderItens(); @@ -2553,11 +2570,24 @@ document.addEventListener("DOMContentLoaded", async () => { renderList(); }); - filtrosColuna.push({ fechar }); + filtrosColuna.push({ fechar, atualizarBotaoAtivo }); } ["codigo_empresa", "nome_operadora", "status", "criado_por"].forEach(criarFiltroColuna); + const listResetBtn = document.getElementById("ips-list-reset-btn"); + if (listResetBtn) { + listResetBtn.addEventListener("click", () => { + fecharTodosOsFiltrosColuna(); + listSortKey = "criado_em"; + listSortDir = -1; + listFiltros = { codigo_empresa: null, nome_operadora: null, status: null, criado_por: null }; + filtrosColuna.forEach((f) => f.atualizarBotaoAtivo()); + listPage = 1; + renderList(); + }); + } + document.addEventListener("click", (event) => { if (!event.target.closest(".ips-col-filter")) fecharTodosOsFiltrosColuna(); }); diff --git a/static/js/widgets.js b/static/js/widgets.js index 0f8db25..ef77742 100644 --- a/static/js/widgets.js +++ b/static/js/widgets.js @@ -4,6 +4,12 @@ const PID_WIDGET_TYPES = { description: "Próximos compromissos da sua agenda pessoal.", href: "calendario-individual.html", linkLabel: "Ver calendário completo", + // Mesmo gate usado pra esconder o item "Calendário Individual" da sidebar + // (data-section="calendario-individual", pidApplyAccessVisibility em + // access.js) — sem isso, um perfil sem esse módulo habilitado ainda + // conseguia adicionar o widget (e, por ele, chegar ao calendário + // completo) mesmo com o link do menu corretamente escondido. + visibleIf: (me) => !!(me.permissoes_efetivas?.["calendario-individual"]?.enabled), }, "links-favoritos": { label: "Links Favoritos", diff --git a/templates/importacao-plano-saude.html b/templates/importacao-plano-saude.html index 800a46d..71849d2 100644 --- a/templates/importacao-plano-saude.html +++ b/templates/importacao-plano-saude.html @@ -335,7 +335,11 @@