eletrotupi / tcc/ frontend/app/auth/forgot-password.tsx6a3fa1a67fda0d405e12bd12123985b1301b7b5a
6.4 KB | 251 lines Raw
1
import React, { useState } from 'react';
2
import {
3
  View,
4
  Text,
5
  StyleSheet,
6
  ScrollView,
7
  KeyboardAvoidingView,
8
  Platform,
9
  Alert,
10
} from 'react-native';
11
import { Link, router } from 'expo-router';
12
import { SafeAreaView } from 'react-native-safe-area-context';
13
import { useThemeColor } from '@/hooks/use-theme-color';
14
import { Button, Input } from '@/components/ui';
15
import { useAuth } from '@/context/AuthContext';
16

17
export default function ForgotPasswordScreen() {
18
  const [email, setEmail] = useState('');
19
  const [emailSent, setEmailSent] = useState(false);
20
  const [resetToken, setResetToken] = useState(''); // Only for development
21
  const [errors, setErrors] = useState<{ email?: string }>({});
22

23
  const { forgotPassword } = useAuth();
24
  const [loading, setLoading] = useState(false);
25
  const textColor = useThemeColor({}, 'text');
26
  const backgroundColor = useThemeColor({}, 'background');
27
  const tintColor = useThemeColor({}, 'tint');
28

29
  const validateForm = () => {
30
    const newErrors: { email?: string } = {};
31

32
    if (!email) {
33
      newErrors.email = 'Email is required';
34
    } else if (!/\S+@\S+\.\S+/.test(email)) {
35
      newErrors.email = 'Please enter a valid email';
36
    }
37

38
    setErrors(newErrors);
39
    return Object.keys(newErrors).length === 0;
40
  };
41

42
  const handleForgotPassword = async () => {
43
    if (!validateForm()) return;
44

45
    setLoading(true);
46
    try {
47
      const data = await forgotPassword(email);
48
      setEmailSent(true);
49
      // In development, show the reset token
50
      if (data.token) {
51
        setResetToken(data.token);
52
      }
53
    } catch (error: any) {
54
      Alert.alert('Erro: ', error.message || 'Falha ao enviar link de recuperação');
55
    } finally {
56
      setLoading(false);
57
    }
58
  };
59

60
  const handleUseToken = () => {
61
    if (resetToken) {
62
      router.push({
63
        pathname: '/auth/reset-password',
64
        params: { token: resetToken },
65
      });
66
    }
67
  };
68

69
  if (emailSent) {
70
    return (
71
      <SafeAreaView style={[styles.container, { backgroundColor }]}>
72
        <View style={styles.successContainer}>
73
          <Text style={[styles.title, { color: textColor }]}>Verifique seu email</Text>
74
          <Text style={[styles.message, { color: textColor, opacity: 0.7 }]}>
75
            Enviamos as instruções para resetar sua senha para {email}
76
          </Text>
77

78
          {/* Development only - show reset token */}
79
          {resetToken && (
80
            <View style={styles.devSection}>
81
              <Text style={[styles.devTitle, { color: tintColor }]}>
82
                Dev mode:
83
              </Text>
84
              <Text style={[styles.devText, { color: textColor, opacity: 0.7 }]}>
85
                Token: {resetToken}
86
              </Text>
87
              <Button
88
                title="Usar token para resetar senha"
89
                onPress={handleUseToken}
90
                style={styles.devButton}
91
              />
92
            </View>
93
          )}
94

95
          <View style={styles.actions}>
96
            <Button
97
              title="Reenviar email"
98
              variant="outline"
99
              onPress={() => setEmailSent(false)}
100
              style={styles.resendButton}
101
            />
102

103
            <Link href="/auth/login" asChild style={[styles.link, { color: tintColor }]}>
104
              <Text style={[styles.link, { color: tintColor }]}>
105
                Voltar para login
106
              </Text>
107
            </Link>
108
          </View>
109
        </View>
110
      </SafeAreaView>
111
    );
112
  }
113

114
  return (
115
    <SafeAreaView style={[styles.container, { backgroundColor }]}>
116
      <KeyboardAvoidingView
117
        behavior='height'
118
        style={styles.keyboardView}
119
      >
120
        <ScrollView
121
          contentContainerStyle={styles.scrollContainer}
122
          showsVerticalScrollIndicator={false}
123
        >
124
          <View style={styles.header}>
125
            <Text style={[styles.title, { color: textColor }]}>Esqueceu a senha?</Text>
126
            <Text style={[styles.subtitle, { color: textColor, opacity: 0.7 }]}>
127
              Insira seu email para receber as instruções de recuperação
128
            </Text>
129
          </View>
130

131
          <View style={styles.form}>
132
            <Input
133
              label="Email"
134
              type="email"
135
              value={email}
136
              onChangeText={setEmail}
137
              placeholder="Qual seu email?"
138
              error={errors.email}
139
              autoCapitalize="none"
140
            />
141

142
            <Button
143
              title="Enviar link de recuperação"
144
              onPress={handleForgotPassword}
145
              loading={loading}
146
              style={styles.resetButton}
147
            />
148
          </View>
149

150
          <View style={styles.footer}>
151
            <Text style={[styles.footerText, { color: textColor, opacity: 0.7 }]}>
152
              Lembra tua senha?{' '}
153
            </Text>
154
            <Link href="/auth/login" asChild style={[styles.link, { color: tintColor }]}>
155
              <Text style={[styles.link, { color: tintColor }]}>
156
                Faça login
157
              </Text>
158
            </Link>
159
          </View>
160
        </ScrollView>
161
      </KeyboardAvoidingView>
162
    </SafeAreaView>
163
  );
164
}
165

