- 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
155 lines
5.0 KiB
JavaScript
155 lines
5.0 KiB
JavaScript
import { useState, useRef, useEffect } from 'react';
|
||
import './FiltroSelos.css';
|
||
|
||
const SELOS_CONFIG = {
|
||
funcoes: {
|
||
label: 'Funções',
|
||
selos: [
|
||
{ codigo: 'PRESID_CAMARA', label: 'Presidente Câmara', icone: '👑' },
|
||
{ codigo: 'COORD_PPG', label: 'Coord. PPG', icone: '🎓' },
|
||
{ codigo: 'BPQ', label: 'Bolsista PQ', icone: '🏅' },
|
||
],
|
||
},
|
||
premiacoes: {
|
||
label: 'Premiações',
|
||
selos: [
|
||
{ codigo: 'AUTOR_GP', label: 'Autor GP', icone: '🏆' },
|
||
{ codigo: 'AUTOR_PREMIO', label: 'Autor Prêmio', icone: '🥇' },
|
||
{ codigo: 'AUTOR_MENCAO', label: 'Autor Menção', icone: '🥈' },
|
||
{ codigo: 'ORIENT_GP', label: 'Orient. GP', icone: '🏆' },
|
||
{ codigo: 'ORIENT_PREMIO', label: 'Orient. Prêmio', icone: '🎖️' },
|
||
{ codigo: 'ORIENT_MENCAO', label: 'Orient. Menção', icone: '📜' },
|
||
],
|
||
},
|
||
orientacoes: {
|
||
label: 'Orientações',
|
||
selos: [
|
||
{ codigo: 'ORIENT_POS_DOC', label: 'Pós-Doc', icone: '🔬' },
|
||
{ codigo: 'ORIENT_TESE', label: 'Tese', icone: '📚' },
|
||
{ codigo: 'ORIENT_DISS', label: 'Dissertação', icone: '📄' },
|
||
{ codigo: 'CO_ORIENT_POS_DOC', label: 'Co-orient. Pós-Doc', icone: '🔬' },
|
||
{ codigo: 'CO_ORIENT_TESE', label: 'Co-orient. Tese', icone: '📚' },
|
||
{ codigo: 'CO_ORIENT_DISS', label: 'Co-orient. Diss.', icone: '📄' },
|
||
],
|
||
},
|
||
};
|
||
|
||
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)) {
|
||
setAberto(false);
|
||
}
|
||
};
|
||
document.addEventListener('mousedown', handleClickOutside);
|
||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||
}, []);
|
||
|
||
const toggleSelo = (codigo) => {
|
||
if (selosTemp.includes(codigo)) {
|
||
setSelosTemp(selosTemp.filter((s) => s !== codigo));
|
||
} else {
|
||
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
|
||
);
|
||
|
||
return (
|
||
<div className="filtro-selos" ref={ref}>
|
||
<button
|
||
className={`filtro-selos-trigger ${selecionados.length > 0 ? 'ativo' : ''}`}
|
||
onClick={() => setAberto(!aberto)}
|
||
>
|
||
<span className="filtro-icone">🏷️</span>
|
||
<span className="filtro-label">
|
||
{selecionados.length > 0
|
||
? `${selecionados.length} selo${selecionados.length > 1 ? 's' : ''}`
|
||
: 'Filtrar por selos'}
|
||
</span>
|
||
<span className={`filtro-seta ${aberto ? 'aberto' : ''}`}>▼</span>
|
||
{selecionados.length > 0 && (
|
||
<span className="filtro-limpar" onClick={limparFiltros} title="Limpar filtros">
|
||
✕
|
||
</span>
|
||
)}
|
||
</button>
|
||
|
||
{aberto && (
|
||
<div className="filtro-selos-dropdown">
|
||
<div className="filtro-selos-header">
|
||
<span>Selecione os selos para filtrar</span>
|
||
{selosTemp.length > 0 && (
|
||
<button className="filtro-limpar-todos" onClick={limparTemp}>
|
||
Limpar ({selosTemp.length})
|
||
</button>
|
||
)}
|
||
</div>
|
||
|
||
<div className="filtro-selos-grupos">
|
||
{Object.entries(SELOS_CONFIG).map(([grupoKey, grupo]) => (
|
||
<div key={grupoKey} className="filtro-grupo">
|
||
<div className="filtro-grupo-titulo">{grupo.label}</div>
|
||
<div className="filtro-grupo-selos">
|
||
{grupo.selos.map((selo) => (
|
||
<label
|
||
key={selo.codigo}
|
||
className={`filtro-selo-item ${selosTemp.includes(selo.codigo) ? 'selecionado' : ''}`}
|
||
>
|
||
<input
|
||
type="checkbox"
|
||
checked={selosTemp.includes(selo.codigo)}
|
||
onChange={() => toggleSelo(selo.codigo)}
|
||
/>
|
||
<span className="selo-icone">{selo.icone}</span>
|
||
<span className="selo-label">{selo.label}</span>
|
||
</label>
|
||
))}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="filtro-selos-footer">
|
||
<span className="filtro-info">
|
||
{selosTemp.length} de {totalSelos} selecionado{selosTemp.length !== 1 ? 's' : ''}
|
||
</span>
|
||
<button className="filtro-aplicar" onClick={aplicarFiltro}>
|
||
Aplicar
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default FiltroSelos;
|