first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

234
app/index.tsx Normal file
View File

@@ -0,0 +1,234 @@
import React, { useState } from 'react';
import {
View,
TextInput,
TouchableOpacity,
Text,
StyleSheet,
Alert,
ActivityIndicator,
SafeAreaView,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { useRouter } from 'expo-router';
import { usuariosService } from '../Fluxup/src/lib/supabase';
import { Colors } from '../Fluxup/src/constants/theme';
import { Lock, Mail, User } from 'lucide-react-native';
export default function LoginScreen() {
const router = useRouter();
const [email, setEmail] = useState('');
const [palavraPasse, setPalavraPasse] = useState('');
const [idUsuario, setIdUsuario] = useState('');
const [usuario, setUsuario] = useState('');
const [loading, setLoading] = useState(false);
const handleLogin = async () => {
// Validação dos campos
if (!email || !palavraPasse || !idUsuario || !usuario) {
Alert.alert('Erro', 'Por favor, preencha todos os campos');
return;
}
// Validação de email
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
Alert.alert('Erro', 'Email inválido');
return;
}
setLoading(true);
try {
// login no Supabase
const { data, error } = await usuariosService.login(email, palavraPasse);
if (error) {
Alert.alert('Erro', 'Email ou palavra passe incorretos');
return;
}
if (data) {
Alert.alert('Sucesso', `Bem-vindo, ${data.usuario}!`);
// quando o login é bemsucedido, vai para a página inicial
router.replace('/inicio' as any);
}
} catch (err) {
Alert.alert('Erro', 'Erro ao conectar ao servidor');
console.error(err);
} finally {
setLoading(false);
}
};
return (
<SafeAreaView style={styles.safe}>
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<Text style={styles.title}>Fluxup</Text>
<Text style={styles.subtitle}>Entre na sua conta</Text>
{/* Campo de Email */}
<View style={styles.inputContainer}>
<Mail size={20} color={Colors.light.icon} style={styles.icon} />
<TextInput
style={styles.input}
placeholder="Email"
placeholderTextColor="#999"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
editable={!loading}
/>
</View>
{/* Campo de Palavra Passe */}
<View style={styles.inputContainer}>
<Lock size={20} color={Colors.light.icon} style={styles.icon} />
<TextInput
style={styles.input}
placeholder="Palavra Passe"
placeholderTextColor="#999"
value={palavraPasse}
onChangeText={setPalavraPasse}
secureTextEntry
editable={!loading}
/>
</View>
{/* Campo de ID Usuário */}
<View style={[styles.inputContainer, { marginBottom: 8 }]}>
<TextInput
style={styles.input}
placeholder="ID Usuário"
placeholderTextColor="#999"
value={idUsuario}
onChangeText={setIdUsuario}
editable={!loading}
/>
</View>
{/* Campo de Usuário */}
<View style={[styles.inputContainer, { marginBottom: 8 }]}>
<TextInput
style={styles.input}
placeholder="Usuário"
placeholderTextColor="#999"
value={usuario}
onChangeText={setUsuario}
editable={!loading}
/>
</View>
{/* Botão de Login */}
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
onPress={handleLogin}
disabled={loading}
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Entrar</Text>
)}
</TouchableOpacity>
<View style={styles.footerLinks}>
{/* Botão de Registo */}
<TouchableOpacity onPress={() => router.push('/registo')}>
<Text style={styles.linkText}>
Não tem conta? <Text style={styles.linkBold}>Registe-se</Text>
</Text>
</TouchableOpacity>
{/* Botão de Esqueci Palavra Passe */}
<TouchableOpacity
onPress={() => router.push('/esqueciPalavraPasse' as any)}
>
<Text style={styles.linkText}>Esqueci a palavrapasse</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
const primary = Colors.light.tint;
const styles = StyleSheet.create({
safe: {
flex: 1,
backgroundColor: Colors.light.background,
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: Colors.light.background,
},
title: {
fontSize: 32,
fontWeight: 'bold',
marginBottom: 8,
color: primary,
},
subtitle: {
fontSize: 16,
color: Colors.light.icon,
marginBottom: 24,
},
inputContainer: {
flexDirection: 'row',
alignItems: 'center',
width: '100%',
backgroundColor: '#fff',
borderRadius: 8,
borderWidth: 1,
borderColor: '#ddd',
marginBottom: 15,
paddingHorizontal: 10,
},
icon: {
marginRight: 10,
},
input: {
flex: 1,
height: 50,
fontSize: 16,
color: Colors.light.text,
},
button: {
width: '100%',
height: 50,
borderRadius: 8,
backgroundColor: primary,
justifyContent: 'center',
alignItems: 'center',
marginTop: 20,
marginBottom: 20,
},
buttonDisabled: {
backgroundColor: '#ccc',
},
buttonText: {
color: '#fff',
fontSize: 18,
fontWeight: 'bold',
},
linkText: {
color: primary,
fontSize: 14,
marginTop: 10,
textAlign: 'center',
},
linkBold: {
fontWeight: 'bold',
},
footerLinks: {
marginTop: 10,
},
});