import React, {Component} from 'react';
import Input from "../components/Input";
import * as authActions from "../store/authActions";
import {connect} from "react-redux";
import ButtonWithProgress from "../components/ButtonWithProgress";
import * as apiCalls from "../apiCalls/apiCalls";
import handleError from "../shared/failureHandler";
import PageContentContainer from "../components/PageContentContainer";
import Breadcrumbs from "../components/Breadcrumbs";
import PageInfo from "../components/PageInfo";
/**
* page with user's profile
*/
class ProfilePage extends Component {
/**
* current page state
*/
state = {
username: this.props.user.username,
email: this.props.user.email,
password: "",
passwordRepeat: "",
passwordRepeatConfirmed: true,
pendingApiCallUpdateUser: false,
pendingApiCallUpdatePassword: false,
userUpdated: false,
passwordUpdated: false,
errors: {},
}
/**
* called when some of the text inputs change value
* @param event input event
*/
onChange = (event) => {
if (event.target.name === "passwordRepeat") {
// for password repeat input
const value = event.target.value;
// checks if passwords are the same
const passwordRepeatConfirmed = this.state.password === value;
const errors = {...this.state.errors};
errors.passwordRepeat = passwordRepeatConfirmed ? "" : "Passwords do not match";
this.setState({passwordRepeatConfirmed, errors, passwordUpdated: false});
} else if (event.target.name === "password") {
// for password input
const value = event.target.value;
// check if password are the same
const passwordRepeatConfirmed = this.state.passwordRepeat === value;
const errors = {...this.state.errors};
errors.passwordRepeat = passwordRepeatConfirmed ? "" : "Passwords do not match";
delete errors[event.target.name];
// update password confirmed value and errors
this.setState({passwordRepeatConfirmed, errors, passwordUpdated: false});
} else {
// for other fields
const errors = {...this.state.errors};
delete errors[event.target.name];
this.setState({errors, userUpdated: false});
}
// change value for input
this.setState({[event.target.name]: event.target.value});
}
/**
* handles error from http request
* @param apiError error
* @param apiCall api call name
*/
handleApiError = (apiError, apiCall) => {
if (apiError.response.data && apiError.response.data.validationErrors) {
let errors = {
...this.state.errors,
...apiError.response.data.validationErrors
};
// set new errors and set api call to false
this.setState({
[apiCall]: false,
errors
});
}
}
/**
* called when user submit user info update
*/
onClickUserUpdate = (e) => {
e.preventDefault();
this.setState({pendingApiCallUpdateUser: true});
const {username, email} = this.state;
// sends updated info to server
apiCalls.updateUser({username, email}).then(response => {
this.setState({pendingApiCallUpdateUser: false, userUpdated: true});
this.props.setUsername(username);
this.props.setEmail(email);
}).catch(error => {
// handles unauthorized state
return handleError(error);
}).catch(apiError => {
// handle errors in input
this.handleApiError(apiError, "pendingApiCallUpdateUser");
});
}
/**
* called when user submit password update
*/
onClickPasswordUpdate = (e) => {
e.preventDefault();
this.setState({pendingApiCallUpdatePassword: true});
const {password} = this.state;
// sends new password to server
apiCalls.updatePassword({password}).then(response => {
let errors = {...this.state.errors};
delete errors["passwordRepeat"];
this.setState({errors, pendingApiCallUpdatePassword: false, passwordUpdated: true, password: "", passwordRepeat: ""});
}).catch(error => {
// handles unauthorized state
return handleError(error);
}).catch(apiError => {
// handle errors in input
this.handleApiError(apiError, "pendingApiCallUpdatePassword");
});
}
/**
* renders user profile page
* @returns {JSX.Element} page
*/
render() {
const {
username,
email,
password,
passwordRepeat,
pendingApiCallUpdateUser,
pendingApiCallUpdatePassword,
passwordRepeatConfirmed,
userUpdated,
passwordUpdated,
errors,
} = this.state;
const {createdAt} = this.props.user;
// render page
return (
<PageContentContainer>
<Breadcrumbs>
<li className="breadcrumb-item active">My Profile</li>
</Breadcrumbs>
<PageInfo name="My Profile">Edit your profile information</PageInfo>
<div className="mb-4">
<span className="font-weight-bold">Registration date: </span>
{new Date(createdAt * 1).toLocaleDateString("en-UK")}
</div>
<form className="mb-4">
{
userUpdated &&
<div className="alert alert-success" role="alert">
Personal information has been updated
</div>
}
<div className="form-group">
<Input label="Name" name="username"
value={username}
onChange={this.onChange} hasError={errors.username && true}
error={errors.username}/>
</div>
<div className="form-group">
<Input label="E-mail" name="email"
value={email}
onChange={this.onChange} hasError={errors.email && true}
error={errors.email}/>
</div>
<ButtonWithProgress onClick={(e) => this.onClickUserUpdate(e)}
className="btn btn-primary w-100 my-2"
disabled={pendingApiCallUpdateUser || username === "" || email === ""}
pendingApiCall={pendingApiCallUpdateUser}
hasChildren>
<i className="fa fa-paper-plane" /> Update information
</ButtonWithProgress>
</form>
<form>
{
passwordUpdated &&
<div className="alert alert-success" role="alert">
Password ha been updated
</div>
}
<div className="form-group">
<Input
label="Password"
placeholder="Enter password" name="password" value={password}
onChange={this.onChange} type="password"
hasError={errors.password && true}
error={errors.password}
/>
</div>
<div className="form-group">
<Input
label="Confirm Password"
placeholder="Enter password again" name="passwordRepeat" value={passwordRepeat}
onChange={this.onChange} type="password"
hasError={errors.passwordRepeat && true}
error={errors.passwordRepeat}
/>
</div>
<ButtonWithProgress onClick={(e) => this.onClickPasswordUpdate(e)}
className="btn btn-primary w-100 my-2"
disabled={pendingApiCallUpdatePassword || !passwordRepeatConfirmed || password === "" || passwordRepeat === ""}
pendingApiCall={pendingApiCallUpdatePassword}
hasChildren>
<i className="fa fa-paper-plane" /> Change password
</ButtonWithProgress>
</form>
</PageContentContainer>
);
}
}
/**
* map redux state to page props
* @param state redux state
*/
const mapStateToProps = (state) => {
return {
user: state,
};
}
/**
* map redux dispatch to props
* @param dispatch redux dispatch
*/
const mapDispatchToProps = (dispatch) => {
return {
setUsername: (username) => dispatch(authActions.setUsername(username)),
setEmail: (email) => dispatch(authActions.setEmail(email))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ProfilePage);