diff --git a/src/libs/API.js b/src/libs/API.js
index 852dee8497d8..b735e12d1bca 100644
--- a/src/libs/API.js
+++ b/src/libs/API.js
@@ -34,6 +34,7 @@ function isAuthTokenRequired(command) {
'SetPassword',
'User_SignUp',
'ResendValidateCode',
+ 'ResetPassword',
], command);
}
@@ -539,6 +540,17 @@ function ResendValidateCode(parameters) {
return Network.post(commandName, parameters);
}
+/**
+ * @param {Object} parameters
+ * @param {Number} parameters.email
+ * @returns {Promise}
+ */
+function ResetPassword(parameters) {
+ const commandName = 'ResetPassword';
+ requireParameters(['email'], parameters, commandName);
+ return Network.post(commandName, parameters);
+}
+
/**
* @param {Object} parameters
* @param {String} parameters.password
@@ -642,6 +654,7 @@ export {
Report_TogglePinned,
Report_UpdateLastRead,
ResendValidateCode,
+ ResetPassword,
SetNameValuePair,
SetPassword,
UpdateAccount,
diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js
index a00ae68d0eda..759a7ba6c385 100644
--- a/src/libs/actions/Session.js
+++ b/src/libs/actions/Session.js
@@ -87,6 +87,8 @@ function fetchAccountDetails(login) {
Onyx.merge(ONYXKEYS.ACCOUNT, {
accountExists: response.accountExists,
requiresTwoFactorAuth: response.requiresTwoFactorAuth,
+ validated: response.validated,
+ forgotPassword: false,
});
if (!response.accountExists) {
@@ -194,6 +196,17 @@ function resendValidationLink() {
});
}
+/**
+ * User forgot the password so let's send them the link to reset their password
+ */
+function resetPassword() {
+ Onyx.merge(ONYXKEYS.ACCOUNT, {loading: true, forgotPassword: true});
+ API.ResetPassword({email: credentials.login})
+ .finally(() => {
+ Onyx.merge(ONYXKEYS.ACCOUNT, {loading: false});
+ });
+}
+
/**
* Restart the sign in process by clearing everything from Onyx
*/
@@ -238,5 +251,6 @@ export {
signIn,
signOut,
resendValidationLink,
+ resetPassword,
restartSignin,
};
diff --git a/src/pages/signin/ChangeExpensifyLoginLink.js b/src/pages/signin/ChangeExpensifyLoginLink.js
index 75341f8c5af2..901bb8d4906c 100644
--- a/src/pages/signin/ChangeExpensifyLoginLink.js
+++ b/src/pages/signin/ChangeExpensifyLoginLink.js
@@ -1,10 +1,21 @@
import React from 'react';
import {Text, TouchableOpacity, View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import PropTypes from 'prop-types';
import styles from '../../styles/styles';
import {restartSignin} from '../../libs/actions/Session';
import themeColors from '../../styles/themes/default';
+import ONYXKEYS from '../../ONYXKEYS';
-const ChangeExpensifyLoginLink = () => (
+const propTypes = {
+ // The credentials of the logged in person
+ credentials: PropTypes.shape({
+ // The email the user logged in with
+ login: PropTypes.string,
+ }).isRequired,
+};
+
+const ChangeExpensifyLoginLink = ({credentials}) => (
(
underlayColor={themeColors.componentBG}
>
- Change Expensify login
+ Not
+ {credentials.login}
);
+ChangeExpensifyLoginLink.propTypes = propTypes;
ChangeExpensifyLoginLink.displayName = 'ChangeExpensifyLoginLink';
-export default ChangeExpensifyLoginLink;
+export default withOnyx({
+ credentials: {key: ONYXKEYS.CREDENTIALS},
+})(ChangeExpensifyLoginLink);
diff --git a/src/pages/signin/PasswordForm.js b/src/pages/signin/PasswordForm.js
index 68aca6d584ae..dc2428360e62 100644
--- a/src/pages/signin/PasswordForm.js
+++ b/src/pages/signin/PasswordForm.js
@@ -1,13 +1,13 @@
import React from 'react';
import {
- Text, TextInput, View,
+ Text, TextInput, TouchableOpacity, View,
} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import styles from '../../styles/styles';
import ButtonWithLoader from '../../components/ButtonWithLoader';
import themeColors from '../../styles/themes/default';
-import {signIn} from '../../libs/actions/Session';
+import {signIn, resetPassword} from '../../libs/actions/Session';
import ONYXKEYS from '../../ONYXKEYS';
import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink';
@@ -78,6 +78,15 @@ class PasswordForm extends React.Component {
autoFocus
/>
+
+
+ Forgot?
+
+
{this.props.account.requiresTwoFactorAuth && (
Two Factor Code
diff --git a/src/pages/signin/ResendValidationForm.js b/src/pages/signin/ResendValidationForm.js
index 19ea6c5e41a9..b5a598de5e1f 100644
--- a/src/pages/signin/ResendValidationForm.js
+++ b/src/pages/signin/ResendValidationForm.js
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
import _ from 'underscore';
import styles from '../../styles/styles';
import ButtonWithLoader from '../../components/ButtonWithLoader';
-import {resendValidationLink} from '../../libs/actions/Session';
+import {resendValidationLink, resetPassword} from '../../libs/actions/Session';
import ONYXKEYS from '../../ONYXKEYS';
import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink';
@@ -16,6 +16,9 @@ const propTypes = {
account: PropTypes.shape({
// Whether or not a sign on form is loading (being submitted)
loading: PropTypes.bool,
+
+ // Weather or not the account is validated
+ validated: PropTypes.bool,
}),
};
@@ -48,7 +51,13 @@ class ResendValidationForm extends React.Component {
formSuccess: 'Link has been re-sent',
});
- resendValidationLink();
+ if (!this.props.account.validated) {
+ resendValidationLink();
+ console.debug('Account is unvalidated: Sending validation link.');
+ } else {
+ resetPassword();
+ console.debug('Account forgot password: Sending reset password link.');
+ }
this.successMessageTimer = setTimeout(() => {
this.setState({formSuccess: ''});
@@ -60,7 +69,7 @@ class ResendValidationForm extends React.Component {
- Please validate your account by clicking on the link we just sent you.
+ We've sent you a magic sign in link – just click on it to log in!
diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js
index 7c805d6f58f4..4979f972b5a3 100644
--- a/src/pages/signin/SignInPage.js
+++ b/src/pages/signin/SignInPage.js
@@ -23,6 +23,12 @@ const propTypes = {
// Error to display when there is an account error returned
error: PropTypes.string,
+
+ // Weather or not the account is validated
+ validated: PropTypes.bool,
+
+ // Weather or not the account is validated
+ forgotPassword: PropTypes.bool,
}),
// The credentials of the person signing in
@@ -56,21 +62,24 @@ class SignInPage extends Component {
// - A login has not been entered yet
const showLoginForm = !this.props.credentials.login;
+ const validAccount = this.props.account.accountExists
+ && this.props.account.validated
+ && !this.props.account.forgotPassword;
+
// Show the password form if
// - A login has been entered
// - AND a GitHub username has been entered OR they already have access to expensify cash
- // - AND an account exists already for this login
+ // - AND an account exists and is validated for this login
// - AND a password hasn't been entered yet
const showPasswordForm = this.props.credentials.login
- && this.props.account.accountExists
+ && validAccount
&& !this.props.credentials.password;
// Show the resend validation link form if
// - A login has been entered
// - AND a GitHub username has been entered OR they already have access to this app
- // - AND an account did not exist for that login
- const showResendValidationLinkForm = this.props.credentials.login
- && !this.props.account.accountExists;
+ // - AND an account did not exist or is not validated for that login
+ const showResendValidationLinkForm = this.props.credentials.login && !validAccount;
return (
<>