fix(filtros): corrigir extração de selos e melhorar UX do filtro
- Corrigir lógica de extração de selos para usar códigos exatos - Filtro agora exige todos os selos selecionados (AND em vez de OR) - Botão Aplicar volta: seleção não dispara filtro automaticamente - Layout dos controles unificado em barra com fundo
This commit is contained in:
@@ -45,12 +45,14 @@ def extrair_selos_entry(detalhes: Dict[str, Any]) -> Set[str]:
|
||||
papel = (prem.get("papel") or "").lower()
|
||||
codigo = prem.get("codigo", "")
|
||||
|
||||
if "GP" in codigo or "grande" in codigo.lower():
|
||||
if codigo == "PREMIACAO":
|
||||
tipo_prem = "GP"
|
||||
elif "MENCAO" in codigo or "menção" in codigo.lower():
|
||||
elif codigo == "PREMIACAO_GP":
|
||||
tipo_prem = "PREMIO"
|
||||
elif codigo == "MENCAO":
|
||||
tipo_prem = "MENCAO"
|
||||
else:
|
||||
tipo_prem = "PREMIO"
|
||||
continue
|
||||
|
||||
if "autor" in papel:
|
||||
selos.add(f"AUTOR_{tipo_prem}")
|
||||
@@ -64,18 +66,18 @@ def extrair_selos_entry(detalhes: Dict[str, Any]) -> Set[str]:
|
||||
is_coorient = orient.get("coorientacao", False)
|
||||
|
||||
if is_coorient:
|
||||
if "POS_DOC" in codigo:
|
||||
if codigo == "CO_ORIENT_POS_DOC":
|
||||
selos.add("CO_ORIENT_POS_DOC")
|
||||
elif "TESE" in codigo:
|
||||
elif codigo == "CO_ORIENT_TESE":
|
||||
selos.add("CO_ORIENT_TESE")
|
||||
elif "DISS" in codigo:
|
||||
elif codigo == "CO_ORIENT_DISS":
|
||||
selos.add("CO_ORIENT_DISS")
|
||||
else:
|
||||
if "POS_DOC" in codigo:
|
||||
if codigo == "ORIENT_POS_DOC":
|
||||
selos.add("ORIENT_POS_DOC")
|
||||
elif "TESE" in codigo:
|
||||
elif codigo == "ORIENT_TESE":
|
||||
selos.add("ORIENT_TESE")
|
||||
elif "DISS" in codigo:
|
||||
elif codigo == "ORIENT_DISS":
|
||||
selos.add("ORIENT_DISS")
|
||||
|
||||
return selos
|
||||
@@ -146,7 +148,7 @@ class RankingStore:
|
||||
selos_set = set(filtro_selos)
|
||||
entries = [
|
||||
e for e in entries
|
||||
if selos_set & extrair_selos_entry(e.detalhes)
|
||||
if selos_set.issubset(extrair_selos_entry(e.detalhes))
|
||||
]
|
||||
|
||||
total = len(entries)
|
||||
|
||||
@@ -48,22 +48,30 @@
|
||||
|
||||
.controls {
|
||||
margin: 1.5rem 0;
|
||||
background: linear-gradient(165deg, rgba(15, 23, 42, 0.6), rgba(30, 41, 59, 0.4));
|
||||
border: 1px solid var(--stroke);
|
||||
border-radius: 12px;
|
||||
padding: 0.75rem 1rem;
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.controls label {
|
||||
.control-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.control-group-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.controls select {
|
||||
padding: 0.5rem 1rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(255,255,255,0.06);
|
||||
border: 1px solid var(--stroke);
|
||||
border-radius: 8px;
|
||||
@@ -81,23 +89,25 @@
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
padding: 0.55rem 0.8rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(255,255,255,0.06);
|
||||
border: 1px solid var(--stroke);
|
||||
border-radius: 8px;
|
||||
color: var(--text);
|
||||
min-width: 240px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-box input:focus {
|
||||
outline: 1px solid var(--accent-2);
|
||||
outline: none;
|
||||
border-color: var(--accent-2);
|
||||
}
|
||||
|
||||
.search-box button {
|
||||
padding: 0.55rem 1rem;
|
||||
padding: 0.5rem 0.9rem;
|
||||
background: var(--accent);
|
||||
border: 1px solid var(--accent);
|
||||
color: white;
|
||||
@@ -120,17 +130,17 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pagination button {
|
||||
padding: 0.6rem 0.9rem;
|
||||
border-radius: 8px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--stroke);
|
||||
background: rgba(255,255,255,0.06);
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
transition: all 150ms ease;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.pagination button:hover:not(:disabled) {
|
||||
@@ -145,6 +155,20 @@
|
||||
.page-info {
|
||||
color: var(--muted);
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
padding: 0 0.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.controls {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
min-width: 100%;
|
||||
order: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-list {
|
||||
|
||||
@@ -182,16 +182,16 @@ function App() {
|
||||
<Header total={total} />
|
||||
|
||||
<div className="controls">
|
||||
<label>
|
||||
Limite de consultores:
|
||||
<div className="control-group">
|
||||
<span className="control-group-label">Exibir:</span>
|
||||
<select value={pageSize} onChange={(e) => { setPageSize(Number(e.target.value)); setPage(1); }}>
|
||||
<option value={10}>Top 10</option>
|
||||
<option value={50}>Top 50</option>
|
||||
<option value={100}>Top 100</option>
|
||||
<option value={200}>Top 200</option>
|
||||
<option value={500}>Top 500</option>
|
||||
<option value={10}>10</option>
|
||||
<option value={50}>50</option>
|
||||
<option value={100}>100</option>
|
||||
<option value={200}>200</option>
|
||||
<option value={500}>500</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<FiltroSelos
|
||||
selecionados={filtroSelos}
|
||||
@@ -201,23 +201,21 @@ function App() {
|
||||
<form className="search-box" onSubmit={handleSubmitBuscar}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Digite o nome para localizar"
|
||||
placeholder="Buscar por nome..."
|
||||
value={busca}
|
||||
onChange={(e) => setBusca(e.target.value)}
|
||||
/>
|
||||
<button type="submit" disabled={buscando || busca.length < 3}>
|
||||
{buscando ? 'Buscando...' : 'Buscar'}
|
||||
{buscando ? '...' : 'Buscar'}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="pagination">
|
||||
<button onClick={() => setPage(1)} disabled={page <= 1}>« Primeira</button>
|
||||
<button onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page <= 1}>‹ Anterior</button>
|
||||
<span className="page-info">
|
||||
Página {page} de {totalPages || '?'}
|
||||
</span>
|
||||
<button onClick={() => setPage((p) => (totalPages ? Math.min(totalPages, p + 1) : p + 1))} disabled={totalPages && page >= totalPages}>Próxima ›</button>
|
||||
<button onClick={() => totalPages && setPage(totalPages)} disabled={totalPages && page >= totalPages}>Última »</button>
|
||||
<button onClick={() => setPage(1)} disabled={page <= 1}>«</button>
|
||||
<button onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page <= 1}>‹</button>
|
||||
<span className="page-info">{page} / {totalPages || '?'}</span>
|
||||
<button onClick={() => setPage((p) => (totalPages ? Math.min(totalPages, p + 1) : p + 1))} disabled={totalPages && page >= totalPages}>›</button>
|
||||
<button onClick={() => totalPages && setPage(totalPages)} disabled={totalPages && page >= totalPages}>»</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -36,8 +36,15 @@ const SELOS_CONFIG = {
|
||||
|
||||
function FiltroSelos({ selecionados, onChange }) {
|
||||
const [aberto, setAberto] = useState(false);
|
||||
const [selosTemp, setSelosTemp] = useState([]);
|
||||
const ref = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (aberto) {
|
||||
setSelosTemp([...selecionados]);
|
||||
}
|
||||
}, [aberto, selecionados]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (e) => {
|
||||
if (ref.current && !ref.current.contains(e.target)) {
|
||||
@@ -49,18 +56,27 @@ function FiltroSelos({ selecionados, onChange }) {
|
||||
}, []);
|
||||
|
||||
const toggleSelo = (codigo) => {
|
||||
if (selecionados.includes(codigo)) {
|
||||
onChange(selecionados.filter((s) => s !== codigo));
|
||||
if (selosTemp.includes(codigo)) {
|
||||
setSelosTemp(selosTemp.filter((s) => s !== codigo));
|
||||
} else {
|
||||
onChange([...selecionados, codigo]);
|
||||
setSelosTemp([...selosTemp, codigo]);
|
||||
}
|
||||
};
|
||||
|
||||
const limparTemp = () => {
|
||||
setSelosTemp([]);
|
||||
};
|
||||
|
||||
const limparFiltros = (e) => {
|
||||
e.stopPropagation();
|
||||
onChange([]);
|
||||
};
|
||||
|
||||
const aplicarFiltro = () => {
|
||||
onChange(selosTemp);
|
||||
setAberto(false);
|
||||
};
|
||||
|
||||
const totalSelos = Object.values(SELOS_CONFIG).reduce(
|
||||
(acc, g) => acc + g.selos.length,
|
||||
0
|
||||
@@ -90,9 +106,9 @@ function FiltroSelos({ selecionados, onChange }) {
|
||||
<div className="filtro-selos-dropdown">
|
||||
<div className="filtro-selos-header">
|
||||
<span>Selecione os selos para filtrar</span>
|
||||
{selecionados.length > 0 && (
|
||||
<button className="filtro-limpar-todos" onClick={limparFiltros}>
|
||||
Limpar ({selecionados.length})
|
||||
{selosTemp.length > 0 && (
|
||||
<button className="filtro-limpar-todos" onClick={limparTemp}>
|
||||
Limpar ({selosTemp.length})
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -105,11 +121,11 @@ function FiltroSelos({ selecionados, onChange }) {
|
||||
{grupo.selos.map((selo) => (
|
||||
<label
|
||||
key={selo.codigo}
|
||||
className={`filtro-selo-item ${selecionados.includes(selo.codigo) ? 'selecionado' : ''}`}
|
||||
className={`filtro-selo-item ${selosTemp.includes(selo.codigo) ? 'selecionado' : ''}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selecionados.includes(selo.codigo)}
|
||||
checked={selosTemp.includes(selo.codigo)}
|
||||
onChange={() => toggleSelo(selo.codigo)}
|
||||
/>
|
||||
<span className="selo-icone">{selo.icone}</span>
|
||||
@@ -123,9 +139,9 @@ function FiltroSelos({ selecionados, onChange }) {
|
||||
|
||||
<div className="filtro-selos-footer">
|
||||
<span className="filtro-info">
|
||||
{selecionados.length} de {totalSelos} selecionado{selecionados.length !== 1 ? 's' : ''}
|
||||
{selosTemp.length} de {totalSelos} selecionado{selosTemp.length !== 1 ? 's' : ''}
|
||||
</span>
|
||||
<button className="filtro-aplicar" onClick={() => setAberto(false)}>
|
||||
<button className="filtro-aplicar" onClick={aplicarFiltro}>
|
||||
Aplicar
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user