Skip to content

Commit

Permalink
ft(password-reset): users should be able to reset their passwords.
Browse files Browse the repository at this point in the history
- add test for the password reset feature
- add views files for the feature
- add validations for the form fields
- add loaders for the feature

 [Finishes 164798252]
  • Loading branch information
anyatibrian authored and anyatibrian committed May 19, 2019
1 parent a5c350e commit de36343
Show file tree
Hide file tree
Showing 46 changed files with 1,517 additions and 561 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@material-ui/icons": "^3.0.2",
"axios": "^0.18.0",
"babel-jest": "^24.8.0",
"bootstrap": "^4.3.1",
"classnames": "^2.2.6",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.12.1",
Expand Down Expand Up @@ -67,6 +68,7 @@
"eslint-config-prettier": "^4.2.0",
"eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-react": "^7.12.4",
"file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0",
"jest": "^24.8.0",
"moxios": "^0.4.0",
Expand All @@ -78,6 +80,7 @@
"redux-mock-store": "^1.5.3",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.1",
"webpack-dev-server": "^3.3.1"
Expand Down
81 changes: 81 additions & 0 deletions src/actions/passwordResetActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import axios from "axios";
import { toast } from "react-toastify";
import {
ERROR_DURING_SENDING_LINK,
IS_LOADING,
RESET_PASSWORD,
RESET_PASSWORD_ERROR,
SENDPASSWORD_RESET_LINK
} from "./types";

export const sendPasswordResetLink = data => async dispatch => {
dispatch({
type: IS_LOADING
});
return await axios
.post(
`https://ah-backend-prime-staging.herokuapp.com/api/v1/users/password/reset/email/`,
data
)
.then(res => {
dispatch({
type: SENDPASSWORD_RESET_LINK,
payload: res.data
});
toast.dismiss();
toast.success(`${res.data.message}`, {
position: toast.POSITION.TOP_RIGHT,
autoClose: 3000,
hideProgressBar: false
});
})
.catch(error => {
dispatch({
type: ERROR_DURING_SENDING_LINK,
payload: error.response.data
});
toast.dismiss();
toast.error(`${error.response.data.error}`, {
position: toast.POSITION.TOP_RIGHT,
autoClose: false,
hideProgressBar: false
});
});
};

export const passwordReset = (data, token) => async dispatch => {
dispatch({
type: IS_LOADING
});
return await axios
.put(
`https://ah-backend-prime-staging.herokuapp.com/api/v1/users/password/${token}/reset/`,
{
user: data
}
)
.then(res => {
dispatch({
type: RESET_PASSWORD,
payload: res.data
});
toast.dismiss();
toast.success(`${res.data.message}`, {
position: toast.POSITION.TOP_RIGHT,
autoClose: 3000,
hideProgressBar: false
});
})
.catch(err => {
dispatch({
type: RESET_PASSWORD_ERROR,
payload: { error: "there was error during the password reset" }
});
toast.dismiss();
toast.error("there was error during the password reset", {
position: toast.POSITION.TOP_RIGHT,
autoClose: false,
hideProgressBar: false
});
});
};
6 changes: 3 additions & 3 deletions src/actions/registerActions.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {
IS_REGISTERING,
REGISTRATION_ERROR_MESSAGE,
RIGISTRATION_SUCCESS_MESSAGE
RIGISTRATION_SUCCESS_MESSAGE,
IS_LOADING
} from "../actions/types";
import axios from "axios";
import { toast } from "react-toastify";

