diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e07b4682..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.codeActionsOnSave": { - "source.formatDocument": "explicit", - } -} diff --git a/package-lock.json b/package-lock.json index 29d5a254..b7a1c1e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "react-native-url-polyfill": "^2.0.0", "react-native-vector-icons": "^10.0.2", "react-scroll-to-top": "^3.0.0", + "use-debounce": "^10.0.0", "validator": "^13.11.0" }, "devDependencies": { @@ -19124,6 +19125,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/use-debounce": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.0.tgz", + "integrity": "sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A==", + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/use-latest-callback": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.6.tgz", diff --git a/package.json b/package.json index d25b4adf..9904cb90 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "react-native-url-polyfill": "^2.0.0", "react-native-vector-icons": "^10.0.2", "react-scroll-to-top": "^3.0.0", + "use-debounce": "^10.0.0", "validator": "^13.11.0" }, "devDependencies": { diff --git a/src/app/auth/forgotPassword/index.tsx b/src/app/auth/forgotPassword/index.tsx index f9a4af63..99692e48 100644 --- a/src/app/auth/forgotPassword/index.tsx +++ b/src/app/auth/forgotPassword/index.tsx @@ -1,116 +1,107 @@ -import { router } from 'expo-router'; -import React, { useState } from 'react'; -import { Alert, TextInput, View } from 'react-native'; -import { Button, Input } from 'react-native-elements'; +import { router, Link } from 'expo-router'; +import { useState, useRef, useEffect } from 'react'; +import { Alert, Text, View } from 'react-native'; +import validator from 'validator'; +import { useDebounce } from 'use-debounce'; import styles from './styles'; import globalStyles from '../../../styles/globalStyles'; import { useSession } from '../../../utils/AuthContext'; +import UserStringInput from '../../../components/UserStringInput/UserStringInput'; +import StyledButton from '../../../components/StyledButton/StyledButton'; +import { isEmailTaken } from '../../../queries/profiles'; +import { queryEmailByUsername } from '../../../queries/auth'; +import colors from '../../../styles/colors'; function ForgotPasswordScreen() { - const { updateUser, signOut, resetPassword, verifyOtp } = useSession(); + const { resetPassword } = useSession(); const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [loading, setLoading] = useState(false); - const [verificationCode, setCode] = useState(''); - const [changingPassword, setChangingPassword] = useState(false); + const [emailToReset, setEmailToReset] = useState(''); + const [emailError, setEmailError] = useState(''); + const [value] = useDebounce(email, 250); + const [validEmail, setValidEmail] = useState(false); const sendResetEmail = async () => { - const { error } = await resetPassword(email); + const { error } = await resetPassword(emailToReset); if (error) Alert.alert('Could not send a reset password email. Please try again.'); - else - Alert.alert( - 'Enter the verification code from your email to change your password', - ); + else router.replace('auth/signup'); }; - const verifyCode = async () => { - setLoading(true); - if (email && verificationCode) { - const { error } = await verifyOtp(email, verificationCode); + useEffect(() => { + checkEmailOrUsername(value); + }, [value]); - if (error) { - Alert.alert(error.message); - setChangingPassword(false); - } else { - router.push('auth/resetPassword'); + const checkEmailOrUsername = async (newEmail: string) => { + setValidEmail(false); + if (validator.isEmail(newEmail)) { + if (newEmail.length === 0) { + setEmailError(''); + return; + } + const emailIsTaken = await isEmailTaken(newEmail); + if (!emailIsTaken) { + setEmailError( + 'An account with that email does not exist. Please try again.', + ); + setValidEmail(false); + return; } - } else if (!verificationCode) { - Alert.alert(`Please enter a verification code`); + setEmailToReset(newEmail); } else { - Alert.alert(`Please sign up again.`); - } + const { data, error } = await queryEmailByUsername(newEmail); - setLoading(false); - }; - - const changePassword = async () => { - setLoading(true); - const { error } = await updateUser({ password }); - - if (error) { - Alert.alert('Updating password failed'); - } else { - await signOut(); - router.replace('/auth/login'); + if (data && data?.length > 0 && !error) { + setValidEmail(true); + setEmailToReset(data[0].email); + } else { + setEmailError( + 'An account with that username does not exist. Please try again.', + ); + setValidEmail(false); + return; + } } - - setLoading(false); + setValidEmail(true); + setEmailError(''); }; return ( - - setEmail(text)} - value={email} - placeholder="email@address.com" - autoCapitalize="none" - /> - - -