blob: d5f3018e54703b3523769c22b4dd3535df0ad71c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, { Component } from "react";
import { Button, Nav, Tab, Row, Col } from "react-bootstrap";
import { Form, Field } from "react-final-form";
import { toast } from "react-toastify";
import { getUserProfile, setUserProfile } from "Utils/appState";
import { InfoIcon } from "../utils/XAUtils";
import { BlockUi, scrollToError } from "../components/CommonComponents";
import withRouter from "Hooks/withRouter";
import { UserTypes, RegexValidation } from "Utils/XAEnums";
import { cloneDeep, has, isEmpty, isUndefined } from "lodash";
import { RegexMessage } from "../utils/XAMessages";
import { fetchApi } from "Utils/fetchAPI";
import CustomBreadcrumb from "./CustomBreadcrumb";
class UserProfile extends Component {
constructor(props) {
super(props);
this.state = {
blockUI: false
};
}
updateUserInfo = async (values) => {
const userProps = cloneDeep(getUserProfile());
userProps.firstName = values.firstName;
userProps.emailAddress = values.emailAddress;
userProps.lastName = values.lastName;
try {
this.setState({ blockUI: true });
const profResp = await fetchApi({
url: "users",
method: "put",
data: userProps,
skipNavigate: true
});
this.setState({ blockUI: false });
setUserProfile(profResp.data);
this.props.navigate("/");
toast.success("Successfully updated user profile");
} catch (error) {
this.setState({ blockUI: false });
if (
error?.response !== undefined &&
has(error?.response, "data.msgDesc")
) {
toast.error(
`Error occurred while updating user profile! ${error?.response?.data?.msgDesc}`
);
}
console.error(`Error occurred while updating user profile! ${error}`);
}
};
updatePassword = async (values) => {
const userProps = getUserProfile();
let jsonData = {};
jsonData["loginId"] = userProps.loginId;
jsonData["oldPassword"] = values.oldPassword;
jsonData["updPassword"] = values.newPassword;
try {
this.setState({ blockUI: true });
await fetchApi({
url: "users/" + userProps.id + "/passwordchange",
method: "post",
data: jsonData,
skipNavigate: true
});
this.setState({ blockUI: false });
toast.success("Successfully updated user password");
this.props.navigate("/");
} catch (error) {
this.setState({ blockUI: false });
if (
has(error?.response, "data.msgDesc") &&
(error?.response?.data?.msgDesc == "serverMsg.userMgrOldPassword" ||
error?.response?.data?.msgDesc == "serverMsg.userMgrNewPassword")
) {
toast.error("Error occured while updating user password!");
}
console.error(`Error occurred while updating user password! ${error}`);
}
};
validatePasswordForm = (values) => {
const errors = {};
if (!values.oldPassword) {
errors.oldPassword = "Required";
}
if (!values.newPassword) {
errors.newPassword = "Required";
}
if (
values &&
has(values, "newPassword") &&
!RegexValidation.PASSWORD.regexExpression.test(values.newPassword)
) {
errors.newPassword = RegexValidation.PASSWORD.message;
}
if (!values.reEnterPassword) {
errors.reEnterPassword = "Required";
} else if (
has(values, "newPassword") &&
values.newPassword !== values.reEnterPassword
) {
errors.reEnterPassword =
"Re-enter New Password must match with New Password";
}
if (values && has(values, "oldPassword") && has(values, "newPassword")) {
if (values.oldPassword === values.newPassword) {
errors.newPassword = "New Password cannot be same as Old Password";
}
}
return errors;
};
validateUserForm = (values) => {
const errors = {};
if (!values.firstName) {
errors.firstName = "Required";
}
if (
values &&
has(values, "firstName") &&
!RegexValidation.NAME_VALIDATION.regexExpressionForFirstAndLastName.test(
values.firstName
)
) {
errors.firstName = RegexMessage.MESSAGE.firstNameValidationMsg;
}
if (
values &&
!isEmpty(values?.lastName) &&
!RegexValidation.NAME_VALIDATION.regexExpressionForFirstAndLastName.test(
values.lastName
)
) {
errors.lastName = RegexMessage.MESSAGE.lastNameValidationMsg;
}
if (
(!isEmpty(values.emailAddress) || !isUndefined(values.emailAddress)) &&
!RegexValidation.EMAIL_VALIDATION.regexExpressionForEmail.test(
values.emailAddress
)
) {
errors.emailAddress = RegexValidation.EMAIL_VALIDATION.message;
}
return errors;
};
render() {
const userProps = getUserProfile();
return (
<div>
<div className="header-wraper">
<h3 className="wrap-header bold">User Profile</h3>
<CustomBreadcrumb />
</div>
<div className="wrap">
<BlockUi isUiBlock={this.state.blockUI} />
<Tab.Container transition={false} defaultActiveKey="edit-basic-info">
{userProps.userSource == UserTypes.USER_INTERNAL.value && (
<Nav variant="tabs">
<Nav.Item>
<Nav.Link eventKey="edit-basic-info">
<i className="fa-fw fa fa-edit bigger-125"></i>Basic Info
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="edit-password">
<i className="fa-fw fa fa-key bigger-125"></i>Change
Password
</Nav.Link>
</Nav.Item>
</Nav>
)}
<div className="user-profile">
<Tab.Content>
<Tab.Pane eventKey="edit-basic-info">
<Form
onSubmit={this.updateUserInfo}
validate={this.validateUserForm}
initialValues={{
firstName: userProps.firstName,
lastName: userProps.lastName,
emailAddress: userProps.emailAddress,
userRoleList: userProps.userRoleList[0]
}}
render={({ handleSubmit, form, invalid, errors }) => (
<form
onSubmit={(event) => {
if (invalid) {
let selector =
document.getElementById("isError") ||
document.querySelector(
`input[name=${Object.keys(errors)[0]}]`
);
scrollToError(selector);
}
handleSubmit(event);
}}
>
<Field name="firstName">
{({ input, meta }) => (
<Row className="form-group">
<Col xs={3}>
<label className="form-label pull-right">
First Name *
</label>
</Col>
<Col xs={4}>
<input
{...input}
type="text"
name="firstName"
placeholder="First Name"
id={
meta.error && meta.touched
? "isError"
: "firstName"
}
className={
meta.error && meta.touched
? "form-control border-danger"
: "form-control"
}
disabled={
userProps.userSource ==
UserTypes.USER_INTERNAL.value
? false
: true
}
data-cy="firstName"
/>
<InfoIcon
css="info-user-role-grp-icon"
position="right"
message={
RegexMessage.MESSAGE.firstNameValidationMsg
}
/>
{meta.error && meta.touched && (
<span className="invalid-field">
{meta.error}
</span>
)}
</Col>
</Row>
)}
</Field>
<Field name="lastName">
{({ input, meta }) => (
<Row className="form-group">
<Col xs={3}>
<label className="form-label pull-right">
Last Name
</label>
</Col>
<Col xs={4}>
<input
{...input}
type="text"
name="lastName"
placeholder="Last Name"
id={
meta.error && meta.touched
? "isError"
: "lastName"
}
className={
meta.error && meta.touched
? "form-control border-danger"
: "form-control"
}
disabled={
userProps.userSource ==
UserTypes.USER_INTERNAL.value
? false
: true
}
data-cy="lastName"
/>
<InfoIcon
css="info-user-role-grp-icon"
position="right"
message={
RegexMessage.MESSAGE.lastNameValidationMsg
}
/>
{meta.error && meta.touched && (
<span className="invalid-field">
{meta.error}
</span>
)}
</Col>
</Row>
)}
</Field>
<Field name="emailAddress">
{({ input, meta }) => (
<Row className="form-group">
<Col xs={3}>
<label className="form-label pull-right">
Email Address
</label>
</Col>
<Col xs={4}>
<input
{...input}
name="emailAddress"
type="email"
placeholder="Email Address"
id={
meta.error && meta.touched
? "isError"
: "emailAddress"
}
className={
meta.error && meta.touched
? "form-control border-danger"
: "form-control"
}
disabled={
userProps.userSource ==
UserTypes.USER_INTERNAL.value
? false
: true
}
data-cy="emailAddress"
/>
<InfoIcon
css="info-user-role-grp-icon"
position="right"
message={
RegexMessage.MESSAGE
.emailvalidationinfomessage
}
/>
{meta.error && meta.touched && (
<span className="invalid-field">
{meta.error}
</span>
)}
</Col>
</Row>
)}
</Field>
<Row className="form-group">
<Col xs={3}>
{" "}
<label className="form-label pull-right">
Select Role *
</label>
</Col>
<Col xs={4}>
<Field
name="userRoleList"
component="select"
className="form-control"
disabled
>
<option value="ROLE_SYS_ADMIN">Admin</option>
<option value="ROLE_KEY_ADMIN">KeyAdmin</option>
<option value="ROLE_USER">User</option>
<option value="ROLE_ADMIN_AUDITOR">
Auditor
</option>
<option value="ROLE_KEY_ADMIN_AUDITOR">
KeyAuditor
</option>
</Field>
</Col>
</Row>
<div className="row form-actions">
<div className="col-md-9 offset-md-3">
<Button
variant="primary"
type="submit"
size="sm"
disabled={
userProps.userSource ==
UserTypes.USER_INTERNAL.value
? false
: true
}
data-id="save"
data-cy="save"
>
Save
</Button>
<Button
variant="secondary"
type="button"
size="sm"
onClick={() => {
form.reset();
this.props.navigate("/");
}}
data-id="cancel"
data-cy="cancel"
>
Cancel
</Button>
</div>
</div>
</form>
)}
/>
</Tab.Pane>
</Tab.Content>
<Tab.Content>
<Tab.Pane eventKey="edit-password">
<Form
onSubmit={this.updatePassword}
validate={this.validatePasswordForm}
render={({
handleSubmit,
form,
submitting,
invalid,
errors
}) => (
<form
onSubmit={(event) => {
if (invalid) {
let selector =
document.getElementById("isError") ||
document.getElementById(Object.keys(errors)[0]) ||
document.querySelector(
`input[name=${Object.keys(errors)[0]}]`
) ||
document.querySelector(
`input[id=${Object.keys(errors)[0]}]`
) ||
document.querySelector(
`span[className="invalid-field"]`
);
scrollToError(selector);
}
handleSubmit(event);
}}
>
<Field name="oldPassword">
{({ input, meta }) => (
<Row className="form-group">
<Col xs={3}>
<label className="form-label pull-right">
Old Password *
</label>
</Col>
<Col xs={4}>
<input
{...input}
type="password"
autoComplete="off"
name="oldPassword"
placeholder="Old Password"
id={
meta.error && meta.touched
? "isError"
: "oldPassword"
}
className={
meta.error && meta.touched
? "form-control border-danger"
: "form-control"
}
data-cy="oldPassword"
/>
<InfoIcon
css="info-user-role-grp-icon"
position="right"
message={
<p
className="pd-10 mb-0"
style={{ fontSize: "small" }}
>
{RegexValidation.PASSWORD.message}
</p>
}
/>
{meta.error && meta.touched && (
<span className="invalid-field">
{meta.error}
</span>
)}
</Col>
</Row>
)}
</Field>
<Field name="newPassword">
{({ input, meta }) => (
<Row className="form-group">
<Col xs={3}>
<label className="form-label pull-right">
New Password *
</label>
</Col>
<Col xs={4}>
<input
{...input}
type="password"
autoComplete="off"
name="newPassword"
placeholder="New Password"
id={
meta.error && meta.touched
? "isError"
: "newPassword"
}
className={
meta.error && meta.touched
? "form-control border-danger"
: "form-control"
}
data-cy="newPassword"
/>
<InfoIcon
css="info-user-role-grp-icon"
position="right"
message={
<p
className="pd-10 mb-0"
style={{ fontSize: "small" }}
>
{RegexValidation.PASSWORD.message}
</p>
}
/>
{meta.error && meta.touched && (
<span className="invalid-field">
{meta.error}
</span>
)}
</Col>
</Row>
)}
</Field>
<Field name="reEnterPassword">
{({ input, meta }) => (
<Row className="form-group">
<Col xs={3}>
<label className="form-label pull-right">
Re-enter New Password *
</label>
</Col>
<Col xs={4}>
<input
{...input}
type="password"
autoComplete="off"
name="reEnterPassword"
placeholder="Re-enter New Password"
id={
meta.error && meta.touched
? "isError"
: "reEnterPassword"
}
className={
meta.error && meta.touched
? "form-control border-danger"
: "form-control"
}
data-cy="reEnterPassword"
/>
<InfoIcon
css="info-user-role-grp-icon"
position="right"
message={
<p
className="pd-10 mb-0"
style={{ fontSize: "small" }}
>
{RegexValidation.PASSWORD.message}
</p>
}
/>
{meta.error && meta.touched && (
<span className="invalid-field">
{meta.error}
</span>
)}
</Col>
</Row>
)}
</Field>
<div className="row form-actions">
<div className="col-md-9 offset-md-3">
<Button
variant="primary"
type="submit"
size="sm"
disabled={submitting}
data-id="save"
data-cy="save"
>
Save
</Button>
<Button
variant="secondary"
type="button"
size="sm"
onClick={() => {
form.reset();
this.props.navigate("/");
}}
data-id="cancel"
data-cy="cancel"
>
Cancel
</Button>
</div>
</div>
</form>
)}
/>
</Tab.Pane>
</Tab.Content>
</div>
</Tab.Container>
</div>
</div>
);
}
}
export default withRouter(UserProfile);