ATUALIZACOES
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
// components/Auth.tsx
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { useState } from 'react';
|
||||
import { ActivityIndicator, Alert, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import { supabase } from '../app/lib/supabase';
|
||||
|
||||
interface AuthProps {
|
||||
@@ -11,96 +20,206 @@ export default function Auth({ onLoginSuccess }: AuthProps) {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isFocused, setIsFocused] = useState<string | null>(null);
|
||||
|
||||
// ESTADO PARA OS AVISOS MODERNOS
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const handleLogin = async () => {
|
||||
setErrorMessage(null); // Limpa erros anteriores
|
||||
|
||||
if (!email || !password) {
|
||||
Alert.alert('Atenção', 'Preencha todos os campos');
|
||||
setErrorMessage('Preencha todos os campos para continuar.');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// 1. LOGIN NO AUTH DO SUPABASE
|
||||
const { data: { user }, error: authError } = await supabase.auth.signInWithPassword({ email, password });
|
||||
if (authError) throw authError;
|
||||
|
||||
// 2. BUSCAR DADOS NA TABELA PROFILES LOGO APÓS O LOGIN
|
||||
if (user) {
|
||||
const { data: profile, error: profileError } = await supabase
|
||||
const { error: profileError } = await supabase
|
||||
.from('profiles')
|
||||
.select('*')
|
||||
.eq('id', user.id)
|
||||
.single();
|
||||
|
||||
if (profileError) {
|
||||
console.warn("Perfil não encontrado na tabela profiles.");
|
||||
} else {
|
||||
console.log("Perfil carregado com sucesso:", profile.nome);
|
||||
}
|
||||
if (profileError) console.warn("Perfil não encontrado.");
|
||||
}
|
||||
|
||||
Alert.alert('Bem-vindo(a)!');
|
||||
|
||||
// 3. SE SUCESSO, EXECUTA O CALLBACK E NAVEGA
|
||||
if (onLoginSuccess) {
|
||||
onLoginSuccess();
|
||||
} else {
|
||||
router.replace('/(tabs)/estagios'); // Caminho padrão caso não venha callback
|
||||
router.replace('/(tabs)/estagios');
|
||||
}
|
||||
|
||||
} catch (err: any) {
|
||||
Alert.alert('Erro', err.message);
|
||||
// Tradução simples de erro comum
|
||||
const msg = err.message === 'Invalid login credentials'
|
||||
? 'Email ou palavra-passe incorretos.'
|
||||
: 'Ocorreu um erro ao entrar. Tenta novamente.';
|
||||
setErrorMessage(msg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.form}>
|
||||
<Text style={styles.label}>Email</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="email@address.com"
|
||||
value={email}
|
||||
onChangeText={setEmail}
|
||||
autoCapitalize="none"
|
||||
keyboardType="email-address"
|
||||
editable={!loading}
|
||||
/>
|
||||
<View style={styles.container}>
|
||||
|
||||
{/* AVISO DE ERRO MODERNO */}
|
||||
{errorMessage && (
|
||||
<View style={styles.errorBanner}>
|
||||
<Ionicons name="alert-circle" size={20} color="#EF4444" />
|
||||
<Text style={styles.errorText}>{errorMessage}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<Text style={styles.label}>Palavra-passe</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Insira a sua palavra-passe"
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
secureTextEntry
|
||||
editable={!loading}
|
||||
/>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Text style={[styles.label, isFocused === 'email' && { color: '#2390a6' }]}>Email</Text>
|
||||
<TextInput
|
||||
style={[styles.input, isFocused === 'email' && styles.inputFocused]}
|
||||
placeholder="Insira o seu email"
|
||||
placeholderTextColor="#94A3B8"
|
||||
value={email}
|
||||
onChangeText={(val) => {
|
||||
setEmail(val);
|
||||
if(errorMessage) setErrorMessage(null);
|
||||
}}
|
||||
onFocus={() => setIsFocused('email')}
|
||||
onBlur={() => setIsFocused(null)}
|
||||
autoCapitalize="none"
|
||||
keyboardType="email-address"
|
||||
editable={!loading}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputWrapper}>
|
||||
<View style={styles.labelRow}>
|
||||
<Text style={[styles.label, isFocused === 'pass' && { color: '#2390a6' }]}>Palavra-passe</Text>
|
||||
</View>
|
||||
<TextInput
|
||||
style={[styles.input, isFocused === 'pass' && styles.inputFocused]}
|
||||
placeholder="Insira a sua palavra-passe"
|
||||
placeholderTextColor="#94A3B8"
|
||||
value={password}
|
||||
onChangeText={(val) => {
|
||||
setPassword(val);
|
||||
if(errorMessage) setErrorMessage(null);
|
||||
}}
|
||||
onFocus={() => setIsFocused('pass')}
|
||||
onBlur={() => setIsFocused(null)}
|
||||
secureTextEntry
|
||||
editable={!loading}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
style={[styles.button, loading && styles.buttonDisabled]}
|
||||
onPress={handleLogin}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.buttonText}>ENTRAR</Text>}
|
||||
{loading ? (
|
||||
<ActivityIndicator color="#fff" />
|
||||
) : (
|
||||
<Text style={styles.buttonText}>ENTRAR</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity onPress={() => router.push('/redefenirsenha')}>
|
||||
<Text style={styles.forgotText}>Esqueceu a palavra-passe?</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.forgotButton}
|
||||
onPress={() => router.push('/redefenirsenha')}
|
||||
>
|
||||
<Text style={styles.forgotText}>Esqueceu-se da palavra-passe?</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// ... (teus estilos mantêm-se iguais)
|
||||
const styles = StyleSheet.create({
|
||||
form: { backgroundColor: '#fff', borderRadius: 16, padding: 24, marginTop: 20, shadowColor: '#000', shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 5 },
|
||||
label: { fontSize: 14, fontWeight: '600', color: '#2d3436', marginBottom: 8 },
|
||||
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' },
|
||||
forgotText: { color: '#0984e3', fontSize: 15, fontWeight: '500', textAlign: 'center', marginTop: 8 },
|
||||
container: {
|
||||
width: '100%',
|
||||
marginTop: 10,
|
||||
},
|
||||
errorBanner: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#FEF2F2',
|
||||
padding: 16,
|
||||
borderRadius: 16,
|
||||
marginBottom: 20,
|
||||
borderWidth: 1,
|
||||
borderColor: '#FEE2E2',
|
||||
},
|
||||
errorText: {
|
||||
color: '#B91C1C',
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
marginLeft: 10,
|
||||
flex: 1,
|
||||
},
|
||||
inputWrapper: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
labelRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
color: '#475569',
|
||||
marginBottom: 10,
|
||||
marginLeft: 4,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#FBFDFF',
|
||||
borderRadius: 18,
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 18,
|
||||
fontSize: 16,
|
||||
color: '#0F172A',
|
||||
borderWidth: 1.5,
|
||||
borderColor: '#F1F5F9',
|
||||
},
|
||||
inputFocused: {
|
||||
borderColor: '#2390a6',
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
button: {
|
||||
backgroundColor: '#dd8707', // A cor que pediste
|
||||
borderRadius: 18,
|
||||
paddingVertical: 20,
|
||||
alignItems: 'center',
|
||||
marginTop: 10,
|
||||
shadowColor: '#dd8707',
|
||||
shadowOffset: { width: 0, height: 6 },
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 10,
|
||||
elevation: 6,
|
||||
},
|
||||
buttonDisabled: {
|
||||
backgroundColor: '#E2E8F0',
|
||||
elevation: 0,
|
||||
},
|
||||
buttonText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
letterSpacing: 1,
|
||||
},
|
||||
forgotButton: {
|
||||
marginTop: 20,
|
||||
alignItems: 'center',
|
||||
},
|
||||
forgotText: {
|
||||
color: '#2390a6',
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user