diff --git a/client/src/components/Dashboard.jsx b/client/src/components/Dashboard.jsx index a27bb73..4706e08 100755 --- a/client/src/components/Dashboard.jsx +++ b/client/src/components/Dashboard.jsx @@ -42,15 +42,24 @@ function useMediaQuery(query) { return matches; } +// Filter keys +const FILTER_NONE = null; +const FILTER_TOTAL = 'total'; +const FILTER_ELITE = 'elite'; +const FILTER_ACTIVE = 'active'; +const FILTER_AT_RISK = 'at_risk'; + const s = { wrap: { padding: '32px 40px', color: '#f8f9fa' }, header: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '24px', flexWrap: 'wrap', gap: '12px' }, title: { fontSize: '24px', fontWeight: 700, color: '#f8f9fa' }, subtitle: { fontSize: '13px', color: '#b5b5c0', marginTop: '3px' }, statsRow: { display: 'flex', gap: '16px', flexWrap: 'wrap', marginBottom: '28px' }, - statCard: { flex: '1', minWidth: '140px', background: '#181924', border: '1px solid #303136', borderRadius: '8px', padding: '16px', textAlign: 'center' }, + statCard: { flex: '1', minWidth: '140px', background: '#181924', border: '1px solid #303136', borderRadius: '8px', padding: '16px', textAlign: 'center', cursor: 'pointer', transition: 'border-color 0.15s, box-shadow 0.15s' }, + statCardActive: { boxShadow: '0 0 0 2px #d4af37', border: '1px solid #d4af37' }, statNum: { fontSize: '28px', fontWeight: 800, color: '#f8f9fa' }, statLbl: { fontSize: '11px', color: '#b5b5c0', marginTop: '4px' }, + filterBadge: { fontSize: '10px', color: '#d4af37', marginTop: '4px', fontWeight: 600 }, search: { padding: '10px 14px', border: '1px solid #333544', borderRadius: '6px', fontSize: '14px', width: '260px', background: '#050608', color: '#f8f9fa' }, table: { width: '100%', borderCollapse: 'collapse', background: '#111217', borderRadius: '8px', overflow: 'hidden', boxShadow: '0 1px 8px rgba(0,0,0,0.6)', border: '1px solid #222' }, th: { background: '#000000', color: '#f8f9fa', padding: '10px 14px', textAlign: 'left', fontSize: '12px', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px' }, @@ -119,6 +128,7 @@ export default function Dashboard() { const [selectedId, setSelectedId] = useState(null); const [showAudit, setShowAudit] = useState(false); const [loading, setLoading] = useState(true); + const [activeFilter, setActiveFilter] = useState(FILTER_NONE); const isMobile = useMediaQuery('(max-width: 768px)'); const load = useCallback(() => { @@ -130,20 +140,50 @@ export default function Dashboard() { useEffect(() => { load(); }, [load]); + // Apply search + badge filter together useEffect(() => { const q = search.toLowerCase(); - setFiltered(employees.filter(e => - e.name.toLowerCase().includes(q) || - (e.department || '').toLowerCase().includes(q) || - (e.supervisor || '').toLowerCase().includes(q) - )); - }, [search, employees]); + let base = employees; + + if (activeFilter === FILTER_ELITE) { + base = base.filter(e => e.active_points >= 0 && e.active_points <= 4); + } else if (activeFilter === FILTER_ACTIVE) { + base = base.filter(e => e.active_points > 0); + } else if (activeFilter === FILTER_AT_RISK) { + base = base.filter(e => isAtRisk(e.active_points)); + } + // FILTER_TOTAL and FILTER_NONE show all + + if (q) { + base = base.filter(e => + e.name.toLowerCase().includes(q) || + (e.department || '').toLowerCase().includes(q) || + (e.supervisor || '').toLowerCase().includes(q) + ); + } + + setFiltered(base); + }, [search, employees, activeFilter]); const atRiskCount = employees.filter(e => isAtRisk(e.active_points)).length; const activeCount = employees.filter(e => e.active_points > 0).length; - const cleanCount = employees.filter(e => e.active_points === 0).length; + // Elite Standing: 0–4 pts (Tier 0-1) + const eliteCount = employees.filter(e => e.active_points >= 0 && e.active_points <= 4).length; const maxPoints = employees.reduce((m, e) => Math.max(m, e.active_points), 0); + function handleBadgeClick(filterKey) { + setActiveFilter(prev => prev === filterKey ? FILTER_NONE : filterKey); + } + + function cardStyle(filterKey, extra = {}) { + const isActive = activeFilter === filterKey; + return { + ...s.statCard, + ...(isActive ? s.statCardActive : {}), + ...extra, + }; + } + return ( <> @@ -151,7 +191,19 @@ export default function Dashboard() {