From 249025e860023d2644c69069dd0e15af56b6a2fc Mon Sep 17 00:00:00 2001 From: Ricardo Gomes <230413@epvc.pt> Date: Tue, 3 Feb 2026 17:20:24 +0000 Subject: [PATCH] 1 --- app/Professor/Alunos/DetalhesAluno.tsx | 222 +++++++++++-------------- app/Professor/Alunos/ListaAlunos.tsx | 211 ++++++----------------- 2 files changed, 154 insertions(+), 279 deletions(-) diff --git a/app/Professor/Alunos/DetalhesAluno.tsx b/app/Professor/Alunos/DetalhesAluno.tsx index fd03192..dd78220 100644 --- a/app/Professor/Alunos/DetalhesAluno.tsx +++ b/app/Professor/Alunos/DetalhesAluno.tsx @@ -1,158 +1,134 @@ import { Ionicons } from '@expo/vector-icons'; import { useLocalSearchParams, useRouter } from 'expo-router'; import { memo, useEffect, useState } from 'react'; -import { Platform, SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { useTheme } from '../../../themecontext'; +import { + SafeAreaView, + ScrollView, + StatusBar, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import { supabase } from '../../lib/supabase'; -const DetalhesAluno = memo(() => { - const { isDarkMode } = useTheme(); +const DetalhesAlunos = memo(() => { const router = useRouter(); - const params = useLocalSearchParams(); - const alunoParam = Array.isArray(params.aluno) ? params.aluno[0] : params.aluno; - const aluno = alunoParam ? JSON.parse(alunoParam) : null; + const { alunoId } = useLocalSearchParams(); - const [datas, setDatas] = useState({ inicio: '05/01/2026', fim: '30/05/2026' }); - const [stats, setStats] = useState({ horasConcluidas: 0, faltasTotais: 0, faltasJustificadas: 0, horasFaltam: 300 }); - - const cores = { - fundo: isDarkMode ? '#121212' : '#f1f3f5', - card: isDarkMode ? '#1e1e1e' : '#fff', - texto: isDarkMode ? '#fff' : '#000', - textoSecundario: isDarkMode ? '#adb5bd' : '#6c757d', - borda: isDarkMode ? '#333' : '#f1f3f5', - azul: '#0d6efd', - verde: '#198754', - vermelho: '#dc3545' - }; + const [aluno, setAluno] = useState(null); + const [loading, setLoading] = useState(true); useEffect(() => { - // Simulação de cálculo de horas/faltas para este aluno - const totalHorasEstagio = 300; - const horasConcluidas = Math.floor(Math.random() * 250); // exemplo randomizado - const faltasTotais = Math.floor(Math.random() * 10); - const faltasJustificadas = Math.floor(Math.random() * faltasTotais); - setStats({ - horasConcluidas, - faltasTotais, - faltasJustificadas, - horasFaltam: Math.max(0, totalHorasEstagio - horasConcluidas) + if (alunoId) fetchAluno(); + }, [alunoId]); + + const fetchAluno = async () => { + setLoading(true); + + const { data: alunoData } = await supabase + .from('alunos') + .select('*') + .eq('id', alunoId) + .single(); + + if (!alunoData) { + setLoading(false); + return; + } + + const { data: perfil } = await supabase + .from('profile') + .select('email, telefone') + .eq('n_escola', alunoData.n_escola) + .single(); + + const { data: estagio } = await supabase + .from('estagios') + .select('estado') + .eq('aluno_id', alunoId) + .single(); + + setAluno({ + ...alunoData, + ...perfil, + estagio, }); - }, []); + + setLoading(false); + }; + + if (loading) { + return ( + + A carregar... + + ); + } if (!aluno) { return ( - - Nenhum aluno selecionado. + + Aluno não encontrado ); } return ( - - - + + + - router.back()}> - + router.back()}> + - {aluno.nome} - + {aluno.nome} + - + + + Número Escola + {aluno.n_escola} - {/* Dados Pessoais */} - - Dados Pessoais - Nome - {aluno.nome} + Turma + + {aluno.ano}º {aluno.turma_curso} + - Email - {aluno.email} + Email + {aluno.email || '-'} - Telefone - {aluno.telefone} + Telefone + {aluno.telefone || '-'} - Turma - {aluno.turma} + Estado Estágio + {aluno.estagio?.estado || '-'} - - {/* Empresa de Estágio */} - - Empresa de Estágio - Empresa - {aluno.empresa} - - Cargo - {aluno.cargo} - - - {/* Dados do Estágio / Horas */} - - Horas de Estágio - - - Totais - {300}h - - - Concluídas - {stats.horasConcluidas}h - - - Faltam - {stats.horasFaltam}h - - - - Horário Semanal - - - Período - Horário - - - Manhã - 09:30 - 13:00 - - - Almoço - 13:00 - 14:30 - - - Tarde - 14:30 - 17:30 - - - - Total: 7 horas diárias por presença - - ); }); -export default DetalhesAluno; +export default DetalhesAlunos; const styles = StyleSheet.create({ - safe: { flex: 1, paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0 }, - header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 20, paddingVertical: 10 }, - btnVoltar: { width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', elevation: 2 }, - spacer: { width: 40 }, - tituloGeral: { fontSize: 22, fontWeight: 'bold' }, - container: { padding: 20, gap: 20, paddingBottom: 40 }, - card: { padding: 20, borderRadius: 16, elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4 }, - tituloCard: { fontSize: 18, fontWeight: 'bold', textAlign: 'center', marginBottom: 10, borderBottomWidth: 1, paddingBottom: 8 }, - label: { marginTop: 12, fontSize: 13 }, + safe: { flex: 1, backgroundColor: '#f1f3f5' }, + center: { marginTop: 50, textAlign: 'center' }, + header: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + padding: 16, + }, + titulo: { fontSize: 20, fontWeight: 'bold' }, + container: { padding: 16 }, + card: { + backgroundColor: '#fff', + padding: 16, + borderRadius: 12, + elevation: 2, + }, + label: { fontSize: 12, color: '#6c757d', marginTop: 10 }, valor: { fontSize: 16, fontWeight: '600' }, - rowStats: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 5 }, - itemStat: { alignItems: 'center', flex: 1 }, - labelHorario: { fontSize: 16, fontWeight: 'bold', marginTop: 20, marginBottom: 10, textAlign: 'center' }, - tabela: { borderWidth: 1, borderRadius: 8, overflow: 'hidden' }, - linhaTab: { flexDirection: 'row', borderBottomWidth: 1, paddingVertical: 8, alignItems: 'center' }, - celulaHeader: { flex: 1, fontWeight: 'bold', textAlign: 'center', fontSize: 13 }, - celulaLabel: { flex: 1, paddingLeft: 12, fontSize: 14 }, - celulaValor: { flex: 1, textAlign: 'center', fontSize: 14, fontWeight: '600' }, - notaTotal: { textAlign: 'center', fontSize: 12, marginTop: 8, fontWeight: '500' } }); diff --git a/app/Professor/Alunos/ListaAlunos.tsx b/app/Professor/Alunos/ListaAlunos.tsx index 076aee8..cfdd9cc 100644 --- a/app/Professor/Alunos/ListaAlunos.tsx +++ b/app/Professor/Alunos/ListaAlunos.tsx @@ -15,35 +15,19 @@ import { import { useTheme } from '../../../themecontext'; import { supabase } from '../../lib/supabase'; -/* ======================= - Interfaces -======================= */ - export interface Aluno { id: string; nome: string; - email: string; - telefone: string; - estado: string; // virá da tabela estagios + n_escola: string; turma: string; } -interface Turma { - nome: string; - alunos: Aluno[]; -} - -/* ======================= - Componente -======================= */ - const ListaAlunosProfessor = memo(() => { const { isDarkMode } = useTheme(); const router = useRouter(); const [search, setSearch] = useState(''); - const [expanded, setExpanded] = useState>({}); - const [turmas, setTurmas] = useState([]); + const [turmas, setTurmas] = useState<{ nome: string; alunos: Aluno[] }[]>([]); const [loading, setLoading] = useState(true); const cores = { @@ -54,10 +38,6 @@ const ListaAlunosProfessor = memo(() => { azul: '#0d6efd', }; - /* ======================= - Fetch Supabase - ======================= */ - useEffect(() => { fetchAlunos(); }, []); @@ -66,59 +46,48 @@ const ListaAlunosProfessor = memo(() => { setLoading(true); const { data, error } = await supabase - .from('profiles') - .select(` - id, - nome, - email, - telefone, - turma_curso, - ano, - n_escola - `) + .from('alunos') + .select('id, nome, n_escola, ano, turma_curso') .order('ano', { ascending: false }); if (error) { - console.error('Erro ao buscar alunos:', error); + console.error('Erro Supabase:', error); setLoading(false); return; } + if (!data || data.length === 0) { + console.log('Nenhum aluno encontrado'); + setTurmas([]); + setLoading(false); + return; + } + + // Agrupar por ano + turma_curso const agrupadas: Record = {}; - data.forEach((item: any) => { - const nomeTurma = `${item.ano} ${item.turma_curso}`; - - if (!agrupadas[nomeTurma]) { - agrupadas[nomeTurma] = []; - } + data.forEach(item => { + const nomeTurma = `${item.ano}º ${item.turma_curso}`; + if (!agrupadas[nomeTurma]) agrupadas[nomeTurma] = []; agrupadas[nomeTurma].push({ id: item.id, nome: item.nome, - email: item.email, - telefone: item.telefone ?? '—', - estado: 'Sem estágio', + n_escola: item.n_escola, turma: nomeTurma, }); }); - const turmasFormatadas: Turma[] = Object.keys(agrupadas).map(nome => ({ - nome, - alunos: agrupadas[nome], - })); + setTurmas( + Object.keys(agrupadas).map(nome => ({ + nome, + alunos: agrupadas[nome], + })) + ); - setTurmas(turmasFormatadas); setLoading(false); }; - const toggleExpand = (turmaNome: string) => - setExpanded(prev => ({ ...prev, [turmaNome]: !prev[turmaNome] })); - - /* ======================= - Pesquisa - ======================= */ - const filteredTurmas = turmas .map(turma => ({ ...turma, @@ -128,15 +97,10 @@ const ListaAlunosProfessor = memo(() => { })) .filter(t => t.alunos.length > 0); - /* ======================= - Render - ======================= */ - return ( - {/* Header */} { - {/* Pesquisa */} { )} - {/* Lista */} item.nome} - contentContainerStyle={{ paddingBottom: 20 }} renderItem={({ item }) => ( - toggleExpand(item.nome)}> - - {item.nome} ({item.alunos.length}) - - + + {item.nome} ({item.alunos.length}) + - {expanded[item.nome] && ( - - {item.alunos.map(aluno => ( - - router.push({ - pathname: '/Professor/Alunos/DetalhesAluno', - params: { aluno: JSON.stringify(aluno) }, - }) - } - > - - {aluno.nome} - - - {aluno.estado} - - - ))} - - )} + + {item.alunos.map(aluno => ( + + router.push({ + pathname: '/Professor/Alunos/DetalhesAluno', + params: { aluno: JSON.stringify(aluno) }, + }) + } + > + + {aluno.n_escola} – {aluno.nome} + + + ))} + )} /> @@ -217,66 +166,16 @@ const ListaAlunosProfessor = memo(() => { export default ListaAlunosProfessor; -/* ======================= - Styles -======================= */ - const styles = StyleSheet.create({ - safe: { - flex: 1, - paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0, - }, - header: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: 20, - paddingVertical: 10, - }, - btnVoltar: { - width: 40, - height: 40, - borderRadius: 20, - justifyContent: 'center', - alignItems: 'center', - elevation: 2, - }, - tituloGeral: { - fontSize: 22, - fontWeight: 'bold', - }, - spacer: { - width: 40, - }, - search: { - borderRadius: 10, - padding: 10, - margin: 10, - }, - card: { - borderRadius: 10, - padding: 15, - marginHorizontal: 10, - marginBottom: 10, - elevation: 2, - }, - turmaNome: { - fontSize: 18, - fontWeight: 'bold', - }, - listaAlunos: { - marginTop: 10, - paddingLeft: 10, - }, - alunoItem: { - paddingVertical: 8, - }, - alunoNome: { - fontSize: 16, - fontWeight: '600', - }, - alunoEstado: { - fontSize: 14, - marginTop: 2, - }, + safe: { flex: 1, paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0 }, + header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 20, paddingVertical: 10 }, + btnVoltar: { width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', elevation: 2 }, + tituloGeral: { fontSize: 22, fontWeight: 'bold' }, + spacer: { width: 40 }, + search: { borderRadius: 10, padding: 10, margin: 10 }, + card: { borderRadius: 10, padding: 15, marginHorizontal: 10, marginBottom: 10, elevation: 2 }, + turmaNome: { fontSize: 18, fontWeight: 'bold' }, + listaAlunos: { marginTop: 10, paddingLeft: 10 }, + alunoItem: { paddingVertical: 5 }, + alunoNome: { fontSize: 16, fontWeight: '600' }, });