primeiro commit

This commit is contained in:
2026-04-15 12:46:50 +01:00
commit fa1accd4bb
961 changed files with 124535 additions and 0 deletions

219
app/(tabs)/index.tsx Normal file
View File

@@ -0,0 +1,219 @@
import React, { useState } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Alert,
ActivityIndicator,
SafeAreaView,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { useRouter } from 'expo-router';
import { usuariosService } from '../../src/lib/supabase';
import { Colors } from '../../src/components/common/theme';
import { useColorScheme } from '../../src/hooks/use-color-scheme';
import { Lock, Mail } from 'lucide-react-native';
import { Input } from '../../src/components/common/input';
import { Button } from '../../src/components/common/button';
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 colorScheme = useColorScheme();
const theme = colorScheme === 'dark' ? 'dark' : 'light';
const primary = Colors[theme].primary;
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 as any).usuario || 'usuário'}!`);
// quando o login é bemsucedido, vai para a página inicial
router.replace('/inicio');
}
} catch (err) {
Alert.alert('Erro', 'Erro ao conectar ao servidor');
console.error(err);
} finally {
setLoading(false);
}
};
return (
<SafeAreaView style={[styles.safe, { backgroundColor: Colors[theme].background }]}>
<KeyboardAvoidingView
style={[styles.container, { backgroundColor: Colors[theme].background }]}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<Text style={[styles.title, { color: primary } ]}>Fluxup</Text>
<Text style={[styles.subtitle, { color: Colors[theme].textMuted } ]}>Entre na sua conta</Text>
{/* Campo de Email */}
<View style={[styles.inputContainer, { backgroundColor: Colors[theme].card, borderColor: Colors[theme].border }] }>
<Mail size={20} color={Colors[theme].icon} style={styles.icon} />
<Input
placeholder="Email"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
editable={!loading}
style={styles.input}
/>
</View>
{/* Campo de Palavra Passe */}
<View style={[styles.inputContainer, { backgroundColor: Colors[theme].card, borderColor: Colors[theme].border }] }>
<Lock size={20} color={Colors[theme].icon} style={styles.icon} />
<Input
placeholder="Palavra Passe"
value={palavraPasse}
onChangeText={setPalavraPasse}
secureTextEntry
editable={!loading}
style={styles.input}
/>
</View>
{/* Campo de ID Usuário */}
<Input
placeholder="ID Usuário"
value={idUsuario}
onChangeText={setIdUsuario}
editable={!loading}
/>
{/* Campo de Usuário */}
<Input
placeholder="Usuário"
value={usuario}
onChangeText={setUsuario}
editable={!loading}
/>
{/* Botão de Login */}
<Button
title="Entrar"
onPress={handleLogin}
isLoading={loading}
disabled={loading}
variant="primary"
size="lg"
containerStyle={styles.button}
textStyle={styles.buttonText}
/>
<View style={styles.footerLinks}>
{/* Botão de Registo */}
<TouchableOpacity onPress={() => router.push('/registo')}>
<Text style={[styles.linkText, { color: primary }]}>
Não tem conta? <Text style={[styles.linkBold, { color: primary } ]}>Registe-se</Text>
</Text>
</TouchableOpacity>
{/* Botão de Esqueci Palavra Passe */}
<TouchableOpacity
onPress={() => router.push('/esqueciPalavraPasse')}
>
<Text style={[styles.linkText, { color: primary }]}>Esqueci a palavrapasse</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safe: {
flex: 1,
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 32,
fontWeight: 'bold',
marginBottom: 8,
},
subtitle: {
fontSize: 16,
marginBottom: 24,
},
inputContainer: {
flexDirection: 'row',
alignItems: 'center',
width: '100%',
borderRadius: 8,
borderWidth: 1,
borderColor: '#ddd',
marginBottom: 15,
paddingHorizontal: 10,
},
icon: {
marginRight: 10,
},
input: {
flex: 1,
height: 50,
fontSize: 16,
},
button: {
width: '100%',
height: 50,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
marginTop: 20,
marginBottom: 20,
},
buttonDisabled: {
backgroundColor: '#ccc',
},
buttonText: {
color: '#fff',
fontSize: 18,
fontWeight: 'bold',
},
linkText: {
fontSize: 14,
marginTop: 10,
textAlign: 'center',
},
linkBold: {
fontWeight: 'bold',
},
footerLinks: {
marginTop: 10,
},
});