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
@@ -0,0 +1,293 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import axios from "axios";
import "../css/AddUser.css";
const AddUser = (props) => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const [addYourself, setAddYourself] = useState(false);
const [isLoader, setIsLoader] = useState(false);
const [isUserExist, setIsUserExist] = useState(false);
const parseBaseUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId");
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
useEffect(() => {
checkUserExist();
}, []);
// Load user details from localStorage when the component mounts
useEffect(() => {
const savedUserDetails = JSON.parse(
localStorage.getItem("UserInformation")
);
if (savedUserDetails && addYourself) {
setName(savedUserDetails.name);
setPhone(savedUserDetails.phone);
setEmail(savedUserDetails.email);
}
}, [addYourself]);
const checkUserExist = async () => {
const user = Parse.User.current();
try {
const query = new Parse.Query("contracts_Contactbook");
query.equalTo("CreatedBy", user);
query.notEqualTo("IsDeleted", true);
query.equalTo("Email", user.getEmail());
const res = await query.first();
// console.log(res);
if (!res) {
setIsUserExist(true);
}
} catch (err) {
console.log("err", err);
}
};
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsLoader(true);
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
try {
const contactQuery = new Parse.Object("contracts_Contactbook");
contactQuery.set("Name", name);
contactQuery.set("Phone", phone);
contactQuery.set("Email", email);
contactQuery.set("UserRole", "contracts_Guest");
if (localStorage.getItem("TenetId")) {
contactQuery.set("TenantId", {
__type: "Pointer",
className: "partners_Tenant",
objectId: localStorage.getItem("TenetId")
});
}
try {
const _users = Parse.Object.extend("User");
const _user = new _users();
_user.set("name", name);
_user.set("username", email);
_user.set("email", email);
_user.set("phone", phone);
_user.set("password", 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: localStorage.getItem("_appName"),
roleName: "contracts_Guest",
userId: user.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", user);
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
props.details(parseData);
if (props.closePopup) {
props.closePopup();
}
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
setName("");
setPhone("");
setEmail("");
}
} catch (err) {
console.log("err ", err);
if (err.code === 202) {
const params = { email: 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: localStorage.getItem("_appName"),
roleName: "contracts_Guest",
userId: userRes.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.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);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
if (props.closePopup) {
props.closePopup();
}
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
setName("");
setPhone("");
setEmail("");
}
}
} catch (err) {
// console.log("err", err);
setIsLoader(false);
alert("something went wrong!");
}
};
// Define a function to handle the "add yourself" checkbox
const handleAddYourselfChange = () => {
if (addYourself) {
setAddYourself(false);
setName("");
setPhone("");
setEmail("");
} else {
setAddYourself(true);
}
};
const handleReset = () => {
setAddYourself(false);
};
return (
<div className="addusercontainer">
{isLoader && (
<div className="loaderdiv">
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
)}
<div className="form-wrapper">
<div style={{ fontSize: 14, fontWeight: "700" }}>Add User</div>
{isUserExist && (
<div className="form-section">
<input
type="checkbox"
id="addYourself"
checked={addYourself}
onChange={handleAddYourselfChange}
className="form-checkbox"
/>
<label htmlFor="addYourself" className="checkbox-label ">
Add Yourself
</label>
</div>
)}
<form onSubmit={handleSubmit}>
<div className="form-section">
<label htmlFor="name" style={{ fontSize: 13 }}>
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="text"
id="name"
value={name}
onChange={(e) => setName(e.target.value)}
required
disabled={addYourself}
className="addUserInput"
/>
</div>
<div className="form-section">
<label htmlFor="email" style={{ fontSize: 13 }}>
Email
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={addYourself}
className="addUserInput"
/>
</div>
<div className="form-section">
<label htmlFor="phone" style={{ fontSize: 13 }}>
Phone
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="text"
id="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
required
disabled={addYourself}
className="addUserInput"
/>
</div>
<div className="buttoncontainer">
<button type="submit" className="submitbutton">
Submit
</button>
<button
type="button"
onClick={() => handleReset()}
className="resetbutton"
>
Reset
</button>
</div>
</form>
</div>
</div>
);
};
export default AddUser;
@@ -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;
@@ -0,0 +1,94 @@
import React, { useState } from "react";
import Parse from "parse";
import "../css/AddUser.css";
import AsyncSelect from "react-select/async";
const customStyles = {
control: (provided) => ({
...provided,
fontSize: "13px" // Font size for the control
}),
option: (provided) => ({
...provided,
fontSize: "13px" // Font size for the options
})
};
const SelectSigners = (props) => {
const [userList, setUserList] = useState([]);
const [selected, setSelected] = useState();
const [userData, setUserData] = useState({});
const parseBaseUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId");
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
// `handleOptions` is used to set just save from quick form to selected option in dropdown
const handleOptions = (item) => {
setSelected(item);
const userData = userList.filter((x) => x.objectId === item.value);
if (userData.length > 0) {
setUserData(userData[0]);
}
};
const handleAdd = () => {
props.details(userData);
if (props.closePopup) {
props.closePopup();
}
};
const loadOptions = async (inputValue) => {
try {
const currentUser = Parse.User.current();
const contactbook = new Parse.Query("contracts_Contactbook");
contactbook.equalTo(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
if (inputValue.length > 1) {
contactbook.matches("Name", new RegExp(inputValue, "i"));
}
contactbook.notEqualTo("IsDeleted", true);
const contactRes = await contactbook.find();
if (contactRes) {
const res = JSON.parse(JSON.stringify(contactRes));
// console.log("userList ", res);
setUserList(res);
return await res.map((item) => ({
label: item.Name,
value: item.objectId
}));
}
} catch (error) {
console.log("err", error);
}
};
return (
<div className="addusercontainer">
<div className="form-wrapper">
<div className="form-section">
<label style={{ fontSize: 14 , fontWeight: "700"}}>Choose User</label>
<AsyncSelect
cacheOptions
defaultOptions
value={selected}
loadingMessage={() => "Loading..."}
noOptionsMessage={() => "User not Found"}
loadOptions={loadOptions}
onChange={handleOptions}
styles={customStyles}
/>
</div>
<div className="buttoncontainer">
<button className="submitbutton" onClick={() => handleAdd()}>
Add Signer
</button>
</div>
</div>
</div>
);
};
export default SelectSigners;