feat: enable custom file storage for document siging

This commit is contained in:
prafull-opensignlabs
2024-10-04 12:59:10 +05:30
parent 356ab4e7cb
commit 00fcd17285
26 changed files with 1856 additions and 1451 deletions
+553 -558
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -6,14 +6,14 @@
"@formkit/auto-animate": "^0.8.2",
"@lottiefiles/dotlottie-react": "^0.9.0",
"@pdf-lib/fontkit": "^1.1.1",
"@radix-ui/themes": "^3.1.3",
"@radix-ui/themes": "^3.1.4",
"@react-pdf/renderer": "^4.0.0",
"@reduxjs/toolkit": "^2.2.7",
"axios": "^1.7.7",
"file-saver": "^2.0.5",
"i18next": "^23.15.1",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.6.1",
"i18next-http-backend": "^2.6.2",
"jszip": "^3.10.1",
"jwt-decode": "^4.0.0",
"moment": "^2.30.1",
@@ -95,22 +95,22 @@
}
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.4",
"@babel/preset-react": "^7.24.7",
"@babel/runtime-corejs2": "^7.25.6",
"@babel/core": "^7.25.7",
"@babel/preset-env": "^7.25.7",
"@babel/preset-react": "^7.25.7",
"@babel/runtime-corejs2": "^7.25.7",
"autoprefixer": "^10.4.20",
"babel-loader": "^9.2.1",
"clean-webpack-plugin": "^4.0.0",
"commitizen": "^4.3.1",
"concurrently": "^9.0.1",
"css-loader": "^7.1.2",
"daisyui": "^4.12.10",
"daisyui": "^4.12.11",
"dotenv": "^16.4.5",
"dotenv-webpack": "^8.1.0",
"eslint": "^9.11.1",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.0",
"eslint-plugin-react": "^7.37.1",
"lint-staged": "^15.2.10",
"mini-css-extract-plugin": "^2.9.1",
"postcss": "^8.4.47",
@@ -30,16 +30,15 @@ function EmailComponent({
const pdfName = pdfDetails[0]?.Name;
setIsLoading(true);
let sendMail;
const docId = !pdfDetails?.[0]?.IsEnableOTP
? pdfDetails?.[0]?.objectId
: "";
const docId = pdfDetails?.[0]?.objectId || "";
const isFileAdapter = pdfDetails?.[0]?.IsFileAdapter
? pdfDetails?.[0]?.IsFileAdapter
: false;
let presignedUrl = pdfUrl;
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
const axiosRes = await axios.post(
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl, docId: docId },
{ url: pdfUrl, docId: docId, isFileAdapter: isFileAdapter },
{
headers: {
"content-type": "Application/json",
@@ -41,9 +41,9 @@ const SuggestionInput = (props) => {
const handleInputChange = async (e) => {
const value = e.target.value;
setInputValue(value?.toLowerCase());
setInputValue(value?.toLowerCase()?.replace(/\s/g, ""));
if (props.onChange) {
props.onChange(value);
props.onChange(value?.toLowerCase()?.replace(/\s/g, ""));
}
if (value.trim() === "") {
+22 -6
View File
@@ -2048,11 +2048,21 @@ export const fetchUrl = async (url, pdfName) => {
console.error("Error downloading the file:", error);
}
};
export const getSignedUrl = async (pdfUrl, docId) => {
export const getSignedUrl = async (
pdfUrl,
docId,
isFileAdapter,
templateId
) => {
//use only axios here due to public template sign
const axiosRes = await axios.post(
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl, docId: docId || "" },
{
url: pdfUrl,
docId: docId || "",
isFileAdapter: isFileAdapter,
templateId: templateId || ""
},
{
headers: {
"content-type": "Application/json",
@@ -2069,9 +2079,12 @@ export const handleDownloadPdf = async (pdfDetails, setIsDownloading) => {
const pdfName = pdfDetails[0] && pdfDetails[0]?.Name;
const pdfUrl = pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL;
setIsDownloading && setIsDownloading("pdf");
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
const docId = pdfDetails?.[0]?.objectId || "";
const isFileAdapter = pdfDetails?.[0]?.IsFileAdapter
? pdfDetails?.[0]?.IsFileAdapter
: false;
try {
const url = await getSignedUrl(pdfUrl, docId);
const url = await getSignedUrl(pdfUrl, docId, isFileAdapter);
await fetchUrl(url, pdfName);
setIsDownloading && setIsDownloading("");
} catch (err) {
@@ -2094,14 +2107,17 @@ export const handleToPrint = async (
) => {
event.preventDefault();
setIsDownloading("pdf");
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
const docId = pdfDetails?.[0]?.objectId || "";
const isFileAdapter = pdfDetails?.[0]?.IsFileAdapter
? pdfDetails?.[0]?.IsFileAdapter
: false;
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
//`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign
//if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url
const axiosRes = await axios.post(
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl, docId: docId },
{ url: pdfUrl, docId: docId, isFileAdapter: isFileAdapter },
{
headers: {
"content-type": "Application/json",
+266 -129
View File
@@ -85,6 +85,9 @@ const Forms = (props) => {
setIsCorrectPass(true);
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const extUserData =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
useEffect(() => {
handleReset();
return () => abortController.abort();
@@ -153,10 +156,7 @@ const Forms = (props) => {
formData.append("file", files[0]);
formData.append("password", "");
const config = {
headers: {
"content-type": "multipart/form-data"
// sessiontoken: Parse.User.current().getSessionToken()
},
headers: { "content-type": "multipart/form-data" },
responseType: "blob"
};
const response = await axios.post(url, formData, config);
@@ -168,35 +168,58 @@ const Forms = (props) => {
});
setIsDecrypting(false);
setfileload(true);
// Upload the file to Parse Server
const parseFile = new Parse.File(
name,
pdfFile,
"application/pdf"
);
await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round(
(loaded * 100) / total
);
setpercentage(percentCompleted);
}
if (extUserData?.TenantId?.ActiveFileAdapter) {
const base64 = await toDataUrl(pdfFile);
const fileBase64 = base64.split(",").pop();
const ext = files?.[0]?.name?.split(".").pop();
const fileRes = await saveToCustomFile(
fileBase64,
`${name}.${ext}`
);
if (fileRes.url) {
setFileUpload(fileRes.url);
setfileload(false);
setpercentage(0);
const title = generateTitleFromFilename(files?.[0]?.name);
setFormData((obj) => ({ ...obj, Name: title }));
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, fileRes.url, tenantId);
return fileRes.url;
} else {
setfileload(false);
setpercentage(0);
setFileUpload("");
e.target.value = "";
}
});
} else {
// Upload the file to Parse Server
const parseFile = new Parse.File(
name,
pdfFile,
"application/pdf"
);
// Retrieve the URL of the uploaded file
if (parseFile.url()) {
setFileUpload(parseFile.url());
setfileload(false);
const title = generateTitleFromFilename(files?.[0]?.name);
setFormData((obj) => ({ ...obj, Name: title }));
SaveFileSize(size, response.url(), tenantId);
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, parseFile.url(), tenantId);
return parseFile.url();
await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round(
(loaded * 100) / total
);
setpercentage(percentCompleted);
}
}
});
// Retrieve the URL of the uploaded file
if (parseFile.url()) {
setFileUpload(parseFile.url());
setfileload(false);
const title = generateTitleFromFilename(files?.[0]?.name);
setFormData((obj) => ({ ...obj, Name: title }));
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, parseFile.url(), tenantId);
return parseFile.url();
}
}
} catch (err) {
setfileload(false);
@@ -237,46 +260,73 @@ const Forms = (props) => {
width: imageWidth,
height: imageHeight
});
const getFile = await pdfDoc.save({
useObjectStreams: false
});
setfileload(true);
const size = files[0].size;
const size = files?.[0]?.size;
const name = generatePdfName(16);
const pdfName = `${name?.split(".")[0]}.pdf`;
const parseFile = new Parse.File(
pdfName,
[...getFile],
"application/pdf"
);
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);
}
}
if (extUserData?.TenantId?.ActiveFileAdapter) {
const base64 = await pdfDoc.saveAsBase64({
useObjectStreams: false
});
// 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()) {
const tenantId = localStorage.getItem("TenantId");
setfileload(true);
const fileBase64 = base64.split(",").pop();
const ext = files?.[0]?.name?.split(".").pop();
const fileRes = await saveToCustomFile(
fileBase64,
`${name}.${ext}`
);
if (fileRes.url) {
setFileUpload(fileRes.url);
setfileload(false);
setpercentage(0);
const title = generateTitleFromFilename(files?.[0]?.name);
setFormData((obj) => ({ ...obj, Name: title }));
SaveFileSize(size, response.url(), tenantId);
return response.url();
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, fileRes.url, tenantId);
return fileRes.url;
} else {
setfileload(false);
setpercentage(0);
e.target.value = "";
}
} else {
const getFile = await pdfDoc.save({
useObjectStreams: false
});
setfileload(true);
const pdfName = `${name?.split(".")[0]}.pdf`;
const parseFile = new Parse.File(
pdfName,
[...getFile],
"application/pdf"
);
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()) {
const tenantId = localStorage.getItem("TenantId");
const title = generateTitleFromFilename(files?.[0]?.name);
setFormData((obj) => ({ ...obj, Name: title }));
SaveFileSize(size, response.url(), tenantId);
return response.url();
}
} catch (error) {
e.target.value = "";
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
} catch (error) {
e.target.value = "";
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
} else {
if (isEnableSubscription) {
@@ -322,41 +372,78 @@ const Forms = (props) => {
}
};
const saveToCustomFile = async (base64, filname) => {
try {
const savetos3 = await Parse.Cloud.run("savetofileadapter", {
fileBase64: base64,
fileName: filname
});
return { url: savetos3.url };
} catch (err) {
console.log("err in save to customfile", err);
return { url: "" };
}
};
const handleFileUpload = async (file) => {
setfileload(true);
const size = file.size;
const name = generatePdfName(16);
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()) {
if (extUserData?.TenantId?.ActiveFileAdapter) {
const base64 = await toDataUrl(file);
const fileBase64 = base64.split(",").pop();
const ext = file?.name?.split(".").pop();
const fileRes = await saveToCustomFile(fileBase64, `${name}.${ext}`);
if (fileRes.url) {
setFileUpload(fileRes?.url);
const tenantId = localStorage.getItem("TenantId");
const title = generateTitleFromFilename(file.name);
setFormData((obj) => ({ ...obj, Name: title }));
SaveFileSize(size, response.url(), tenantId);
return response.url();
SaveFileSize(size, fileRes.url, tenantId);
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
} else {
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()) {
const tenantId = localStorage.getItem("TenantId");
const title = generateTitleFromFilename(file.name);
setFormData((obj) => ({ ...obj, Name: title }));
SaveFileSize(size, response.url(), tenantId);
return response.url();
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
}
};
async function uriToBase64(uri) {
const response = await fetch(uri);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob); // Convert to Base64
});
}
const dropboxSuccess = async (files) => {
setfileload(true);
const file = files[0];
@@ -371,30 +458,49 @@ const Forms = (props) => {
return;
} else {
const name = generatePdfName(16);
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()) {
const tenantId = localStorage.getItem("TenantId");
const title = generateTitleFromFilename(file.name);
if (extUserData?.TenantId?.ActiveFileAdapter) {
const base64 = await uriToBase64(url);
const fileBase64 = base64.split(",").pop();
const ext = file?.name?.split(".").pop();
const fileRes = await saveToCustomFile(fileBase64, `${name}.${ext}`);
if (fileRes.url) {
setFileUpload(fileRes.url);
setfileload(false);
setpercentage(0);
const title = generateTitleFromFilename(files?.[0]?.name);
setFormData((obj) => ({ ...obj, Name: title }));
SaveFileSize(size, response.url(), tenantId);
return response.url();
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, fileRes.url, tenantId);
return fileRes.url;
} else {
setfileload(false);
setpercentage(0);
}
} else {
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()) {
const tenantId = localStorage.getItem("TenantId");
const title = generateTitleFromFilename(file.name);
setFormData((obj) => ({ ...obj, Name: title }));
SaveFileSize(size, response.url(), tenantId);
return response.url();
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
}
};
@@ -447,6 +553,9 @@ const Forms = (props) => {
className: "contracts_Users",
objectId: ExtCls[0].objectId
});
if (extUserData?.TenantId?.ActiveFileAdapter) {
object.set("IsFileAdapter", true);
}
const res = await object.save();
if (res) {
setSigners([]);
@@ -550,27 +659,55 @@ const Forms = (props) => {
});
setIsDecrypting(false);
// Upload the file to Parse Server
const parseFile = new Parse.File(name, pdfFile, "application/pdf");
await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total);
setpercentage(percentCompleted);
if (extUserData?.TenantId?.ActiveFileAdapter) {
const base64 = await toDataUrl(pdfFile);
const fileBase64 = base64.split(",").pop();
const ext = formData?.file?.name?.split(".").pop();
const fileRes = await saveToCustomFile(fileBase64, `${name}.${ext}`);
if (fileRes.url) {
setFormData((prev) => ({ ...prev, password: "" }));
setFileUpload(fileRes?.url);
setfileload(false);
setpercentage(0);
const title = generateTitleFromFilename(formData?.file?.name);
setFormData((obj) => ({ ...obj, Name: title }));
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, fileRes.url, tenantId);
return fileRes.url;
} else {
setfileload(false);
setpercentage(0);
}
} else {
const parseFile = new Parse.File(name, pdfFile, "application/pdf");
await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total);
setpercentage(percentCompleted);
}
}
});
// Retrieve the URL of the uploaded file
if (parseFile.url()) {
setFormData((prev) => ({ ...prev, password: "" }));
setFileUpload(parseFile.url());
setfileload(false);
setpercentage(0);
const title = generateTitleFromFilename(formData?.file?.name);
setFormData((obj) => ({ ...obj, Name: title }));
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, parseFile.url(), tenantId);
return parseFile.url();
} else {
setfileload(false);
setpercentage(0);
setFormData((prev) => ({ ...prev, password: "" }));
setIsDecrypting(false);
if (inputFileRef.current) {
inputFileRef.current.value = ""; // Set file input value to empty string
}
}
});
// Retrieve the URL of the uploaded file
if (parseFile.url()) {
setFormData((prev) => ({ ...prev, password: "" }));
setFileUpload(parseFile.url());
setfileload(false);
const title = generateTitleFromFilename(formData?.file?.name);
setFormData((obj) => ({ ...obj, Name: title }));
const tenantId = localStorage.getItem("TenantId");
SaveFileSize(size, parseFile.url(), tenantId);
return parseFile.url();
}
} catch (err) {
setfileload(false);
+1 -1
View File
@@ -901,7 +901,7 @@ function PlaceHolderSign() {
useEffect(() => {
const timer = setTimeout(() => {
if (signerPos?.length > 0) {
if (signerPos?.length > 0 && !pdfDetails?.[0]?.IsCompleted) {
autosavedetails();
}
}, 2000);
+1 -1
View File
@@ -558,7 +558,7 @@ function SignYourSelf() {
};
useEffect(() => {
const timer = setTimeout(() => {
if (xyPostion?.length > 0) {
if (xyPostion?.length > 0 && !pdfDetails?.[0]?.IsCompleted) {
autosavedetails();
}
}, 2000);
@@ -34,11 +34,13 @@ function DownloadPdfZip(props) {
try {
// Fetch the first PDF (Signed Document)
const docId =
props.isDocId && !pdfDetails?.[0]?.IsEnableOTP
? pdfDetails?.[0]?.objectId
: "";
const signedUrl = await getSignedUrl(pdfUrl, docId);
const docId = pdfDetails?.[0]?.objectId || "";
const isFileAdapter = pdfDetails?.[0]?.IsFileAdapter
? pdfDetails?.[0]?.IsFileAdapter
: false;
console.log("pdfDetails?.[0] ", pdfDetails?.[0]);
const signedUrl = await getSignedUrl(pdfUrl, docId, isFileAdapter);
console.log("signedUrl ", signedUrl);
const pdf1Response = await fetch(signedUrl);
if (!pdf1Response.ok) {
throw new Error(`Failed to fetch PDF: ${signedUrl}`);
@@ -671,12 +671,21 @@ const ReportTable = (props) => {
const url = item?.SignedUrl || item?.URL || "";
const pdfName = item?.Name || "exported_file";
const isCompleted = item?.IsCompleted || false;
const templateId = props?.ReportName === "Templates" && item.objectId;
const docId = props?.ReportName !== "Templates" && item.objectId;
const isFileAdapter = item?.IsFileAdapter ? item?.IsFileAdapter : false;
if (url) {
try {
if (isCompleted) {
setIsDownloadModal({ [item.objectId]: true });
} else {
const signedUrl = await getSignedUrl(url);
const signedUrl = await getSignedUrl(
url,
docId,
isFileAdapter,
templateId
);
await fetchUrl(signedUrl, pdfName);
}
setActLoader({});