166
const styles = StyleSheet.create({
167
  container: {
168
    flex: 1,
169
  },
170
  keyboardView: {
171
    flex: 1,
172
  },
173
  scrollContainer: {
174
    flexGrow: 1,
175
    paddingHorizontal: 24,
176
    justifyContent: 'center',
177
    minHeight: '100%',
178
  },
179
  successContainer: {
180
    flex: 1,
181
    justifyContent: 'center',
182
    paddingHorizontal: 24,
183
  },
184
  header: {
185
    alignItems: 'center',
186
    marginBottom: 40,
187
  },
188
  title: {
189
    fontSize: 28,
190
    fontWeight: 'bold',
191
    marginBottom: 8,
192
    textAlign: 'center',
193
  },
194
  subtitle: {
195
    fontSize: 16,
196
    textAlign: 'center',
197
    lineHeight: 24,
198
  },
199
  message: {
200
    fontSize: 16,
201
    textAlign: 'center',
202
    lineHeight: 24,
203
    marginBottom: 32,
204
  },
205
  form: {
206
    marginBottom: 32,
207
  },
208
  resetButton: {
209
    marginTop: 8,
210
  },
211
  actions: {
212
    gap: 16,
213
  },
214
  resendButton: {
215
    marginBottom: 8,
216
  },
217
  devSection: {
218
    marginBottom: 32,
219
    padding: 16,
220
    borderRadius: 8,
221
    backgroundColor: 'rgba(74, 144, 226, 0.1)',
222
  },
223
  devTitle: {
224
    fontSize: 14,
225
    fontWeight: '600',
226
    marginBottom: 8,
227
  },
228
  devText: {
229
    fontSize: 12,
230
    marginBottom: 12,
231
    fontFamily: 'monospace',
232
  },
233
  devButton: {
234
    marginTop: 8,
235
  },
236
  link: {
237
    textAlign: 'center',
238
    fontSize: 14,
239
    fontWeight: '500',
240
  },
241
  footer: {
242
    flexDirection: 'row',
243
    justifyContent: 'center',
244
    alignItems: 'center',
245
    marginTop: 'auto',
246
    paddingBottom: 20,
247
  },
248
  footerText: {
249
    fontSize: 14,
250
  },
251
});