From 17b9fc772e0f1c4ba6384508c2be3438c3962d7b Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs Date: Fri, 28 Jun 2024 21:12:58 +0530 Subject: [PATCH] feat: add department and add user form in reports --- apps/OpenSign/src/App.js | 3 + apps/OpenSign/src/components/AddDepartment.js | 411 +++++++----------- apps/OpenSign/src/components/AddUser.js | 8 +- apps/OpenSign/src/pages/DepartmentList.js | 131 +++--- apps/OpenSign/src/pages/UserList.js | 6 - apps/OpenSignServer/index.js | 7 +- 6 files changed, 254 insertions(+), 312 deletions(-) diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index 1fce1146d..5154e248b 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -20,6 +20,7 @@ import SSOVerify from "./pages/SSOVerify"; import Loader from "./primitives/Loader"; import DepartmentList from "./pages/DepartmentList"; import UserList from "./pages/UserList"; +import AddDepartment from "./components/AddDepartment"; const DebugPdf = lazy(() => import("./pages/DebugPdf")); const ForgetPassword = lazy(() => import("./pages/ForgetPassword")); const GuestLogin = lazy(() => import("./pages/GuestLogin")); @@ -123,6 +124,8 @@ function App() { )} }> } /> + } /> + } /> { const [formdata, setFormdata] = useState({ name: "", - phone: "", - email: "", - department: "", - role: "" + department: "" }); const [isLoader, setIsLoader] = useState(false); - const [isUserExist, setIsUserExist] = useState(false); + const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); const [departmentList, setDepartmentList] = useState([]); - const role = ["OrgAdmin", "Manager", "User", "Guest"]; - const parseBaseUrl = localStorage.getItem("baseUrl"); - const parseAppId = localStorage.getItem("parseAppId"); - + const [parentDepartments, setParentDepartments] = useState([]); + const [level, setLevel] = useState(1); useEffect(() => { getDepartmentList(); }, []); const getDepartmentList = async () => { - const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - console.log("extUser ", extUser); - const department = new Parse.Query("contracts_Departments"); - department.equalTo("OrganizationId", { - __type: "Pointer", - className: "contracts_Organizations", - objectId: extUser.OrganizationId.objectId - }); - department.doesNotExist("DepartmentParentId"); - department.doesNotExist("Ancestors"); - const departmentRes = await department.find(); - if (departmentRes.length > 0) { - const _departmentRes = JSON.parse(JSON.stringify(departmentRes)); - setDepartmentList(_departmentRes); - } - }; - const checkUserExist = async () => { - const user = Parse.User.current(); try { - const res = await Parse.Cloud.run("getUserDetails", { - email: user.get("email"), - userId: user.id + const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; + const department = new Parse.Query("contracts_Departments"); + department.equalTo("OrganizationId", { + __type: "Pointer", + className: "contracts_Organizations", + objectId: extUser.OrganizationId.objectId }); - if (res) { - return true; - } else { - return false; + 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) { - console.log("err", err); + console.log("Err in fetch top level departmentlist", err); } }; + + 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(); - const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; + // Extracting values except for the 'name' key + const ancestors = Object.entries(formdata) + .filter(([key]) => key !== "name") + .map(([key, value]) => value); - setIsLoader(true); - const res = await checkUserExist(); - if (res) { - setIsUserExist(true); - setIsLoader(false); - setTimeout(() => { - setIsUserExist(false); - }, 1000); - } else { - try { - const extUser = new Parse.Object("contracts_Users"); - extUser.set("Name", formdata.name); - if (formdata.phone) { - extUser.set("Phone", formdata.phone); + 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 = ""; + department.equalTo("ParentId", ParentId); + } + if (localUser && localUser.OrganizationId) { + department.equalTo("OrganizationId", { + __type: "Pointer", + className: "contracts_Organizations", + objectId: localUser.OrganizationId.objectId + }); + } + const isDepartment = await department.first(); + if (isDepartment) { + setIsAlert({ type: "info", msg: "Department already exists." }); + setIsLoader(false); + } else { + const newDepartment = new Parse.Object("contracts_Departments"); + newDepartment.set("Name", formdata.name); + if (ancestors.length > 0) { + newDepartment.set("ParentId", ParentId); } - extUser.set("Email", formdata.email); - extUser.set("UserRole", `contracts_${formdata.role}`); - extUser.set("DepartmentIds", [ - { - __type: "Pointer", - className: "contracts_Departments", - objectId: formdata.department - } - ]); if (localUser && localUser.OrganizationId) { - extUser.set("OrganizationId", { + newDepartment.set("OrganizationId", { __type: "Pointer", className: "contracts_Organizations", objectId: localUser.OrganizationId.objectId }); } - - if (localStorage.getItem("TenantId")) { - extUser.set("TenantId", { - __type: "Pointer", - className: "partners_Tenant", - objectId: localStorage.getItem("TenantId") + const newdepartmentRes = await newDepartment.save(); + if (ancestors.length > 0) { + newDepartment.set("ParentId", ParentId); + props.handleDepartmentInfo({ + objectId: newdepartmentRes.id, + Name: formdata.name, + ParentId: ParentId, + Ancestors: ancestors, + IsActive: true + }); + } else { + props.handleDepartmentInfo({ + objectId: newdepartmentRes.id, + Name: formdata.name, + ParentId: "", + Ancestors: "", + IsActive: true }); } - try { - const _users = Parse.Object.extend("User"); - const _user = new _users(); - _user.set("name", formdata.name); - _user.set("username", formdata.email); - _user.set("email", formdata.email); - _user.set("password", formdata.email); - if (formdata.phone) { - _user.set("phone", formdata.phone); - } - - const user = await _user.save(); - if (user) { - const roleurl = `${parseBaseUrl}functions/AddUserToRole`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - sessionToken: localStorage.getItem("accesstoken") - }; - const body = { - appName: "contracts", - roleName: "contracts_" + formdata.role, - userId: user.id - }; - await axios.post(roleurl, body, { headers: headers }); - const currentUser = Parse.User.current(); - extUser.set( - "CreatedBy", - Parse.User.createWithoutData(currentUser.id) - ); - - extUser.set("UserId", user); - const acl = new Parse.ACL(); - acl.setPublicReadAccess(true); - acl.setPublicWriteAccess(true); - acl.setReadAccess(currentUser.id, true); - acl.setWriteAccess(currentUser.id, true); - - extUser.setACL(acl); - - const res = await extUser.save(); - - const parseData = JSON.parse(JSON.stringify(res)); - - if (props.closePopup) { - props.closePopup(); - } - if (props.handleUserData) { - props.handleUserData(parseData); - } - - setIsLoader(false); - setFormdata({ - name: "", - email: "", - phone: "", - department: "", - role: "" - }); - } - } catch (err) { - console.log("err ", err); - if (err.code === 202) { - const user = Parse.User.current(); - const params = { email: user.get("email") }; - const userRes = await Parse.Cloud.run("getUserId", params); - const roleurl = `${parseBaseUrl}functions/AddUserToRole`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - sessionToken: localStorage.getItem("accesstoken") - }; - const body = { - appName: "contracts", - roleName: "contracts_" + formdata.role, - userId: userRes.id - }; - await axios.post(roleurl, body, { headers: headers }); - const currentUser = Parse.User.current(); - extUser.set( - "CreatedBy", - Parse.User.createWithoutData(currentUser.id) - ); - - extUser.set("UserId", { - __type: "Pointer", - className: "_User", - objectId: userRes.id - }); - const acl = new Parse.ACL(); - acl.setPublicReadAccess(true); - acl.setPublicWriteAccess(true); - acl.setReadAccess(currentUser.id, true); - acl.setWriteAccess(currentUser.id, true); - - extUser.setACL(acl); - const res = await extUser.save(); - - const parseData = JSON.parse(JSON.stringify(res)); - if (props.closePopup) { - props.closePopup(); - } - if (props.handleUserData) { - props.handleUserData(parseData); - } - setIsLoader(false); - setFormdata({ - name: "", - email: "", - phone: "", - department: "", - role: "" - }); - } + if (props.closePopup) { + props.closePopup(); } - } catch (err) { - console.log("err", err); - setIsLoader(false); - alert("something went wrong!"); + setFormdata({ + name: "", + department: { name: "", objectId: "" } + }); + setIsAlert({ + type: "success", + msg: "Department created successfully." + }); } + } catch (err) { + console.log("err in save department", err); + setIsAlert({ type: "danger", msg: "Something went wrong." }); + } finally { + setTimeout(() => { + setIsAlert({ type: "success", msg: "" }); + }, 1500); + setIsLoader(false); } }; @@ -231,10 +175,7 @@ const AddDepartment = (props) => { const handleReset = () => { setFormdata({ name: "", - email: "", - phone: "", - department: "", - role: "" + department: { name: "", objectId: "" } }); }; const handleChange = (e) => { @@ -243,8 +184,12 @@ const AddDepartment = (props) => { return (
- - {isUserExist && <Alert type="danger">User already exists!</Alert>} + <Title title={"Add Department"} /> + {isAlert.msg && ( + <Alert type={isAlert.type}> + <div className="ml-3">{isAlert.msg}</div> + </Alert> + )} {isLoader && ( <div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50 rounded-box"> <Loader /> @@ -270,40 +215,7 @@ const AddDepartment = (props) => { className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" /> </div> - <div className="mb-3"> - <label - htmlFor="email" - className="block text-xs text-gray-700 font-semibold" - > - Email - <span className="text-[red] text-[13px]"> *</span> - </label> - <input - type="email" - name="email" - value={formdata.email} - onChange={(e) => handleChange(e)} - required - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <div className="mb-3"> - <label - htmlFor="phone" - className="block text-xs text-gray-700 font-semibold" - > - Phone - {/* <span className="text-[red] text-[13px]"> *</span> */} - </label> - <input - type="text" - name="phone" - value={formdata.phone} - onChange={(e) => handleChange(e)} - // required - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> + <div className="mb-3"> <label htmlFor="phone" @@ -314,11 +226,11 @@ const AddDepartment = (props) => { </label> <select value={formdata.department} - onChange={(e) => handleChange(e)} + onChange={(e) => handleDropdown(e)} name="department" className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" > - <option disabled>select</option> + <option>select</option> {departmentList.length > 0 && departmentList.map((x) => ( <option key={x.objectId} value={x.objectId}> @@ -327,28 +239,33 @@ const AddDepartment = (props) => { ))} </select> </div> - <div className="mb-3"> - <label - htmlFor="phone" - className="block text-xs text-gray-700 font-semibold" - > - Role - {/* <span className="text-[red] text-[13px]"> *</span> */} - </label> - <select - value={formdata.role} - onChange={(e) => handleChange(e)} - name="role" - className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" - > - {role.length > 0 && - role.map((x) => ( - <option key={x} value={x}> - {x} + {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> + </select> + </div> + ))} <div className="flex items-center mt-3 gap-2 text-white"> <button type="submit" className="op-btn op-btn-primary"> Submit diff --git a/apps/OpenSign/src/components/AddUser.js b/apps/OpenSign/src/components/AddUser.js index 6d3d611df..4e9e7cdaf 100644 --- a/apps/OpenSign/src/components/AddUser.js +++ b/apps/OpenSign/src/components/AddUser.js @@ -26,7 +26,6 @@ const AddUser = (props) => { const getDepartmentList = async () => { const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - console.log("extUser ", extUser); const department = new Parse.Query("contracts_Departments"); department.equalTo("OrganizationId", { __type: "Pointer", @@ -55,7 +54,6 @@ const AddUser = (props) => { console.log("err", err); } }; - console.log("formdata", formdata); // Define a function to handle form submission const handleSubmit = async (e) => { e.preventDefault(); @@ -308,13 +306,14 @@ const AddUser = (props) => { className="block text-xs text-gray-700 font-semibold" > Department - {/* <span className="text-[red] text-[13px]"> *</span> */} + <span className="text-[red] text-[13px]"> *</span> </label> <select value={formdata.department} onChange={(e) => handleChange(e)} name="department" className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" + required > <option disabled>select</option> {departmentList.length > 0 && @@ -331,13 +330,14 @@ const AddUser = (props) => { className="block text-xs text-gray-700 font-semibold" > Role - {/* <span className="text-[red] text-[13px]"> *</span> */} + <span className="text-[red] text-[13px]"> *</span> </label> <select value={formdata.role} onChange={(e) => handleChange(e)} name="role" className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" + required > {role.length > 0 && role.map((x) => ( diff --git a/apps/OpenSign/src/pages/DepartmentList.js b/apps/OpenSign/src/pages/DepartmentList.js index 22e6875d7..cac6b0498 100644 --- a/apps/OpenSign/src/pages/DepartmentList.js +++ b/apps/OpenSign/src/pages/DepartmentList.js @@ -6,26 +6,19 @@ import { useLocation } from "react-router-dom"; import Tooltip from "../primitives/Tooltip"; import ModalUi from "../primitives/ModalUi"; import pad from "../assets/images/pad.svg"; +import AddDepartment from "../components/AddDepartment"; -const heading = ["Sr.No", "Name", "Actions"]; -const actions = [ - { - btnId: "1231", - hoverLabel: "Edit", - btnColor: "op-btn-primary", - btnIcon: "fa-light fa-pen", - redirectUrl: "draftDocument", - action: "redirect" - }, - { - btnId: "2142", - hoverLabel: "Delete", - btnColor: "op-btn-secondary", - btnIcon: "fa-light fa-trash", - redirectUrl: "", - action: "delete" - } -]; +const heading = ["Sr.No", "Name", "Parent Department", "Status"]; +// const actions = [ +// { +// btnId: "1231", +// hoverLabel: "Edit", +// btnColor: "op-btn-primary", +// btnIcon: "fa-light fa-pen", +// redirectUrl: "draftDocument", +// action: "redirect" +// } +// ]; const DepartmentList = () => { const recordperPage = 10; @@ -36,7 +29,7 @@ const DepartmentList = () => { const isDashboard = location?.pathname === "/dashboard/35KBoSgoAK" ? true : false; const [currentPage, setCurrentPage] = useState(1); - const [isDeleteModal, setIsDeleteModal] = useState(false); + const [isActiveModal, setIsActiveModal] = useState(false); const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); const startIndex = (currentPage - 1) * recordperPage; // user per page @@ -127,19 +120,39 @@ const DepartmentList = () => { const indexOfLastDoc = currentPage * recordperPage; const indexOfFirstDoc = indexOfLastDoc - recordperPage; const currentList = departmentList?.slice(indexOfFirstDoc, indexOfLastDoc); - const handleDelete = () => {}; + const handleClose = () => { - setIsDeleteModal({}); + setIsActiveModal({}); }; // 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 handleToggleBtn = (department) => { + setIsActiveModal({ [department.objectId]: true }); + }; + const handleToggleSubmit = (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({}); } }; + const handleDepartmentInfo = (department) => { + setDepartmentList((prev) => [department, ...prev]); + }; return ( <div className="relative"> {isLoader && ( @@ -170,12 +183,6 @@ const DepartmentList = () => { <th className="px-4 py-2">{item}</th> </React.Fragment> ))} - - {actions?.length > 0 && ( - <th className="px-4 py-2 text-transparent pointer-events-none"> - Action - </th> - )} </tr> </thead> <tbody className="text-[12px]"> @@ -186,35 +193,34 @@ const DepartmentList = () => { {heading.includes("Sr.No") && ( <th className="px-4 py-2">{startIndex + index + 1}</th> )} - <td className="px-4 py-2 font-semibold">{item?.Name} </td> - <td className="px-3 py-2 text-white flex flex-wrap gap-1"> - {actions?.length > 0 && - actions.map((act, index) => ( - <button - key={index} - onClick={() => handleActionBtn(act, item)} - title={act.hoverLabel} - className={`${ - act?.btnColor ? act.btnColor : "" - } op-btn op-btn-sm w-[50px]`} - > - <i className={act.btnIcon}></i> - </button> - ))} - {isDeleteModal[item.objectId] && ( + <td className="px-4 py-2 font-semibold">{item?.Name}</td> + <td className="px-4 py-2 font-semibold"> + {item?.ParentId?.Name || "-"} + </td> + <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?.IsActive} + onChange={() => handleToggleBtn(item)} + /> + </label> + {isActiveModal[item.objectId] && ( <ModalUi isOpen - title={"Delete Department"} + title={"Department status"} handleClose={handleClose} > <div className="m-[20px]"> <div className="text-lg font-normal text-black"> - Are you sure you want to delete this department? + Are you sure you want to disable this + department? </div> <hr className="bg-[#ccc] mt-4 " /> <div className="flex items-center mt-3 gap-2 text-white"> <button - onClick={() => handleDelete(item)} + onClick={() => handleToggleSubmit(item)} className="op-btn op-btn-primary" > Yes @@ -230,6 +236,21 @@ const DepartmentList = () => { </ModalUi> )} </td> + {/* <td className="px-3 py-2 text-white flex flex-wrap gap-1"> + {actions?.length > 0 && + actions.map((act, index) => ( + <button + key={index} + onClick={() => handleActionBtn(act, item)} + title={act.hoverLabel} + className={`${ + act?.btnColor ? act.btnColor : "" + } op-btn op-btn-sm w-[50px]`} + > + <i className={act.btnIcon}></i> + </button> + ))} + </td> */} </tr> ))} </> @@ -283,6 +304,16 @@ const DepartmentList = () => { <div className="text-sm font-semibold">No Data Available</div> </div> )} + <ModalUi + title={"Add Department"} + isOpen={isModal} + handleClose={handleFormModal} + > + <AddDepartment + handleDepartmentInfo={handleDepartmentInfo} + closePopup={handleFormModal} + /> + </ModalUi> </div> </div> ); diff --git a/apps/OpenSign/src/pages/UserList.js b/apps/OpenSign/src/pages/UserList.js index 1ee09b963..a0a688a7e 100644 --- a/apps/OpenSign/src/pages/UserList.js +++ b/apps/OpenSign/src/pages/UserList.js @@ -160,12 +160,6 @@ const UserList = () => { <th className="px-4 py-2">{item}</th> </React.Fragment> ))} - - {actions?.length > 0 && ( - <th className="px-4 py-2 text-transparent pointer-events-none"> - Action - </th> - )} </tr> </thead> <tbody className="text-[12px]"> diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index 9fccf17cd..670b7d64c 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -204,10 +204,7 @@ app.use('/v1', v1); // Parse Server plays nicely with the rest of your web routes app.get('/', function (req, res) { - // res.statusCode = 200; - // res.setHeader('Content-Type', 'text/plain'); - // res.end('I dream of being a website. Please star the parse-server repo on GitHub!'); - res.status(200).send('open-sign-server is running !!!'); + res.status(200).send('opensign-server is running !!!'); }); if (!process.env.TESTING) { @@ -217,7 +214,7 @@ if (!process.env.TESTING) { httpServer.keepAliveTimeout = 100000; // in milliseconds httpServer.headersTimeout = 100000; // in milliseconds httpServer.listen(port, '0.0.0.0', function () { - console.log('parse-server-example running on port ' + port + '.'); + console.log('opensign-server running on port ' + port + '.'); const isWindows = process.platform === 'win32'; // console.log('isWindows', isWindows);