diff --git a/app/Aluno/AlunoHome.tsx b/app/Aluno/AlunoHome.tsx
index 296fbd3..eaac02b 100644
--- a/app/Aluno/AlunoHome.tsx
+++ b/app/Aluno/AlunoHome.tsx
@@ -174,11 +174,11 @@ const AlunoHome = memo(() => {
- router.push('/perfil')}>
+ router.push('/Aluno/perfil')}>
Estágios+
- router.push('/definicoes')}>
+ router.push('/Aluno/definicoes')}>
diff --git a/app/Professor/Alunos/Faltas.tsx b/app/Professor/Alunos/Faltas.tsx
index 1d964ad..8553f45 100644
--- a/app/Professor/Alunos/Faltas.tsx
+++ b/app/Professor/Alunos/Faltas.tsx
@@ -2,22 +2,21 @@ import { Ionicons } from '@expo/vector-icons';
import { useRouter } from 'expo-router';
import { useState } from 'react';
import {
- Modal,
- Platform,
- SafeAreaView,
- ScrollView,
- StatusBar,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
+ Modal,
+ Platform,
+ SafeAreaView,
+ ScrollView,
+ StatusBar,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
} from 'react-native';
import { WebView } from 'react-native-webview';
-import { useTheme } from '../../../themecontext'; // <- seu contexto de tema
+import { useTheme } from '../../../themecontext';
interface Falta {
dia: string;
- motivo?: string;
pdfUrl?: string;
}
@@ -33,16 +32,22 @@ const alunosData: Aluno[] = [
id: 1,
nome: 'João Silva',
faltas: [
- { dia: '2026-01-20', motivo: 'Doença', pdfUrl: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' },
- { dia: '2026-01-22', motivo: 'Atraso' },
+ {
+ dia: '2026-01-20',
+ pdfUrl: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf',
+ },
+ { dia: '2026-01-22' },
],
},
{
id: 2,
nome: 'Maria Fernandes',
faltas: [
- { dia: '2026-01-21', motivo: 'Consulta médica' },
- { dia: '2026-01-23', motivo: 'Doença', pdfUrl: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' },
+ { dia: '2026-01-21' },
+ {
+ dia: '2026-01-23',
+ pdfUrl: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf',
+ },
],
},
];
@@ -82,18 +87,22 @@ export default function FaltasAlunos() {
{/* Top Bar */}
- {
- if (alunoSelecionado) {
- setAlunoSelecionado(null); // voltar para lista de alunos
- } else {
- router.back(); // voltar para menu
- }
- }}>
+ {
+ if (alunoSelecionado) {
+ setAlunoSelecionado(null);
+ } else {
+ router.back();
+ }
+ }}
+ >
+
{!alunoSelecionado ? 'Faltas dos Alunos' : alunoSelecionado.nome}
+
@@ -107,8 +116,14 @@ export default function FaltasAlunos() {
onPress={() => setAlunoSelecionado(aluno)}
>
- {aluno.nome}
-
+
+ {aluno.nome}
+
+
))}
@@ -118,17 +133,38 @@ export default function FaltasAlunos() {
{alunoSelecionado && (
{alunoSelecionado.faltas.map((falta, idx) => (
-
+
- {falta.dia}
- {falta.motivo || 'Sem motivo'}
-
- {falta.pdfUrl ? 'Justificada com PDF' : 'Não justificada'}
+
+ {falta.dia}
+
+
+
+ {falta.pdfUrl
+ ? 'Falta justificada'
+ : 'Falta não justificada'}
+
{falta.pdfUrl && (
verPdf(falta)}>
-
+
)}
@@ -140,13 +176,21 @@ export default function FaltasAlunos() {
{/* Modal PDF */}
-
+
setPdfModalVisible(false)}>
- Visualizador de PDF
+
+ Visualizador de PDF
+
+
{pdfUrl && }
@@ -155,10 +199,23 @@ export default function FaltasAlunos() {
}
const styles = StyleSheet.create({
- safe: { flex: 1, paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0 },
+ safe: {
+ flex: 1,
+ paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
+ },
container: { padding: 20, paddingBottom: 40 },
- topBar: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 },
- topTitle: { fontSize: 20, fontWeight: '700', textAlign: 'center', flex: 1 },
+ topBar: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginBottom: 16,
+ },
+ topTitle: {
+ fontSize: 20,
+ fontWeight: '700',
+ textAlign: 'center',
+ flex: 1,
+ },
alunoCard: {
flexDirection: 'row',
alignItems: 'center',
@@ -171,7 +228,12 @@ const styles = StyleSheet.create({
shadowRadius: 4,
elevation: 2,
},
- alunoName: { fontSize: 16, fontWeight: '600', marginLeft: 12, flex: 1 },
+ alunoName: {
+ fontSize: 16,
+ fontWeight: '600',
+ marginLeft: 12,
+ flex: 1,
+ },
faltaCard: {
flexDirection: 'row',
alignItems: 'center',
@@ -185,9 +247,15 @@ const styles = StyleSheet.create({
shadowRadius: 4,
elevation: 2,
},
- dia: { fontSize: 14, fontWeight: '700', marginBottom: 4 },
- motivo: { fontSize: 14, marginBottom: 4 },
- status: { fontSize: 13, fontWeight: '600' },
+ dia: {
+ fontSize: 14,
+ fontWeight: '700',
+ marginBottom: 6,
+ },
+ status: {
+ fontSize: 13,
+ fontWeight: '600',
+ },
pdfHeader: {
flexDirection: 'row',
alignItems: 'center',
@@ -195,5 +263,8 @@ const styles = StyleSheet.create({
padding: 16,
borderBottomWidth: 1,
},
- pdfTitle: { fontSize: 18, fontWeight: '700' },
+ pdfTitle: {
+ fontSize: 18,
+ fontWeight: '700',
+ },
});
diff --git a/app/Professor/Empresas/DetalhesEmpresa.tsx b/app/Professor/Empresas/DetalhesEmpresa.tsx
index 1a129bb..e2ffd1f 100644
--- a/app/Professor/Empresas/DetalhesEmpresa.tsx
+++ b/app/Professor/Empresas/DetalhesEmpresa.tsx
@@ -2,6 +2,7 @@ import { Ionicons } from '@expo/vector-icons';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { memo, useMemo, useState } from 'react';
import {
+ ActivityIndicator,
Alert,
Platform,
SafeAreaView,
@@ -14,22 +15,38 @@ import {
View
} from 'react-native';
import { useTheme } from '../../../themecontext';
-import type { Empresa } from './ListaEmpresas';
+import { supabase } from '../../lib/supabase';
+
+// Interface atualizada para incluir a lista de alunos
+export interface Empresa {
+ id: number;
+ nome: string;
+ morada: string;
+ tutor_nome: string;
+ tutor_telefone: string;
+ curso: string;
+ alunos?: string[]; // Array com nomes dos alunos
+}
const DetalhesEmpresa = memo(() => {
const { isDarkMode } = useTheme();
const router = useRouter();
const params = useLocalSearchParams();
- // Parse da empresa recebida
+ // Parse seguro dos dados vindos da navegação
const empresaOriginal: Empresa = useMemo(() => {
- if (!params.empresa) return null as any;
+ if (!params.empresa) return {} as Empresa;
const str = Array.isArray(params.empresa) ? params.empresa[0] : params.empresa;
- return JSON.parse(str);
+ try {
+ return JSON.parse(str);
+ } catch {
+ return {} as Empresa;
+ }
}, [params.empresa]);
const [empresaLocal, setEmpresaLocal] = useState({ ...empresaOriginal });
const [editando, setEditando] = useState(false);
+ const [loading, setLoading] = useState(false);
const cores = {
fundo: isDarkMode ? '#121212' : '#f1f3f5',
@@ -41,115 +58,150 @@ const DetalhesEmpresa = memo(() => {
vermelho: '#dc3545',
};
- const handleSave = () => {
- setEditando(false);
- Alert.alert('Sucesso', 'Empresa atualizada!');
- // Aqui depois substituis por update no Supabase
+ const handleSave = async () => {
+ try {
+ setLoading(true);
+ const { error } = await supabase
+ .from('empresas')
+ .update({
+ nome: empresaLocal.nome,
+ morada: empresaLocal.morada,
+ tutor_nome: empresaLocal.tutor_nome,
+ tutor_telefone: empresaLocal.tutor_telefone,
+ curso: empresaLocal.curso,
+ })
+ .eq('id', empresaLocal.id);
+
+ if (error) throw error;
+ setEditando(false);
+ Alert.alert('Sucesso', 'Dados atualizados!');
+ } catch (error: any) {
+ Alert.alert('Erro', error.message);
+ } finally {
+ setLoading(false);
+ }
};
const handleDelete = () => {
- Alert.alert(
- 'Apagar Empresa',
- 'Tem a certeza que deseja apagar esta empresa?',
- [
- { text: 'Cancelar', style: 'cancel' },
- { text: 'Apagar', style: 'destructive', onPress: () => router.back() }
- ]
- );
+ Alert.alert('Apagar', `Apagar ${empresaLocal.nome}?`, [
+ { text: 'Cancelar', style: 'cancel' },
+ {
+ text: 'Apagar',
+ style: 'destructive',
+ onPress: async () => {
+ await supabase.from('empresas').delete().eq('id', empresaLocal.id);
+ router.back();
+ }
+ }
+ ]);
};
return (
-
-
+
+
-
- router.back()}>
-
-
-
- {empresaLocal.nome}
-
-
- setEditando(!editando)}>
-
+
+
+ router.back()}>
+
-
-
-
-
-
-
- {/* Dados da Empresa */}
-
- Dados da Empresa
-
- {['nome', 'curso', 'morada', 'tutor', 'telefone'].map((campo) => (
-
-
- {campo.charAt(0).toUpperCase() + campo.slice(1)}
-
- {editando ? (
- setEmpresaLocal({ ...empresaLocal, [campo]: v })}
- />
- ) : (
-
- {(empresaLocal as any)[campo]}
-
- )}
-
- ))}
-
-
- {/* Botão Guardar alterações */}
- {editando && (
-
- Guardar alterações
-
- )}
-
- {/* Estatísticas */}
-
- Estatísticas
- Total de Alunos
-
- {empresaLocal.alunos?.length || 0}
+
+ {empresaLocal.nome || 'Detalhes'}
+
+
+ setEditando(!editando)}
+ >
+
+
+
+
+
+
- {/* Lista de Alunos */}
- {empresaLocal.alunos && empresaLocal.alunos.length > 0 && (
+
+ {/* CARD DE DADOS */}
- Alunos na Empresa
- {empresaLocal.alunos.map((aluno, index) => (
-
- {aluno}
-
+ Informações da Empresa
+ {[
+ { label: 'Nome', key: 'nome' },
+ { label: 'Curso', key: 'curso' },
+ { label: 'Morada', key: 'morada' },
+ { label: 'Tutor', key: 'tutor_nome' },
+ { label: 'Telefone', key: 'tutor_telefone' },
+ ].map((item) => (
+
+ {item.label}
+ {editando ? (
+ setEmpresaLocal(prev => ({ ...prev, [item.key]: v }))}
+ />
+ ) : (
+ {(empresaLocal as any)[item.key] || '---'}
+ )}
+
))}
- )}
-
-
+ {editando && (
+
+ {loading ? : Confirmar Alterações}
+
+ )}
+
+ {/* ESTATÍSTICAS COM LISTA DE ALUNOS */}
+
+ Alunos em Estágio
+
+ {empresaLocal.alunos && empresaLocal.alunos.length > 0 ? (
+ empresaLocal.alunos.map((aluno, index) => (
+
+
+ {aluno}
+
+ ))
+ ) : (
+
+ Nenhum aluno associado.
+
+ )}
+
+
+ Total de Alunos
+
+ {empresaLocal.alunos?.length || 0}
+
+
+
+
+
+
);
});
export default DetalhesEmpresa;
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 },
+ safe: { flex: 1, paddingTop: Platform.OS === 'android' ? (StatusBar.currentHeight || 0) : 0 },
+ header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 15, paddingVertical: 10 },
+ headerAcoes: { flexDirection: 'row', gap: 8 },
btnVoltar: { width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', elevation: 2 },
- btnAcao: { width: 40, height: 40, borderRadius: 10, justifyContent: 'center', alignItems: 'center' },
- 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 },
- valor: { fontSize: 16, fontWeight: '600' },
- input: { borderWidth: 1, borderRadius: 10, padding: 10, marginTop: 2 },
- saveButton: { padding: 16, borderRadius: 10, marginTop: 16 },
-});
+ btnAcao: { width: 38, height: 38, borderRadius: 10, justifyContent: 'center', alignItems: 'center', elevation: 2 },
+ tituloGeral: { fontSize: 18, fontWeight: 'bold', flex: 1, textAlign: 'center', marginHorizontal: 10 },
+ container: { padding: 20, gap: 15 },
+ card: { padding: 20, borderRadius: 16, elevation: 3, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4 },
+ tituloCard: { fontSize: 16, fontWeight: 'bold', marginBottom: 15, textAlign: 'center', borderBottomWidth: 1, borderBottomColor: '#f0f0f0', paddingBottom: 8 },
+ campoWrapper: { marginBottom: 15 },
+ label: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', marginBottom: 4 },
+ valor: { fontSize: 16, fontWeight: '500' },
+ alunoRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 8, paddingLeft: 5 },
+ input: { borderWidth: 1, borderRadius: 8, padding: 10, fontSize: 16, marginTop: 2 },
+ saveButton: { padding: 16, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginBottom: 10 },
+ txtBtn: { color: '#fff', fontWeight: 'bold', fontSize: 16 }
+});
\ No newline at end of file
diff --git a/app/Professor/Empresas/ListaEmpresas.tsx b/app/Professor/Empresas/ListaEmpresas.tsx
index e2af789..1856cdb 100644
--- a/app/Professor/Empresas/ListaEmpresas.tsx
+++ b/app/Professor/Empresas/ListaEmpresas.tsx
@@ -1,136 +1,321 @@
import { Ionicons } from '@expo/vector-icons';
import { useRouter } from 'expo-router';
-import { memo, useMemo, useState } from 'react';
+import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import {
+ ActivityIndicator,
Alert,
- FlatList, Platform, SafeAreaView, StatusBar,
- StyleSheet, Text, TextInput, TouchableOpacity, View
+ FlatList,
+ Modal,
+ Platform,
+ RefreshControl,
+ SafeAreaView,
+ ScrollView,
+ StatusBar,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableOpacity,
+ View
} from 'react-native';
import { useTheme } from '../../../themecontext';
+import { supabase } from '../../lib/supabase';
export interface Empresa {
id: number;
nome: string;
morada: string;
- tutor: string;
- telefone: string;
+ tutor_nome: string;
+ tutor_telefone: string;
curso: string;
- alunos?: string[];
}
-const initialEmpresasData: Empresa[] = [
- { id: 1, nome: 'Empresa X', morada: 'Rua das Flores, 12', tutor: 'João Santos', telefone: '912345678', curso: 'Técnico de Informática', alunos: ['João Silva'] },
- { id: 2, nome: 'Empresa W', morada: 'Av. Central, 45', tutor: 'Ana Costa', telefone: '912345679', curso: 'Técnico de Design', alunos: ['Maria Fernandes'] },
-];
-
const ListaEmpresasProfessor = memo(() => {
const { isDarkMode } = useTheme();
const router = useRouter();
- const [search, setSearch] = useState('');
- const [empresas, setEmpresas] = useState(initialEmpresasData);
- const cores = {
+ const [search, setSearch] = useState('');
+ const [empresas, setEmpresas] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [refreshing, setRefreshing] = useState(false);
+
+ // MODAL + FORM
+ const [modalVisible, setModalVisible] = useState(false);
+ const [nome, setNome] = useState('');
+ const [morada, setMorada] = useState('');
+ const [tutorNome, setTutorNome] = useState('');
+ const [tutorTelefone, setTutorTelefone] = useState('');
+ const [curso, setCurso] = useState('');
+
+ const cores = useMemo(() => ({
fundo: isDarkMode ? '#121212' : '#f1f3f5',
card: isDarkMode ? '#1e1e1e' : '#fff',
texto: isDarkMode ? '#fff' : '#000',
textoSecundario: isDarkMode ? '#adb5bd' : '#6c757d',
azul: '#0d6efd',
+ }), [isDarkMode]);
+
+ const fetchEmpresas = async () => {
+ try {
+ setLoading(true);
+ const { data, error } = await supabase
+ .from('empresas')
+ .select('*')
+ .order('nome', { ascending: true });
+
+ if (error) throw error;
+ setEmpresas(data || []);
+ } catch (error: any) {
+ Alert.alert('Erro ao carregar', error.message);
+ } finally {
+ setLoading(false);
+ setRefreshing(false);
+ }
};
- // Filtrar empresas
+ useEffect(() => {
+ fetchEmpresas();
+ }, []);
+
+ const onRefresh = useCallback(() => {
+ setRefreshing(true);
+ fetchEmpresas();
+ }, []);
+
const filteredEmpresas = useMemo(
- () => empresas.filter(e => e.nome.toLowerCase().includes(search.toLowerCase())),
+ () => empresas.filter(e =>
+ e.nome?.toLowerCase().includes(search.toLowerCase())
+ ),
[search, empresas]
);
- // Criar nova empresa
- const criarEmpresa = () => {
- Alert.prompt(
- 'Nova Empresa',
- 'Insira o nome da empresa',
- (nome) => {
- if (!nome) return;
- const nova: Empresa = {
- id: Date.now(),
- nome,
- morada: 'Não definida',
- tutor: 'Não definido',
- telefone: '000000000',
- curso: 'Não definido',
- alunos: []
- };
- setEmpresas(prev => [nova, ...prev]);
- router.push({
- pathname: '/Professor/Empresas/DetalhesEmpresa',
- params: { empresa: JSON.stringify(nova) }
- });
- }
- );
+ // 👉 CRIAR EMPRESA (AGORA COM TODOS OS CAMPOS)
+ const criarEmpresa = async () => {
+ if (!nome || !morada || !tutorNome || !tutorTelefone || !curso) {
+ Alert.alert('Erro', 'Preenche todos os campos.');
+ return;
+ }
+
+ try {
+ setLoading(true);
+
+ const { data, error } = await supabase
+ .from('empresas')
+ .insert([{
+ nome: nome.trim(),
+ morada: morada.trim(),
+ tutor_nome: tutorNome.trim(),
+ tutor_telefone: tutorTelefone.trim(),
+ curso: curso.trim(),
+ }])
+ .select();
+
+ if (error) throw error;
+
+ setEmpresas(prev => [data![0], ...prev]);
+
+ // limpar form
+ setNome('');
+ setMorada('');
+ setTutorNome('');
+ setTutorTelefone('');
+ setCurso('');
+
+ setModalVisible(false);
+ Alert.alert('Sucesso', 'Empresa criada com sucesso!');
+ } catch (error: any) {
+ Alert.alert('Erro ao criar', error.message);
+ } finally {
+ setLoading(false);
+ }
};
return (
-
-
-
- {/* Header com botão voltar */}
-
- router.back()}>
-
-
- Empresas
-
-
-
- {/* Input de pesquisa */}
-
+
- {/* Botão criar empresa */}
-
- + Criar Empresa
-
-
- {/* Lista de empresas */}
- item.id.toString()}
- renderItem={({ item }) => (
+
+ {/* HEADER */}
+
- router.push({
- pathname: '/Professor/Empresas/DetalhesEmpresa',
- params: { empresa: JSON.stringify(item) }
- })
- }
+ style={[styles.btnVoltar, { backgroundColor: cores.card }]}
+ onPress={() => router.back()}
>
- {item.nome}
- {item.curso}
- {item.tutor}
+
+
+ Empresas
+
+
+
+
+ {/* SEARCH */}
+
+
+
+
+
+ {/* BOTÃO NOVA EMPRESA */}
+ setModalVisible(true)}
+ >
+
+ Nova Empresa
+
+
+ {/* LISTA */}
+ {loading && !refreshing ? (
+
+ ) : (
+ item.id.toString()}
+ refreshControl={
+
+ }
+ renderItem={({ item }) => (
+
+ router.push({
+ pathname: '/Professor/Empresas/DetalhesEmpresa',
+ params: { empresa: JSON.stringify(item) }
+ })
+ }
+ >
+
+ {item.nome}
+
+ {item.curso}
+
+
+ {item.tutor_nome}
+
+
+
+
+ )}
+ contentContainerStyle={styles.listContent}
+ />
)}
- />
-
+
+
+ {/* MODAL */}
+
+
+
+
+ Nova Empresa
+
+
+
+
+
+
+
+
+
+
+
+ setModalVisible(false)}>
+
+ Cancelar
+
+
+
+
+
+ Criar
+
+
+
+
+
+
+
);
});
export default ListaEmpresasProfessor;
+/* INPUT */
+const Input = ({ label, cores, ...props }: any) => (
+
+
+ {label}
+
+
+
+);
+
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 },
+ safe: { flex: 1, paddingTop: Platform.OS === 'android' ? 10 : 0 },
+ header: { flexDirection: 'row', justifyContent: 'space-between', padding: 20 },
+ btnVoltar: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center' },
tituloGeral: { fontSize: 22, fontWeight: 'bold' },
- spacer: { width: 40 },
- search: { borderRadius: 10, padding: 10, margin: 10 },
- btnCriar: { marginHorizontal: 10, padding: 12, borderRadius: 10, alignItems: 'center', marginBottom: 10 },
- card: { borderRadius: 10, padding: 15, marginBottom: 10, elevation: 2 },
+ searchContainer: { marginHorizontal: 15, marginBottom: 10 },
+ searchIcon: { position: 'absolute', left: 15, top: 14 },
+ search: { borderRadius: 12, padding: 12, paddingLeft: 45 },
+ btnCriar: { flexDirection: 'row', margin: 15, padding: 15, borderRadius: 12, justifyContent: 'center', gap: 8 },
+ txtBtnCriar: { color: '#fff', fontWeight: 'bold' },
+ listContent: { padding: 15 },
+ card: { flexDirection: 'row', justifyContent: 'space-between', padding: 18, borderRadius: 15, marginBottom: 12 },
nomeEmpresa: { fontSize: 18, fontWeight: 'bold' },
- curso: { fontSize: 14, marginTop: 2 },
- tutor: { fontSize: 14, marginTop: 2 },
+ info: { fontSize: 14, marginTop: 3 },
+
+ modalOverlay: {
+ flex: 1,
+ backgroundColor: 'rgba(0,0,0,0.5)',
+ justifyContent: 'center',
+ padding: 20,
+ },
+ modalContent: {
+ borderRadius: 16,
+ padding: 20,
+ maxHeight: '90%',
+ },
+ modalTitle: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ marginBottom: 15,
+ textAlign: 'center',
+ },
+ modalButtons: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginTop: 15,
+ },
+ btnConfirmar: {
+ padding: 14,
+ borderRadius: 10,
+ minWidth: 100,
+ alignItems: 'center',
+ },
});
diff --git a/app/index.tsx b/app/index.tsx
index 50e2589..9f3d161 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -1,25 +1,79 @@
// app/index.tsx
import { useRouter } from 'expo-router';
-import { KeyboardAvoidingView, Platform, ScrollView, StyleSheet, Text, View } from 'react-native';
+import {
+ Alert,
+ KeyboardAvoidingView,
+ Platform,
+ ScrollView,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
import Auth from '../components/Auth';
+import { supabase } from './lib/supabase';
export default function LoginScreen() {
const router = useRouter();
- const handleLoginSuccess = () => {
- router.replace('/Professor/ProfessorHome');
+ const handleLoginSuccess = async () => {
+ try {
+ // 1️⃣ buscar utilizador autenticado
+ const {
+ data: { user },
+ error: userError,
+ } = await supabase.auth.getUser();
+
+ if (userError || !user) {
+ Alert.alert('Erro', 'Utilizador não autenticado');
+ return;
+ }
+
+ // 2️⃣ buscar tipo (professor / aluno)
+ const { data, error } = await supabase
+ .from('profiles')
+ .select('tipo')
+ .eq('id', user.id)
+ .single();
+
+ if (error || !data) {
+ Alert.alert(
+ 'Erro',
+ 'Não foi possível obter o tipo de utilizador'
+ );
+ return;
+ }
+
+ // 3️⃣ redirecionar conforme o tipo
+ if (data.tipo === 'professor') {
+ router.replace('/Professor/ProfessorHome');
+ } else if (data.tipo === 'aluno') {
+ router.replace('/Aluno/AlunoHome');
+ } else {
+ Alert.alert('Erro', 'Tipo de utilizador inválido');
+ }
+ } catch (err) {
+ Alert.alert('Erro', 'Erro inesperado no login');
+ }
};
return (
-
-
+
+
📱 Estágios+
- Escola Profissional de Vila do Conde
+
+ Escola Profissional de Vila do Conde
+
- {/* Componente Auth */}
+ {/* COMPONENTE DE LOGIN */}
@@ -28,9 +82,29 @@ export default function LoginScreen() {
}
const styles = StyleSheet.create({
- scrollContainer: { flexGrow: 1, justifyContent: 'center', paddingHorizontal: 24, paddingVertical: 40 },
- content: { flex: 1, justifyContent: 'center' },
- header: { alignItems: 'center', marginBottom: 48 },
- title: { fontSize: 32, fontWeight: '800', color: '#2d3436', marginBottom: 8 },
- subtitle: { fontSize: 16, color: '#636e72', textAlign: 'center' },
+ scrollContainer: {
+ flexGrow: 1,
+ justifyContent: 'center',
+ paddingHorizontal: 24,
+ paddingVertical: 40,
+ },
+ content: {
+ flex: 1,
+ justifyContent: 'center',
+ },
+ header: {
+ alignItems: 'center',
+ marginBottom: 48,
+ },
+ title: {
+ fontSize: 32,
+ fontWeight: '800',
+ color: '#2d3436',
+ marginBottom: 8,
+ },
+ subtitle: {
+ fontSize: 16,
+ color: '#636e72',
+ textAlign: 'center',
+ },
});