export const registerUser = userData => async dispatch => {
toast.dismiss();
dispatch({
type: IS_REGISTERING
type: IS_LOADING
});
await axios
.post(
Expand Down
6 changes: 5 additions & 1 deletion src/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ export const LOGIN_FAIL = "LOGIN_FAIL";
export const SUCCESSFUL = "SUCCESSFUL";
export const REGISTRATION_ERROR_MESSAGE = "REGISTRATION_ERROR_MESSAGE";
export const RIGISTRATION_SUCCESS_MESSAGE = "REGISTRATION_SUCCESS_MESSAGE";
export const IS_REGISTERING = "IS_REGISTERING";
export const GOOGLE_LOGIN = "GOOGLE_LOGIN";
export const GOOGLE_FAILURE = "GOOGLE_FAILURE";
export const FACEBOOK_LOGIN = "FACEBOOK_LOGIN";
export const FACEBOOK_FAILURE = "FACEBOOK_FAILURE";
export const IS_LOADING = "IS_LOADING";
export const SENDPASSWORD_RESET_LINK = "SENDPASSWOR_RESET_LINK";
export const ERROR_DURING_SENDING_LINK = " ERROR_DURING_SENDING_LINK";
export const RESET_PASSWORD = "RESET_PASSWORD";
export const RESET_PASSWORD_ERROR = "RESET_PASSWORD_ERROR";
1 change: 0 additions & 1 deletion src/components/SocialAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from "react";
import FacebookLogin from "react-facebook-login";
import GoogleLogin from "react-google-login";
import config from "../../src/config.json";
import color from "@material-ui/core/colors/grey";

export const SocialAuth = props => (
<div>
Expand Down
2 changes: 0 additions & 2 deletions src/components/home.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import "../styles/app.scss";
import TopAppBar from "../components/header";
import { getArticlesAction } from "../actions/getArticles";

export class Home extends Component {
Expand Down Expand Up @@ -39,7 +38,6 @@ export class Home extends Component {
);
return (
<div className="big-container">
<TopAppBar />
<div className="articles-top">
<div className="best-article">
<div className="inner">
Expand Down
9 changes: 5 additions & 4 deletions src/components/login/LoginModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Paper from "@material-ui/core/Paper";
import { withStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import { Link } from "react-router-dom";
import "../../styles/register.scss";
import SocialAuthContainer from "../../containers/SocialAuthContainer";

Expand Down Expand Up @@ -91,15 +92,15 @@ const LoginComponent = props => {
</Grid>
<p>
Don't have an account yet?{" "}
<a href="/register" id="link">
<Link to="/register" id="link">
create one now
</a>
</Link>
</p>
<p>
Forgot your password?{" "}
<a href="/passwordreset" id="link">
<Link to="/passwordresetemail" id="link">
reset now
</a>
</Link>
</p>
</Paper>
</Grid>
Expand Down
103 changes: 103 additions & 0 deletions src/components/navbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import "../styles/navbar.scss";
import BellIcon from "../styles/images/icons8-bell-100.png";
import SideDrawer from "./sideDrawer";

export class NavBarComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
navBarDrawer: false
};
}

toggleDrawer = event => {
event.preventDefault();
this.setState(prevState => {
return { navBarDrawer: !prevState.navBarDrawer };
});
};

render() {
let sideDrawer;
if (this.state.navBarDrawer) {
sideDrawer = <SideDrawer />;
}

const { isAuthenticated } = this.props;
return (
<div style={{ height: "100%" }}>
<nav className="navbar navbar-expand-sm ">
<ul className="navbar-nav">
<li className="nav-item">
<a className="nav-link" href="#">
<h4>
<i
className="fas fa-bars"
style={{ marginRight: "20px" }}
onClick={this.toggleDrawer}
id="nav-icon"
/>
Author's Haven
</h4>
</a>
</li>
</ul>
{isAuthenticated ? (
<ul className="nav navbar-nav ml-auto">
<li className="nav-item active">
<div className="form-group has-search">
<span
className="fa fa-search form-control-feedback"
id="search-icon"
/>
<form className="form-inline my-5 my-lg-0">
<input
className="form-control mr-sm-2 form-control-search"
type="search"
aria-label="Search"
/>
</form>
</div>
</li>
<li className="nav-item">
<img src={BellIcon} id="notification-icon" />
</li>
<li className="nav-item" />
<li className="nav-item">
<div>
<img src="" className="profile-section" />
</div>
</li>
</ul>
) : (
<ul className="nav navbar-nav ml-auto">
<li className="nav-item">
<Link className="nav-link" to="/login">
Sign In
</Link>
</li>
<li className="nav-item">
<Link className="nav-link get-started " to="/register">
Get Started
</Link>
</li>
</ul>
)}
</nav>
{sideDrawer}
</div>
);
}
}

NavBarComponent.proptypes = {
isAuthenticated: PropTypes.Boolean
};
const mapStateToProps = state => ({
isAuthenticated: state.auth_login.loginSuccess
});
export default connect(mapStateToProps)(NavBarComponent);
77 changes: 77 additions & 0 deletions src/components/passwordReset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from "react";
import "../styles/passwordreset.scss";
import Loader from "react-loader";

export const PasswordResetComponent = props => {
const {
password,
passwordConfirm,
handleOnChange,
errors,
handleOnSubmit,
isLoading
} = props;
return (
<div>
<div className="container">
<div className="row">
<div className="col col-lg-3 col-sm-1" />
<div className="col col-lg-6 col-md-12 col-sm-12 password-reset-container">
<div className="">
<h2>Password Reset</h2>
<p>
Please enter and confirm a new password that you will use to
sign in into Author's haven
</p>
<form method="post" onSubmit={handleOnSubmit}>
<div className="form-group">
<input
type="password"
id="password"
name="password"
required
className="form-control"
placeholder="Password"
value={password}
onChange={handleOnChange}
/>
{errors.password.length > 0 ? (
<span className="form-errors-email">{errors.password}</span>
) : (
""
)}
</div>
<div className="form-group">
<input
type="password"
id="passwordConfirm"
name="passwordConfirm"
className="form-control"
required
placeholder="confirm Password"
value={passwordConfirm}
onChange={handleOnChange}
/>
{errors.passwordConfirm.length > 0 ? (
<span className="form-errors-email">
{errors.passwordConfirm}
</span>
) : (
""
)}
<br />
</div>
<button type="submit" className="btn btn-primary">
Reset
<span>{isLoading ? <Loader /> : ""}</span>
</button>
</form>
</div>
</div>
<div className="col col-lg-3 col-sm-1 col-sm-auto" />
</div>
</div>
</div>
);
};
export default PasswordResetComponent;
Loading

0 comments on commit de36343

Please sign in to comment.