-
Team sign in
-
- Sign in to interact with your community.
-
-
+
+
Team sign in
+
Sign in to interact with your community.
+ {this.renderForm()}
);
}
}
-AdminLogin.propTypes = {
- email: PropTypes.string,
- password: PropTypes.string,
- onEmailChange: PropTypes.func,
- onPasswordChange: PropTypes.func,
- onForgotPassword: PropTypes.func,
- onSubmit: PropTypes.func,
- errorMessage: PropTypes.string,
- requireRecaptcha: PropTypes.string,
+LoginContainer.propTypes = {
+ forgotPassword: PropTypes.bool.isRequired,
+ onForgotPasswordLink: PropTypes.func.isRequired,
+ onSignInLink: PropTypes.func.isRequired,
};
-export default AdminLogin;
+export default LoginContainer;
diff --git a/client/coral-admin/src/components/SignIn.css b/client/coral-admin/src/components/SignIn.css
new file mode 100644
index 000000000..88d8a452c
--- /dev/null
+++ b/client/coral-admin/src/components/SignIn.css
@@ -0,0 +1,14 @@
+.forgotPasswordCTA {
+ text-align: center;
+ font-size: 16px;
+}
+
+.forgotPasswordLink:hover {
+ text-decoration: underline;
+}
+
+.forgotPasswordLink {
+ color: blue;
+ font-weight: normal;
+ text-decoration: none;
+}
diff --git a/client/coral-admin/src/components/SignIn.js b/client/coral-admin/src/components/SignIn.js
new file mode 100644
index 000000000..71f14d12a
--- /dev/null
+++ b/client/coral-admin/src/components/SignIn.js
@@ -0,0 +1,76 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './SignIn.css';
+import { Button, TextField, Alert } from 'coral-ui';
+
+class SignIn extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+
+ handleForgotPasswordLink = e => {
+ e.preventDefault();
+ this.props.onForgotPasswordLink();
+ };
+ handleEmailChange = e => this.props.onEmailChange(e.target.value);
+ handlePasswordChange = e => this.props.onPasswordChange(e.target.value);
+
+ handleSubmit = e => {
+ e.preventDefault();
+ this.props.onSubmit();
+ };
+
+ render() {
+ const { email, password, errorMessage } = this.props;
+ return (
+
+ );
+ }
+}
+
+SignIn.propTypes = {
+ email: PropTypes.string.isRequired,
+ password: PropTypes.string.isRequired,
+ onEmailChange: PropTypes.func.isRequired,
+ onPasswordChange: PropTypes.func.isRequired,
+ onForgotPasswordLink: PropTypes.func.isRequired,
+ onSubmit: PropTypes.func.isRequired,
+ errorMessage: PropTypes.string.isRequired,
+ requireRecaptcha: PropTypes.bool.isRequired,
+};
+
+export default SignIn;
diff --git a/client/coral-admin/src/containers/ForgotPassword.js b/client/coral-admin/src/containers/ForgotPassword.js
new file mode 100644
index 000000000..4de51fa1e
--- /dev/null
+++ b/client/coral-admin/src/containers/ForgotPassword.js
@@ -0,0 +1,42 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { withForgotPassword } from 'coral-framework/hocs';
+import { compose } from 'recompose';
+import ForgotPassword from '../components/ForgotPassword';
+
+class ForgotPasswordContainer extends Component {
+ state = {
+ email: '',
+ password: '',
+ };
+
+ handleSubmit = () => {
+ this.props.forgotPassword(this.state.email);
+ };
+
+ handleEmailChange = email => {
+ this.setState({ email });
+ };
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+ForgotPasswordContainer.propTypes = {
+ success: PropTypes.bool.isRequired,
+ forgotPassword: PropTypes.func.isRequired,
+ errorMessage: PropTypes.string.isRequired,
+ onSignInLink: PropTypes.func.isRequired,
+};
+
+export default compose(withForgotPassword)(ForgotPasswordContainer);
diff --git a/client/coral-admin/src/containers/Login.js b/client/coral-admin/src/containers/Login.js
index 3d32a2af2..08558bc5c 100644
--- a/client/coral-admin/src/containers/Login.js
+++ b/client/coral-admin/src/containers/Login.js
@@ -1,44 +1,30 @@
import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import { withLogin } from 'coral-framework/hocs';
-import { compose } from 'recompose';
import Login from '../components/Login';
class LoginContainer extends Component {
state = {
- email: '',
- password: '',
+ forgotPassword: false,
};
- handleSubmit = () => {
- this.props.login(this.state.email, this.state.password);
+ switchToForgotPassword = () => {
+ this.setState({ forgotPassword: true });
};
- handleEmailChange = email => {
- this.setState({ email });
- };
-
- handlePasswordChange = password => {
- this.setState({ password });
+ switchToSignIn = () => {
+ this.setState({ forgotPassword: false });
};
render() {
return (
);
}
}
-LoginContainer.propTypes = {
- login: PropTypes.func,
- errorMessage: PropTypes.string,
-};
+LoginContainer.propTypes = {};
-export default compose(withLogin)(LoginContainer);
+export default LoginContainer;
diff --git a/client/coral-admin/src/containers/SignIn.js b/client/coral-admin/src/containers/SignIn.js
new file mode 100644
index 000000000..ab7886c3a
--- /dev/null
+++ b/client/coral-admin/src/containers/SignIn.js
@@ -0,0 +1,48 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { withSignIn } from 'coral-framework/hocs';
+import { compose } from 'recompose';
+import SignIn from '../components/SignIn';
+
+class SignInContainer extends Component {
+ state = {
+ email: '',
+ password: '',
+ };
+
+ handleSubmit = () => {
+ this.props.signIn(this.state.email, this.state.password);
+ };
+
+ handleEmailChange = email => {
+ this.setState({ email });
+ };
+
+ handlePasswordChange = password => {
+ this.setState({ password });
+ };
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+SignInContainer.propTypes = {
+ signIn: PropTypes.func.isRequired,
+ errorMessage: PropTypes.string.isRequired,
+ onForgotPasswordLink: PropTypes.func.isRequired,
+ requireRecaptcha: PropTypes.bool.isRequired,
+};
+
+export default compose(withSignIn)(SignInContainer);
diff --git a/client/coral-framework/hocs/index.js b/client/coral-framework/hocs/index.js
index c871306ae..cfc41676b 100644
--- a/client/coral-framework/hocs/index.js
+++ b/client/coral-framework/hocs/index.js
@@ -6,4 +6,5 @@ export { default as withEmit } from './withEmit';
export { default as excludeIf } from './excludeIf';
export { default as connect } from './connect';
export { default as withMergedSettings } from './withMergedSettings';
-export { default as withLogin } from './withLogin';
+export { default as withSignIn } from './withSignIn';
+export { default as withForgotPassword } from './withForgotPassword';
diff --git a/client/coral-framework/hocs/withForgotPassword.js b/client/coral-framework/hocs/withForgotPassword.js
new file mode 100644
index 000000000..c8b42b8c5
--- /dev/null
+++ b/client/coral-framework/hocs/withForgotPassword.js
@@ -0,0 +1,61 @@
+import React from 'react';
+import hoistStatics from 'recompose/hoistStatics';
+import PropTypes from 'prop-types';
+import { translateError } from '../utils';
+
+/**
+ * WithForgotPassword provides properties `forgotPasssword`, `loading`, `errorMessage`, `success`.
+ */
+export default hoistStatics(WrappedComponent => {
+ class WithForgotPassword extends React.Component {
+ static contextTypes = {
+ store: PropTypes.object,
+ rest: PropTypes.func,
+ };
+
+ state = {
+ error: null,
+ loading: false,
+ success: false,
+ };
+
+ forgotPassword = email => {
+ const { rest } = this.context;
+ const redirectUri = location.href;
+ this.setState({ loading: true, error: null, success: false });
+
+ rest('/account/password/reset', {
+ method: 'POST',
+ body: { email, loc: redirectUri },
+ })
+ .then(() => {
+ this.setState({ loading: false, error: null, success: true });
+ })
+ .catch(error => {
+ console.error(error);
+ this.setState({ loading: false, error });
+ });
+ };
+
+ getErrorMessage() {
+ if (!this.state.error) {
+ return '';
+ }
+ return translateError(this.state.error);
+ }
+
+ render() {
+ return (
+
+ );
+ }
+ }
+
+ return WithForgotPassword;
+});
diff --git a/client/coral-framework/hocs/withLogin.js b/client/coral-framework/hocs/withSignIn.js
similarity index 86%
rename from client/coral-framework/hocs/withLogin.js
rename to client/coral-framework/hocs/withSignIn.js
index 56586b7af..a725f01e9 100644
--- a/client/coral-framework/hocs/withLogin.js
+++ b/client/coral-framework/hocs/withSignIn.js
@@ -6,10 +6,10 @@ import { translateError } from '../utils';
import { t } from '../services/i18n';
/**
- * WithLogin provides properties `login`, `loading` and `errorMessage`, `requireRecaptcha`.
+ * WithSignIn provides properties `signIn`, `loading` and `errorMessage`, `requireRecaptcha`.
*/
export default hoistStatics(WrappedComponent => {
- class WithLogin extends React.Component {
+ class WithSignIn extends React.Component {
static contextTypes = {
store: PropTypes.object,
rest: PropTypes.func,
@@ -20,7 +20,7 @@ export default hoistStatics(WrappedComponent => {
loading: false,
};
- login = (email, password, recaptchaResponse) => {
+ signIn = (email, password, recaptchaResponse) => {
const { store, rest } = this.context;
const params = {
method: 'POST',
@@ -62,7 +62,7 @@ export default hoistStatics(WrappedComponent => {
return (
{
}
}
- return WithLogin;
+ return WithSignIn;
});