87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import { RecoverScreenLayout } from '@/assets/components/auth/RecoverScreenLayout';
|
|
import { LoadingSpinner } from '@/assets/components/LoadingSpinner';
|
|
import { recoverPassword } from '@/assets/services/passwordRecovery';
|
|
import styles from '@/styles/screens/auth/recover.styles';
|
|
import { router, type Href } from 'expo-router';
|
|
import { useState } from 'react';
|
|
import { Image, Pressable, Text, TextInput } from 'react-native';
|
|
|
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
|
export default function RecoverEmailScreen() {
|
|
const [email, setEmail] = useState('');
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const handleSubmit = async () => {
|
|
const trimmed = email.trim();
|
|
if (!trimmed) {
|
|
setError('Indica o teu email para continuar.');
|
|
return;
|
|
}
|
|
if (!EMAIL_REGEX.test(trimmed)) {
|
|
setError('Introduz um email válido.');
|
|
return;
|
|
}
|
|
|
|
setError(null);
|
|
setIsLoading(true);
|
|
try {
|
|
const data = await recoverPassword(trimmed);
|
|
if (data.status === 200) {
|
|
router.push({
|
|
pathname: '/recover/confirm',
|
|
params: { email: trimmed, message: data.message ?? '' },
|
|
} as Href);
|
|
return;
|
|
}
|
|
setError(data.message || 'Não foi possível enviar o código.');
|
|
} catch {
|
|
setError('Falha ao contactar o servidor. Tenta novamente.');
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<RecoverScreenLayout
|
|
title="Repor palavra-passe"
|
|
subtitle="Indica o teu email para receberes um código de 6 dígitos. O código expira ao fim de 1 hora.">
|
|
<Text style={styles.label}>
|
|
Email<Text style={styles.required}>*</Text>
|
|
</Text>
|
|
<TextInput
|
|
value={email}
|
|
onChangeText={setEmail}
|
|
placeholder="hello@domain.pt"
|
|
placeholderTextColor="#9AA0A6"
|
|
autoCapitalize="none"
|
|
keyboardType="email-address"
|
|
autoComplete="email"
|
|
style={styles.input}
|
|
editable={!isLoading}
|
|
/>
|
|
|
|
{!!error && <Text style={styles.errorText}>{error}</Text>}
|
|
|
|
<Pressable
|
|
style={[styles.actionButton, isLoading && styles.actionButtonDisabled]}
|
|
onPress={handleSubmit}
|
|
disabled={isLoading}>
|
|
{isLoading ? (
|
|
<LoadingSpinner size="small" />
|
|
) : (
|
|
<>
|
|
<Text style={styles.actionButtonText}>Enviar código</Text>
|
|
<Image source={require('@/assets/icons/seta-up.png')} style={styles.actionButtonIcon} />
|
|
</>
|
|
)}
|
|
</Pressable>
|
|
|
|
<Pressable onPress={() => router.replace('/login' as Href)} disabled={isLoading}>
|
|
<Text style={styles.backLink}>Voltar ao Login</Text>
|
|
</Pressable>
|
|
</RecoverScreenLayout>
|
|
);
|
|
}
|