/** * Supera Glia - Tab de Alunos * @module tabs/AlunosTab */ (function() { 'use strict'; SuperaGlia.initAlunosTab = function() { const { useState, useEffect } = SuperaGlia.hooks; const { API_BASE } = SuperaGlia.config; const { Icon, perfilColors, AlunoDetalhesModal } = SuperaGlia; SuperaGlia.AlunosTab = ({ dados }) => { const { alunos: alunosBase } = dados; const [search, setSearch] = useState(''); const [selectedAluno, setSelectedAluno] = useState(null); const [filtroTurma, setFiltroTurma] = useState(''); const [filtroSala, setFiltroSala] = useState(''); const [filtroProfessor, setFiltroProfessor] = useState(''); const [filtroSituacao, setFiltroSituacao] = useState(''); const [alunosEnriquecidos, setAlunosEnriquecidos] = useState([]); const [carregandoAusencias, setCarregandoAusencias] = useState(true); // Buscar ausências do Chatwoot e enriquecer dados dos alunos useEffect(() => { const carregarAusencias = async () => { setCarregandoAusencias(true); try { const ausenciasRes = await fetch(`${API_BASE}/ausencias`).then(r => r.json()).catch(() => ({ ausencias: [] })); const ausencias = ausenciasRes.ausencias || []; const enriquecidos = alunosBase.map(aluno => { const ausencia = ausencias.find(a => { if (a.cod_aluno && aluno.cod_aluno && a.cod_aluno.toString() === aluno.cod_aluno.toString()) return true; const telAluno = (aluno.telefone || '').replace(/\D/g, ''); const telAusencia = (a.telefone || '').replace(/\D/g, ''); if (telAluno && telAusencia && (telAluno.includes(telAusencia) || telAusencia.includes(telAluno))) return true; const nomeAluno = (aluno.nome || '').toUpperCase().trim(); const nomeAusencia = (a.nome || '').toUpperCase().trim(); if (nomeAluno && nomeAusencia && nomeAluno === nomeAusencia) return true; return false; }); if (ausencia) { return { ...aluno, ausente_ate: ausencia.ausente_ate, motivo_ausencia: ausencia.motivo_ausencia, status_aluno: ausencia.status_aluno, turma: ausencia.turma || aluno.turma, sala: ausencia.sala || aluno.sala, professor: ausencia.professor || aluno.professor, parcela_atual: ausencia.parcela_atual || aluno.parcela_atual, observacoes: ausencia.observacoes || aluno.observacoes }; } return aluno; }); setAlunosEnriquecidos(enriquecidos); } catch (e) { console.error('Erro ao carregar ausências:', e); setAlunosEnriquecidos(alunosBase); } finally { setCarregandoAusencias(false); } }; if (alunosBase.length > 0) { carregarAusencias(); } }, [alunosBase]); const alunos = alunosEnriquecidos.length > 0 ? alunosEnriquecidos : alunosBase; // Extrair valores únicos para os filtros const turmasUnicas = [...new Set(alunos.map(a => a.turma).filter(Boolean))].sort(); const salasUnicas = [...new Set(alunos.map(a => a.sala || a.sala_aluno).filter(Boolean))].sort(); const professoresUnicos = [...new Set(alunos.map(a => a.professor).filter(Boolean))].sort(); const situacoesUnicas = [...new Set(alunos.map(a => a.situacao_matricula).filter(Boolean))].sort(); // Filtrar alunos const filtered = alunos.filter(a => { const matchNome = a.nome?.toLowerCase().includes(search.toLowerCase()); const matchTurma = !filtroTurma || a.turma === filtroTurma; const matchSala = !filtroSala || (a.sala || a.sala_aluno) === filtroSala; const matchProfessor = !filtroProfessor || a.professor === filtroProfessor; const matchSituacao = !filtroSituacao || a.situacao_matricula === filtroSituacao; return matchNome && matchTurma && matchSala && matchProfessor && matchSituacao; }); const limparFiltros = () => { setSearch(''); setFiltroTurma(''); setFiltroSala(''); setFiltroProfessor(''); setFiltroSituacao(''); }; const temFiltrosAtivos = search || filtroTurma || filtroSala || filtroProfessor || filtroSituacao; return React.createElement('div', { className: 'space-y-4' }, // Barra de busca e filtros React.createElement('div', { className: 'bg-white rounded-2xl p-5 shadow-sm border border-gray-100' }, React.createElement('div', { className: 'relative mb-4' }, React.createElement(Icon, { name: 'search', className: 'absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400' }), React.createElement('input', { type: 'text', placeholder: 'Buscar aluno...', value: search, onChange: e => setSearch(e.target.value), className: 'w-full pl-12 pr-4 py-3 bg-gray-50 border-2 border-gray-200 rounded-xl text-base transition-all' }) ), React.createElement('div', { className: 'grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-3' }, React.createElement('div', null, React.createElement('label', { className: 'block text-xs font-semibold text-gray-500 mb-1.5 uppercase tracking-wide' }, 'Turma'), React.createElement('select', { value: filtroTurma, onChange: e => setFiltroTurma(e.target.value), className: 'w-full px-3 py-2.5 bg-gray-50 border-2 border-gray-200 rounded-xl text-sm transition-all cursor-pointer' }, React.createElement('option', { value: '' }, 'Todas'), turmasUnicas.map(t => React.createElement('option', { key: t, value: t }, t)) ) ), React.createElement('div', null, React.createElement('label', { className: 'block text-xs font-semibold text-gray-500 mb-1.5 uppercase tracking-wide' }, 'Sala'), React.createElement('select', { value: filtroSala, onChange: e => setFiltroSala(e.target.value), className: 'w-full px-3 py-2.5 bg-gray-50 border-2 border-gray-200 rounded-xl text-sm transition-all cursor-pointer' }, React.createElement('option', { value: '' }, 'Todas'), salasUnicas.map(s => React.createElement('option', { key: s, value: s }, s)) ) ), React.createElement('div', null, React.createElement('label', { className: 'block text-xs font-semibold text-gray-500 mb-1.5 uppercase tracking-wide' }, 'Professor'), React.createElement('select', { value: filtroProfessor, onChange: e => setFiltroProfessor(e.target.value), className: 'w-full px-3 py-2.5 bg-gray-50 border-2 border-gray-200 rounded-xl text-sm transition-all cursor-pointer' }, React.createElement('option', { value: '' }, 'Todos'), professoresUnicos.map(p => React.createElement('option', { key: p, value: p }, p)) ) ), React.createElement('div', null, React.createElement('label', { className: 'block text-xs font-semibold text-gray-500 mb-1.5 uppercase tracking-wide' }, 'Situação'), React.createElement('select', { value: filtroSituacao, onChange: e => setFiltroSituacao(e.target.value), className: 'w-full px-3 py-2.5 bg-gray-50 border-2 border-gray-200 rounded-xl text-sm transition-all cursor-pointer' }, React.createElement('option', { value: '' }, 'Todas'), situacoesUnicas.map(s => React.createElement('option', { key: s, value: s }, s)) ) ), React.createElement('div', { className: 'flex items-end' }, temFiltrosAtivos && React.createElement('button', { onClick: limparFiltros, className: 'flex items-center gap-2 px-4 py-2.5 bg-gray-200 hover:bg-gray-300 rounded-xl text-sm font-medium text-gray-700 transition-all' }, React.createElement(Icon, { name: 'x', className: 'w-4 h-4' }), 'Limpar' ) ) ), React.createElement('div', { className: 'mt-4 pt-4 border-t border-gray-100 flex items-center justify-between' }, React.createElement('p', { className: 'text-sm text-gray-500' }, `Mostrando ${Math.min(filtered.length, 50)} de ${filtered.length} aluno${filtered.length !== 1 ? 's' : ''}` ), temFiltrosAtivos && React.createElement('span', { className: 'text-xs px-3 py-1 bg-orange-100 text-orange-700 rounded-full font-medium' }, 'Filtros aplicados' ) ) ), // Tabela React.createElement('div', { className: 'bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden' }, React.createElement('table', { className: 'w-full' }, React.createElement('thead', { className: 'bg-gray-50' }, React.createElement('tr', null, React.createElement('th', { className: 'text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase' }, 'Nome'), React.createElement('th', { className: 'text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase' }, 'Perfil'), React.createElement('th', { className: 'text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase hidden md:table-cell' }, 'Turma'), React.createElement('th', { className: 'text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase hidden lg:table-cell' }, 'Telefone'), React.createElement('th', { className: 'text-center px-4 py-3 text-xs font-semibold text-gray-500 uppercase' }, 'Ações') ) ), React.createElement('tbody', { className: 'divide-y divide-gray-50' }, filtered.length === 0 ? React.createElement('tr', null, React.createElement('td', { colSpan: 5, className: 'px-4 py-8 text-center text-gray-500' }, React.createElement('div', { className: 'flex flex-col items-center' }, React.createElement(Icon, { name: 'search-x', className: 'w-10 h-10 text-gray-300 mb-2' }), React.createElement('p', null, 'Nenhum aluno encontrado'), temFiltrosAtivos && React.createElement('button', { onClick: limparFiltros, className: 'mt-2 text-orange-500 hover:text-orange-600 text-sm' }, 'Limpar filtros') ) ) ) : filtered.slice(0, 50).map(aluno => { const colors = perfilColors[aluno.perfil] || perfilColors['60+']; const isAusente = aluno.ausente_ate && new Date(aluno.ausente_ate) >= new Date(); return React.createElement('tr', { key: aluno.id || aluno.cod_aluno, className: `hover:bg-orange-50 cursor-pointer transition-colors ${isAusente ? 'bg-orange-50/50' : ''}`, onClick: () => setSelectedAluno(aluno) }, React.createElement('td', { className: 'px-4 py-3' }, React.createElement('div', { className: 'flex items-center gap-2' }, React.createElement('span', { className: 'font-medium text-gray-900' }, aluno.nome), isAusente && React.createElement('span', { className: 'text-xs px-1.5 py-0.5 bg-orange-100 text-orange-600 rounded' }, '✈️') ) ), React.createElement('td', { className: 'px-4 py-3' }, React.createElement('span', { className: `text-xs px-2 py-1 rounded-full ${colors.badge}` }, aluno.perfil) ), React.createElement('td', { className: 'px-4 py-3 text-sm text-gray-600 hidden md:table-cell' }, aluno.turma || '-'), React.createElement('td', { className: 'px-4 py-3 text-sm text-gray-600 hidden lg:table-cell' }, aluno.telefone || '-'), React.createElement('td', { className: 'px-4 py-3 text-center' }, React.createElement('button', { onClick: (e) => { e.stopPropagation(); setSelectedAluno(aluno); }, className: 'p-2 hover:bg-orange-100 rounded-lg text-orange-500 transition-colors', title: 'Ver detalhes' }, React.createElement(Icon, { name: 'eye', className: 'w-4 h-4' }) ) ) ); }) ) ) ), // Modal de detalhes selectedAluno && React.createElement(AlunoDetalhesModal, { aluno: selectedAluno, onClose: () => setSelectedAluno(null) }) ); }; }; })();