feat: add create department, user form as well as reports for them

This commit is contained in:
prafull-opensignlabs
2024-07-01 16:47:01 +05:30
parent 17b9fc772e
commit d46ba8f307
10 changed files with 302 additions and 193 deletions
+36 -86
View File
@@ -12,8 +12,6 @@ const AddDepartment = (props) => {
const [isLoader, setIsLoader] = useState(false);
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [departmentList, setDepartmentList] = useState([]);
const [parentDepartments, setParentDepartments] = useState([]);
const [level, setLevel] = useState(1);
useEffect(() => {
getDepartmentList();
}, []);
@@ -27,12 +25,9 @@ const AddDepartment = (props) => {
className: "contracts_Organizations",
objectId: extUser.OrganizationId.objectId
});
department.doesNotExist("ParentId");
department.doesNotExist("Ancestors");
const departmentRes = await department.find();
if (departmentRes.length > 0) {
const _departmentRes = JSON.parse(JSON.stringify(departmentRes));
// console.log("_departmentRes ", _departmentRes);
setDepartmentList(_departmentRes);
}
} catch (err) {
@@ -40,68 +35,47 @@ const AddDepartment = (props) => {
}
};
const fetchDepartmentsbyPtr = async (departmentPtr) => {
setLevel((prev) => prev + 1);
try {
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
const department = new Parse.Query("contracts_Departments");
department.equalTo("ParentId", departmentPtr);
department.equalTo("OrganizationId", {
__type: "Pointer",
className: "contracts_Organizations",
objectId: extUser.OrganizationId.objectId
});
const departmentRes = await department.find();
if (departmentRes.length > 0) {
const _departmentRes = JSON.parse(JSON.stringify(departmentRes));
// console.log("sub", ["DD_" + level] ,_departmentRes)
const departmentName = _departmentRes?.[0]?.ParentId?.Name;
setParentDepartments((prev) => [
...prev,
{
["DD_" + level]: { name: departmentName, opt: _departmentRes }
}
]);
}
} catch (err) {
console.log("Err in fetch departmentlist", err);
}
};
const handleDropdown = (e) => {
setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value }));
const departmentPtr = {
__type: "Pointer",
className: "contracts_Departments",
objectId: e.target.value
};
// const index = parentDepartments.findIndex((x) => x[e.target.name]);
// setParentDepartments((prev) => prev.slice(0, index +1));
// console.log("index ", index);
fetchDepartmentsbyPtr(departmentPtr);
};
console.log("formdata", formdata);
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
// Extracting values except for the 'name' key
const ancestors = Object.entries(formdata)
.filter(([key]) => key !== "name")
.map(([key, value]) => value);
let updatedAncestors = [];
if (formdata.department) {
const Ancestors = departmentList.find(
(x) => x.objectId === formdata.department
)?.Ancestors;
if (Ancestors && Ancestors.length > 0) {
updatedAncestors = [
...Ancestors.map((x) => ({
__type: "Pointer",
className: "contracts_Departments",
objectId: x.objectId
})),
{
__type: "Pointer",
className: "contracts_Departments",
objectId: formdata.department
}
];
} else {
updatedAncestors.push({
__type: "Pointer",
className: "contracts_Departments",
objectId: formdata.department
});
}
}
try {
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
const ParentId = {
__type: "Pointer",
className: "contracts_Departments",
objectId: ""
};
setIsLoader(true);
const department = new Parse.Query("contracts_Departments");
department.equalTo("Name", formdata.name);
if (ancestors.length > 0) {
ParentId.objectId = "";
if (updatedAncestors.length > 0) {
const ParentId = updatedAncestors[updatedAncestors.length - 1];
department.equalTo("ParentId", ParentId);
}
if (localUser && localUser.OrganizationId) {
@@ -118,8 +92,10 @@ const AddDepartment = (props) => {
} else {
const newDepartment = new Parse.Object("contracts_Departments");
newDepartment.set("Name", formdata.name);
if (ancestors.length > 0) {
if (updatedAncestors.length > 0) {
const ParentId = updatedAncestors[updatedAncestors.length - 1];
newDepartment.set("ParentId", ParentId);
newDepartment.set("Ancestors", updatedAncestors);
}
if (localUser && localUser.OrganizationId) {
newDepartment.set("OrganizationId", {
@@ -129,13 +105,15 @@ const AddDepartment = (props) => {
});
}
const newdepartmentRes = await newDepartment.save();
if (ancestors.length > 0) {
newDepartment.set("ParentId", ParentId);
if (updatedAncestors.length > 0) {
const ParentId = departmentList.find(
(x) => x.objectId === formdata.department
);
props.handleDepartmentInfo({
objectId: newdepartmentRes.id,
Name: formdata.name,
ParentId: ParentId,
Ancestors: ancestors,
Ancestors: updatedAncestors,
IsActive: true
});
} else {
@@ -222,7 +200,6 @@ const AddDepartment = (props) => {
className="block text-xs text-gray-700 font-semibold"
>
Department
{/* <span className="text-[red] text-[13px]"> *</span> */}
</label>
<select
value={formdata.department}
@@ -239,33 +216,6 @@ const AddDepartment = (props) => {
))}
</select>
</div>
{parentDepartments?.map((x, i) => (
<div className="mb-3" key={"DD_" + (i + 1)}>
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
{x["DD_" + (i + 1)]?.name} department
{/* <span className="text-[red] text-[13px]"> *</span> */}
</label>
<select
value={formdata["DD_" + (i + 1)]}
onChange={(e) => handleDropdown(e)}
name={"DD_" + (i + 1)}
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
>
<option>select</option>
{x["DD_" + (i + 1)]?.opt?.map((subdepartment) => (
<option
key={subdepartment.objectId}
value={subdepartment.objectId}
>
{subdepartment.Name}
</option>
))}
</select>
</div>
))}
<div className="flex items-center mt-3 gap-2 text-white">
<button type="submit" className="op-btn op-btn-primary">
Submit
+42 -14
View File
@@ -23,29 +23,57 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
const menuItem = async () => {
try {
if (localStorage.getItem("defaultmenuid")) {
const menuId = localStorage.getItem("defaultmenuid") !== "VPh91h0ZHk";
if (menuId) {
setmenuList(sidebarList);
} else {
const addUserForm = {
icon: "fa-light fa-user",
title: "Add User",
target: "_self",
pageType: "form",
description: "",
objectId: "lM0xRnM3iE"
};
const Extand_Class = localStorage.getItem("Extand_Class");
const extClass = Extand_Class && JSON.parse(Extand_Class);
// console.log("extClass ", extClass);
let userRole = "contracts_Users";
if (extClass && extClass.length > 0) {
userRole = extClass[0].UserRole;
}
if (
userRole === "contracts_Admin" ||
userRole === "contracts_OrgAdmin"
) {
// const addUserForm = {
// icon: "fa-light fa-user",
// title: "Add User",
// target: "_self",
// pageType: "form",
// description: "",
// objectId: "lM0xRnM3iE"
// };
const newSidebarList = sidebarList.map((item) => {
if (item.title === "Settings") {
// Make a shallow copy of the item
const newItem = { ...item };
newItem.children = [
...newItem.children,
{
icon: "fa-light fa-building-memo",
title: "Departments",
target: "_self",
pageType: "",
description: "",
objectId: "departments"
},
{
icon: "fa-light fa-users fa-fw",
title: "Users",
target: "_self",
pageType: "",
description: "",
objectId: "users"
}
];
// Insert addUserForm at the second position
newItem.children.splice(1, 0, addUserForm);
// newItem.children.splice(1, 0, addUserForm);
return newItem;
}
return item;
});
setmenuList(newSidebarList);
} else {
setmenuList(sidebarList);
}
}
} catch (e) {
@@ -63,7 +91,7 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
};
return (
<aside
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[999] shadow-lg hide-scrollbar
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[500] shadow-lg hide-scrollbar
${isOpen ? "w-full md:w-[300px]" : "w-0"}`}
>
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
-16
View File
@@ -154,22 +154,6 @@ const sidebarList = [
pageType: "webhook",
description: "",
objectId: ""
},
{
icon: "fa-light fa-building-memo",
title: "Departments",
target: "_self",
pageType: "",
description: "",
objectId: "departments"
},
{
icon: "fa-light fa-building-memo",
title: "Users",
target: "_self",
pageType: "",
description: "",
objectId: "users"
}
]
}
+1 -1
View File
@@ -251,7 +251,7 @@ const HomeLayout = () => {
};
return (
<div>
<div className="sticky top-0 z-[101]">
<div className="sticky top-0 z-[501]">
{!isLoader && <Header showSidebar={showSidebar} />}
</div>
{isUserValid ? (
+35 -10
View File
@@ -8,7 +8,7 @@ import ModalUi from "../primitives/ModalUi";
import pad from "../assets/images/pad.svg";
import AddDepartment from "../components/AddDepartment";
const heading = ["Sr.No", "Name", "Parent Department", "Status"];
const heading = ["Sr.No", "Name", "Parent Department", "IsActive"];
// const actions = [
// {
// btnId: "1231",
@@ -31,6 +31,7 @@ const DepartmentList = () => {
const [currentPage, setCurrentPage] = useState(1);
const [isActiveModal, setIsActiveModal] = useState(false);
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isActLoader, setIsActLoader] = useState({});
const startIndex = (currentPage - 1) * recordperPage; // user per page
const getPaginationRange = () => {
@@ -98,6 +99,7 @@ const DepartmentList = () => {
className: "contracts_Organizations",
objectId: extUser.OrganizationId.objectId
});
department.descending("createdAt");
const departmentRes = await department.find();
if (departmentRes.length > 0) {
const _departmentRes = JSON.parse(JSON.stringify(departmentRes));
@@ -136,18 +138,33 @@ const DepartmentList = () => {
const handleToggleBtn = (department) => {
setIsActiveModal({ [department.objectId]: true });
};
const handleToggleSubmit = (department) => {
const handleToggleSubmit = async (department) => {
const index = departmentList.findIndex(
(obj) => obj.objectId === department.objectId
);
if (index !== -1) {
const newArray = [...departmentList];
newArray[index] = {
...newArray[index],
IsActive: !newArray[index].IsActive
};
setDepartmentList(newArray);
setIsActiveModal({});
setIsActLoader({ [department.objectId]: true });
const newArray = [...departmentList];
const IsActive = newArray[index].IsActive;
newArray[index] = { ...newArray[index], IsActive: !IsActive };
setDepartmentList(newArray);
try {
const departmentCls = new Parse.Object("contracts_Departments");
departmentCls.id = department.objectId;
departmentCls.set("IsActive", !IsActive);
await departmentCls.save();
setIsAlert({
type: "success",
msg: "Department disabled successfully."
});
} catch (err) {
setIsAlert({ type: "danger", msg: "something went wrong." });
console.log("err in disable department", err);
} finally {
setIsActLoader({});
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
}
}
};
const handleDepartmentInfo = (department) => {
@@ -160,9 +177,17 @@ const DepartmentList = () => {
<Loader />
</div>
)}
{Object.keys(isActLoader)?.length > 0 && (
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box">
<Loader />
</div>
)}
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
{isAlert && <Alert type={isAlert.type}>{isAlert.message}</Alert>}
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.message}</div>
</Alert>
)}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">
department list{" "}
+101 -18
View File
@@ -7,8 +7,16 @@ import ModalUi from "../primitives/ModalUi";
import pad from "../assets/images/pad.svg";
import Tooltip from "../primitives/Tooltip";
import AddUser from "../components/AddUser";
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Departments"];
const actions = [];
const heading = [
"Sr.No",
"Name",
"Email",
"Phone",
"Role",
"Departments",
"IsActive"
];
// const actions = [];
const UserList = () => {
const [userList, setUserList] = useState([]);
const [isLoader, setIsLoader] = useState(false);
@@ -18,7 +26,8 @@ const UserList = () => {
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
const [currentPage, setCurrentPage] = useState(1);
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isDeleteModal, setIsDeleteModal] = useState(false);
const [isActiveModal, setIsActiveModal] = useState({});
const [isActLoader, setIsActLoader] = useState({});
const recordperPage = 10;
const startIndex = (currentPage - 1) * recordperPage; // user per page
@@ -100,21 +109,16 @@ const UserList = () => {
setIsModal(!isModal);
};
const handleDelete = () => {};
const handleClose = () => {
setIsDeleteModal({});
};
// Change page
const paginateFront = () => setCurrentPage(currentPage + 1);
const paginateBack = () => setCurrentPage(currentPage - 1);
const handleActionBtn = (act, item) => {
if (act.action === "delete") {
setIsDeleteModal({ [item.objectId]: true });
}
};
// const handleActionBtn = (act, item) => {
// if (act.action === "delete") {
// setIsDeleteModal({ [item.objectId]: true });
// }
// };
const handleUserData = (userData) => {
console.log("userData", userData);
setUserList((prev) => [userData, ...prev]);
};
// `formatRow` is used to show data in poper manner like
// if data is of array type then it will join array items with ","
@@ -130,6 +134,39 @@ const UserList = () => {
return "-";
}
};
const handleClose = () => {
setIsActiveModal({});
};
const handleToggleSubmit = async (user) => {
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
if (index !== -1) {
setIsActiveModal({});
setIsActLoader({ [user.objectId]: true });
const newArray = [...userList];
const IsDisabled = newArray[index]?.IsDisabled;
newArray[index] = { ...newArray[index], IsDisabled: !IsDisabled };
setUserList(newArray);
try {
const extUser = new Parse.Object("contracts_Users");
extUser.id = user.objectId;
extUser.set("IsDisabled", !IsDisabled);
await extUser.save();
setIsAlert({
type: "success",
msg: "User disabled successfully."
});
} catch (err) {
setIsAlert({ type: "danger", msg: "something went wrong." });
console.log("err in disable department", err);
} finally {
setIsActLoader({});
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
}
}
};
const handleToggleBtn = (user) => {
setIsActiveModal({ [user.objectId]: true });
};
return (
<div className="relative">
{isLoader && (
@@ -137,9 +174,17 @@ const UserList = () => {
<Loader />
</div>
)}
{Object.keys(isActLoader)?.length > 0 && (
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box">
<Loader />
</div>
)}
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
{isAlert && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.message}</div>
</Alert>
)}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">
User list{" "}
@@ -179,7 +224,45 @@ const UserList = () => {
<td className="px-4 py-2">
{formatRow(item.DepartmentIds)}
</td>
<td className="px-3 py-2 text-white grid grid-cols-2">
<td className="px-4 py-2 font-semibold">
<label className="cursor-pointer relative block items-center mb-0">
<input
type="checkbox"
className="op-toggle transition-all op-toggle-secondary"
checked={item?.IsDisabled !== true}
onChange={() => handleToggleBtn(item)}
/>
</label>
{isActiveModal[item.objectId] && (
<ModalUi
isOpen
title={"User status"}
handleClose={handleClose}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to deactivate this user?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() => handleToggleSubmit(item)}
className="op-btn op-btn-primary"
>
Yes
</button>
<button
onClick={handleClose}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
)}
</td>
{/* <td className="px-3 py-2 text-white grid grid-cols-2">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
@@ -221,7 +304,7 @@ const UserList = () => {
</div>
</ModalUi>
)}
</td>
</td> */}
</tr>
))}
</>
+2
View File
@@ -46,12 +46,14 @@ import ssoSignin from './parsefunction/ssoSignin.js';
import isextenduser from './parsefunction/isextenduser.js';
import getUserByOrg from './parsefunction/getUserByOrg.js';
import getUserListByOrg from './parsefunction/getUserListByOrg.js';
import DepartmentsAftersave from './parsefunction/DepartmentsAftersave.js';
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
Parse.Cloud.afterSave('contracts_Departments', DepartmentsAftersave);
// This beforeSave function triggers before an object is added or updated in the specified class, allowing for validation or modification.
Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
@@ -3,7 +3,9 @@
//-- Export Modules
import 'dotenv/config.js';
import axios from 'axios';
const appId = process.env.APP_ID;
const masterKey = process.env.MASTER_KEY;
const serverUrl = process.env.SERVER_URL;
export async function addUserToGroups(request) {
try {
var roleName = request.params.roleName;
@@ -36,11 +38,11 @@ export async function addUserToGroups(request) {
function getAccessType(request) {
return new Promise(function (resolve, reject) {
const options = {
url: process.env.SERVER_URL + '/classes/w_appinfo?where={"appname":"' + appName + '"}',
url: serverUrl + '/classes/w_appinfo?where={"appname":"' + appName + '"}',
method: 'get',
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Master-Key': process.env.MASTER_KEY,
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': masterKey,
},
};
@@ -77,33 +79,37 @@ export async function addUserToGroups(request) {
} else {
//--function to get the userid from session token
function getuserid(request) {
return new Promise(function (resolve, reject) {
const options = {
url: process.env.SERVER_URL + '/users/me',
method: 'get',
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
};
try {
return new Promise(function (resolve, reject) {
const options = {
url: serverUrl + '/users/me',
method: 'get',
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
};
axios(options)
.then(x => {
const body = x.data;
var error = body == '' ? true : false;
if (error) {
reject('result not found!');
} else {
resolve(body);
}
})
.catch(err => {
if (err) {
console.error(err);
return;
}
});
});
axios(options)
.then(x => {
const body = x.data;
var error = body == '' ? true : false;
if (error) {
reject('result not found!');
} else {
resolve(body);
}
})
.catch(err => {
if (err) {
console.error(err);
return;
}
});
});
} catch (err) {
console.log('err ', err);
}
}
var userData = await getuserid(request);
if (userData.objectId == undefined) {
@@ -112,7 +118,7 @@ export async function addUserToGroups(request) {
var chkuserid = userData.objectId;
//console.log("chkuserid "+chkuserid);
var url =
process.env.SERVER_URL +
serverUrl +
'/roles?where={"users":{"__type":"Pointer","className":"_User","objectId":"' +
chkuserid +
'"},"name": {"$regex": "' +
@@ -126,7 +132,7 @@ export async function addUserToGroups(request) {
url: url,
method: 'get',
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Application-Id': appId,
},
};
@@ -174,26 +180,26 @@ export async function addUserToGroups(request) {
//--after validation call adduserToRole function
async function adduserToRole() {
var roleNam = roleName;
var roleid = await getroleobjId(roleNam);
console.log('roleid');
console.log(roleid);
var response = await adduserid(roleid);
/*process.stdin.resume();
// listen to the event
process.on('SIGTERM', () => {
process.emit('cleanup');
})*/
return response;
try {
var roleNam = roleName;
var roleid = await getroleobjId(roleNam);
console.log('roleid');
console.log(roleid);
var response = await adduserid(roleid);
return response;
} catch (err) {
console.log('err in addusertorole', err);
}
}
//--function to get the role objId
function getroleobjId(roleNam) {
return new Promise(function (resolve, reject) {
const options = {
url: process.env.SERVER_URL + '/roles?where={"name":"' + roleNam + '"}',
url: serverUrl + '/roles?where={"name":"' + roleNam + '"}',
method: 'get',
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Application-Id': appId,
},
};
axios(options)
@@ -225,11 +231,11 @@ export async function addUserToGroups(request) {
function adduserid(roleid) {
return new Promise(function (resolve, reject) {
const options = {
url: process.env.SERVER_URL + '/roles/' + roleid,
url: serverUrl + '/roles/' + roleid,
method: 'PUT',
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Master-Key': process.env.MASTER_KEY,
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': masterKey,
'Content-Type': 'application/json',
},
data: user,
@@ -0,0 +1,30 @@
export default async function DepartmentsAftersave(req) {
if (!req.original) {
try {
const Ancestors = req.object.get('Ancestors');
let updatedAncestors;
if (Ancestors && Ancestors.length > 0) {
updatedAncestors = [
...Ancestors,
{
__type: 'Pointer',
className: 'contracts_Departments',
objectId: req.object.id,
},
];
} else {
updatedAncestors = [
{
__type: 'Pointer',
className: 'contracts_Departments',
objectId: req.object.id,
},
];
}
req.object.set('Ancestors', updatedAncestors);
await req.object.save(null, { useMasterKey: true });
} catch (err) {
console.log('Err in department aftersave', err);
}
}
}
@@ -12,6 +12,7 @@ export default async function getUserListByOrg(req) {
const extUser = new Parse.Query('contracts_Users');
extUser.equalTo('OrganizationId', orgPtr);
extUser.include('DepartmentIds');
extUser.descending('createdAt');
const userRes = await extUser.find({ useMasterKey: true });
if (userRes.length > 0) {
const _userRes = JSON.parse(JSON.stringify(userRes));