main
Ricardo Gomes 2025-12-12 10:43:24 +00:00
parent 3390923c66
commit 15355007de
3 changed files with 155 additions and 123 deletions

106
app/dashboard.tsx Normal file
View File

@ -0,0 +1,106 @@
// app/dashboard.tsx
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet, ScrollView, SafeAreaView } from 'react-native';
export default function Dashboard() {
return (
<SafeAreaView style={styles.safe}>
<ScrollView style={styles.container} contentContainerStyle={{ padding: 20 }}>
{/* Header */}
<View style={styles.header}>
<Text style={styles.title}>Bem-vindo, João!</Text>
<TouchableOpacity>
<Text style={styles.icon}>🔔</Text>
</TouchableOpacity>
</View>
{/* Sumários */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Sumários Recentes</Text>
<View style={styles.card}>
<Text>Sumário 1 - 10/12/2025</Text>
<Text>Sumário 2 - 09/12/2025</Text>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>Criar Sumário</Text>
</TouchableOpacity>
</View>
</View>
{/* Presença */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Presença</Text>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>📌 Marcar presença</Text>
</TouchableOpacity>
<Text style={styles.lastText}>Última presença: 10/12/2025</Text>
</View>
{/* Calendário */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Calendário</Text>
<View style={styles.card}>
<Text>[Calendário]</Text>
</View>
</View>
{/* Justificar faltas */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Justificar Faltas</Text>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>Justificar falta</Text>
</TouchableOpacity>
</View>
{/* Chat */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Chat com o professor</Text>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>💬 Abrir chat</Text>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safe: {
flex: 1,
backgroundColor: '#f8f9fa',
},
container: {
flex: 1,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20,
paddingHorizontal: 5,
},
title: { fontSize: 24, fontWeight: '700' },
icon: { fontSize: 24 },
section: { marginBottom: 20 },
sectionTitle: { fontSize: 18, fontWeight: '600', marginBottom: 8 },
card: {
backgroundColor: '#fff',
padding: 16,
borderRadius: 12,
shadowColor: '#000',
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 4,
elevation: 3,
},
button: {
marginTop: 10,
backgroundColor: '#0984e3',
paddingVertical: 12,
borderRadius: 10,
alignItems: 'center',
},
buttonText: { color: '#fff', fontWeight: '700' },
lastText: { marginTop: 8 },
});

View File

@ -1,6 +1,4 @@
// app/index.tsx - SUA TELA DE LOGIN
// Adicione esta linha com os outros imports:
import { Link } from 'expo-router';
// app/index.tsx - TELA DE LOGIN
import React, { useState } from 'react';
import {
View,
@ -11,37 +9,42 @@ import {
KeyboardAvoidingView,
Platform,
Alert,
Image,
ActivityIndicator
} from 'react-native';
import { useRouter, Link } from 'expo-router';
export default function LoginScreen() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const router = useRouter(); // Inicializa o router
const handleLogin = () => {
if (!email || !password) {
Alert.alert('Atenção', 'Por favor, preencha todos os campos');
return;
}
if (!email.includes('@')) {
Alert.alert('Email inválido', 'Por favor, insira um email válido');
return;
}
setLoading(true);
// SIMULAÇÃO DE LOGIN (depois troca por API real)
// SIMULAÇÃO DE LOGIN
setTimeout(() => {
setLoading(false);
Alert.alert(
'Login realizado!',
`Bem-vindo(a), ${email.split('@')[0]}!`,
[{ text: 'OK', onPress: () => console.log('Login OK') }]
);
// Aqui você navegaria para o app principal: router.replace('/(tabs)');
// Primeiro navega para a dashboard
router.replace('/dashboard'); // ⬅️ Certifica-te que o ficheiro é app/dashboard.tsx
// Depois mostra alert de boas-vindas (opcional)
setTimeout(() => {
Alert.alert('Login realizado!', `Bem-vindo(a), ${email.split('@')[0]}!`);
}, 300); // delay pequeno para garantir que a navegação ocorreu
}, 1500);
};
@ -106,9 +109,9 @@ export default function LoginScreen() {
<View style={styles.footer}>
<Text style={styles.footerText}>Não tem uma conta?</Text>
<Link href="/register" asChild>
<TouchableOpacity>
<Text style={styles.registerText}> Crie uma conta agora</Text>
</TouchableOpacity>
<TouchableOpacity>
<Text style={styles.registerText}> Crie uma conta agora</Text>
</TouchableOpacity>
</Link>
</View>
@ -119,97 +122,20 @@ export default function LoginScreen() {
// ESTILOS
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8f9fa',
},
content: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 24,
},
header: {
alignItems: 'center',
marginBottom: 48,
},
title: {
fontSize: 32,
fontWeight: '800',
color: '#2d3436',
marginBottom: 8,
},
subtitle: {
fontSize: 16,
color: '#636e72',
textAlign: 'center',
},
form: {
backgroundColor: '#fff',
borderRadius: 20,
padding: 24,
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 5,
},
label: {
fontSize: 14,
fontWeight: '600',
color: '#2d3436',
marginBottom: 8,
marginLeft: 4,
},
input: {
backgroundColor: '#f8f9fa',
borderRadius: 12,
paddingHorizontal: 16,
paddingVertical: 14,
fontSize: 16,
marginBottom: 20,
borderWidth: 1,
borderColor: '#dfe6e9',
color: '#2d3436',
},
button: {
backgroundColor: '#0984e3',
borderRadius: 12,
paddingVertical: 16,
alignItems: 'center',
marginTop: 8,
marginBottom: 24,
},
buttonDisabled: {
backgroundColor: '#74b9ff',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '700',
},
forgotLink: {
alignItems: 'center',
},
forgotText: {
color: '#0984e3',
fontSize: 15,
fontWeight: '500',
},
footer: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 40,
paddingTop: 24,
borderTopWidth: 1,
borderTopColor: '#dfe6e9',
},
footerText: {
color: '#636e72',
fontSize: 15,
},
registerText: {
color: '#0984e3',
fontSize: 15,
fontWeight: '700',
},
container: { flex: 1, backgroundColor: '#f8f9fa' },
content: { flex: 1, justifyContent: 'center', paddingHorizontal: 24 },
header: { alignItems: 'center', marginBottom: 48 },
title: { fontSize: 32, fontWeight: '800', color: '#2d3436', marginBottom: 8 },
subtitle: { fontSize: 16, color: '#636e72', textAlign: 'center' },
form: { backgroundColor: '#fff', borderRadius: 20, padding: 24, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 5 },
label: { fontSize: 14, fontWeight: '600', color: '#2d3436', marginBottom: 8, marginLeft: 4 },
input: { backgroundColor: '#f8f9fa', borderRadius: 12, paddingHorizontal: 16, paddingVertical: 14, fontSize: 16, marginBottom: 20, borderWidth: 1, borderColor: '#dfe6e9', color: '#2d3436' },
button: { backgroundColor: '#0984e3', borderRadius: 12, paddingVertical: 16, alignItems: 'center', marginTop: 8, marginBottom: 24 },
buttonDisabled: { backgroundColor: '#74b9ff' },
buttonText: { color: '#fff', fontSize: 16, fontWeight: '700' },
forgotLink: { alignItems: 'center' },
forgotText: { color: '#0984e3', fontSize: 15, fontWeight: '500' },
footer: { flexDirection: 'row', justifyContent: 'center', marginTop: 40, paddingTop: 24, borderTopWidth: 1, borderTopColor: '#dfe6e9' },
footerText: { color: '#636e72', fontSize: 15 },
registerText: { color: '#0984e3', fontSize: 15, fontWeight: '700' },
});

View File

@ -33,7 +33,7 @@ export default function RegisterScreen() {
const handleRegister = () => {
if (!form.nome.trim()) {
Alert.alert('Erro', 'Por favor, insira seu nome');
Alert.alert('Erro', 'Por favor, insira o seu nome');
return;
}
@ -85,7 +85,7 @@ export default function RegisterScreen() {
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
>
{/* BOTÃO VOLTAR NO TOPO (AGORA SEM BUG DO NOTCH) */}
{/* BOTÃO VOLTAR ATRÁS */}
<Link href="/" asChild>
<TouchableOpacity style={styles.backHeaderButton} disabled={loading}>
<Text style={styles.backHeaderText}></Text>
@ -102,12 +102,12 @@ export default function RegisterScreen() {
{/* FORMULÁRIO */}
<View style={styles.formCard}>
{/* NOME */}
{/* NOME COMPLETO */}
<View style={styles.inputGroup}>
<Text style={styles.label}>Nome Completo</Text>
<TextInput
style={styles.input}
placeholder="Digite seu nome completo"
placeholder="Insira o seu nome completo..."
value={form.nome}
onChangeText={(text) => handleChange('nome', text)}
editable={!loading}
@ -119,7 +119,7 @@ export default function RegisterScreen() {
<Text style={styles.label}>Email</Text>
<TextInput
style={styles.input}
placeholder="exemplo@email.com"
placeholder="Insira o seu email..."
value={form.email}
onChangeText={(text) => handleChange('email', text)}
keyboardType="email-address"
@ -128,12 +128,12 @@ export default function RegisterScreen() {
/>
</View>
{/* TELEFONE */}
{/* Nº TELEMÓVEL */}
<View style={styles.inputGroup}>
<Text style={styles.label}>Telefone</Text>
<TextInput
style={styles.input}
placeholder="912 345 678"
placeholder="Insira o seu nº telemóvel..."
value={form.telefone}
onChangeText={(text) => handleChange('telefone', text)}
keyboardType="phone-pad"
@ -141,12 +141,12 @@ export default function RegisterScreen() {
/>
</View>
{/* SENHA */}
{/* PALAVRA-PASSE */}
<View style={styles.inputGroup}>
<Text style={styles.label}>Senha</Text>
<TextInput
style={styles.input}
placeholder="Mínimo 6 caracteres"
placeholder="Mínimo de 6 caracteres"
value={form.password}
onChangeText={(text) => handleChange('password', text)}
secureTextEntry
@ -154,12 +154,12 @@ export default function RegisterScreen() {
/>
</View>
{/* CONFIRMAR SENHA */}
{/* CONFIRMAR PALAVRA-PASSE */}
<View style={styles.inputGroup}>
<Text style={styles.label}>Confirmar Senha</Text>
<TextInput
style={styles.input}
placeholder="Digite novamente a senha"
placeholder="Insira novamente a sua palavra-passe"
value={form.confirmarPassword}
onChangeText={(text) => handleChange('confirmarPassword', text)}
secureTextEntry
@ -167,7 +167,7 @@ export default function RegisterScreen() {
/>
</View>
{/* BOTÃO REGISTRAR */}
{/* BOTÃO CRIAR CONTA */}
<TouchableOpacity
style={[styles.registerButton, loading && styles.buttonDisabled]}
onPress={handleRegister}
@ -205,7 +205,7 @@ const styles = StyleSheet.create({
scrollContainer: {
flexGrow: 1,
padding: 20,
paddingTop: 20, // SafeArea já resolve o notch
paddingTop: 20,
},
backHeaderButton: {
position: 'absolute',