eletrotupi / tcc/ frontend/app/auth/reset-password.tsx13a51f682d4b5fcaa5c7daa8c766d0d8738d29da
4.9 KB | 181 lines Raw
1
import React, { useState } from 'react';
2
import {
3
  View,
4
  StyleSheet,
5
  ScrollView,
6
  KeyboardAvoidingView,
7
} from 'react-native';
8
import { Text } from '@/components/ui/Text';
9
import { Link, useLocalSearchParams, router } from 'expo-router';
10
import { SafeAreaView } from 'react-native-safe-area-context';
11
import { useThemeColor } from '@/hooks/use-theme-color';
12
import { Button, Input } from '@/components/ui';
13
import { useAuth } from '@/context/AuthContext';
14
import { useToast } from '@/context/ToastContext';
15
import { translateError } from '@/lib/errors/translations';
16

17
export default function ResetPasswordScreen() {
18
  const { token } = useLocalSearchParams<{ token: string }>();
19
  const [password, setPassword] = useState('');
20
  const [confirmPassword, setConfirmPassword] = useState('');
21
  const [errors, setErrors] = useState<{
22
    password?: string;
23
    confirmPassword?: string;
24
  }>({});
25

26
  const { resetPassword } = useAuth();
27
  const { showToast } = useToast();
28
  const [loading, setLoading] = useState(false);
29
  const textColor = useThemeColor({}, 'text');
30
  const backgroundColor = useThemeColor({}, 'background');
31
  const tintColor = useThemeColor({}, 'tint');
32

33
  const validateForm = () => {
34
    const newErrors: typeof errors = {};
35

36
    if (!password) {
37
      newErrors.password = 'A senha é obrigatória';
38
    } else if (password.length < 6) {
39
      newErrors.password = 'A senha deve conter pelo menos 6 caracteres';
40
    }
41

42
    if (!confirmPassword) {
43
      newErrors.confirmPassword = 'Por favor confirme sua senha';
44
    } else if (password !== confirmPassword) {
45
      newErrors.confirmPassword = 'As senhas não coincidem';
46
    }
47

48
    setErrors(newErrors);
49
    return Object.keys(newErrors).length === 0;
50
  };
51

52
  const handleResetPassword = async () => {
53
    if (!validateForm()) return;
54

55
    if (!token) {
56
      showToast('Token não encontrado. Solicite um novo link de recuperação.', 'error');
57
      return;
58
    }
59

60
    setLoading(true);
61
    try {
62
      await resetPassword(token, password);
63
      showToast('Senha recuperada com sucesso!', 'success');
64
      router.replace('/auth/login');
65
    } catch (error) {
66
      showToast(translateError(error) || 'Falha em recuperar a conta', 'error');
67
    } finally {
68
      setLoading(false);
69
    }
70
  };
71

72
  return (
73
    <SafeAreaView style={[styles.container, { backgroundColor }]}>
74
      <KeyboardAvoidingView
75
        behavior='height'
76
        style={styles.keyboardView}
77
      >
78
        <ScrollView
79
          contentContainerStyle={styles.scrollContainer}
80
          showsVerticalScrollIndicator={false}
81
        >
82
          <View style={styles.header}>
83
            <Text style={[styles.title, { color: textColor }]}>Recuperar a conta</Text>
84
            <Text style={[styles.subtitle, { color: textColor, opacity: 0.7 }]}>
85
              Digite uma nova senha para sua conta
86
            </Text>
87
          </View>
88

89
          <View style={styles.form}>
90
            <Input
91
              label="Nova senha"
92
              type="password"
93
              value={password}
94
              onChangeText={setPassword}
95
              placeholder="Digite uma nova senha"
96
              error={errors.password}
97
              showPasswordToggle
98
            />
99

100
            <Input
101
              label="Confirmar nova senha"
102
              type="password"
103
              value={confirmPassword}
104
              onChangeText={setConfirmPassword}
105
              placeholder="Confirme a nova senha"
106
              error={errors.confirmPassword}
107
              showPasswordToggle
108
            />
109

110
            <Button
111
              title="Trocar senha"
112
              onPress={handleResetPassword}
113
              loading={loading}
114
              style={styles.resetButton}
115
            />
116
          </View>
117

118
          <View style={styles.footer}>
119
            <Text style={[styles.footerText, { color: textColor, opacity: 0.7 }]}>
120
              Lembrou da senha?{' '}
121
            </Text>
122
            <Link href="/auth/login" asChild style={StyleSheet.flatten([styles.link, { color: tintColor }])}>
123
              <Text style={StyleSheet.flatten([styles.link, { color: tintColor }])}>
124
                Faça login
125
              </Text>
126
            </Link>
127
          </View>
128
        </ScrollView>
129
      </KeyboardAvoidingView>
130
    </SafeAreaView>
131
  );
132
}
133

134
const styles = StyleSheet.create({
135
  container: {
136
    flex: 1,
137
  },
138
  keyboardView: {
139
    flex: 1,
140
  },
141
  scrollContainer: {
142
    flexGrow: 1,
143
    paddingHorizontal: 24,
144
    justifyContent: 'center',
145
    minHeight: '100%',
146
  },
147
  header: {
148
    alignItems: 'center',
149
    marginBottom: 40,
150
  },
151
  title: {
152
    fontSize: 28,
153
    fontWeight: 'bold',
154
    marginBottom: 8,
155
  },
156
  subtitle: {
157
    fontSize: 16,
158
    textAlign: 'center',
159
  },
160
  form: {
161
    marginBottom: 32,
162
  },
163
  resetButton: {
164
    marginTop: 8,
165
  },
166
  link: {
167
    textAlign: 'center',
168
    fontSize: 14,
169
    fontWeight: '500',
170
  },
171
  footer: {
172
    flexDirection: 'row',
173
    justifyContent: 'center',
174
    alignItems: 'center',
175
    marginTop: 'auto',
176
    paddingBottom: 20,
177
  },
178
  footerText: {
179
    fontSize: 14,
180
  },
181
});