diff --git a/app/AlunoHome.tsx b/app/Aluno/AlunoHome.tsx similarity index 99% rename from app/AlunoHome.tsx rename to app/Aluno/AlunoHome.tsx index bed089f..296fbd3 100644 --- a/app/AlunoHome.tsx +++ b/app/Aluno/AlunoHome.tsx @@ -9,7 +9,7 @@ import { Alert, Platform, SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { Calendar, LocaleConfig } from 'react-native-calendars'; -import { useTheme } from '../themecontext'; +import { useTheme } from '../../themecontext'; // Configuração PT LocaleConfig.locales['pt'] = { diff --git a/app/definicoes.tsx b/app/Aluno/definicoes.tsx similarity index 96% rename from app/definicoes.tsx rename to app/Aluno/definicoes.tsx index 8a1eb45..444709e 100644 --- a/app/definicoes.tsx +++ b/app/Aluno/definicoes.tsx @@ -1,19 +1,19 @@ import { Ionicons } from '@expo/vector-icons'; import { useRouter } from 'expo-router'; -import React, { memo, useMemo, useState } from 'react'; // Importado useMemo e memo +import { memo, useMemo, useState } from 'react'; // Importado useMemo e memo import { - Alert, - Linking, - Platform, - SafeAreaView, - StatusBar, - StyleSheet, - Switch, - Text, - TouchableOpacity, - View + Alert, + Linking, + Platform, + SafeAreaView, + StatusBar, + StyleSheet, + Switch, + Text, + TouchableOpacity, + View } from 'react-native'; -import { useTheme } from '../themecontext'; +import { useTheme } from '../../themecontext'; const Definicoes = memo(() => { const router = useRouter(); diff --git a/app/mainmenu.tsx b/app/Aluno/mainmenu.tsx similarity index 96% rename from app/mainmenu.tsx rename to app/Aluno/mainmenu.tsx index 1e76c03..cf739d3 100644 --- a/app/mainmenu.tsx +++ b/app/Aluno/mainmenu.tsx @@ -1,6 +1,5 @@ -import React from 'react'; import { SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { useTheme } from '../themecontext'; // Ajusta o caminho conforme a tua estrutura +import { useTheme } from '../../themecontext'; // Ajusta o caminho conforme a tua estrutura const MainMenu = () => { const { isDarkMode } = useTheme(); diff --git a/app/perfil.tsx b/app/Aluno/perfil.tsx similarity index 99% rename from app/perfil.tsx rename to app/Aluno/perfil.tsx index abb9d35..1836295 100644 --- a/app/perfil.tsx +++ b/app/Aluno/perfil.tsx @@ -8,7 +8,7 @@ import { Platform, SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { useTheme } from '../themecontext'; +import { useTheme } from '../../themecontext'; export default function Perfil() { const { isDarkMode } = useTheme(); diff --git a/app/Professor/ListaAlunos.tsx b/app/Professor/ListaAlunos.tsx new file mode 100644 index 0000000..4dd0a12 --- /dev/null +++ b/app/Professor/ListaAlunos.tsx @@ -0,0 +1,97 @@ +import { + StyleSheet +} from 'react-native'; + +/* DADOS MOCK (SUBSTITUI PELO SUPABASE DEPOIS) */ +const alunos = [ + { + id: '1', + nome: 'Ana Martins', + curso: 'Técnico de Informática', + turma: '12ºTIG', + empresa: 'Tech Solutions', + }, + { + id: '2', + nome: 'Pedro Costa', + curso: 'Técnico de Informática', + turma: '11ºTIG', + empresa: 'SoftDev Lda', + }, + { + id: '3', + nome: 'Rita Fernandes', + curso: 'Técnico de Informática', + turma: '12ºTIG', + empresa: 'WebWorks', + }, +]; + + +/* ESTILOS */ + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#f1f3f5', + }, + content: { + padding: 20, + }, + header: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: 24, + }, + title: { + flex: 1, + textAlign: 'center', + fontSize: 20, + fontWeight: '800', + color: '#212529', + }, + card: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: '#fff', + borderRadius: 16, + padding: 16, + marginBottom: 12, + shadowColor: '#000', + shadowOpacity: 0.06, + shadowRadius: 8, + elevation: 3, + }, + avatar: { + width: 44, + height: 44, + borderRadius: 22, + backgroundColor: '#0d6efd', + alignItems: 'center', + justifyContent: 'center', + marginRight: 14, + }, + avatarText: { + color: '#fff', + fontWeight: '800', + fontSize: 18, + }, + info: { + flex: 1, + }, + nome: { + fontSize: 16, + fontWeight: '700', + color: '#212529', + }, + sub: { + fontSize: 13, + color: '#6c757d', + marginTop: 2, + }, + empresa: { + fontSize: 13, + color: '#495057', + marginTop: 4, + }, +}); diff --git a/app/Professor/PerfilProf.tsx b/app/Professor/PerfilProf.tsx new file mode 100644 index 0000000..e82bf37 --- /dev/null +++ b/app/Professor/PerfilProf.tsx @@ -0,0 +1,254 @@ +import { Ionicons } from '@expo/vector-icons'; +import { useRouter } from 'expo-router'; +import { useState } from 'react'; +import { + Alert, + SafeAreaView, + ScrollView, + StyleSheet, + Text, + TextInput, + TouchableOpacity, + View, +} from 'react-native'; +import { supabase } from '../lib/supabase'; + +export default function PerfilProfessor() { + const router = useRouter(); + + const [editando, setEditando] = useState(false); + + const [perfil, setPerfil] = useState({ + nome: 'João Miranda', + email: 'joao.miranda@epvc.pt', + mecanografico: 'PROF-174', + area: 'Informática', + turmas: '12ºINF | 11ºINF | 10ºINF', + funcao: 'Orientador de Estágio', + }); + + const terminarSessao = async () => { + await supabase.auth.signOut(); + router.replace('/'); + }; + + const guardarPerfil = () => { + setEditando(false); + Alert.alert('Sucesso', 'Perfil atualizado com sucesso!'); + // aqui depois ligas ao Supabase (update) + }; + + return ( + + + + {/* TOPO COM VOLTAR */} + + router.back()}> + + + Perfil + + + + {/* HEADER */} + + + + + {perfil.nome} + {perfil.funcao} + + + {/* INFORMAÇÕES */} + + + setPerfil({ ...perfil, nome: v })} + /> + + + + setPerfil({ ...perfil, mecanografico: v })} + /> + + setPerfil({ ...perfil, area: v })} + /> + + setPerfil({ ...perfil, turmas: v })} + /> + + + + {/* AÇÕES */} + + + {editando ? ( + + + Guardar alterações + + ) : ( + setEditando(true)} + /> + )} + + router.push('/redefenirsenha2')} + /> + + + + + + + + ); +} + +/* COMPONENTES */ + +function InfoField({ + label, + value, + editable, + onChange, +}: { + label: string; + value: string; + editable: boolean; + onChange?: (v: string) => void; +}) { + return ( + + {label} + {editable ? ( + + ) : ( + {value} + )} + + ); +} + +function ActionButton({ + icon, + text, + onPress, + danger = false, +}: { + icon: any; + text: string; + onPress: () => void; + danger?: boolean; +}) { + return ( + + + + {text} + + + ); +} + +/* ESTILOS */ + +const styles = StyleSheet.create({ + container: { flex: 1, backgroundColor: '#f1f3f5' }, + content: { padding: 24 }, + + topBar: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + marginBottom: 20, + }, + topTitle: { + fontSize: 18, + fontWeight: '700', + color: '#212529', + }, + + header: { alignItems: 'center', marginBottom: 32 }, + avatar: { + width: 90, height: 90, borderRadius: 45, + backgroundColor: '#0d6efd', + alignItems: 'center', justifyContent: 'center', + marginBottom: 12, + }, + name: { fontSize: 22, fontWeight: '800', color: '#212529' }, + role: { fontSize: 14, color: '#6c757d', marginTop: 4 }, + + card: { + backgroundColor: '#fff', + borderRadius: 18, + padding: 20, + marginBottom: 24, + elevation: 4, + }, + + infoField: { marginBottom: 16 }, + label: { fontSize: 12, color: '#6c757d', marginBottom: 4 }, + value: { fontSize: 15, fontWeight: '600', color: '#212529' }, + input: { + borderWidth: 1, + borderColor: '#ced4da', + borderRadius: 10, + padding: 10, + fontSize: 15, + backgroundColor: '#f8f9fa', + }, + + actions: { gap: 12 }, + + actionButton: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: '#fff', + borderRadius: 14, + padding: 16, + }, + actionText: { + fontSize: 15, + fontWeight: '600', + marginLeft: 12, + color: '#0d6efd', + }, + + primaryButton: { + backgroundColor: '#0d6efd', + borderRadius: 14, + padding: 16, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + }, + primaryText: { color: '#fff', fontWeight: '700', marginLeft: 8 }, + + dangerButton: { + borderWidth: 1, + borderColor: '#dc3545', + }, + dangerText: { color: '#dc3545' }, +}); diff --git a/app/Professor/ProfessorHome.tsx b/app/Professor/ProfessorHome.tsx new file mode 100644 index 0000000..414f23c --- /dev/null +++ b/app/Professor/ProfessorHome.tsx @@ -0,0 +1,147 @@ +import { Ionicons } from '@expo/vector-icons'; +import { useRouter } from 'expo-router'; +import { + SafeAreaView, + ScrollView, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; + +export default function ProfessorMenu() { + const router = useRouter(); + + return ( + + + + {/* HEADER */} + + Bem-vindo, + Professor 👨‍🏫 + Painel de gestão + + + {/* GRID DE OPÇÕES */} + + + router.push('/perfil')} + /> + + router.push('/definicoes')} + /> + + router.push('/professor/sumarios')} + /> + + router.push('/professor/alunos')} + /> + + router.push('/professor/empresas')} + /> + + + + + + ); +} + +/* CARD REUTILIZÁVEL */ +function MenuCard({ + icon, + title, + subtitle, + onPress, +}: { + icon: any; + title: string; + subtitle: string; + onPress: () => void; +}) { + return ( + + + {title} + {subtitle} + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#f1f3f5', + }, + content: { + padding: 24, + }, + header: { + marginBottom: 32, + }, + welcome: { + fontSize: 16, + color: '#6c757d', + }, + name: { + fontSize: 28, + fontWeight: '800', + color: '#212529', + marginTop: 4, + }, + subtitle: { + fontSize: 14, + color: '#6c757d', + marginTop: 6, + }, + grid: { + flexDirection: 'row', + flexWrap: 'wrap', + justifyContent: 'space-between', + }, + card: { + width: '48%', + backgroundColor: '#fff', + borderRadius: 18, + padding: 20, + marginBottom: 16, + alignItems: 'flex-start', + shadowColor: '#000', + shadowOffset: { width: 0, height: 4 }, + shadowOpacity: 0.08, + shadowRadius: 10, + elevation: 4, + }, + cardTitle: { + fontSize: 16, + fontWeight: '700', + marginTop: 12, + color: '#212529', + }, + cardSubtitle: { + fontSize: 13, + color: '#6c757d', + marginTop: 4, + }, +}); diff --git a/app/Professor/redefenirsenha2.tsx b/app/Professor/redefenirsenha2.tsx new file mode 100644 index 0000000..f8d4551 --- /dev/null +++ b/app/Professor/redefenirsenha2.tsx @@ -0,0 +1,131 @@ +// app/forgot-password.tsx +import { useRouter } from 'expo-router'; +import { useState } from 'react'; +import { + ActivityIndicator, + Alert, + KeyboardAvoidingView, + Platform, + ScrollView, + StyleSheet, + Text, + TextInput, + TouchableOpacity, + View +} from 'react-native'; +import { supabase } from '../lib/supabase'; + +export default function ForgotPassword() { + const [email, setEmail] = useState(''); + const [loading, setLoading] = useState(false); + const router = useRouter(); + + const handleSendResetEmail = async () => { + if (!email) { + Alert.alert('Atenção', 'Insira seu email'); + return; + } + + setLoading(true); + try { + const { error } = await supabase.auth.resetPasswordForEmail(email); + if (error) throw error; + + Alert.alert('Sucesso!', 'Verifique seu email para redefinir a palavra-passe'); + router.back(); // volta para login + } catch (err: any) { + Alert.alert('Erro', err.message); + } finally { + setLoading(false); + } + }; + + return ( + + + + + Recuperar Palavra-passe + Insira seu email para receber o link de redefinição + + {/* INPUT EMAIL */} + + + {/* BOTÃO ENVIAR LINK */} + + {loading ? : ENVIAR LINK} + + + {/* BOTÃO VOLTAR */} + router.push('/Professor/PerfilProf')} style={styles.backContainer}> + ← Voltar atrás + + + + + + ); +} + +const styles = StyleSheet.create({ + scrollContainer: { flexGrow: 1, justifyContent: 'center', padding: 24 }, + container: { + backgroundColor: '#fff', + borderRadius: 16, + padding: 24, + shadowColor: '#000', + shadowOffset: { width: 0, height: 6 }, + shadowOpacity: 0.1, + shadowRadius: 12, + elevation: 5, + }, + logo: { + width: 120, + height: 120, + alignSelf: 'center', + marginBottom: 20, + }, + title: { fontSize: 24, fontWeight: '700', color: '#2d3436', marginBottom: 8, textAlign: 'center' }, + subtitle: { fontSize: 14, color: '#636e72', marginBottom: 20, textAlign: 'center' }, + input: { + backgroundColor: '#f1f2f6', + borderRadius: 12, + paddingHorizontal: 16, + paddingVertical: 14, + fontSize: 16, + marginBottom: 20, + borderWidth: 0, + color: '#2d3436', + }, + button: { + backgroundColor: '#0984e3', + borderRadius: 12, + paddingVertical: 16, + alignItems: 'center', + marginBottom: 12, + shadowColor: '#0984e3', + shadowOffset: { width: 0, height: 4 }, + shadowOpacity: 0.3, + shadowRadius: 6, + elevation: 3, + }, + buttonDisabled: { backgroundColor: '#74b9ff' }, + buttonText: { color: '#fff', fontSize: 17, fontWeight: '700' }, + backContainer: { marginTop: 8, alignItems: 'center' }, + backText: { color: '#0984e3', fontSize: 15, fontWeight: '500' }, +}); diff --git a/app/index.tsx b/app/index.tsx index 058d1f4..50e2589 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -7,7 +7,7 @@ export default function LoginScreen() { const router = useRouter(); const handleLoginSuccess = () => { - router.replace('/AlunoHome'); + router.replace('/Professor/ProfessorHome'); }; return (