blob: e08917bf21bda53ffb1cb4ee2dba36295c114890 [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, { useEffect, useReducer } from "react";
import { Tab, Button, Nav, Row, Col } from "react-bootstrap";
import { Form, Field } from "react-final-form";
import UserFormComp from "Views/UserGroupRoleListing/users_details/UserFormComp";
import { Loader, scrollToError } from "Components/CommonComponents";
import { fetchApi } from "Utils/fetchAPI";
import { UserTypes, RegexValidation } from "Utils/XAEnums";
import { toast } from "react-toastify";
import { useParams, useNavigate } from "react-router-dom";
import { has } from "lodash";
import { commonBreadcrumb, InfoIcon } from "../../../utils/XAUtils";
const initialState = {
userInfo: {},
loader: true
};
const userFormReducer = (state, action) => {
switch (action.type) {
case "SET_LOADER":
return {
...state,
loader: action.loader
};
case "SET_USER_DATA":
return {
...state,
userInfo: action.userInfo,
loader: action.loader
};
default:
throw new Error();
}
};
function AddUserView() {
const params = useParams();
const [userDetails, dispatch] = useReducer(userFormReducer, initialState);
const { userInfo, loader } = userDetails;
const navigate = useNavigate();
useEffect(() => {
if (params?.userID) {
fetchUserData(params.userID);
} else {
dispatch({
type: "SET_LOADER",
loader: false
});
}
}, []);
const fetchUserData = async (userID) => {
let userRespData;
try {
userRespData = await fetchApi({
url: "xusers/secure/users/" + userID
});
} catch (error) {
console.error(
`Error occurred while fetching Users or CSRF headers! ${error}`
);
}
dispatch({
type: "SET_USER_DATA",
userInfo: userRespData?.data,
loader: false
});
};
const validateForm = (values) => {
const errors = {};
if (!values.newPassword) {
errors.newPassword = "Required";
} else {
if (!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 = "Password must be match with new password";
}
return errors;
};
const handleSubmit = async (values) => {
let userDetails = {};
userDetails.password = values.newPassword;
userDetails = {
...userInfo,
...userDetails
};
try {
await fetchApi({
url: `xusers/secure/users/${params.userID}`,
method: "PUT",
data: userDetails
});
toast.success("User password change successfully!!");
navigate("/users/usertab");
} catch (error) {
toast.error("Error occured while updating user details!");
console.error(`Error occurred while updating user details! ${error}`);
}
};
const closeForm = () => {
navigate("/users/usertab");
};
return loader ? (
<Loader />
) : userInfo.userSource == UserTypes.USER_EXTERNAL.value ? (
<>
<div className="header-wraper">
<h3 className="wrap-header bold">User Detail</h3>
{commonBreadcrumb(["Users", "UserEdit"], params.userID)}
</div>
<UserFormComp
isEditView={true}
userID={params.userID}
userInfo={userInfo}
/>
</>
) : (
<>
<div className="header-wraper">
<h3 className="wrap-header bold">User Detail</h3>
{commonBreadcrumb(["Users", "UserEdit"], params.userID)}
</div>
<div className="wrap">
<Tab.Container transition={false} defaultActiveKey="edit-basic-info">
<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-details">
<Tab.Content>
<Tab.Pane eventKey="edit-basic-info">
<UserFormComp
isEditView={true}
userID={params.userID}
userInfo={userInfo}
/>
</Tab.Pane>
</Tab.Content>
<Tab.Content>
<Tab.Pane eventKey="edit-password">
<>
<Form
onSubmit={handleSubmit}
validate={validateForm}
render={({
handleSubmit,
form,
submitting,
invalid,
errors
}) => (
<div className="wrap">
<form
onSubmit={(event) => {
if (invalid) {
let selector =
document.getElementById("isError") ||
document.querySelector(
`input[name=${Object.keys(errors)[0]}]`
);
scrollToError(selector);
}
handleSubmit(event);
}}
>
<Field name="newPassword">
{({ input, meta }) => (
<Row className="form-group">
<Col xs={3}>
<label className="form-label float-end">
New Password *
</label>
</Col>
<Col xs={4} className={"position-relative"}>
<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="input-box-info-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 float-end">
Password Confirm *
</label>
</Col>
<Col xs={4} className={"position-relative"}>
<input
{...input}
name="reEnterPassword"
autoComplete="off"
type="password"
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="input-box-info-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"
disabled={submitting}
size="sm"
data-id="save"
data-cy="save"
>
Save
</Button>
<Button
variant="secondary"
type="button"
onClick={() => {
form.reset;
closeForm();
}}
size="sm"
data-id="save"
data-cy="save"
>
Cancel
</Button>
</div>
</div>
</form>
</div>
)}
/>
</>
</Tab.Pane>
</Tab.Content>
</div>
</Tab.Container>
</div>
</>
);
}
export default AddUserView;