diff --git a/apps/OpenSign/src/components/AppendFormInForm.js b/apps/OpenSign/src/components/AppendFormInForm.js
index 22017e423..f5c1d51c2 100644
--- a/apps/OpenSign/src/components/AppendFormInForm.js
+++ b/apps/OpenSign/src/components/AppendFormInForm.js
@@ -46,6 +46,7 @@ const AppendFormInForm = (props) => {
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
+ e.stopPropagation();
setIsLoader(true);
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
diff --git a/apps/OpenSign/src/components/TreeWidget.js b/apps/OpenSign/src/components/TreeWidget.js
index ecbce7af4..569112d71 100644
--- a/apps/OpenSign/src/components/TreeWidget.js
+++ b/apps/OpenSign/src/components/TreeWidget.js
@@ -5,7 +5,7 @@ import Parse from "parse";
import axios from "axios";
import "../styles/spinner.css";
import TreeFormComponent from "./TreeFormComponent";
-import TreeEditForm from "./TreeEditForm";
+// import TreeEditForm from "./TreeEditForm";
import "../styles/modal.css";
import Modal from "react-modal";
@@ -22,7 +22,7 @@ const TreeWidget = (props) => {
const [schemaState, setSchemaState] = useState({});
const [TabURL, setTabURL] = useState("");
const [editable, setEditable] = useState(false);
- const [editId, setEditId] = useState("");
+ // const [editId, setEditId] = useState("");
const [defaultState, setDefaultState] = useState(false);
const [isShowModal, setIsShowModal] = useState(false);
const selectFolderHandle = async () => {
diff --git a/apps/OpenSign/src/components/fields/CreateFolder.js b/apps/OpenSign/src/components/fields/CreateFolder.js
new file mode 100644
index 000000000..9b6f4beec
--- /dev/null
+++ b/apps/OpenSign/src/components/fields/CreateFolder.js
@@ -0,0 +1,148 @@
+import React, { useEffect, useState } from "react";
+import Parse from "parse";
+import { templateCls } from "../../constant/const";
+import Alert from "../../primitives/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 fetchFolder = new Parse.Query(folderCls);
+ if (parentFolderId) {
+ fetchFolder.equalTo("Folder", folderPtr);
+ fetchFolder.equalTo("Type", "Folder");
+ } else {
+ fetchFolder.doesNotExist("Folder");
+ fetchFolder.equalTo("Type", "Folder");
+ }
+
+ const res = await fetchFolder.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(templateCls);
+ 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(templateCls);
+ 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 (
+
+ {isAlert &&
{alert.message}}
+
+
Create Folder
+
+
+ setName(e.target.value)}
+ required
+ />
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default CreateFolder;
diff --git a/apps/OpenSign/src/components/fields/FileUpload.js b/apps/OpenSign/src/components/fields/FileUpload.js
index 09a11e8d2..66eca92b0 100644
--- a/apps/OpenSign/src/components/fields/FileUpload.js
+++ b/apps/OpenSign/src/components/fields/FileUpload.js
@@ -271,10 +271,12 @@ const FileUpload = (props) => {
-
+ {process.env.DROPBOX_APP_KEY && (
+
+ )}
) : (
@@ -294,10 +296,12 @@ const FileUpload = (props) => {
accept="application/pdf,application/vnd.ms-excel"
onChange={onChange}
/>
-
+ {process.env.DROPBOX_APP_KEY && (
+
+ )}
)}
>
diff --git a/apps/OpenSign/src/components/fields/SelectFolder.js b/apps/OpenSign/src/components/fields/SelectFolder.js
new file mode 100644
index 000000000..434bbed7d
--- /dev/null
+++ b/apps/OpenSign/src/components/fields/SelectFolder.js
@@ -0,0 +1,271 @@
+import React, { useEffect, useState } from "react";
+import Parse from "parse";
+import CreateFolder from "./CreateFolder";
+import { templateCls } from "../../constant/const";
+
+const SelectFolder = ({ required, onSuccess }) => {
+ 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 fetchFolder = new Parse.Query(templateCls);
+ if (folderPtr) {
+ fetchFolder.equalTo("Folder", folderPtr);
+ fetchFolder.equalTo("Type", "Folder");
+ } else {
+ fetchFolder.doesNotExist("Folder");
+ fetchFolder.equalTo("Type", "Folder");
+ }
+
+ const res = await fetchFolder.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: templateCls,
+ objectId: item.objectId
+ };
+ fetchFolder(folderPtr);
+ }
+ } else {
+ setTabList((tabs) => [...tabs, item]);
+ const folderPtr = {
+ __type: "Pointer",
+ className: templateCls,
+ 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: templateCls,
+ 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: templateCls,
+ objectId: clickFolder.ObjectId
+ });
+ } else {
+ fetchFolder();
+ }
+ };
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {selectFolder && selectFolder.Name ? selectFolder.Name : "Root"}
+
+
SetIsOpen(true)}>
+
+
+
+
+ {selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
+
+
+
+ {isOpen && (
+
+
+
+ Select Folder
+
+
+
+
+
+
+
+
+ removeTabListItem(e)}
+ >
+ Root /{" "}
+
+ {tabList &&
+ tabList.map((tab, i) => (
+
+ removeTabListItem(e, i)}
+ >
+ {tab.Name}
+
+ {" / "}
+
+ ))}
+
+
+
+ {!isAdd &&
+ folderList.length > 0 &&
+ folderList.map((folder) => (
+
handleSelect(folder)}
+ >
+
+
+ {folder.Name}
+
+
+ ))}
+ {isAdd && (
+
+ )}
+ {isLoader && (
+
+
+
+ )}
+
+
+
+
+
+ {isAdd ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ )}
+
+ );
+};
+
+export default SelectFolder;
diff --git a/apps/OpenSign/src/components/fields/SignersInput.js b/apps/OpenSign/src/components/fields/SignersInput.js
new file mode 100644
index 000000000..0e9697965
--- /dev/null
+++ b/apps/OpenSign/src/components/fields/SignersInput.js
@@ -0,0 +1,190 @@
+import React, { useState, useEffect } from "react";
+import Select from "react-select";
+import AppendFormInForm from "../AppendFormInForm";
+import Modal from "react-modal";
+import Parse from "parse";
+function arrayMove(array, from, to) {
+ array = array.slice();
+ array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
+ return array;
+}
+
+/**
+ * react-sortable-hoc is depcreated not usable from react 18.x.x
+ * need to replace it with @dnd-kit
+ * code changes required
+ */
+
+const SignersInput = (props) => {
+ Modal.setAppElement("body");
+ const [state, setState] = useState(undefined);
+ // const [editFormData, setEditFormData] = useState([]);
+ const [selected, setSelected] = React.useState([]);
+ const [isModal, setIsModel] = useState(false);
+ const onChange = (selectedOptions) => setSelected(selectedOptions);
+ const [modalIsOpen, setModalIsOpen] = useState(false);
+
+ const onSortEnd = ({ oldIndex, newIndex }) => {
+ const newValue = arrayMove(selected, oldIndex, newIndex);
+ setSelected(newValue);
+ };
+
+ const GetSelectListData = async () => {
+ try {
+ const currentUser = Parse.User.current();
+ const contactbook = new Parse.Query("contracts_Contactbook");
+ contactbook.equalTo(
+ "CreatedBy",
+ Parse.User.createWithoutData(currentUser.id)
+ );
+ contactbook.notEqualTo("IsDeleted", true);
+ const contactRes = await contactbook.find();
+ if (contactRes) {
+ const res = JSON.parse(JSON.stringify(contactRes));
+ let list = [];
+
+ // let _selected = [];
+ res.forEach((x) => {
+ let obj = {
+ label: x.Name,
+ value: x.objectId,
+ isChecked: true
+ };
+
+ list.push(obj);
+ });
+ setState(list);
+ }
+ } catch (error) {
+ console.log("err", error);
+ }
+ };
+
+ useEffect(() => {
+ GetSelectListData();
+ }, []);
+
+ useEffect(() => {
+ if (selected && selected.length) {
+ let newData = [];
+ selected.forEach((x) => {
+ newData.push(x.value);
+ });
+ if (props.onChange) {
+ props.onChange(newData);
+ }
+ }
+
+ // eslint-disable-next-line
+ }, [selected]);
+
+ const handleModalCloseClick = () => {
+ setIsModel(false);
+ setModalIsOpen(false);
+ };
+
+ const openModal = () => {
+ setModalIsOpen(true);
+ };
+
+ // `handleNewDetails` is used to set just save from quick form to selected option in dropdown
+ const handleNewDetails = (data) => {
+ setState([...state, data]);
+ if (selected.length > 0) {
+ setSelected([...selected, data]);
+ } else {
+ setSelected([data]);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
{
+ setIsModel(true);
+ openModal();
+ }}
+ style={{
+ cursor: "pointer",
+ borderRadius: 4,
+ border: "1px solid #ccc",
+ minHeight: 38,
+ minWidth: 48,
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center"
+ }}
+ >
+
+
+
+
+
+
+ {isModal && (
+
+ )}
+
+
+
+
+ );
+};
+
+export default SignersInput;
diff --git a/apps/OpenSign/src/constant/const.js b/apps/OpenSign/src/constant/const.js
new file mode 100644
index 000000000..2e5e40948
--- /dev/null
+++ b/apps/OpenSign/src/constant/const.js
@@ -0,0 +1,2 @@
+export const contactCls = "contracts_Contactbook"
+export const templateCls = "contracts_Template"
diff --git a/apps/OpenSign/src/json/ReportJson.js b/apps/OpenSign/src/json/ReportJson.js
index f39898594..b538cd34f 100644
--- a/apps/OpenSign/src/json/ReportJson.js
+++ b/apps/OpenSign/src/json/ReportJson.js
@@ -1,7 +1,9 @@
export default function reportJson(id) {
// console.log("json ", json);
- const head = ["Sr.No", "Name", "Note", "Folder", "File", "Owner", "Signers"];
- const contactbook = ["Sr.No", "Name", "Email", "Phone"];
+ const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
+ const contactbook = ["Sr.No", "Title", "Email", "Phone"];
+ const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
+
switch (id) {
// draft documents report
case "ByHuevtCFY":
@@ -103,7 +105,7 @@ export default function reportJson(id) {
case "d9k3UfYHBc":
return {
reportName: "Recently sent for signatures",
- heading: head,
+ heading: dashboardReportHead,
actions: [
{
btnLabel: "View",
@@ -119,7 +121,7 @@ export default function reportJson(id) {
case "5Go51Q7T8r":
return {
reportName: "Recent signature requests",
- heading: head,
+ heading: dashboardReportHead,
actions: [
{
btnLabel: "Sign",
@@ -135,7 +137,7 @@ export default function reportJson(id) {
case "kC5mfynCi4":
return {
reportName: "Drafts",
- heading: head,
+ heading: ["Title", "Note", "Folder", "File", "Owner", "Signers"],
actions: [
{
btnLabel: "sign",
diff --git a/apps/OpenSign/src/primitives/Alert.js b/apps/OpenSign/src/primitives/Alert.js
new file mode 100644
index 000000000..72e3d1458
--- /dev/null
+++ b/apps/OpenSign/src/primitives/Alert.js
@@ -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 && (
+
+ {children}
+
+ )}
+ >
+ );
+};
+
+export default Alert;
diff --git a/apps/OpenSign/src/primitives/GetReportDisplay.js b/apps/OpenSign/src/primitives/GetReportDisplay.js
index 22be8a6c0..6c603d76d 100644
--- a/apps/OpenSign/src/primitives/GetReportDisplay.js
+++ b/apps/OpenSign/src/primitives/GetReportDisplay.js
@@ -135,7 +135,9 @@ const ReportTable = ({
{currentLists.map((item, index) =>
ReportName === "Contactbook" ? (
- | {index + 1} |
+ {heading.includes("Sr.No") && (
+ {index + 1} |
+ )}
{item?.Name} |
{item?.Email || "-"} |
{item?.Phone || "-"} |
@@ -179,12 +181,18 @@ const ReportTable = ({
) : (
- | {index + 1} |
+ {heading.includes("Sr.No") && (
+ {index + 1} |
+ )}
{item?.Name} |
- {item?.Note || "-"} |
-
- {item?.Folder?.Name || "OpenSignDrive"}
- |
+ {heading.includes("Note") && (
+ {item?.Note || "-"} |
+ )}
+ {heading.includes("Folder") && (
+
+ {item?.Folder?.Name || "OpenSignDrive"}
+ |
+ )}
- // )
))}
|
diff --git a/apps/OpenSign/src/primitives/Modal.js b/apps/OpenSign/src/primitives/Modal.js
new file mode 100644
index 000000000..9069b592b
--- /dev/null
+++ b/apps/OpenSign/src/primitives/Modal.js
@@ -0,0 +1,28 @@
+import React, { useState } from "react";
+
+const Modal = ({ children, Title }) => {
+ const [isOpen, SetIsOpen] = useState(false);
+ return (
+ <>
+ {children && (
+
+
+
{Title}
+
SetIsOpen()}
+ className="px-2 py-1 bg-gray-400 rounded cursor-pointer"
+ >
+
+
+
+
+ {isOpen &&
{children}
}
+
+ )}
+ >
+ );
+};
+
+export default Modal;
diff --git a/apps/OpenSign/src/primitives/TemplateForm.js b/apps/OpenSign/src/primitives/TemplateForm.js
new file mode 100644
index 000000000..66c431bbb
--- /dev/null
+++ b/apps/OpenSign/src/primitives/TemplateForm.js
@@ -0,0 +1,304 @@
+import React, { useState } from "react";
+import sanitizeFileName from "./sanitizeFileName";
+import Parse from "parse";
+import DropboxChooser from "../components/fields/DropboxChoose";
+import Alert from "./Alert";
+import SelectFolder from "../components/fields/SelectFolder";
+import SignersInput from "../components/fields/SignersInput";
+import Title from "../components/Title";
+const TemplateForm = () => {
+ const [signers, setSigners] = useState([]);
+ const [folder, setFolder] = useState({ ObjectId: "", Name: "" });
+ const [formData, setFormData] = useState({
+ Name: "",
+ Description: "",
+ Note: ""
+ });
+ const [fileupload, setFileUpload] = useState([]);
+ const [fileload, setfileload] = useState(false);
+ const [percentage, setpercentage] = useState(0);
+ const [isAlert, setIsAlert] = useState(false);
+ const handleStrInput = (e) => {
+ setFormData({ ...formData, [e.target.name]: e.target.value });
+ };
+
+ const handleFileInput = (e) => {
+ setpercentage(0);
+ try {
+ let files = e.target.files;
+ if (typeof files[0] !== "undefined") {
+ const mb = Math.round(files[0].bytes / Math.pow(1024, 2));
+ if (mb > 10) {
+ alert(
+ `The selected file size is too large. Please select a file less than ${Math.round(
+ 10
+ )} MB`
+ );
+ return;
+ }
+
+ handleFileUpload(files[0]);
+ } else {
+ alert("Please select file.");
+ return false;
+ }
+ } catch (error) {
+ alert(error.message);
+ return false;
+ }
+ };
+
+ const handleFileUpload = async (file) => {
+ Parse.serverURL = process.env.REACT_APP_SERVERURL;
+ Parse.initialize(process.env.REACT_APP_APPID);
+ setfileload(true);
+ const fileName = file.name;
+ const name = sanitizeFileName(fileName);
+ const pdfFile = file;
+ const parseFile = new Parse.File(name, pdfFile);
+
+ try {
+ const response = await parseFile.save({
+ progress: (progressValue, loaded, total, { type }) => {
+ if (type === "upload" && progressValue !== null) {
+ const percentCompleted = Math.round((loaded * 100) / total);
+ setpercentage(percentCompleted);
+ }
+ }
+ });
+
+ // The response object will contain information about the uploaded file
+ // You can access the URL of the uploaded file using response.url()
+ setFileUpload(response.url());
+ setfileload(false);
+ if (response.url()) {
+ return response.url();
+ }
+ } catch (error) {
+ setfileload(false);
+ setpercentage(0);
+ console.error("Error uploading file:", error);
+ }
+ };
+
+ const dropboxSuccess = async (files) => {
+ setfileload(true);
+ const file = files[0];
+ const url = file.link;
+ const mb = Math.round(file.bytes / Math.pow(1024, 2));
+
+ if (mb > 10) {
+ setTimeout(() => {
+ alert(
+ `The selected file size is too large. Please select a file less than 10 MB`
+ );
+ }, 500);
+ return;
+ } else {
+ const name = sanitizeFileName(file.name);
+
+ const parseFile = new Parse.File(name, { uri: url });
+
+ try {
+ const response = await parseFile.save({
+ progress: (progressValue, loaded, total, { type }) => {
+ if (type === "upload" && progressValue !== null) {
+ const percentCompleted = Math.round((loaded * 100) / total);
+ setpercentage(percentCompleted);
+ }
+ }
+ });
+ setFileUpload(response.url());
+ setfileload(false);
+
+ if (response.url()) {
+ return response.url();
+ }
+ } catch (error) {
+ setfileload(false);
+ setpercentage(0);
+ console.error("Error uploading file:", error);
+ }
+ }
+ };
+ const dropboxCancel = async () => {};
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ try {
+ const currentUser = Parse.User.current();
+ const template = new Parse.Object("contracts_Template");
+ Object.entries(formData).forEach((item) =>
+ template.set(item[0], item[1])
+ );
+ template.set("URL", fileupload);
+ template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
+ if (folder && folder.ObjectId) {
+ template.set("Folder", {
+ __type: "Pointer",
+ className: "contracts_Template",
+ objectId: folder.ObjectId
+ });
+ }
+ if (signers && signers.length > 0) {
+ template.set("Signers", signers);
+ }
+ const res = await template.save();
+ if (res) {
+ setIsAlert(true);
+ setTimeout(() => {
+ setIsAlert(false);
+ }, 1000);
+ setSigners([]);
+ setFolder({ ObjectId: "", Name: "" });
+ setFormData({
+ Name: "",
+ Description: "",
+ Note: ""
+ });
+ setFileUpload([]);
+ setpercentage(0);
+ }
+ } catch (err) {
+ console.log("err ", err);
+ setIsAlert(true);
+ }
+ };
+
+ const handleFolder = (data) => {
+ setFolder(data);
+ };
+ const handleSigners = (data) => {
+ if (data && data.length > 0) {
+ const updateSigners = data.map((x) => ({
+ __type: "Pointer",
+ className: "contracts_Contactbook",
+ objectId: x
+ }));
+ setSigners(updateSigners);
+ }
+ };
+
+ const handleReset = () => {
+ setSigners([]);
+ setFolder({ ObjectId: "", Name: "" });
+ setFormData({
+ Name: "",
+ Description: "",
+ Note: ""
+ });
+ setFileUpload([]);
+ setpercentage(0);
+ };
+ return (
+
+
+ {isAlert &&
Template created successfully!}
+
+
+ );
+};
+
+export default TemplateForm;
diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js
index fd5c67449..2c6c67709 100644
--- a/apps/OpenSign/src/routes/Form.js
+++ b/apps/OpenSign/src/routes/Form.js
@@ -25,6 +25,7 @@ import TreeWidget from "../components/TreeWidget";
import parse from "html-react-parser";
import Title from "../components/Title";
import { formJson } from "../json/FormJson";
+import TemplateForm from "../primitives/TemplateForm";
const widget = {
TimeWidget: TimeWidget
};
@@ -41,15 +42,19 @@ const fields = () => {
function FormBuilderFn(props) {
const { id } = useParams();
const navigate = useNavigate();
- return (
-
- );
+ if (id === "template") {
+ return ;
+ } else {
+ return (
+
+ );
+ }
}
class FormBuilder extends Component {
state = {
diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js
index e42ee38e5..ee8cac810 100644
--- a/apps/OpenSignServer/cloud/main.js
+++ b/apps/OpenSignServer/cloud/main.js
@@ -17,6 +17,7 @@ import getUserDetails from './parsefunction/getUserDetails.js';
import getDocument from './parsefunction/getDocument.js';
import getDrive from './parsefunction/getDrive.js';
import getReport from './parsefunction/getReport.js';
+import TemplateAfterSave from './parsefunction/TemplateAfterSave.js';
Parse.Cloud.define('AddUserToRole', addUserToGroups);
Parse.Cloud.define('UserGroups', getUserGroups);
@@ -26,9 +27,6 @@ Parse.Cloud.define('googlesign', GoogleSign);
Parse.Cloud.define('zohodetails', ZohoDetails);
Parse.Cloud.define('usersignup', usersignup);
Parse.Cloud.define('facebooksign', FacebookSign);
-Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
-Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
-Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1);
Parse.Cloud.define('sendmail', SendMailv1);
Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail);
@@ -36,4 +34,8 @@ Parse.Cloud.define('getUserId', getUserId);
Parse.Cloud.define('getUserDetails', getUserDetails);
Parse.Cloud.define('getDocument', getDocument);
Parse.Cloud.define('getDrive', getDrive)
-Parse.Cloud.define('getReport', getReport)
\ No newline at end of file
+Parse.Cloud.define('getReport', getReport)
+Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
+Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
+Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
+Parse.Cloud.afterSave("contracts_Template", TemplateAfterSave)
\ No newline at end of file
diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js
new file mode 100644
index 000000000..7d22ccb86
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js
@@ -0,0 +1,83 @@
+export default async function TemplateAfterSave(request) {
+ try {
+ if (!request.original) {
+ console.log('new entry is insert in contracts_Template');
+ // update acl of New Document If There are signers present in array
+ const signers = request.object.get('Signers');
+
+ if (signers && signers.length > 0) {
+ await updateAclDoc(request.object.id);
+ } else {
+ await updateSelfDoc(request.object.id);
+ }
+ } else {
+ if (request.user) {
+ const signers = request.object.get('Signers');
+ if (signers && signers.length > 0) {
+ await updateAclDoc(request.object.id);
+ } else {
+ await updateSelfDoc(request.object.id);
+ }
+ }
+ }
+ } catch (err) {
+ console.log('err in aftersave of contracts_Template');
+ console.log(err);
+ }
+
+ async function updateAclDoc(objId) {
+ // console.log("In side updateAclDoc func")
+ // console.log(objId)
+ const Query = new Parse.Query('contracts_Template');
+ Query.include('Signers');
+ const updateACL = await Query.get(objId, { useMasterKey: true });
+ const res = JSON.parse(JSON.stringify(updateACL));
+ // console.log("res");
+ // console.log(JSON.stringify(res));
+ const UsersPtr = res.Signers.map(item => item.UserId);
+
+ if (res.Signers[0].ExtUserPtr) {
+ const ExtUserSigners = res.Signers.map(item => {
+ return {
+ __type: 'Pointer',
+ className: 'contracts_Users',
+ objectId: item.ExtUserPtr.objectId,
+ };
+ });
+ updateACL.set('Signers', ExtUserSigners);
+ }
+
+ // console.log("UsersPtr")
+ // console.log(JSON.stringify(UsersPtr))
+ const newACL = new Parse.ACL();
+ newACL.setPublicReadAccess(false);
+ newACL.setPublicWriteAccess(false);
+ newACL.setReadAccess(request.user, true);
+ newACL.setWriteAccess(request.user, true);
+
+ UsersPtr.forEach(x => {
+ newACL.setReadAccess(x.objectId, true);
+ newACL.setWriteAccess(x.objectId, true);
+ });
+
+ updateACL.setACL(newACL);
+ updateACL.save(null, { useMasterKey: true });
+ }
+
+ async function updateSelfDoc(objId) {
+ // console.log("Inside updateSelfDoc func")
+
+ const Query = new Parse.Query('contracts_Template');
+ const updateACL = await Query.get(objId, { useMasterKey: true });
+ // const res = JSON.parse(JSON.stringify(updateACL));
+ // console.log("res");
+ // console.log(JSON.stringify(res));
+ const newACL = new Parse.ACL();
+ newACL.setPublicReadAccess(false);
+ newACL.setPublicWriteAccess(false);
+ newACL.setReadAccess(request.user, true);
+ newACL.setWriteAccess(request.user, true);
+ updateACL.setACL(newACL);
+ updateACL.save(null, { useMasterKey: true });
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js
index 8ad9c47df..66d743a6a 100644
--- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js
+++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js
@@ -154,7 +154,7 @@ export default function reportJson(id, userId) {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
},
- keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
+ keys: ['Name', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// Recent signature requests report show on dashboard
case '5Go51Q7T8r':
@@ -169,16 +169,7 @@ export default function reportJson(id, userId) {
},
Placeholders: { $ne: null },
},
- keys: [
- 'Name',
- 'Note',
- 'Folder.Name',
- 'URL',
- 'ExtUserPtr.Name',
- 'Signers.Name',
- 'Signers.UserId',
- 'AuditTrail',
- ],
+ keys: ['Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name', 'Signers.UserId', 'AuditTrail'],
};
// Drafts report show on dashboard
case 'kC5mfynCi4':
diff --git a/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs b/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs
index 9581be3a8..c897aefac 100644
--- a/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs
+++ b/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs
@@ -39,6 +39,14 @@ exports.up = async Parse => {
description: '',
objectId: '8mZzFxbG1z',
},
+ {
+ icon: 'fas fa-file-signature',
+ title: 'New template',
+ target: '_self',
+ pageType: 'form',
+ description: '',
+ objectId: 'template',
+ },
],
},
{
diff --git a/apps/OpenSignServer/databases/migrations/20231208132950-create_template_cls.cjs b/apps/OpenSignServer/databases/migrations/20231208132950-create_template_cls.cjs
new file mode 100644
index 000000000..47fe71b87
--- /dev/null
+++ b/apps/OpenSignServer/databases/migrations/20231208132950-create_template_cls.cjs
@@ -0,0 +1,40 @@
+/**
+ *
+ * @param {Parse} Parse
+ */
+exports.up = async Parse => {
+ const className = 'contracts_Template';
+ const schema = new Parse.Schema(className);
+
+ schema.addString('Name');
+ schema.addString('URL');
+ schema.addString('Note');
+ schema.addString('Description');
+ schema.addArray('Signers');
+ schema.addBoolean('IsArchive');
+ schema.addArray('Placeholders');
+ schema.addPointer('Folder', 'contracts_Template');
+ schema.addString('Type');
+ schema.addPointer('CreatedBy', '_User');
+ schema.addPointer('ExtUserPtr', 'contracts_Users');
+ schema.addBoolean('EnablePhoneOTP')
+ schema.addBoolean('EnableEmailOTP')
+ schema.addBoolean('SendinOrder')
+ schema.addBoolean('SentToOthers')
+ schema.addBoolean('AutomaticReminders')
+
+
+
+ return schema.save();
+};
+
+/**
+ *
+ * @param {Parse} Parse
+ */
+exports.down = async Parse => {
+ const className = 'contracts_Template';
+ const schema = new Parse.Schema(className);
+
+ return schema.purge().then(() => schema.delete());
+};
diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js
index 819940954..d8944d8d3 100644
--- a/apps/OpenSignServer/index.js
+++ b/apps/OpenSignServer/index.js
@@ -69,7 +69,9 @@ if (process.env.SMTP_ENABLE) {
export const config = {
databaseURI:
process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev',
- cloud: process.env.CLOUD || __dirname + '/cloud/main.js',
+ cloud: function () {
+ import('./cloud/main.js');
+ },
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
masterKeyIps: ['0.0.0.0/0', '::1'], // '::1'