add/Choose form to link user and ui changes

This commit is contained in:
prafull-opensignlabs
2023-12-21 21:40:42 +05:30
parent 4e67ab50fe
commit da42fe97ae
20 changed files with 1150 additions and 189 deletions
@@ -20,16 +20,16 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
const fetchFolder = async () => {
try {
const fetchFolder = new Parse.Query(folderCls);
const FolderQuery = new Parse.Query(folderCls);
if (parentFolderId) {
fetchFolder.equalTo("Folder", folderPtr);
fetchFolder.equalTo("Type", "Folder");
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
fetchFolder.doesNotExist("Folder");
fetchFolder.equalTo("Type", "Folder");
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await fetchFolder.find();
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import CreateFolder from "./CreateFolder";
import ModalUi from "../../primitives/ModalUi";
const SelectFolder = ({ required, onSuccess, folderCls }) => {
const [isOpen, SetIsOpen] = useState(false);
@@ -19,20 +20,21 @@ const SelectFolder = ({ required, onSuccess, folderCls }) => {
setTabList([]);
fetchFolder();
}
// eslint-disable-next-line
}, [isOpen]);
const fetchFolder = async (folderPtr) => {
setIsLoader(true);
try {
const fetchFolder = new Parse.Query(folderCls);
const FolderQuery = new Parse.Query(folderCls);
if (folderPtr) {
fetchFolder.equalTo("Folder", folderPtr);
fetchFolder.equalTo("Type", "Folder");
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
fetchFolder.doesNotExist("Folder");
fetchFolder.equalTo("Type", "Folder");
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await fetchFolder.find();
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
@@ -168,7 +170,86 @@ const SelectFolder = ({ required, onSuccess, folderCls }) => {
</p>
</div>
</div>
{isOpen && (
<ModalUi title={"Select Folder"} isOpen={isOpen} handleClose={handleCancel}>
<div className="w-full min-w-[300px] md:min-w-[500px] px-3">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="Root"
onClick={(e) => removeTabListItem(e)}
>
Root /{" "}
</span>
{tabList &&
tabList.map((tab, i) => (
<React.Fragment key={`${tab.objectId}-${i}`}>
<span
className="cursor-pointer"
title={tab.Name}
onClick={(e) => removeTabListItem(e, i)}
>
{tab.Name}
</span>
{" / "}
</React.Fragment>
))}
<hr />
</div>
<div className="mt-2 mb-3">
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer"
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
</div>
</div>
))}
{isAdd && (
<CreateFolder
parentFolderId={clickFolder && clickFolder.ObjectId}
folderCls={folderCls}
onSuccess={handleAddFolder}
/>
)}
{isLoader && (
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
</div>
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="text-[30px] cursor-pointer text-[#33bbff]"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
) : (
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
)}
</div>
<div
className="text-[30px] cursor-pointer"
title="Save Here"
onClick={handleSubmit}
>
<i className="fas fa-save" aria-hidden="true"></i>
</div>
</div>
</ModalUi>
{/* {isOpen && (
<div
className={`fixed z-40 top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm bg-white rounded `}
>
@@ -262,7 +343,7 @@ const SelectFolder = ({ required, onSuccess, folderCls }) => {
</div>
</div>
</div>
)}
)} */}
</div>
);
};
+12 -1
View File
@@ -4,4 +4,15 @@
body{
background-color: white;
}
}
/* Custom CSS to hide scrollbar */
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
.hide-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
+26
View File
@@ -0,0 +1,26 @@
import React from "react";
const ModalUi = ({ children, title, isOpen, handleClose }) => {
return (
<>
{isOpen && (
<div className="fixed z-[999] top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
<div className="fixed z-[1000] top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-sm bg-white rounded shadow-md max-h-90 md:min-w-500px overflow-y-auto hide-scrollbar">
<div className="flex justify-between bg-[#32a3ac] rounded-t items-center py-[10px] px-[20px] text-white">
<div className="text-[1.2rem] font-normal">{title}</div>
<div
className="text-[1.5rem] cursor-pointer"
onClick={() => handleClose && handleClose()}
>
&times;
</div>
</div>
<div >{children}</div>
</div>
</div>
)}
</>
);
};
export default ModalUi;
+2 -2
View File
@@ -302,13 +302,13 @@ const TemplateForm = () => {
<SelectFolder onSuccess={handleFolder} folderCls={templateCls} />
<div className="flex items-center mt-3 gap-2 text-white">
<button
className="px-2 py-2 uppercase rounded shadow-md bg-sky-300 text-xs font-semibold"
className="bg-[#1ab6ce] rounded-sm shadow-md text-[14px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none"
type="submit"
>
Submit
</button>
<div
className="px-2 py-2 uppercase rounded shadow-md bg-blue-500 text-xs font-semibold"
className="bg-[#188ae2] rounded-sm shadow-md text-[14px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
onClick={() => handleReset()}
>
Reset
@@ -32,6 +32,18 @@ export default function reportJson(id, userId) {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
Placeholders: { $ne: null },
Signers: {
$inQuery: {
where: {
UserId: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
className: 'contracts_Contactbook',
},
},
},
keys: [
'Name',
@@ -168,6 +180,18 @@ export default function reportJson(id, userId) {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
Placeholders: { $ne: null },
Signers: {
$inQuery: {
where: {
UserId: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
className: 'contracts_Contactbook',
},
},
},
keys: ['Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name', 'Signers.UserId', 'AuditTrail'],
};
@@ -30,6 +30,9 @@ import ModalComponent from "./component/modalComponent";
import "../css/AddUser.css";
import Title from "./component/Title";
import LinkUserModal from "./component/LinkUserModal";
import EditTemplate from "./component/EditTemplate";
import ModalUi from "../premitives/ModalUi";
import AddRoleModal from "./component/AddRoleModal";
const TemplatePlaceholder = () => {
const navigate = useNavigate();
const { templateId } = useParams();
@@ -152,7 +155,7 @@ const TemplatePlaceholder = () => {
const [roleName, setRoleName] = useState("");
const [isAddUser, setIsAddUser] = useState({});
const [isCreateDoc, setIsCreateDoc] = useState(false);
const [isEditTemplate, setIsEditTemplate] = useState(false);
const senderUser =
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
@@ -176,6 +179,8 @@ const TemplatePlaceholder = () => {
});
}
}, [divRef.current]);
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
const fetchTemplate = async () => {
// const params = { templateId: templateId };
// const templateDeatils = await axios.post(
@@ -338,6 +343,7 @@ const TemplatePlaceholder = () => {
}
};
// `getSignerPos` is used to get placeholder position when user place it and save it in array
const getSignerPos = (item, monitor) => {
const posZIndex = zIndex + 1;
setZIndex(posZIndex);
@@ -831,6 +837,8 @@ const TemplatePlaceholder = () => {
console.log("axois err ", err);
});
};
// `handleCreateDocModal` is used to create Document from template when user click on yes from modal
const handleCreateDocModal = async () => {
setIsCreateDocModal(false);
setIsCreateDoc(true);
@@ -846,10 +854,14 @@ const TemplatePlaceholder = () => {
}
};
// `handleAddSigner` is used to open Add Role Modal
const handleAddSigner = () => {
setIsModalRole(true);
setRoleName("");
};
// `handleAddRole` function is called when use click on add button in addRole modal
// save Role in entry in signerList and user
const handleAddRole = (e) => {
e.preventDefault();
const count = signersdata.length > 0 ? signersdata.length + 1 : 1;
@@ -861,14 +873,20 @@ const TemplatePlaceholder = () => {
setSignersData((prevArr) => [...prevArr, obj]);
setIsModalRole(false);
setRoleName("");
setUniqueId(Id);
setIsMailSend(false);
};
// `handleDeleteUser` function is used to delete record and placeholder when user click on delete which is place next user name in recipients list
const handleDeleteUser = (Id) => {
const removeUser = signersdata.filter((x) => x.Id !== Id);
setSignersData(removeUser);
const removePlaceholderUser = signerPos.filter((x) => x.Id !== Id);
setSignerPos(removePlaceholderUser);
setIsMailSend(false);
};
// `handleLinkUser` is used to open Add/Choose Signer Modal when user can link existing or new User with placeholder
// and update entry in signersList
const handleLinkUser = (id) => {
setIsAddUser({ [id]: true });
};
@@ -893,19 +911,56 @@ const TemplatePlaceholder = () => {
return { ...x };
});
setSignersData(updateSigner);
setIsMailSend(false);
};
// `closePopup` is used to close Add/Choose signer modal
const closePopup = () => {
setIsAddUser({});
};
// `handleRoleChange` function is call when user update Role name from recipients list
const handleRoleChange = (event, roleId) => {
// Update the role when the content changes
const updatedRoles = signersdata.map((role) =>
role.Id === roleId ? { ...role, Role: event.target.textContent } : role
role.Id === roleId ? { ...role, Role: event.target.value } : role
);
setSignersData(updatedRoles);
setIsMailSend(false);
};
// `handleOnBlur` function is call when user click outside input box
const handleOnBlur = (updateRole, roleId) => {
// Update the role when the content changes
if (!updateRole) {
const updatedRoles = signersdata.map((role) =>
role.Id === roleId ? { ...role, Role: roleName } : role
);
setSignersData(updatedRoles);
}
};
const handleEditTemplateModal = () => {
setIsEditTemplate(!isEditTemplate);
};
const handleEditTemplateForm = (data) => {
console.log("data", data);
setIsEditTemplate(false);
const updateTemplate = pdfDetails.map((x) => {
return { ...x, ...data };
});
console.log("updateTemplate ", updateTemplate);
setPdfDetails(updateTemplate);
setIsMailSend(false);
};
const handleCloseRoleModal = () => {
setIsModalRole(false);
};
console.log("pdfDetails ", pdfDetails)
console.log("signerPos ", signerPos)
return (
<div>
<Title title={"Template"} />
@@ -949,52 +1004,34 @@ const TemplatePlaceholder = () => {
}}
>
{/* this modal is used show alert set placeholder for all signers before send mail */}
<Modal show={isSendAlert}>
<Modal.Header className="bg-danger">
<span style={{ color: "white" }}>Fields required</span>
</Modal.Header>
{/* signature modal */}
<Modal.Body>
<ModalUi
headerColor={"#dc3545"}
isOpen={isSendAlert}
title={"Fields required"}
handleClose={() => setIsSendAlert(false)}
>
<div style={{ height: "100%", padding: 20 }}>
<p>Please add field for all recipients.</p>
</Modal.Body>
<Modal.Footer>
<button
onClick={() => setIsSendAlert(false)}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Close
</button>
</Modal.Footer>
</Modal>
</div>
</ModalUi>
{/* this modal is used show send mail message and after send mail success message */}
<Modal show={isCreateDocModal}>
{/* signature modal */}
<Modal.Body>
<ModalUi
isOpen={isCreateDocModal}
title={"Create Document"}
handleClose={() => setIsCreateDocModal(false)}
>
<div style={{ height: "100%", padding: 20 }}>
<p>Do you want to create document right now ?</p>
</Modal.Body>
<Modal.Footer>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginBottom: "15px"
}}
></div>
{currentEmail.length > 0 && (
<>
<button
onClick={() => {
setIsCreateDocModal(false);
}}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
No
</button>
<button
onClick={() => {
handleCreateDocModal();
@@ -1008,16 +1045,22 @@ const TemplatePlaceholder = () => {
>
Yes
</button>
<button
onClick={() => {
setIsCreateDocModal(false);
}}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
No
</button>
</>
)}
</Modal.Footer>
</Modal>
{isCreateDoc && <Loader isLoading={isLoading} />}
<ModalComponent
isShow={isShowEmail}
type={"signersAlert"}
setIsShowEmail={setIsShowEmail}
/>
</div>
</ModalUi>
{/* pdf header which contain funish back button */}
<Header
completeBtnTitle={"Save"}
@@ -1032,6 +1075,7 @@ const TemplatePlaceholder = () => {
alertSendEmail={alertSendEmail}
isShowHeader={true}
currentSigner={true}
setIsEditTemplate={handleEditTemplateModal}
dataTut4="reactourFour"
/>
<div data-tut="reactourThird">
@@ -1115,6 +1159,7 @@ const TemplatePlaceholder = () => {
setUniqueId={setUniqueId}
handleDeleteUser={handleDeleteUser}
handleRoleChange={handleRoleChange}
handleOnBlur={handleOnBlur}
/>
<div data-tut="reactourSecond">
<FieldsComponent
@@ -1141,66 +1186,14 @@ const TemplatePlaceholder = () => {
)}
</DndProvider>
<div>
<Modal show={isModalRole}>
<Modal.Header className={"bg-info"}>
<span style={{ color: "white" }}>Add Role</span>
</Modal.Header>
<Modal.Body>
<form
style={{ display: "flex", flexDirection: "column" }}
onSubmit={handleAddRole}
>
<input
value={roleName}
onChange={(e) => setRoleName(e.target.value)}
placeholder={
signersdata.length > 0
? "User " + (signersdata.length + 1)
: "User 1"
}
className="addUserInput"
/>
<p
style={{
color: "grey",
fontSize: 11,
margin: "2px 0 10px 5px"
}}
>
e.g: Account, Hr, Director, Manager, New joinee etc...
</p>
<div>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginBottom: "15px"
}}
></div>
<button
type="submit"
style={{
background: "#00a2b7"
}}
className="finishBtn"
>
Add
</button>
<button
onClick={() => setIsModalRole(false)}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Close
</button>
</div>
</form>
</Modal.Body>
</Modal>
<AddRoleModal
isModalRole={isModalRole}
roleName={roleName}
signersdata={signersdata}
setRoleName={setRoleName}
handleAddRole={handleAddRole}
handleCloseRoleModal={handleCloseRoleModal}
/>
</div>
<div>
<LinkUserModal
@@ -1210,6 +1203,16 @@ const TemplatePlaceholder = () => {
closePopup={closePopup}
/>
</div>
<ModalUi
title={"Edit Template"}
isOpen={isEditTemplate}
handleClose={handleEditTemplateModal}
>
<EditTemplate
template={pdfDetails?.[0]}
onSuccess={handleEditTemplateForm}
/>
</ModalUi>
</div>
);
};
@@ -0,0 +1,70 @@
import React from "react";
import ModalUi from "../../premitives/ModalUi";
const AddRoleModal = (props) => {
return (
<ModalUi
title={"Add Role"}
isOpen={props.isModalRole}
handleClose={props.handleCloseRoleModal}
>
<div className="addusercontainer">
<form
style={{ display: "flex", flexDirection: "column" }}
onSubmit={props.handleAddRole}
>
<input
value={props.roleName}
onChange={(e) => props.setRoleName(e.target.value)}
placeholder={
props.signersdata.length > 0
? "User " + (props.signersdata.length + 1)
: "User 1"
}
className="addUserInput"
/>
<p
style={{
color: "grey",
fontSize: 11,
margin: "2px 0 10px 5px"
}}
>
e.g: Account, Hr, Director, Manager, New joinee etc...
</p>
<div>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginBottom: "15px"
}}
></div>
<button
type="submit"
style={{
background: "#00a2b7"
}}
className="finishBtn"
>
Add
</button>
<button
onClick={props.handleCloseRoleModal}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Close
</button>
</div>
</form>
</div>
</ModalUi>
);
};
export default AddRoleModal;
@@ -0,0 +1,102 @@
import React, { useState, useEffect } from "react";
import "../../css/AddUser.css";
// import SelectFolder from "../../premitives/SelectFolder";
const EditTemplate = ({ template, onSuccess }) => {
const [folder, setFolder] = useState({ ObjectId: "", Name: "" });
const [formData, setFormData] = useState({
Name: template?.Name || "",
Note: template?.Note || "",
Description: template?.Description || ""
});
console.log("template", template);
const handleStrInput = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleFolder = (data) => {
console.log("handleFolder ", data)
setFolder(data);
};
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
const data = {...formData }
onSuccess(data);
};
return (
<div className="addusercontainer">
<div className="form-wrapper">
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name" style={{ fontSize: 13 }}>
File
</label>
<div
style={{
padding: "0.5rem 0.75rem",
border: "1px solid #d1d5db",
borderRadius: "0.375rem",
fontSize: "0.75rem",
fontWeight: "700"
}}
>
file selected : {template.URL?.split("/")[3]?.split("_")[1]}
</div>
</div>
<div className="form-section">
<label htmlFor="name" style={{ fontSize: 13 }}>
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="text"
name="Name"
value={formData.Name}
onChange={(e) => handleStrInput(e)}
required
className="addUserInput"
/>
</div>
<div className="form-section">
<label htmlFor="Note" style={{ fontSize: 13 }}>
Note
</label>
<input
type="text"
name="Note"
id="Note"
value={formData.Note}
onChange={(e) => handleStrInput(e)}
className="addUserInput"
/>
</div>
<div className="form-section">
<label htmlFor="Description" style={{ fontSize: 13 }}>
Description
</label>
<input
type="text"
name="Description"
id="Description"
value={formData.Description}
onChange={(e) => handleStrInput(e)}
className="addUserInput"
/>
</div>
{/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */}
<div className="buttoncontainer">
<button type="submit" className="submitbutton">
Submit
</button>
</div>
</form>
</div>
</div>
);
};
export default EditTemplate;
@@ -1,33 +1,16 @@
import React from "react";
import Modal from "react-bootstrap/Modal";
import SelectSigners from "./SelectSigners";
import AddUser from "./AddUser";
import SelectSigners from "../../premitives/SelectSigners";
import AddUser from "../../premitives/AddUser";
import ModalUi from "../../premitives/ModalUi";
const LinkUserModal = (props) => {
return (
<Modal show={props.isAddUser[props.uniqueId]}>
<Modal.Header
className={"bg-info"}
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center"
}}
>
<span style={{ color: "white" }}>Add/Choose Signer</span>
<span
style={{ color: "white", cursor: "pointer" }}
onClick={() => props.closePopup()}
>
X
</span>
</Modal.Header>
<Modal.Body>
<SelectSigners
<ModalUi title={"Add/Choose Signer"} isOpen={props.isAddUser[props.uniqueId]} handleClose={props.closePopup}>
<SelectSigners
details={props.handleAddUser}
closePopup={props.closePopup}
/>
<div style={{ display: "flex", alignItems: "center", gap: 5 }}>
<div style={{ display: "flex", alignItems: "center", gap: 5 }}>
<span
style={{
height: 1,
@@ -45,8 +28,7 @@ const LinkUserModal = (props) => {
></span>
</div>
<AddUser details={props.handleAddUser} closePopup={props.closePopup} />
</Modal.Body>
</Modal>
</ModalUi>
);
};
@@ -35,7 +35,8 @@ function Header({
alreadySign,
isSignYourself,
setIsEmail,
completeBtnTitle
completeBtnTitle,
setIsEditTemplate
}) {
const isMobile = window.innerWidth < 767;
const navigate = useNavigate();
@@ -346,7 +347,7 @@ function Header({
}}
>
<i
class="fa fa-envelope"
className="fa fa-envelope"
style={{ marginRight: "2px" }}
aria-hidden="true"
></i>
@@ -552,6 +553,11 @@ function Header({
)}
<div>
{setIsEditTemplate && (
<button onClick={() => setIsEditTemplate(true)} style={{border:"none", outline:"none", textAlign:"center"}}>
<i className="fa-solid fa-gear fa-lg"></i>
</button>
)}
<button
onClick={() => {
navigate(-1);
@@ -724,7 +730,7 @@ function Header({
onClick={() => setIsEmail(true)}
>
<i
class="fa fa-envelope"
className="fa fa-envelope"
style={{
color: "white",
fontSize: "15px",
@@ -13,7 +13,8 @@ function SignerListPlace({
setUniqueId,
setRoleName,
handleDeleteUser,
handleRoleChange
handleRoleChange,
handleOnBlur
}) {
const color = [
"#93a3db",
@@ -45,7 +46,7 @@ function SignerListPlace({
"#cc9900"
];
const [isHover, setIsHover] = useState();
const [isEdit, setIsEdit] = useState(false);
//function for onhover signer name change background color
const onHoverStyle = (ind, blockColor) => {
const style = {
@@ -107,7 +108,7 @@ function SignerListPlace({
padding: "5px"
}}
>
<span className="signedStyle">Reicipents</span>
<span className="signedStyle">Recipients</span>
</div>
<div className="signerList">
@@ -183,24 +184,47 @@ function SignerListPlace({
}}
>
{obj.Name ? (
<span className="userName">{obj.Name}</span>
<span
className="userName"
style={{ cursor: "default" }}
>
{obj.Name}
</span>
) : (
<>
{handleRoleChange ? (
<span
className="userName"
contentEditable
onBlur={(e) => handleRoleChange(e, obj.Id)}
>
{obj.Role}
</span>
) : (
<span className="userName">{obj.Role}</span>
)}
<span
className="userName"
onClick={() => {
setIsEdit({ [obj.Id]: true });
setRoleName(obj.Role);
}}
>
{isEdit?.[obj.Id] && handleRoleChange ? (
<input
style={{
backgroundColor: "transparent",
width: "inherit"
}}
value={obj.Role}
onChange={(e) => handleRoleChange(e, obj.Id)}
onBlur={() => {
setIsEdit({});
handleOnBlur(obj.Role, obj.Id);
}}
/>
) : (
obj.Role
)}
</span>
</>
)}
{obj.Email && (
<span className="useEmail">{obj.Email}</span>
<span
className="useEmail"
style={{ cursor: "default" }}
>
{obj.Email}
</span>
)}
</div>
</div>
@@ -50,23 +50,30 @@
}
.submitbutton {
background-color: #1ab6ce;
font-size: 0.875rem;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.2);
background: #1ab6ce;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
border: none;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
padding: 0.375rem 0.75rem;
text-align: center;
color: #ffffff;
outline: none;
}
/* For classes: bg-[#188ae2] text-sm text-white px-4 py-2 rounded ml-2 shadow focus:outline-none */
.resetbutton {
background-color: #188ae2;
font-size: 0.875rem;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.2);
margin-left: 0.5rem;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
border: none;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
padding: 0.375rem 0.75rem;
text-align: center;
color: #ffffff;
outline: none;
margin-left: 8px;
}
@@ -0,0 +1,71 @@
.modaloverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
justify-content: center;
align-items: center;
z-index: 900;
}
.modalcontainer {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 901;
max-height: 80%;
min-width: 500px;
overflow-y: auto;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Internet Explorer and Edge */
}
/* Hide scrollbar for Webkit browsers */
.modalcontainer::-webkit-scrollbar {
display: none;
}
.modalheader {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
border-bottom: 1px solid #ccc;
color: #ffffff;
}
/* Styling for the modal title */
.modaltitle {
font-size: 1.2rem;
font-weight:normal;
}
/* Styling for the close button */
.closebtn {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
}
@media (max-width:767px) {
.modalcontainer {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 1000;
max-height: 80%;
overflow-y: auto;
}
}
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import axios from "axios";
import "../../css/AddUser.css";
import "../css/AddUser.css";
const AddUser = (props) => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
@@ -209,7 +209,7 @@ const AddUser = (props) => {
</div>
)}
<div className="form-wrapper">
<div style={{ fontSize: 14 }}>Add User</div>
<div style={{ fontSize: 14, fontWeight: "700" }}>Add User</div>
{isUserExist && (
<div className="form-section">
@@ -0,0 +1,30 @@
import React from "react";
const Alert = ({ children, type }) => {
const textcolor = type ? theme(type) : theme();
function theme(color) {
switch (color) {
case "success":
return "border-[#c3e6cb] bg-[#d4edda] text-[#155724]";
case "info":
return "border-[#adcdeb] bg-[#c1daf0] text-[#153756]";
case "danger":
return "border-[#f0a8a8] bg-[#f4bebe] text-[#c42121]";
default:
return "border-[#d6d6d6] bg-[#d9d9d9] text-[#575757]";
}
}
return (
<>
{children && (
<div
className={`z-40 fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm ${textcolor} rounded py-[.75rem] px-[1.25rem] `}
>
{children}
</div>
)}
</>
);
};
export default Alert;
@@ -0,0 +1,147 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Alert from "./Alert";
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: parentFolderId
};
const [name, setName] = useState("");
const [folderList, setFolderList] = useState([]);
const [isAlert, setIsAlert] = useState(false);
const [selectedParent, setSelectedParent] = useState();
const [alert, setAlert] = useState({ type: "info", message: "" });
useEffect(() => {
fetchFolder();
// eslint-disable-next-line
}, []);
const fetchFolder = async () => {
try {
const FolderQuery = new Parse.Query(folderCls);
if (parentFolderId) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
setFolderList(result);
}
}
} catch (error) {
console.log("Err ", error);
}
};
const handleCreateFolder = async (event) => {
event.preventDefault();
if (name) {
const currentUser = Parse.User.current();
const exsitQuery = new Parse.Query(folderCls);
exsitQuery.equalTo("Name", name);
exsitQuery.equalTo("Type", "Folder");
if (parentFolderId) {
exsitQuery.equalTo("Folder", folderPtr);
}
const templExist = await exsitQuery.first();
if (templExist) {
setAlert({ type: "dange", message: "Folder already exist!" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
} else {
const template = new Parse.Object(folderCls);
template.set("Name", name);
template.set("Type", "Folder");
if (selectedParent) {
template.set("Folder", {
__type: "Pointer",
className: folderCls,
objectId: selectedParent
});
} else if (parentFolderId) {
template.set("Folder", folderPtr);
}
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
const res = await template.save();
if (res) {
if (onSuccess) {
setAlert({
type: "success",
message: "Folder created successfully!"
});
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
onSuccess(res);
}
}
}
} else {
setAlert({ type: "info", message: "Please fill folder name" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
}
};
const handleOptions = (e) => {
setSelectedParent(e.target.value);
};
return (
<div>
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
<div id="createFolder">
<h1 className="text-base font-semibold">Create Folder</h1>
<div className="text-xs mt-2">
<label className="block">
Name<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div className="text-xs mt-2">
<label className="block">Parent Folder</label>
<select
value={selectedParent}
onChange={handleOptions}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
>
<option>select</option>
{folderList.length > 0 &&
folderList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
<div>
<button
onClick={handleCreateFolder}
className="flex items-center rounded p-2 bg-[#33bbff] text-white mt-3"
>
<i className="fa-solid fa-plus mr-1"></i>
<span>Create</span>
</button>
</div>
</div>
</div>
);
};
export default CreateFolder;
@@ -0,0 +1,29 @@
import React from "react";
import "../css/ModalUi.css";
const ModalUi = ({ children, title, isOpen, handleClose, headerColor }) => {
return (
<>
{isOpen && (
<div className="modaloverlay">
<div className="modalcontainer">
{title && <div
style={{ background: headerColor ? headerColor : "#32a3ac" }}
className="modalheader"
>
<div className="modaltitle">{title}</div>
<div
className="closebtn"
onClick={() => handleClose && handleClose()}
>
&times;
</div>
</div>}
<div>{children}</div>
</div>
</div>
)}
</>
);
};
export default ModalUi;
@@ -0,0 +1,348 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import CreateFolder from "./CreateFolder";
import ModalUi from './ModalUi'
const SelectFolder = ({ required, onSuccess, folderCls }) => {
const [isOpen, SetIsOpen] = useState(false);
const [clickFolder, setClickFolder] = useState("");
const [selectFolder, setSelectedFolder] = useState({});
const [folderList, setFolderList] = useState([]);
const [tabList, setTabList] = useState([]);
const [isLoader, setIsLoader] = useState(false);
const [folderPath, setFolderPath] = useState("");
const [isAdd, setIsAdd] = useState(false);
useEffect(() => {
if (isOpen) {
setIsAdd(false);
setClickFolder({});
setFolderList([]);
setTabList([]);
fetchFolder();
}
}, [isOpen]);
const fetchFolder = async (folderPtr) => {
setIsLoader(true);
try {
const FolderQuery = new Parse.Query(folderCls);
if (folderPtr) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
setFolderList(result);
setIsLoader(false);
}
setIsLoader(false);
}
} catch (error) {
setIsLoader(false);
}
};
const handleSelect = (item) => {
setFolderList([]);
setClickFolder({ ObjectId: item.objectId, Name: item.Name });
if (tabList.length > 0) {
const tab = tabList.some((x) => x.objectId === item.objectId);
if (!tab) {
setTabList((tabs) => [...tabs, item]);
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: item.objectId
};
fetchFolder(folderPtr);
}
} else {
setTabList((tabs) => [...tabs, item]);
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: item.objectId
};
fetchFolder(folderPtr);
}
};
const handleSubmit = () => {
let url = "Root";
tabList.forEach((t) => {
url = url + " / " + t.Name;
});
setFolderPath(url);
setSelectedFolder(clickFolder);
if (onSuccess) {
onSuccess(clickFolder);
}
SetIsOpen(false);
};
const handleCancel = () => {
SetIsOpen(false);
setClickFolder({});
setFolderList([]);
setTabList([]);
};
const removeTabListItem = async (e, i) => {
e.preventDefault();
// setEditable(false);
if (!isAdd) {
setIsLoader(true);
let folderPtr;
if (i) {
setFolderList([]);
let list = tabList.filter((itm, j) => {
if (j <= i) {
return itm;
}
});
let _len = list.length - 1;
folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: list[_len].objectId
};
setTabList(list);
} else {
setClickFolder({});
setSelectedFolder({});
setFolderList([]);
setTabList([]);
}
fetchFolder(folderPtr);
}
};
const handleCreate = () => {
setIsAdd(!isAdd);
};
const handleAddFolder = () => {
setFolderList([]);
if (clickFolder && clickFolder.ObjectId) {
fetchFolder({
__type: "Pointer",
className: folderCls,
objectId: clickFolder.ObjectId
});
} else {
fetchFolder();
}
};
return (
<div className="text-xs mt-2">
<div>
<label className="block">
Select Folder
{required && <span style={{ color: "red", fontSize: 13 }}> *</span>}
</label>
</div>
<div className="rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center">
<div>
<i
className="far fa-folder-open text-[40px] text-[#33bbff]"
style={{ fontSize: "40px" }}
aria-hidden="true"
></i>
</div>
<div className="font-semibold ">
<div className="flex items-center gap-2">
<p>
{selectFolder && selectFolder.Name ? selectFolder.Name : "Root"}
</p>
<div className="text-black text-sm" onClick={() => SetIsOpen(true)}>
<i
className="fa fa-pencil"
title="Select Folder"
aria-hidden="true"
></i>
</div>
</div>
<p className="text-[10px] text-gray-400">
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
</p>
</div>
</div>
<ModalUi id="asd" title={"Select Folder"} isOpen={isOpen} handleClose={handleCancel}> <div className="w-full min-w-[300px] md:min-w-[500px] px-3">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="Root"
onClick={(e) => removeTabListItem(e)}
>
Root /{" "}
</span>
{tabList &&
tabList.map((tab, i) => (
<React.Fragment key={`${tab.objectId}-${i}`}>
<span
className="cursor-pointer"
title={tab.Name}
onClick={(e) => removeTabListItem(e, i)}
>
{tab.Name}
</span>
{" / "}
</React.Fragment>
))}
<hr />
</div>
<div className="mt-2 mb-3">
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer"
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
</div>
</div>
))}
{isAdd && (
<CreateFolder
parentFolderId={clickFolder && clickFolder.ObjectId}
folderCls={folderCls}
onSuccess={handleAddFolder}
/>
)}
{isLoader && (
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
</div>
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="text-[30px] cursor-pointer text-[#33bbff]"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
) : (
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
)}
</div>
<div
className="text-[30px] cursor-pointer"
title="Save Here"
onClick={handleSubmit}
>
<i className="fas fa-save" aria-hidden="true"></i>
</div>
</div></ModalUi>
{/* {isOpen && (
<div
className={`fixed z-40 top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm bg-white rounded `}
>
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem] bg-[#f5f5f5]">
<div className="font-semibold text-lg text-black">
Select Folder
</div>
<div
onClick={handleCancel}
className="px-2 py-1 border-[1px] border-[#8a8a8a] bg-white rounded cursor-pointer"
>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
<hr />
<div className="w-full min-w-[300px] md:min-w-[500px] px-3">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="Root"
onClick={(e) => removeTabListItem(e)}
>
Root /{" "}
</span>
{tabList &&
tabList.map((tab, i) => (
<React.Fragment key={`${tab.objectId}-${i}`}>
<span
className="cursor-pointer"
title={tab.Name}
onClick={(e) => removeTabListItem(e, i)}
>
{tab.Name}
</span>
{" / "}
</React.Fragment>
))}
<hr />
</div>
<div className="mt-2 mb-3">
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer"
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
</div>
</div>
))}
{isAdd && (
<CreateFolder
parentFolderId={clickFolder && clickFolder.ObjectId}
folderCls={folderCls}
onSuccess={handleAddFolder}
/>
)}
{isLoader && (
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
</div>
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="text-[30px] cursor-pointer text-[#33bbff]"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
) : (
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
)}
</div>
<div
className="text-[30px] cursor-pointer"
title="Save Here"
onClick={handleSubmit}
>
<i className="fas fa-save" aria-hidden="true"></i>
</div>
</div>
</div>
)} */}
</div>
);
};
export default SelectFolder;
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import Parse from "parse";
import "../../css/AddUser.css";
import "../css/AddUser.css";
import AsyncSelect from "react-select/async";
const customStyles = {
@@ -68,7 +68,7 @@ const SelectSigners = (props) => {
<div className="addusercontainer">
<div className="form-wrapper">
<div className="form-section">
<label style={{ fontSize: 14 }}>Choose User</label>
<label style={{ fontSize: 14 , fontWeight: "700"}}>Choose User</label>
<AsyncSelect
cacheOptions
defaultOptions