From fbbd3535a797e17589eaa5a85dbe5399c1fb5327 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Tue, 7 Jan 2025 12:25:19 +0530
Subject: [PATCH 01/26] Implement multiple File uploading

---
 src/hooks/useFileUpload.tsx                   | 41 ++++++++++++++++++-
 .../Encounters/tabs/EncounterFilesTab.tsx     |  9 +++-
 2 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index d8aea1fa1b1..d570e164dbb 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -1,6 +1,7 @@
 import { useMutation, useQueryClient } from "@tanstack/react-query";
 import imageCompression from "browser-image-compression";
 import { t } from "i18next";
+import jsPDF from "jspdf";
 import {
   ChangeEvent,
   DetailedHTMLProps,
@@ -97,6 +98,33 @@ export default function useFileUpload(
   const [files, setFiles] = useState<File[]>([]);
   const queryClient = useQueryClient();
 
+  const generatePDF = async (files: File[]): Promise<File | null> => {
+    try {
+      const pdf = new jsPDF();
+      for (const [index, file] of files.entries()) {
+        const imgData = await new Promise<string>((resolve, reject) => {
+          const reader = new FileReader();
+          reader.onload = () => resolve(reader.result as string);
+          reader.onerror = () => reject("Error reading file");
+          reader.readAsDataURL(file);
+        });
+
+        pdf.addImage(imgData, "JPEG", 10, 10, 190, 0);
+        if (index < files.length - 1) pdf.addPage();
+      }
+
+      const pdfBlob = pdf.output("blob");
+      const pdfFile = new File([pdfBlob], "combined.pdf", {
+        type: "application/pdf",
+      });
+
+      console.log("Generated PDF file:", pdfFile); // Log the generated file
+      return pdfFile;
+    } catch (error) {
+      console.error("Error generating PDF:", error);
+      return null;
+    }
+  };
   const onFileChange = (e: ChangeEvent<HTMLInputElement>): any => {
     if (!e.target.files?.length) {
       return;
@@ -238,8 +266,19 @@ export default function useFileUpload(
     if (!validateFileUpload()) return;
 
     setProgress(0);
+    let filesToUpload = files;
+
+    if (files.length > 1) {
+      const pdfFile = await generatePDF(files);
+      if (pdfFile) {
+        filesToUpload = [pdfFile];
+      } else {
+        console.error("Failed to generate PDF from multiple files.");
+        return;
+      }
+    }
 
-    for (const [index, file] of files.entries()) {
+    for (const [index, file] of filesToUpload.entries()) {
       const filename =
         allowNameFallback && uploadFileNames[index] === "" && file
           ? file.name
diff --git a/src/pages/Encounters/tabs/EncounterFilesTab.tsx b/src/pages/Encounters/tabs/EncounterFilesTab.tsx
index 053637b75d8..8d979bc912e 100644
--- a/src/pages/Encounters/tabs/EncounterFilesTab.tsx
+++ b/src/pages/Encounters/tabs/EncounterFilesTab.tsx
@@ -136,6 +136,7 @@ export const EncounterFilesTab = (props: EncounterTabProps) => {
     ],
     allowNameFallback: false,
     onUpload: () => refetch(),
+    multiple: true,
   });
 
   useEffect(() => {
@@ -543,8 +544,12 @@ const FileUploadDialog = ({
         </DialogHeader>
         <div className="mb-1 flex items-center justify-between gap-2 rounded-md bg-secondary-300 px-4 py-2">
           <span>
-            <CareIcon icon="l-paperclip" className="mr-2" />
-            {fileUpload.files?.[0]?.name}
+            {fileUpload.files?.map((file, index) => (
+              <div key={index} className="flex items-center mb-2">
+                <CareIcon icon="l-paperclip" className="mr-2" />
+                {file.name}
+              </div>
+            ))}
           </span>
         </div>
         <TextFormField

From f1364650a0daa2ecc97e020c236159508e258f09 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Tue, 7 Jan 2025 12:32:57 +0530
Subject: [PATCH 02/26] Added jspdf to package.json

---
 package-lock.json | 146 +++++++++++++++++++++++++++++++++++++++++++++-
 package.json      |   1 +
 2 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index aae20921b8a..7d8532b6234 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -63,6 +63,7 @@
         "i18next-browser-languagedetector": "^8.0.2",
         "i18next-http-backend": "^3.0.1",
         "input-otp": "^1.4.1",
+        "jspdf": "^2.5.2",
         "lodash-es": "^4.17.21",
         "lucide-react": "^0.469.0",
         "markdown-it": "^14.1.0",
@@ -146,8 +147,8 @@
         "node": ">=22.8.0"
       },
       "optionalDependencies": {
-        "@esbuild/linux-arm64": "*",
-        "@esbuild/linux-x64": "*",
+        "@esbuild/linux-arm64": "latest",
+        "@esbuild/linux-x64": "latest",
         "@rollup/rollup-linux-arm64-gnu": "4.29.1",
         "@rollup/rollup-linux-x64-gnu": "4.29.1"
       }
@@ -6729,6 +6730,13 @@
       "devOptional": true,
       "license": "MIT"
     },
+    "node_modules/@types/raf": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
+      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
+      "license": "MIT",
+      "optional": true
+    },
     "node_modules/@types/react": {
       "version": "18.3.18",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
@@ -7613,6 +7621,18 @@
         "node": ">= 4.0.0"
       }
     },
+    "node_modules/atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "license": "(MIT OR Apache-2.0)",
+      "bin": {
+        "atob": "bin/atob.js"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
     "node_modules/autoprefixer": {
       "version": "10.4.20",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
@@ -7938,6 +7958,18 @@
         "browserslist": ">=4.0.0"
       }
     },
+    "node_modules/btoa": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
+      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
+      "license": "(MIT OR Apache-2.0)",
+      "bin": {
+        "btoa": "bin/btoa.js"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
     "node_modules/buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -8107,6 +8139,33 @@
         "node": ">=6"
       }
     },
+    "node_modules/canvg": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
+      "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@babel/runtime": "^7.12.5",
+        "@types/raf": "^3.4.0",
+        "core-js": "^3.8.3",
+        "raf": "^3.4.1",
+        "regenerator-runtime": "^0.13.7",
+        "rgbcolor": "^1.0.1",
+        "stackblur-canvas": "^2.0.0",
+        "svg-pathdata": "^6.0.3"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/canvg/node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "license": "MIT",
+      "optional": true
+    },
     "node_modules/caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -8546,6 +8605,18 @@
         "toggle-selection": "^1.0.6"
       }
     },
+    "node_modules/core-js": {
+      "version": "3.39.0",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz",
+      "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
     "node_modules/core-js-compat": {
       "version": "3.39.0",
       "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz",
@@ -10711,6 +10782,12 @@
         "pend": "~1.2.0"
       }
     },
+    "node_modules/fflate": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
+      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
+      "license": "MIT"
+    },
     "node_modules/figures": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -12884,6 +12961,31 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/jspdf": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz",
+      "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.23.2",
+        "atob": "^2.1.2",
+        "btoa": "^1.2.1",
+        "fflate": "^0.8.1"
+      },
+      "optionalDependencies": {
+        "canvg": "^3.0.6",
+        "core-js": "^3.6.0",
+        "dompurify": "^2.5.4",
+        "html2canvas": "^1.0.0-rc.5"
+      }
+    },
+    "node_modules/jspdf/node_modules/dompurify": {
+      "version": "2.5.8",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz",
+      "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
+      "license": "(MPL-2.0 OR Apache-2.0)",
+      "optional": true
+    },
     "node_modules/jsprim": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
@@ -17003,6 +17105,16 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/raf": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "performance-now": "^2.1.0"
+      }
+    },
     "node_modules/raf-schd": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
@@ -18017,6 +18129,16 @@
       "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
       "license": "MIT"
     },
+    "node_modules/rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.8.15"
+      }
+    },
     "node_modules/rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -18842,6 +18964,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/stackblur-canvas": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
+      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.1.14"
+      }
+    },
     "node_modules/stop-iteration-iterator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -19298,6 +19430,16 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/svg-pathdata": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/symbol-tree": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
diff --git a/package.json b/package.json
index e66c7f8a6aa..9d18368f6a1 100644
--- a/package.json
+++ b/package.json
@@ -101,6 +101,7 @@
     "i18next-browser-languagedetector": "^8.0.2",
     "i18next-http-backend": "^3.0.1",
     "input-otp": "^1.4.1",
+    "jspdf": "^2.5.2",
     "lodash-es": "^4.17.21",
     "lucide-react": "^0.469.0",
     "markdown-it": "^14.1.0",

From 21cd51d451bf0af1e437119c7ce60d664da4949c Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Tue, 7 Jan 2025 12:25:19 +0530
Subject: [PATCH 03/26] Implement multiple File uploading

---
 src/hooks/useFileUpload.tsx                   | 41 ++++++++++++++++++-
 .../Encounters/tabs/EncounterFilesTab.tsx     |  9 +++-
 2 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index d8aea1fa1b1..d570e164dbb 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -1,6 +1,7 @@
 import { useMutation, useQueryClient } from "@tanstack/react-query";
 import imageCompression from "browser-image-compression";
 import { t } from "i18next";
+import jsPDF from "jspdf";
 import {
   ChangeEvent,
   DetailedHTMLProps,
@@ -97,6 +98,33 @@ export default function useFileUpload(
   const [files, setFiles] = useState<File[]>([]);
   const queryClient = useQueryClient();
 
+  const generatePDF = async (files: File[]): Promise<File | null> => {
+    try {
+      const pdf = new jsPDF();
+      for (const [index, file] of files.entries()) {
+        const imgData = await new Promise<string>((resolve, reject) => {
+          const reader = new FileReader();
+          reader.onload = () => resolve(reader.result as string);
+          reader.onerror = () => reject("Error reading file");
+          reader.readAsDataURL(file);
+        });
+
+        pdf.addImage(imgData, "JPEG", 10, 10, 190, 0);
+        if (index < files.length - 1) pdf.addPage();
+      }
+
+      const pdfBlob = pdf.output("blob");
+      const pdfFile = new File([pdfBlob], "combined.pdf", {
+        type: "application/pdf",
+      });
+
+      console.log("Generated PDF file:", pdfFile); // Log the generated file
+      return pdfFile;
+    } catch (error) {
+      console.error("Error generating PDF:", error);
+      return null;
+    }
+  };
   const onFileChange = (e: ChangeEvent<HTMLInputElement>): any => {
     if (!e.target.files?.length) {
       return;
@@ -238,8 +266,19 @@ export default function useFileUpload(
     if (!validateFileUpload()) return;
 
     setProgress(0);
+    let filesToUpload = files;
+
+    if (files.length > 1) {
+      const pdfFile = await generatePDF(files);
+      if (pdfFile) {
+        filesToUpload = [pdfFile];
+      } else {
+        console.error("Failed to generate PDF from multiple files.");
+        return;
+      }
+    }
 
-    for (const [index, file] of files.entries()) {
+    for (const [index, file] of filesToUpload.entries()) {
       const filename =
         allowNameFallback && uploadFileNames[index] === "" && file
           ? file.name
diff --git a/src/pages/Encounters/tabs/EncounterFilesTab.tsx b/src/pages/Encounters/tabs/EncounterFilesTab.tsx
index 053637b75d8..8d979bc912e 100644
--- a/src/pages/Encounters/tabs/EncounterFilesTab.tsx
+++ b/src/pages/Encounters/tabs/EncounterFilesTab.tsx
@@ -136,6 +136,7 @@ export const EncounterFilesTab = (props: EncounterTabProps) => {
     ],
     allowNameFallback: false,
     onUpload: () => refetch(),
+    multiple: true,
   });
 
   useEffect(() => {
@@ -543,8 +544,12 @@ const FileUploadDialog = ({
         </DialogHeader>
         <div className="mb-1 flex items-center justify-between gap-2 rounded-md bg-secondary-300 px-4 py-2">
           <span>
-            <CareIcon icon="l-paperclip" className="mr-2" />
-            {fileUpload.files?.[0]?.name}
+            {fileUpload.files?.map((file, index) => (
+              <div key={index} className="flex items-center mb-2">
+                <CareIcon icon="l-paperclip" className="mr-2" />
+                {file.name}
+              </div>
+            ))}
           </span>
         </div>
         <TextFormField

From a757ad57f797c20a5d64231903e0b9bf0ca85e38 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Tue, 7 Jan 2025 12:32:57 +0530
Subject: [PATCH 04/26] Added jspdf to package.json

---
 package-lock.json | 148 +++++++++++++++++++++++++++++++++++++++++++++-
 package.json      |   3 +-
 2 files changed, 147 insertions(+), 4 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index edfd7250ef1..f5a9e517dc0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -62,7 +62,8 @@
         "i18next": "^24.2.1",
         "i18next-browser-languagedetector": "^8.0.2",
         "i18next-http-backend": "^3.0.1",
-        "input-otp": "^1.4.2",
+        "input-otp": "^1.4.1",
+        "jspdf": "^2.5.2",
         "lodash-es": "^4.17.21",
         "lucide-react": "^0.469.0",
         "markdown-it": "^14.1.0",
@@ -146,8 +147,8 @@
         "node": ">=22.8.0"
       },
       "optionalDependencies": {
-        "@esbuild/linux-arm64": "*",
-        "@esbuild/linux-x64": "*",
+        "@esbuild/linux-arm64": "latest",
+        "@esbuild/linux-x64": "latest",
         "@rollup/rollup-linux-arm64-gnu": "4.29.1",
         "@rollup/rollup-linux-x64-gnu": "4.29.1"
       }
@@ -6729,6 +6730,13 @@
       "devOptional": true,
       "license": "MIT"
     },
+    "node_modules/@types/raf": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
+      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
+      "license": "MIT",
+      "optional": true
+    },
     "node_modules/@types/react": {
       "version": "18.3.18",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
@@ -7613,6 +7621,18 @@
         "node": ">= 4.0.0"
       }
     },
+    "node_modules/atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "license": "(MIT OR Apache-2.0)",
+      "bin": {
+        "atob": "bin/atob.js"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
     "node_modules/autoprefixer": {
       "version": "10.4.20",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
@@ -7938,6 +7958,18 @@
         "browserslist": ">=4.0.0"
       }
     },
+    "node_modules/btoa": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
+      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
+      "license": "(MIT OR Apache-2.0)",
+      "bin": {
+        "btoa": "bin/btoa.js"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
     "node_modules/buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -8107,6 +8139,33 @@
         "node": ">=6"
       }
     },
+    "node_modules/canvg": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
+      "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@babel/runtime": "^7.12.5",
+        "@types/raf": "^3.4.0",
+        "core-js": "^3.8.3",
+        "raf": "^3.4.1",
+        "regenerator-runtime": "^0.13.7",
+        "rgbcolor": "^1.0.1",
+        "stackblur-canvas": "^2.0.0",
+        "svg-pathdata": "^6.0.3"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/canvg/node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "license": "MIT",
+      "optional": true
+    },
     "node_modules/caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -8546,6 +8605,18 @@
         "toggle-selection": "^1.0.6"
       }
     },
+    "node_modules/core-js": {
+      "version": "3.39.0",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz",
+      "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
     "node_modules/core-js-compat": {
       "version": "3.39.0",
       "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz",
@@ -10711,6 +10782,12 @@
         "pend": "~1.2.0"
       }
     },
+    "node_modules/fflate": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
+      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
+      "license": "MIT"
+    },
     "node_modules/figures": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -12884,6 +12961,31 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/jspdf": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz",
+      "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.23.2",
+        "atob": "^2.1.2",
+        "btoa": "^1.2.1",
+        "fflate": "^0.8.1"
+      },
+      "optionalDependencies": {
+        "canvg": "^3.0.6",
+        "core-js": "^3.6.0",
+        "dompurify": "^2.5.4",
+        "html2canvas": "^1.0.0-rc.5"
+      }
+    },
+    "node_modules/jspdf/node_modules/dompurify": {
+      "version": "2.5.8",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz",
+      "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
+      "license": "(MPL-2.0 OR Apache-2.0)",
+      "optional": true
+    },
     "node_modules/jsprim": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
@@ -17003,6 +17105,16 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/raf": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "performance-now": "^2.1.0"
+      }
+    },
     "node_modules/raf-schd": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
@@ -18017,6 +18129,16 @@
       "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
       "license": "MIT"
     },
+    "node_modules/rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.8.15"
+      }
+    },
     "node_modules/rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -18842,6 +18964,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/stackblur-canvas": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
+      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.1.14"
+      }
+    },
     "node_modules/stop-iteration-iterator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -19298,6 +19430,16 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/svg-pathdata": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/symbol-tree": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
diff --git a/package.json b/package.json
index cd0f1948a36..3ae8a1761a9 100644
--- a/package.json
+++ b/package.json
@@ -100,7 +100,8 @@
     "i18next": "^24.2.1",
     "i18next-browser-languagedetector": "^8.0.2",
     "i18next-http-backend": "^3.0.1",
-    "input-otp": "^1.4.2",
+    "input-otp": "^1.4.1",
+    "jspdf": "^2.5.2",
     "lodash-es": "^4.17.21",
     "lucide-react": "^0.469.0",
     "markdown-it": "^14.1.0",

From 1dbf18f075c8e2b85592e15d5b897f1cbaec0506 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 11 Jan 2025 14:08:31 +0530
Subject: [PATCH 05/26] Add jspdf to package.json

---
 package-lock.json | 146 +++++++++++++++++++++++++++++++++++++++++++++-
 package.json      |   1 +
 2 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index edfd7250ef1..25b3b0c7e12 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -63,6 +63,7 @@
         "i18next-browser-languagedetector": "^8.0.2",
         "i18next-http-backend": "^3.0.1",
         "input-otp": "^1.4.2",
+        "jspdf": "^2.5.2",
         "lodash-es": "^4.17.21",
         "lucide-react": "^0.469.0",
         "markdown-it": "^14.1.0",
@@ -146,8 +147,8 @@
         "node": ">=22.8.0"
       },
       "optionalDependencies": {
-        "@esbuild/linux-arm64": "*",
-        "@esbuild/linux-x64": "*",
+        "@esbuild/linux-arm64": "latest",
+        "@esbuild/linux-x64": "latest",
         "@rollup/rollup-linux-arm64-gnu": "4.29.1",
         "@rollup/rollup-linux-x64-gnu": "4.29.1"
       }
@@ -6729,6 +6730,13 @@
       "devOptional": true,
       "license": "MIT"
     },
+    "node_modules/@types/raf": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
+      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
+      "license": "MIT",
+      "optional": true
+    },
     "node_modules/@types/react": {
       "version": "18.3.18",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
@@ -7613,6 +7621,18 @@
         "node": ">= 4.0.0"
       }
     },
+    "node_modules/atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "license": "(MIT OR Apache-2.0)",
+      "bin": {
+        "atob": "bin/atob.js"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
     "node_modules/autoprefixer": {
       "version": "10.4.20",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
@@ -7938,6 +7958,18 @@
         "browserslist": ">=4.0.0"
       }
     },
+    "node_modules/btoa": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
+      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
+      "license": "(MIT OR Apache-2.0)",
+      "bin": {
+        "btoa": "bin/btoa.js"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
     "node_modules/buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -8107,6 +8139,33 @@
         "node": ">=6"
       }
     },
+    "node_modules/canvg": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
+      "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@babel/runtime": "^7.12.5",
+        "@types/raf": "^3.4.0",
+        "core-js": "^3.8.3",
+        "raf": "^3.4.1",
+        "regenerator-runtime": "^0.13.7",
+        "rgbcolor": "^1.0.1",
+        "stackblur-canvas": "^2.0.0",
+        "svg-pathdata": "^6.0.3"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/canvg/node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "license": "MIT",
+      "optional": true
+    },
     "node_modules/caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -8546,6 +8605,18 @@
         "toggle-selection": "^1.0.6"
       }
     },
+    "node_modules/core-js": {
+      "version": "3.40.0",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz",
+      "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
     "node_modules/core-js-compat": {
       "version": "3.39.0",
       "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz",
@@ -10711,6 +10782,12 @@
         "pend": "~1.2.0"
       }
     },
+    "node_modules/fflate": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
+      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
+      "license": "MIT"
+    },
     "node_modules/figures": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -12884,6 +12961,31 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/jspdf": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz",
+      "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.23.2",
+        "atob": "^2.1.2",
+        "btoa": "^1.2.1",
+        "fflate": "^0.8.1"
+      },
+      "optionalDependencies": {
+        "canvg": "^3.0.6",
+        "core-js": "^3.6.0",
+        "dompurify": "^2.5.4",
+        "html2canvas": "^1.0.0-rc.5"
+      }
+    },
+    "node_modules/jspdf/node_modules/dompurify": {
+      "version": "2.5.8",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz",
+      "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
+      "license": "(MPL-2.0 OR Apache-2.0)",
+      "optional": true
+    },
     "node_modules/jsprim": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
@@ -17003,6 +17105,16 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/raf": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "performance-now": "^2.1.0"
+      }
+    },
     "node_modules/raf-schd": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
@@ -18017,6 +18129,16 @@
       "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
       "license": "MIT"
     },
+    "node_modules/rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.8.15"
+      }
+    },
     "node_modules/rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -18842,6 +18964,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/stackblur-canvas": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
+      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.1.14"
+      }
+    },
     "node_modules/stop-iteration-iterator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -19298,6 +19430,16 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/svg-pathdata": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/symbol-tree": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
diff --git a/package.json b/package.json
index cd0f1948a36..bfe88062249 100644
--- a/package.json
+++ b/package.json
@@ -101,6 +101,7 @@
     "i18next-browser-languagedetector": "^8.0.2",
     "i18next-http-backend": "^3.0.1",
     "input-otp": "^1.4.2",
+    "jspdf": "^2.5.2",
     "lodash-es": "^4.17.21",
     "lucide-react": "^0.469.0",
     "markdown-it": "^14.1.0",

From ece5d709aca5783ad669ae064de7e10398c929ca Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 11 Jan 2025 14:13:11 +0530
Subject: [PATCH 06/26] resolve package-lock.json

---
 package-lock.json | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 10343c4edc1..b3e4b75b088 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -147,10 +147,8 @@
         "node": ">=22.8.0"
       },
       "optionalDependencies": {
-        "@esbuild/linux-arm64": "latest",
-        "@esbuild/linux-x64": "latest",
-        "@esbuild/linux-arm64": "latest",
-        "@esbuild/linux-x64": "latest",
+        "@esbuild/linux-arm64": "*",
+        "@esbuild/linux-x64": "*",
         "@rollup/rollup-linux-arm64-gnu": "4.29.1",
         "@rollup/rollup-linux-x64-gnu": "4.29.1"
       }

From 8014bf81187e6904235ab339789737c3fb418841 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 11 Jan 2025 15:28:15 +0530
Subject: [PATCH 07/26] Remove duplicates package-lock.json

---
 package-lock.json | 130 ----------------------------------------------
 package.json      |   2 +-
 2 files changed, 1 insertion(+), 131 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 48d61f2960c..ecfddcb61af 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,7 +38,6 @@
         "@radix-ui/react-tabs": "^1.1.1",
         "@radix-ui/react-toast": "^1.2.4",
         "@radix-ui/react-tooltip": "^1.1.6",
-        "@rollup/rollup-linux-x64-gnu": "4.30.1",
         "@sentry/browser": "^8.48.0",
         "@tanstack/react-query": "^5.62.8",
         "@tanstack/react-query-devtools": "^5.63.0",
@@ -6736,13 +6735,6 @@
       "license": "MIT",
       "optional": true
     },
-    "node_modules/@types/raf": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
-      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
-      "license": "MIT",
-      "optional": true
-    },
     "node_modules/@types/react": {
       "version": "18.3.18",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
@@ -7639,18 +7631,6 @@
         "node": ">= 4.5.0"
       }
     },
-    "node_modules/atob": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
-      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
-      "license": "(MIT OR Apache-2.0)",
-      "bin": {
-        "atob": "bin/atob.js"
-      },
-      "engines": {
-        "node": ">= 4.5.0"
-      }
-    },
     "node_modules/autoprefixer": {
       "version": "10.4.20",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
@@ -7988,18 +7968,6 @@
         "node": ">= 0.4.0"
       }
     },
-    "node_modules/btoa": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
-      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
-      "license": "(MIT OR Apache-2.0)",
-      "bin": {
-        "btoa": "bin/btoa.js"
-      },
-      "engines": {
-        "node": ">= 0.4.0"
-      }
-    },
     "node_modules/buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -8196,33 +8164,6 @@
       "license": "MIT",
       "optional": true
     },
-    "node_modules/canvg": {
-      "version": "3.0.10",
-      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
-      "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@babel/runtime": "^7.12.5",
-        "@types/raf": "^3.4.0",
-        "core-js": "^3.8.3",
-        "raf": "^3.4.1",
-        "regenerator-runtime": "^0.13.7",
-        "rgbcolor": "^1.0.1",
-        "stackblur-canvas": "^2.0.0",
-        "svg-pathdata": "^6.0.3"
-      },
-      "engines": {
-        "node": ">=10.0.0"
-      }
-    },
-    "node_modules/canvg/node_modules/regenerator-runtime": {
-      "version": "0.13.11",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
-      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
-      "license": "MIT",
-      "optional": true
-    },
     "node_modules/caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -10845,12 +10786,6 @@
       "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
       "license": "MIT"
     },
-    "node_modules/fflate": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
-      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
-      "license": "MIT"
-    },
     "node_modules/figures": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -13049,31 +12984,6 @@
       "license": "(MPL-2.0 OR Apache-2.0)",
       "optional": true
     },
-    "node_modules/jspdf": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz",
-      "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.23.2",
-        "atob": "^2.1.2",
-        "btoa": "^1.2.1",
-        "fflate": "^0.8.1"
-      },
-      "optionalDependencies": {
-        "canvg": "^3.0.6",
-        "core-js": "^3.6.0",
-        "dompurify": "^2.5.4",
-        "html2canvas": "^1.0.0-rc.5"
-      }
-    },
-    "node_modules/jspdf/node_modules/dompurify": {
-      "version": "2.5.8",
-      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz",
-      "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
-      "license": "(MPL-2.0 OR Apache-2.0)",
-      "optional": true
-    },
     "node_modules/jsprim": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
@@ -17203,16 +17113,6 @@
         "performance-now": "^2.1.0"
       }
     },
-    "node_modules/raf": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
-      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "performance-now": "^2.1.0"
-      }
-    },
     "node_modules/raf-schd": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
@@ -18237,16 +18137,6 @@
         "node": ">= 0.8.15"
       }
     },
-    "node_modules/rgbcolor": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
-      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
-      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
-      "optional": true,
-      "engines": {
-        "node": ">= 0.8.15"
-      }
-    },
     "node_modules/rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -19108,16 +18998,6 @@
         "node": ">=0.1.14"
       }
     },
-    "node_modules/stackblur-canvas": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
-      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
-      "license": "MIT",
-      "optional": true,
-      "engines": {
-        "node": ">=0.1.14"
-      }
-    },
     "node_modules/stop-iteration-iterator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -19584,16 +19464,6 @@
         "node": ">=12.0.0"
       }
     },
-    "node_modules/svg-pathdata": {
-      "version": "6.0.3",
-      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
-      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
-      "license": "MIT",
-      "optional": true,
-      "engines": {
-        "node": ">=12.0.0"
-      }
-    },
     "node_modules/symbol-tree": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
diff --git a/package.json b/package.json
index f90ac36fb69..49648689311 100644
--- a/package.json
+++ b/package.json
@@ -213,4 +213,4 @@
     "node": ">=22.8.0"
   },
   "packageManager": "npm@10.9.0"
-}
\ No newline at end of file
+}

From 74186e60005341fe4eb08cc5015bac7a21f9d2c1 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 11 Jan 2025 15:31:32 +0530
Subject: [PATCH 08/26] remove extra space package.json

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 49648689311..f90ac36fb69 100644
--- a/package.json
+++ b/package.json
@@ -213,4 +213,4 @@
     "node": ">=22.8.0"
   },
   "packageManager": "npm@10.9.0"
-}
+}
\ No newline at end of file

From 18bb454bb1534f4524037d4177399e2a392422d4 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 11 Jan 2025 15:33:02 +0530
Subject: [PATCH 09/26] package-lock.json mistake solved

---
 package-lock.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/package-lock.json b/package-lock.json
index ecfddcb61af..ee7896e955d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,6 +38,7 @@
         "@radix-ui/react-tabs": "^1.1.1",
         "@radix-ui/react-toast": "^1.2.4",
         "@radix-ui/react-tooltip": "^1.1.6",
+        "@rollup/rollup-linux-x64-gnu": "4.30.1",
         "@sentry/browser": "^8.48.0",
         "@tanstack/react-query": "^5.62.8",
         "@tanstack/react-query-devtools": "^5.63.0",

From 127acde0fcb1ca81eafd21df95199d0b351c7968 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Thu, 16 Jan 2025 21:58:11 +0530
Subject: [PATCH 10/26] Add PDF combination feature to file upload

---
 public/locale/en.json             |  1 +
 src/components/Files/FilesTab.tsx | 18 ++++++++++++++++++
 src/hooks/useFileUpload.tsx       | 13 ++++++++++++-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/public/locale/en.json b/public/locale/en.json
index 65a010592db..589a52e412a 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -588,6 +588,7 @@
   "close": "Close",
   "close_scanner": "Close Scanner",
   "collapse_sidebar": "Collapse Sidebar",
+  "combine_files_pdf": "Combine Files To PDF",
   "comment_added_successfully": "Comment added successfully",
   "comment_min_length": "Comment Should Contain At Least 1 Character",
   "comments": "Comments",
diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index fadb4358883..485475ea403 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -66,6 +66,7 @@ export const FilesTab = (props: FilesTabProps) => {
   });
   const { t } = useTranslation();
   const [openUploadDialog, setOpenUploadDialog] = useState(false);
+  const [isPdf, setIsPdf] = useState(false);
   const [selectedAudioFile, setSelectedAudioFile] =
     useState<FileUploadModel | null>(null);
   const [openAudioPlayerDialog, setOpenAudioPlayerDialog] = useState(false);
@@ -126,6 +127,7 @@ export const FilesTab = (props: FilesTabProps) => {
   const fileUpload = useFileUpload({
     type: type,
     multiple: true,
+    CombineToPDF: isPdf,
     allowedExtensions: [
       "jpg",
       "jpeg",
@@ -360,6 +362,22 @@ export const FilesTab = (props: FilesTabProps) => {
             </label>
             {fileUpload.Input({ className: "hidden" })}
           </DropdownMenuItem>
+          <DropdownMenuItem
+            className="flex flex-row items-center"
+            onSelect={(e) => {
+              e.preventDefault();
+              setIsPdf(true);
+            }}
+          >
+            <label
+              htmlFor="file_upload_patient"
+              className="flex flex-row items-center cursor-pointer text-primary-900 font-normal w-full"
+            >
+              <CareIcon icon="l-file-upload-alt" className="mr-1" />
+              <span>{t("combine_files_pdf")}</span>
+            </label>
+            {fileUpload.Input({ className: "hidden" })}
+          </DropdownMenuItem>
           <DropdownMenuItem className="flex flex-row items-center text-primary-900">
             <button
               onClick={() => fileUpload.handleCameraCapture()}
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 804ef036100..c93d68a8832 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -29,6 +29,7 @@ export type FileUploadOptions = {
   multiple?: boolean;
   type: string;
   category?: FileCategory;
+  CombineToPDF?: boolean;
   onUpload?: (file: FileUploadModel) => void;
   // if allowed, will fallback to the name of the file if a seperate filename is not defined.
   allowNameFallback?: boolean;
@@ -86,6 +87,7 @@ export default function useFileUpload(
     category = "unspecified",
     multiple,
     allowNameFallback = true,
+    CombineToPDF,
   } = options;
 
   const [uploadFileNames, setUploadFileNames] = useState<string[]>([]);
@@ -281,7 +283,16 @@ export default function useFileUpload(
     setProgress(0);
     const errors: File[] = [];
 
-    for (const [index, file] of filesToUpload.entries()) {
+    if (CombineToPDF && files.length > 1) {
+      const pdfFile = await generatePDF(files);
+      if (pdfFile) {
+        files.splice(0, files.length, pdfFile);
+      } else {
+        console.error("Failed to generate PDF from multiple files.");
+        return;
+      }
+    }
+    for (const [index, file] of files.entries()) {
       const filename =
         allowNameFallback && uploadFileNames[index] === "" && file
           ? file.name

From 14d397fd0aa8e490984559cd778b107b796ac76c Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 18 Jan 2025 15:03:46 +0530
Subject: [PATCH 11/26] Add error handling for PDF generation + Reset isPdf
 wherever necessary

---
 public/locale/en.json             |  1 +
 src/components/Files/FilesTab.tsx | 59 +++++++++++++++++--------------
 src/hooks/useFileUpload.tsx       |  5 ++-
 3 files changed, 38 insertions(+), 27 deletions(-)

diff --git a/public/locale/en.json b/public/locale/en.json
index 589a52e412a..f4d2fb0d4ee 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -1025,6 +1025,7 @@
   "file_error__file_name": "Please give a name for all files!",
   "file_error__file_size": "Maximum size of files is 100 MB",
   "file_error__file_type": "Invalid file type \".{{extension}}\" Allowed types: {{allowedExtensions}}",
+  "file_error__generate_pdf": "Failed to generate PDF",
   "file_error__mark_complete_failed": "Error while marking file upload as complete",
   "file_error__network": "Error Uploading File: Network Error",
   "file_error__single_file_name": "Please give a name for the file",
diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index 485475ea403..e0340e160eb 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -128,33 +128,37 @@ export const FilesTab = (props: FilesTabProps) => {
     type: type,
     multiple: true,
     CombineToPDF: isPdf,
-    allowedExtensions: [
-      "jpg",
-      "jpeg",
-      "png",
-      "gif",
-      "bmp",
-      "tiff",
-      "mp4",
-      "mov",
-      "avi",
-      "wmv",
-      "mp3",
-      "wav",
-      "ogg",
-      "txt",
-      "csv",
-      "rtf",
-      "doc",
-      "odt",
-      "pdf",
-      "xls",
-      "xlsx",
-      "ods",
-      "pdf",
-    ],
+    allowedExtensions: isPdf
+      ? ["jpg", "jpeg", "png"]
+      : [
+          "jpg",
+          "jpeg",
+          "png",
+          "gif",
+          "bmp",
+          "tiff",
+          "mp4",
+          "mov",
+          "avi",
+          "wmv",
+          "mp3",
+          "wav",
+          "ogg",
+          "txt",
+          "csv",
+          "rtf",
+          "doc",
+          "odt",
+          "pdf",
+          "xls",
+          "xlsx",
+          "ods",
+        ],
     allowNameFallback: false,
-    onUpload: () => refetch(),
+    onUpload: () => {
+      refetch();
+      setIsPdf(false);
+    },
   });
 
   useEffect(() => {
@@ -162,12 +166,14 @@ export const FilesTab = (props: FilesTabProps) => {
       setOpenUploadDialog(true);
     } else {
       setOpenUploadDialog(false);
+      setIsPdf(false);
     }
   }, [fileUpload.files]);
 
   useEffect(() => {
     if (!openUploadDialog) {
       fileUpload.clearFiles();
+      setIsPdf(false);
     }
   }, [openUploadDialog]);
 
@@ -350,6 +356,7 @@ export const FilesTab = (props: FilesTabProps) => {
           <DropdownMenuItem
             className="flex flex-row items-center"
             onSelect={(e) => {
+              setIsPdf(false);
               e.preventDefault();
             }}
           >
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index c93d68a8832..52c7b97831e 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -124,6 +124,8 @@ export default function useFileUpload(
       return pdfFile;
     } catch (error) {
       console.error("Error generating PDF:", error);
+      toast.error(t("file_error__generate_pdf"));
+      setError(t("file_error__generate_pdf"));
       return null;
     }
   };
@@ -288,7 +290,8 @@ export default function useFileUpload(
       if (pdfFile) {
         files.splice(0, files.length, pdfFile);
       } else {
-        console.error("Failed to generate PDF from multiple files.");
+        clearFiles();
+        setError(t("file_error__generate_pdf"));
         return;
       }
     }

From f1c77d2a1aea90087fe3beffe5f88e671d37b0c9 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Tue, 21 Jan 2025 16:23:17 +0530
Subject: [PATCH 12/26] Add checkbox For image to pdf conversion.

---
 src/components/Files/FilesTab.tsx | 92 +++++++++++++++----------------
 src/hooks/useFileUpload.tsx       | 17 ++++--
 2 files changed, 56 insertions(+), 53 deletions(-)

diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index e0340e160eb..2e582b121ad 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -66,7 +66,6 @@ export const FilesTab = (props: FilesTabProps) => {
   });
   const { t } = useTranslation();
   const [openUploadDialog, setOpenUploadDialog] = useState(false);
-  const [isPdf, setIsPdf] = useState(false);
   const [selectedAudioFile, setSelectedAudioFile] =
     useState<FileUploadModel | null>(null);
   const [openAudioPlayerDialog, setOpenAudioPlayerDialog] = useState(false);
@@ -127,37 +126,34 @@ export const FilesTab = (props: FilesTabProps) => {
   const fileUpload = useFileUpload({
     type: type,
     multiple: true,
-    CombineToPDF: isPdf,
-    allowedExtensions: isPdf
-      ? ["jpg", "jpeg", "png"]
-      : [
-          "jpg",
-          "jpeg",
-          "png",
-          "gif",
-          "bmp",
-          "tiff",
-          "mp4",
-          "mov",
-          "avi",
-          "wmv",
-          "mp3",
-          "wav",
-          "ogg",
-          "txt",
-          "csv",
-          "rtf",
-          "doc",
-          "odt",
-          "pdf",
-          "xls",
-          "xlsx",
-          "ods",
-        ],
+    allowedExtensions: [
+      "jpg",
+      "jpeg",
+      "png",
+      "gif",
+      "bmp",
+      "tiff",
+      "mp4",
+      "mov",
+      "avi",
+      "wmv",
+      "mp3",
+      "wav",
+      "ogg",
+      "txt",
+      "csv",
+      "rtf",
+      "doc",
+      "odt",
+      "pdf",
+      "xls",
+      "xlsx",
+      "ods",
+      "pdf",
+    ],
     allowNameFallback: false,
     onUpload: () => {
       refetch();
-      setIsPdf(false);
     },
   });
 
@@ -166,14 +162,12 @@ export const FilesTab = (props: FilesTabProps) => {
       setOpenUploadDialog(true);
     } else {
       setOpenUploadDialog(false);
-      setIsPdf(false);
     }
   }, [fileUpload.files]);
 
   useEffect(() => {
     if (!openUploadDialog) {
       fileUpload.clearFiles();
-      setIsPdf(false);
     }
   }, [openUploadDialog]);
 
@@ -356,7 +350,6 @@ export const FilesTab = (props: FilesTabProps) => {
           <DropdownMenuItem
             className="flex flex-row items-center"
             onSelect={(e) => {
-              setIsPdf(false);
               e.preventDefault();
             }}
           >
@@ -369,22 +362,6 @@ export const FilesTab = (props: FilesTabProps) => {
             </label>
             {fileUpload.Input({ className: "hidden" })}
           </DropdownMenuItem>
-          <DropdownMenuItem
-            className="flex flex-row items-center"
-            onSelect={(e) => {
-              e.preventDefault();
-              setIsPdf(true);
-            }}
-          >
-            <label
-              htmlFor="file_upload_patient"
-              className="flex flex-row items-center cursor-pointer text-primary-900 font-normal w-full"
-            >
-              <CareIcon icon="l-file-upload-alt" className="mr-1" />
-              <span>{t("combine_files_pdf")}</span>
-            </label>
-            {fileUpload.Input({ className: "hidden" })}
-          </DropdownMenuItem>
           <DropdownMenuItem className="flex flex-row items-center text-primary-900">
             <button
               onClick={() => fileUpload.handleCameraCapture()}
@@ -594,6 +571,7 @@ const FileUploadDialog = ({
   associatingId: string;
 }) => {
   const { t } = useTranslation();
+  const [isPdf, setIsPdf] = useState(false);
   return (
     <Dialog
       open={open}
@@ -642,10 +620,26 @@ const FileUploadDialog = ({
             </div>
           ))}
         </div>
+        {fileUpload.files.length > 1 && (
+          <div className="flex items-center gap-2 mt-4">
+            <input
+              type="checkbox"
+              id="combine_as_pdf"
+              checked={isPdf}
+              onChange={(e) => setIsPdf(e.target.checked)}
+              disabled={fileUpload.uploading}
+              className="cursor-pointer"
+            />
+            <label htmlFor="file_upload_patient">
+              {t("combine_files_pdf")}
+            </label>
+          </div>
+        )}
+
         <div className="flex items-center gap-2 mt-4">
           <Button
             variant="outline_primary"
-            onClick={() => fileUpload.handleFileUpload(associatingId)}
+            onClick={() => fileUpload.handleFileUpload(associatingId, isPdf)}
             disabled={fileUpload.uploading}
             className="w-full"
             id="upload_file_button"
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 52c7b97831e..7745784f591 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -29,7 +29,6 @@ export type FileUploadOptions = {
   multiple?: boolean;
   type: string;
   category?: FileCategory;
-  CombineToPDF?: boolean;
   onUpload?: (file: FileUploadModel) => void;
   // if allowed, will fallback to the name of the file if a seperate filename is not defined.
   allowNameFallback?: boolean;
@@ -54,7 +53,10 @@ export type FileUploadReturn = {
   validateFiles: () => boolean;
   handleCameraCapture: () => void;
   handleAudioCapture: () => void;
-  handleFileUpload: (associating_id: string) => Promise<void>;
+  handleFileUpload: (
+    associating_id: string,
+    CombineToPDF?: boolean,
+  ) => Promise<void>;
   Dialogues: JSX.Element;
   Input: (_: FileInputProps) => JSX.Element;
   fileNames: string[];
@@ -87,7 +89,6 @@ export default function useFileUpload(
     category = "unspecified",
     multiple,
     allowNameFallback = true,
-    CombineToPDF,
   } = options;
 
   const [uploadFileNames, setUploadFileNames] = useState<string[]>([]);
@@ -104,6 +105,11 @@ export default function useFileUpload(
     try {
       const pdf = new jsPDF();
       for (const [index, file] of files.entries()) {
+        if (!file.type.startsWith("image/")) {
+          console.error(`Unsupported file type: ${file.name}`);
+          toast.error(t("file_error__file_type"));
+          return null;
+        }
         const imgData = await new Promise<string>((resolve, reject) => {
           const reader = new FileReader();
           reader.onload = () => resolve(reader.result as string);
@@ -279,7 +285,10 @@ export default function useFileUpload(
       })(body),
   });
 
-  const handleUpload = async (associating_id: string) => {
+  const handleUpload = async (
+    associating_id: string,
+    CombineToPDF?: boolean,
+  ) => {
     if (!validateFileUpload()) return;
 
     setProgress(0);

From 677fd46dcc3dd0c713915207dbddb0bcf3f2b795 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Wed, 22 Jan 2025 18:22:05 +0530
Subject: [PATCH 13/26] Indicate file conversion progress,replace checkbox
 shadcn

---
 public/locale/en.json             |  2 ++
 src/components/Files/FilesTab.tsx | 10 +++++-----
 src/hooks/useFileUpload.tsx       | 23 +++++++++++------------
 3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/public/locale/en.json b/public/locale/en.json
index f4d2fb0d4ee..61c14aa37bb 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -1017,6 +1017,8 @@
   "fetching": "Fetching",
   "field_required": "This field is required",
   "file_archived_successfully": "File archived successfully",
+  "file_conversion_in_progress": "File conversion in progress",
+  "file_conversion_success": "File conversion successful",
   "file_download_completed": "File download completed",
   "file_download_failed": "Failed to download file",
   "file_download_started": "Downloading file...",
diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index 2e582b121ad..ddda3451747 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -7,6 +7,7 @@ import CareIcon, { IconName } from "@/CAREUI/icons/CareIcon";
 
 import { Badge } from "@/components/ui/badge";
 import { Button } from "@/components/ui/button";
+import { Checkbox } from "@/components/ui/checkbox";
 import {
   Dialog,
   DialogContent,
@@ -622,15 +623,14 @@ const FileUploadDialog = ({
         </div>
         {fileUpload.files.length > 1 && (
           <div className="flex items-center gap-2 mt-4">
-            <input
-              type="checkbox"
-              id="combine_as_pdf"
+            <Checkbox
+              id="file_upload_patient"
               checked={isPdf}
-              onChange={(e) => setIsPdf(e.target.checked)}
+              onCheckedChange={(checked) => setIsPdf(!!checked)}
               disabled={fileUpload.uploading}
               className="cursor-pointer"
             />
-            <label htmlFor="file_upload_patient">
+            <label htmlFor="file_upload_patient" className="cursor-pointer">
               {t("combine_files_pdf")}
             </label>
           </div>
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 7745784f591..210b7902760 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -103,35 +103,34 @@ export default function useFileUpload(
 
   const generatePDF = async (files: File[]): Promise<File | null> => {
     try {
+      toast.info(t("file_conversion_in_progress"));
       const pdf = new jsPDF();
+      const totalFiles = files.length;
+
       for (const [index, file] of files.entries()) {
         if (!file.type.startsWith("image/")) {
-          console.error(`Unsupported file type: ${file.name}`);
           toast.error(t("file_error__file_type"));
+          setProgress(0);
           return null;
         }
-        const imgData = await new Promise<string>((resolve, reject) => {
-          const reader = new FileReader();
-          reader.onload = () => resolve(reader.result as string);
-          reader.onerror = () => reject("Error reading file");
-          reader.readAsDataURL(file);
-        });
-
+        const imgData = URL.createObjectURL(file);
         pdf.addImage(imgData, "JPEG", 10, 10, 190, 0);
+        URL.revokeObjectURL(imgData);
         if (index < files.length - 1) pdf.addPage();
+        const progress = Math.round(((index + 1) / totalFiles) * 100);
+        setProgress(progress);
       }
-
       const pdfBlob = pdf.output("blob");
       const pdfFile = new File([pdfBlob], "combined.pdf", {
         type: "application/pdf",
       });
-
-      console.log("Generated PDF file:", pdfFile); // Log the generated file
+      setProgress(0);
+      toast.success(t("file_conversion_success"));
       return pdfFile;
     } catch (error) {
-      console.error("Error generating PDF:", error);
       toast.error(t("file_error__generate_pdf"));
       setError(t("file_error__generate_pdf"));
+      setProgress(0);
       return null;
     }
   };

From 66ddf425eb97634593ba3634bb4580a9ae9303bf Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Fri, 24 Jan 2025 19:19:54 +0530
Subject: [PATCH 14/26] Seperate Textbox for CombineToPdf and replace textbox
 with  input shadcn

---
 public/locale/en.json             |   1 +
 src/components/Files/FilesTab.tsx | 119 ++++++++++++++++++++++--------
 2 files changed, 88 insertions(+), 32 deletions(-)

diff --git a/public/locale/en.json b/public/locale/en.json
index 61c14aa37bb..9b7868018dc 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -947,6 +947,7 @@
   "enter_aadhaar_otp": "Enter OTP sent to the registered mobile with Aadhaar",
   "enter_abha_address": "Enter ABHA Address",
   "enter_any_id": "Enter any ID linked with your ABHA number",
+  "enter_combined_file_name": "Enter Combined File Name",
   "enter_file_name": "Enter File Name",
   "enter_message": "Start typing...",
   "enter_mobile_number": "Enter Mobile Number",
diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index ddda3451747..d784e96591a 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -20,6 +20,7 @@ import {
   DropdownMenuItem,
   DropdownMenuTrigger,
 } from "@/components/ui/dropdown-menu";
+import { Input } from "@/components/ui/input";
 import { Progress } from "@/components/ui/progress";
 import {
   Table,
@@ -39,7 +40,6 @@ import {
 
 import AudioPlayer from "@/components/Common/AudioPlayer";
 import Loading from "@/components/Common/Loading";
-import TextFormField from "@/components/Form/FormFields/TextFormField";
 import { FileUploadModel } from "@/components/Patient/models";
 
 import useFileManager from "@/hooks/useFileManager";
@@ -571,12 +571,19 @@ const FileUploadDialog = ({
   fileUpload: FileUploadReturn;
   associatingId: string;
 }) => {
+  const handleDialogClose = (open: boolean) => {
+    if (!open) {
+      setIsPdf(false);
+      fileUpload.clearFiles();
+    }
+    onOpenChange(open);
+  };
   const { t } = useTranslation();
   const [isPdf, setIsPdf] = useState(false);
   return (
     <Dialog
       open={open}
-      onOpenChange={onOpenChange}
+      onOpenChange={handleDialogClose}
       aria-labelledby="file-upload-dialog"
     >
       <DialogContent
@@ -589,44 +596,92 @@ const FileUploadDialog = ({
           </DialogTitle>
         </DialogHeader>
         <div className="space-y-4">
-          {fileUpload.files.map((file, index) => (
-            <div key={index} className="space-y-2">
-              <div className="flex items-center justify-between gap-2 rounded-md bg-secondary-300 px-4 py-2">
-                <span className="flex items-center truncate">
-                  <CareIcon icon="l-paperclip" className="mr-2 shrink-0" />
-                  <span className="truncate">{file.name}</span>
-                </span>
-                <Button
-                  variant="ghost"
-                  size="icon"
-                  onClick={() => fileUpload.removeFile(index)}
-                  disabled={fileUpload.uploading}
+          {isPdf ? (
+            <>
+              <div className="space-y-2">
+                <ul className="list-disc list-inside space-y-1">
+                  {fileUpload.files.map((file, index) => (
+                    <li key={index} className="truncate">
+                      {file.name}
+                    </li>
+                  ))}
+                </ul>
+              </div>
+              <div>
+                <label
+                  htmlFor="upload-file-name-0"
+                  className="block text-sm font-medium text-gray-700"
                 >
-                  <CareIcon icon="l-times" />
-                </Button>
+                  {t("enter_combined_file_name")}
+                </label>
+                <Input
+                  name="combined_file_name"
+                  type="text"
+                  id="combined-file-name"
+                  required
+                  value={fileUpload.fileNames[0] || ""}
+                  disabled={fileUpload.uploading}
+                  onChange={(e) => fileUpload.setFileName(e.target.value)}
+                />
+                {fileUpload.error && (
+                  <p className="mt-2 text-sm text-red-600">
+                    {fileUpload.error}
+                  </p>
+                )}
               </div>
-              <TextFormField
-                name={`file_name_${index}`}
-                type="text"
-                label={t("enter_file_name")}
-                id={`upload-file-name-${index}`}
-                required
-                value={fileUpload.fileNames[index] || ""}
-                disabled={fileUpload.uploading}
-                onChange={(e) => fileUpload.setFileName(e.value, index)}
-                error={
-                  index === 0 && fileUpload.error ? fileUpload.error : undefined
-                }
-              />
-            </div>
-          ))}
+            </>
+          ) : (
+            fileUpload.files.map((file, index) => (
+              <div key={index} className="space-y-2">
+                <div className="flex items-center justify-between gap-2 rounded-md bg-secondary-300 px-4 py-2">
+                  <span className="flex items-center truncate">
+                    <CareIcon icon="l-paperclip" className="mr-2 shrink-0" />
+                    <span className="truncate">{file.name}</span>
+                  </span>
+                  <Button
+                    variant="ghost"
+                    size="icon"
+                    onClick={() => fileUpload.removeFile(index)}
+                    disabled={fileUpload.uploading}
+                  >
+                    <CareIcon icon="l-times" />
+                  </Button>
+                </div>
+                <div>
+                  <label
+                    htmlFor={`upload-file-name-${index}`}
+                    className="block text-sm font-medium text-gray-700"
+                  >
+                    {t("enter_file_name")}
+                  </label>
+
+                  <Input
+                    name={`file_name_${index}`}
+                    type="text"
+                    id={`upload-file-name-${index}`}
+                    required
+                    value={fileUpload.fileNames[index] || ""}
+                    disabled={fileUpload.uploading}
+                    onChange={(e) =>
+                      fileUpload.setFileName(e.target.value, index)
+                    }
+                  />
+                  {index === 0 && fileUpload.error && (
+                    <p className="mt-2 text-sm text-red-600">
+                      {fileUpload.error}
+                    </p>
+                  )}
+                </div>
+              </div>
+            ))
+          )}
         </div>
         {fileUpload.files.length > 1 && (
           <div className="flex items-center gap-2 mt-4">
             <Checkbox
               id="file_upload_patient"
               checked={isPdf}
-              onCheckedChange={(checked) => setIsPdf(!!checked)}
+              onCheckedChange={(checked: boolean) => setIsPdf(checked)}
               disabled={fileUpload.uploading}
               className="cursor-pointer"
             />

From cc6e0d8f7d9e3aba4e23c3f78db6e90df7d363e0 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Fri, 24 Jan 2025 19:35:49 +0530
Subject: [PATCH 15/26] Add missing jspdf dependency

---
 package-lock.json | 54 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/package-lock.json b/package-lock.json
index 72f0c2975ff..a8b104d4a39 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7807,6 +7807,16 @@
         "zxing-wasm": "1.3.4"
       }
     },
+    "node_modules/base64-arraybuffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
     "node_modules/base64-js": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -8747,6 +8757,16 @@
         "tiny-invariant": "^1.0.6"
       }
     },
+    "node_modules/css-line-break": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
     "node_modules/cssesc": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -11788,6 +11808,20 @@
       "integrity": "sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==",
       "license": "MIT"
     },
+    "node_modules/html2canvas": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "css-line-break": "^2.1.0",
+        "text-segmentation": "^1.0.3"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
     "node_modules/http-proxy-agent": {
       "version": "7.0.2",
       "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
@@ -19749,6 +19783,16 @@
       "devOptional": true,
       "license": "MIT"
     },
+    "node_modules/text-segmentation": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
     "node_modules/text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -20754,6 +20798,16 @@
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
       "license": "MIT"
     },
+    "node_modules/utrie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "base64-arraybuffer": "^1.0.2"
+      }
+    },
     "node_modules/uuid": {
       "version": "11.0.3",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz",

From eb5b3c2fc3fc8b962206b10da6635c35949c3f8f Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Fri, 24 Jan 2025 19:48:18 +0530
Subject: [PATCH 16/26] Use Shadcn Label instead or normal label tag

---
 src/components/Files/FilesTab.tsx | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index cb6bdb2e21c..b4c1ea3f7fc 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -355,13 +355,13 @@ export const FilesTab = (props: FilesTabProps) => {
               e.preventDefault();
             }}
           >
-            <label
+            <Label
               htmlFor="file_upload_patient"
               className="flex flex-row items-center cursor-pointer text-primary-900 font-normal w-full"
             >
               <CareIcon icon="l-file-upload-alt" className="mr-1" />
               <span>{t("choose_file")}</span>
-            </label>
+            </Label>
             {fileUpload.Input({ className: "hidden" })}
           </DropdownMenuItem>
           <DropdownMenuItem className="flex flex-row items-center text-primary-900">
@@ -609,12 +609,12 @@ const FileUploadDialog = ({
                 </ul>
               </div>
               <div>
-                <label
+                <Label
                   htmlFor="upload-file-name-0"
                   className="block text-sm font-medium text-gray-700"
                 >
                   {t("enter_combined_file_name")}
-                </label>
+                </Label>
                 <Input
                   name="combined_file_name"
                   type="text"
@@ -649,12 +649,12 @@ const FileUploadDialog = ({
                   </Button>
                 </div>
                 <div>
-                  <label
+                  <Label
                     htmlFor={`upload-file-name-${index}`}
                     className="block text-sm font-medium text-gray-700"
                   >
                     {t("enter_file_name")}
-                  </label>
+                  </Label>
 
                   <Input
                     name={`file_name_${index}`}
@@ -686,9 +686,9 @@ const FileUploadDialog = ({
               disabled={fileUpload.uploading}
               className="cursor-pointer"
             />
-            <label htmlFor="file_upload_patient" className="cursor-pointer">
+            <Label htmlFor="file_upload_patient" className="cursor-pointer">
               {t("combine_files_pdf")}
-            </label>
+            </Label>
           </div>
         )}
 

From e59ef7890b6be3f25b8fcc94d7f30c29e6be673b Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 25 Jan 2025 14:06:08 +0530
Subject: [PATCH 17/26] fix: rename error variable in useFileUpload hook for
 clarity

---
 src/hooks/useFileUpload.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index fa78835daa7..6b71d2fb42b 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -126,7 +126,7 @@ export default function useFileUpload(
       setProgress(0);
       toast.success(t("file_conversion_success"));
       return pdfFile;
-    } catch (error) {
+    } catch (error_) {
       toast.error(t("file_error__generate_pdf"));
       setError(t("file_error__generate_pdf"));
       setProgress(0);

From 84d9bd7649d6c2a088b714b4aeb8497f46be636a Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 25 Jan 2025 14:45:19 +0530
Subject: [PATCH 18/26] Fix Deploy preview failure

---
 src/hooks/useFileUpload.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 6b71d2fb42b..8c354cfb800 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -126,9 +126,9 @@ export default function useFileUpload(
       setProgress(0);
       toast.success(t("file_conversion_success"));
       return pdfFile;
-    } catch (error_) {
+    } catch (error) {
       toast.error(t("file_error__generate_pdf"));
-      setError(t("file_error__generate_pdf"));
+      setError(t("file_error__generate_pdf", { error: String(error) }));
       setProgress(0);
       return null;
     }

From 2bc75745c720f4ef88b5fe07c266f9d4007d1f1f Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Mon, 27 Jan 2025 13:21:47 +0530
Subject: [PATCH 19/26] Add title for tooltip . Revert Changes

---
 public/locale/en.json             |  1 -
 src/components/Files/FilesTab.tsx |  8 ++++----
 src/hooks/useFileUpload.tsx       | 14 ++++++--------
 3 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/public/locale/en.json b/public/locale/en.json
index d03dc3477ea..ed85e87caef 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -971,7 +971,6 @@
   "enter_aadhaar_otp": "Enter OTP sent to the registered mobile with Aadhaar",
   "enter_abha_address": "Enter ABHA Address",
   "enter_any_id": "Enter any ID linked with your ABHA number",
-  "enter_combined_file_name": "Enter Combined File Name",
   "enter_dosage_instructions": "Enter Dosage Instructions",
   "enter_file_name": "Enter File Name",
   "enter_message": "Start typing...",
diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index b4c1ea3f7fc..4d41cedf66c 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -602,7 +602,7 @@ const FileUploadDialog = ({
               <div className="space-y-2">
                 <ul className="list-disc list-inside space-y-1">
                   {fileUpload.files.map((file, index) => (
-                    <li key={index} className="truncate">
+                    <li key={index} className="truncate" title={file.name}>
                       {file.name}
                     </li>
                   ))}
@@ -613,12 +613,12 @@ const FileUploadDialog = ({
                   htmlFor="upload-file-name-0"
                   className="block text-sm font-medium text-gray-700"
                 >
-                  {t("enter_combined_file_name")}
+                  {t("enter_file_name")}
                 </Label>
                 <Input
-                  name="combined_file_name"
+                  name="file_name_0"
                   type="text"
-                  id="combined-file-name"
+                  id="upload-file-name-0"
                   required
                   value={fileUpload.fileNames[0] || ""}
                   disabled={fileUpload.uploading}
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 8c354cfb800..c7780e3247e 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -54,7 +54,7 @@ export type FileUploadReturn = {
   handleAudioCapture: () => void;
   handleFileUpload: (
     associating_id: string,
-    CombineToPDF?: boolean,
+    combineToPDF?: boolean,
   ) => Promise<void>;
   Dialogues: JSX.Element;
   Input: (_: FileInputProps) => JSX.Element;
@@ -107,11 +107,6 @@ export default function useFileUpload(
       const totalFiles = files.length;
 
       for (const [index, file] of files.entries()) {
-        if (!file.type.startsWith("image/")) {
-          toast.error(t("file_error__file_type"));
-          setProgress(0);
-          return null;
-        }
         const imgData = URL.createObjectURL(file);
         pdf.addImage(imgData, "JPEG", 10, 10, 190, 0);
         URL.revokeObjectURL(imgData);
@@ -285,14 +280,17 @@ export default function useFileUpload(
 
   const handleUpload = async (
     associating_id: string,
-    CombineToPDF?: boolean,
+    combineToPDF?: boolean,
   ) => {
+    if (combineToPDF && "allowedExtensions" in options) {
+      options.allowedExtensions = ["jpg", "png", "jpeg"];
+    }
     if (!validateFileUpload()) return;
 
     setProgress(0);
     const errors: File[] = [];
 
-    if (CombineToPDF && files.length > 1) {
+    if (combineToPDF && files.length > 1) {
       const pdfFile = await generatePDF(files);
       if (pdfFile) {
         files.splice(0, files.length, pdfFile);

From 4534c6f8dd701e8ba8427cc5e1e3579c76dda292 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Wed, 29 Jan 2025 18:24:51 +0530
Subject: [PATCH 20/26] Fix long filename width issue; add paperclip + bg.

---
 src/components/Files/FilesTab.tsx | 46 +++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index 4d41cedf66c..27779acec8c 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -575,7 +575,6 @@ const FileUploadDialog = ({
   const handleDialogClose = (open: boolean) => {
     if (!open) {
       setIsPdf(false);
-      fileUpload.clearFiles();
     }
     onOpenChange(open);
   };
@@ -599,15 +598,31 @@ const FileUploadDialog = ({
         <div className="space-y-4">
           {isPdf ? (
             <>
-              <div className="space-y-2">
-                <ul className="list-disc list-inside space-y-1">
-                  {fileUpload.files.map((file, index) => (
-                    <li key={index} className="truncate" title={file.name}>
-                      {file.name}
-                    </li>
-                  ))}
-                </ul>
-              </div>
+              {fileUpload.files.map((file, index) => (
+                <div key={index} className="space-y-2">
+                  <div className="flex items-center justify-between gap-2 rounded-md bg-secondary-300 px-4 py-2">
+                    <span
+                      className="flex items-center truncate"
+                      title={file.name}
+                    >
+                      <CareIcon icon="l-paperclip" className="mr-2 shrink-0" />
+                      <span className="truncate">
+                        {file.name.length > 30
+                          ? `${file.name.substring(0, 20)}...`
+                          : file.name}
+                      </span>
+                    </span>
+                    <Button
+                      variant="ghost"
+                      size="icon"
+                      onClick={() => fileUpload.removeFile(index)}
+                      disabled={fileUpload.uploading}
+                    >
+                      <CareIcon icon="l-times" />
+                    </Button>
+                  </div>
+                </div>
+              ))}
               <div>
                 <Label
                   htmlFor="upload-file-name-0"
@@ -635,9 +650,16 @@ const FileUploadDialog = ({
             fileUpload.files.map((file, index) => (
               <div key={index} className="space-y-2">
                 <div className="flex items-center justify-between gap-2 rounded-md bg-secondary-300 px-4 py-2">
-                  <span className="flex items-center truncate">
+                  <span
+                    className="flex items-center truncate"
+                    title={file.name}
+                  >
                     <CareIcon icon="l-paperclip" className="mr-2 shrink-0" />
-                    <span className="truncate">{file.name}</span>
+                    <span className="truncate">
+                      {file.name.length > 30
+                        ? `${file.name.substring(0, 20)}...`
+                        : file.name}
+                    </span>
                   </span>
                   <Button
                     variant="ghost"

From 6fff5bb2e4e62b631402c013c2291225a114b8d4 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Sat, 1 Feb 2025 17:47:46 +0530
Subject: [PATCH 21/26] Enhance file upload dialog and validation logic for
 improved user experience

---
 src/components/Files/FilesTab.tsx | 12 +++++++-----
 src/hooks/useFileUpload.tsx       | 32 ++++++++++++++++++++-----------
 2 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index a4a118d8792..a694bd7d6f6 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -587,7 +587,7 @@ const FileUploadDialog = ({
       aria-labelledby="file-upload-dialog"
     >
       <DialogContent
-        className="mb-8 rounded-lg p-5 max-w-fit"
+        className="mb-8 rounded-lg p-5 max-w-fit md:max-w-[30rem]"
         aria-describedby="file-upload"
       >
         <DialogHeader>
@@ -607,8 +607,8 @@ const FileUploadDialog = ({
                     >
                       <CareIcon icon="l-paperclip" className="mr-2 shrink-0" />
                       <span className="truncate">
-                        {file.name.length > 30
-                          ? `${file.name.substring(0, 20)}...`
+                        {file.name.length > 40
+                          ? `${file.name.substring(0, 30)}...`
                           : file.name}
                       </span>
                     </span>
@@ -638,6 +638,7 @@ const FileUploadDialog = ({
                   value={fileUpload.fileNames[0] || ""}
                   disabled={fileUpload.uploading}
                   onChange={(e) => fileUpload.setFileName(e.target.value)}
+                  className="ml-0.5 mb-1"
                 />
                 {fileUpload.error && (
                   <p className="mt-2 text-sm text-red-600">
@@ -656,8 +657,8 @@ const FileUploadDialog = ({
                   >
                     <CareIcon icon="l-paperclip" className="mr-2 shrink-0" />
                     <span className="truncate">
-                      {file.name.length > 30
-                        ? `${file.name.substring(0, 20)}...`
+                      {file.name.length > 40
+                        ? `${file.name.substring(0, 30)}...`
                         : file.name}
                     </span>
                   </span>
@@ -688,6 +689,7 @@ const FileUploadDialog = ({
                     onChange={(e) =>
                       fileUpload.setFileName(e.target.value, index)
                     }
+                    className="ml-0.5 mb-0.5"
                   />
                   {index === 0 && fileUpload.error && (
                     <p className="mt-2 text-sm text-red-600">
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index c7780e3247e..aaa012c8082 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -289,6 +289,23 @@ export default function useFileUpload(
 
     setProgress(0);
     const errors: File[] = [];
+    if (combineToPDF) {
+      if (!uploadFileNames.length || !uploadFileNames[0]) {
+        setError(t("file_error__single_file_name"));
+        return;
+      }
+    } else {
+      for (const [index, file] of files.entries()) {
+        const filename =
+          allowNameFallback && uploadFileNames[index] === "" && file
+            ? file.name
+            : uploadFileNames[index];
+        if (!filename) {
+          setError(t("file_error__single_file_name"));
+          return;
+        }
+      }
+    }
 
     if (combineToPDF && files.length > 1) {
       const pdfFile = await generatePDF(files);
@@ -300,22 +317,15 @@ export default function useFileUpload(
         return;
       }
     }
-    for (const [index, file] of files.entries()) {
-      const filename =
-        allowNameFallback && uploadFileNames[index] === "" && file
-          ? file.name
-          : uploadFileNames[index];
-      if (!filename) {
-        setError(t("file_error__single_file_name"));
-        return;
-      }
-      setUploading(true);
 
+    setUploading(true);
+
+    for (const [index, file] of files.entries()) {
       try {
         const data = await createUpload({
           original_name: file.name ?? "",
           file_type: fileType,
-          name: filename,
+          name: uploadFileNames[index],
           associating_id,
           file_category: category,
           mime_type: file.type ?? "",

From 781211b82c6dcf389df8fee3d838bc882dea8a87 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Tue, 4 Feb 2025 00:27:34 +0530
Subject: [PATCH 22/26] expose error handling and reset logic.

---
 src/components/Files/FilesTab.tsx | 12 ++++++++----
 src/hooks/useFileUpload.tsx       |  7 ++++++-
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index f787efdf142..b9138e7ae86 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -641,7 +641,10 @@ const FileUploadDialog = ({
                   required
                   value={fileUpload.fileNames[0] || ""}
                   disabled={fileUpload.uploading}
-                  onChange={(e) => fileUpload.setFileName(e.target.value)}
+                  onChange={(e) => {
+                    fileUpload.setFileName(e.target.value);
+                    fileUpload.setError(null);
+                  }}
                   className="ml-0.5 mb-1"
                 />
                 {fileUpload.error && (
@@ -690,9 +693,10 @@ const FileUploadDialog = ({
                     required
                     value={fileUpload.fileNames[index] || ""}
                     disabled={fileUpload.uploading}
-                    onChange={(e) =>
-                      fileUpload.setFileName(e.target.value, index)
-                    }
+                    onChange={(e) => {
+                      fileUpload.setFileName(e.target.value, index);
+                      fileUpload.setError(null);
+                    }}
                     className="ml-0.5 mb-0.5"
                   />
                   {index === 0 && fileUpload.error && (
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 13ab1b571ff..72a6b8a1b85 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -49,6 +49,7 @@ export type FileInputProps = Omit<
 export type FileUploadReturn = {
   progress: null | number;
   error: null | string;
+  setError: (error: string | null) => void;
   validateFiles: () => boolean;
   handleCameraCapture: () => void;
   handleAudioCapture: () => void;
@@ -327,7 +328,10 @@ export default function useFileUpload(
         const data = await createUpload({
           original_name: file.name ?? "",
           file_type: fileType,
-          name: uploadFileNames[index],
+          name:
+            allowNameFallback && uploadFileNames[index] === "" && file
+              ? file.name
+              : uploadFileNames[index],
           associating_id,
           file_category: category,
           mime_type: file.type ?? "",
@@ -398,6 +402,7 @@ export default function useFileUpload(
   return {
     progress,
     error,
+    setError,
     validateFiles: validateFileUpload,
     handleCameraCapture: () => setCameraModalOpen(true),
     handleAudioCapture: () => setAudioModalOpen(true),

From 87613fbb2adfb9dec85521b4362e75b97ffe1ed7 Mon Sep 17 00:00:00 2001
From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com>
Date: Tue, 4 Feb 2025 17:22:12 +0530
Subject: [PATCH 23/26] fixed the build failure

---
 package-lock.json | 159 ++--------------------------------------------
 1 file changed, 6 insertions(+), 153 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index b0853986d6b..66d1c285fa3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7885,16 +7885,6 @@
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
       "license": "MIT"
     },
-    "node_modules/barcode-detector": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.3.1.tgz",
-      "integrity": "sha512-D9KEtrquS1tmBZduxBZl8qublIKnRrFqD8TAHDYcLCyrHQBo+vitIxmjMJ61LvXjXyAMalOlO7q0Oh/9Rl2PbQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/dom-webcodecs": "0.1.11",
-        "zxing-wasm": "1.3.4"
-      }
-    },
     "node_modules/base64-arraybuffer": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
@@ -8237,21 +8227,17 @@
       "license": "CC-BY-4.0"
     },
     "node_modules/canvas": {
-      "version": "2.11.2",
-      "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
-      "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
-      "dev": true,
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.1.0.tgz",
+      "integrity": "sha512-tTj3CqqukVJ9NgSahykNwtGda7V33VLObwrHfzT0vqJXu7J4d4C/7kQQW3fOEGDfZZoILPut5H00gOjyttPGyg==",
       "hasInstallScript": true,
-      "license": "MIT",
       "optional": true,
-      "peer": true,
       "dependencies": {
-        "@mapbox/node-pre-gyp": "^1.0.0",
-        "nan": "^2.17.0",
-        "simple-get": "^3.0.3"
+        "node-addon-api": "^7.0.0",
+        "prebuild-install": "^7.1.1"
       },
       "engines": {
-        "node": ">=6"
+        "node": "^18.12.0 || >= 20.9.0"
       }
     },
     "node_modules/canvg": {
@@ -8613,15 +8599,6 @@
       "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
       "license": "MIT"
     },
-    "node_modules/copy-to-clipboard": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
-      "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
-      "license": "MIT",
-      "dependencies": {
-        "toggle-selection": "^1.0.6"
-      }
-    },
     "node_modules/core-js": {
       "version": "3.40.0",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz",
@@ -9149,19 +9126,6 @@
       "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
       "license": "MIT"
     },
-    "node_modules/decompress-response": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
-      "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "mimic-response": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/deep-equal": {
       "version": "2.2.3",
       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
@@ -13753,19 +13717,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/mimic-response": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
-      "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
-      "license": "MIT",
-      "optional": true,
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/mini-svg-data-uri": {
       "version": "1.4.4",
       "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
@@ -14492,22 +14443,6 @@
         "path2d": "^0.2.1"
       }
     },
-    "node_modules/pdfjs-dist/node_modules/canvas": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.0.0.tgz",
-      "integrity": "sha512-NtcIBY88FjymQy+g2g5qnuP5IslrbWCQ3A6rSr1PeuYxVRapRZ3BZCrDyAakvI6CuDYidgZaf55ygulFVwROdg==",
-      "hasInstallScript": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "node-addon-api": "^7.0.0",
-        "prebuild-install": "^7.1.1",
-        "simple-get": "^3.0.3"
-      },
-      "engines": {
-        "node": "^18.12.0 || >= 20.9.0"
-      }
-    },
     "node_modules/pend": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -16009,69 +15944,6 @@
         "node": ">= 0.8.15"
       }
     },
-    "node_modules/rimraf": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-      "deprecated": "Rimraf versions prior to v4 are no longer supported",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "glob": "^7.1.3"
-      },
-      "bin": {
-        "rimraf": "bin.js"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/rimraf/node_modules/brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
-    "node_modules/rimraf/node_modules/glob": {
-      "version": "7.2.3",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-      "deprecated": "Glob versions prior to v9 are no longer supported",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.1.1",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
-      },
-      "engines": {
-        "node": "*"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/rimraf/node_modules/minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "brace-expansion": "^1.1.7"
-      },
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/roarr": {
       "version": "2.15.4",
       "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
@@ -16595,18 +16467,6 @@
       "license": "MIT",
       "optional": true
     },
-    "node_modules/simple-get": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
-      "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "decompress-response": "^4.2.0",
-        "once": "^1.3.1",
-        "simple-concat": "^1.0.0"
-      }
-    },
     "node_modules/slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -17497,13 +17357,6 @@
         "utrie": "^1.0.2"
       }
     },
-    "node_modules/text-table": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-      "dev": true,
-      "license": "MIT"
-    },
     "node_modules/thenify": {
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",

From 73efe41b165ffb70889c4f0488c687ad9a5648fa Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Wed, 5 Feb 2025 00:33:52 +0530
Subject: [PATCH 24/26] Add zoom  to PDF . Remove Compression

---
 src/components/Common/FilePreviewDialog.tsx | 10 +++++++++-
 src/components/Common/PDFViewer.tsx         |  7 ++++++-
 src/hooks/useFileUpload.tsx                 |  1 -
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/src/components/Common/FilePreviewDialog.tsx b/src/components/Common/FilePreviewDialog.tsx
index d9eb4db62b3..fbcaf9ae69a 100644
--- a/src/components/Common/FilePreviewDialog.tsx
+++ b/src/components/Common/FilePreviewDialog.tsx
@@ -82,6 +82,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => {
   const [page, setPage] = useState(1);
   const [numPages, setNumPages] = useState(1);
   const [index, setIndex] = useState<number>(currentIndex);
+  const [scale, setScale] = useState(1.0);
 
   useEffect(() => {
     if (uploadedFiles && show) {
@@ -95,6 +96,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => {
       ...file_state,
       zoom: !checkFull ? file_state.zoom + 1 : file_state.zoom,
     });
+    setScale((prevScale) => Math.min(prevScale + 0.25, 2));
   };
 
   const handleZoomOut = () => {
@@ -103,6 +105,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => {
       ...file_state,
       zoom: !checkFull ? file_state.zoom - 1 : file_state.zoom,
     });
+    setScale((prevScale) => Math.max(prevScale - 0.25, 0.5));
   };
 
   const fileName = file_state?.name
@@ -133,6 +136,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => {
     setPage(1);
     setNumPages(1);
     setIndex(-1);
+    setScale(1);
     onClose?.();
   };
 
@@ -214,7 +218,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => {
                   </a>
                 </Button>
               )}
-              <Button variant="outline" type="button" onClick={onClose}>
+              <Button variant="outline" type="button" onClick={handleClose}>
                 {t("close")}
               </Button>
             </div>
@@ -249,6 +253,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => {
                       setNumPages(numPages);
                     }}
                     pageNumber={page}
+                    scale={scale}
                   />
                 </Suspense>
               ) : previewExtensions.includes(file_state.extension) ? (
@@ -341,6 +346,9 @@ const FilePreviewDialog = (props: FilePreviewProps) => {
               {file_state.extension === "pdf" && (
                 <>
                   {[
+                    ["Zoom In", "l-search-plus", handleZoomIn, scale >= 2],
+                    [`${Math.round(scale * 100)}%`, false, () => {}, false],
+                    ["Zoom Out", "l-search-minus", handleZoomOut, scale <= 0.5],
                     [
                       "Previous",
                       "l-arrow-left",
diff --git a/src/components/Common/PDFViewer.tsx b/src/components/Common/PDFViewer.tsx
index 1a20fa9e133..6e135f7b673 100644
--- a/src/components/Common/PDFViewer.tsx
+++ b/src/components/Common/PDFViewer.tsx
@@ -7,6 +7,7 @@ export default function PDFViewer(
     url: string;
     pageNumber: number;
     onDocumentLoadSuccess: (numPages: number) => void;
+    scale: number;
   }>,
 ) {
   pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.mjs";
@@ -21,7 +22,11 @@ export default function PDFViewer(
           }
           className="w-full"
         >
-          <Page pageNumber={props.pageNumber} height={650} />
+          <Page
+            pageNumber={props.pageNumber}
+            height={650}
+            scale={props.scale}
+          />
         </Document>
       </div>
     </div>
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 72a6b8a1b85..14b9119add7 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -142,7 +142,6 @@ export default function useFileUpload(
       const ext: string = file.name.split(".")[1];
       if (ExtImage.includes(ext)) {
         const options = {
-          initialQuality: 0.6,
           alwaysKeepResolution: true,
         };
         imageCompression(file, options).then((compressedFile: File) => {

From ce45fde331f61b8c10d9384f8f642df92afa2667 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Wed, 5 Feb 2025 16:10:32 +0530
Subject: [PATCH 25/26] optional compression prop added

---
 src/components/Files/FilesTab.tsx |  1 +
 src/hooks/useFileUpload.tsx       | 31 +++++++++++++++++--------------
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx
index b9138e7ae86..723eb8f7119 100644
--- a/src/components/Files/FilesTab.tsx
+++ b/src/components/Files/FilesTab.tsx
@@ -157,6 +157,7 @@ export const FilesTab = (props: FilesTabProps) => {
     onUpload: () => {
       refetch();
     },
+    compress: false,
   });
 
   useEffect(() => {
diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx
index 14b9119add7..d53b9497e08 100644
--- a/src/hooks/useFileUpload.tsx
+++ b/src/hooks/useFileUpload.tsx
@@ -32,6 +32,7 @@ export type FileUploadOptions = {
   onUpload?: (file: FileUploadModel) => void;
   // if allowed, will fallback to the name of the file if a seperate filename is not defined.
   allowNameFallback?: boolean;
+  compress?: boolean;
 } & (
   | {
       allowedExtensions?: string[];
@@ -137,20 +138,22 @@ export default function useFileUpload(
     }
     const selectedFiles = Array.from(e.target.files);
     setFiles((prev) => [...prev, ...selectedFiles]);
-
-    selectedFiles.forEach((file) => {
-      const ext: string = file.name.split(".")[1];
-      if (ExtImage.includes(ext)) {
-        const options = {
-          alwaysKeepResolution: true,
-        };
-        imageCompression(file, options).then((compressedFile: File) => {
-          setFiles((prev) =>
-            prev.map((f) => (f.name === file.name ? compressedFile : f)),
-          );
-        });
-      }
-    });
+    if (options.compress) {
+      selectedFiles.forEach((file) => {
+        const ext: string = file.name.split(".")[1];
+        if (ExtImage.includes(ext)) {
+          const options = {
+            initialQuality: 0.6,
+            alwaysKeepResolution: true,
+          };
+          imageCompression(file, options).then((compressedFile: File) => {
+            setFiles((prev) =>
+              prev.map((f) => (f.name === file.name ? compressedFile : f)),
+            );
+          });
+        }
+      });
+    }
   };
 
   useEffect(() => {

From 8ef106987d94a488b4a9ecbd6d96464b2fb34aa9 Mon Sep 17 00:00:00 2001
From: Don Xavier <mail.donxavier@gmail.com>
Date: Wed, 5 Feb 2025 16:11:22 +0530
Subject: [PATCH 26/26] unimport error fix

---
 package-lock.json | 48 ++++++++++++++++++-----------------------------
 1 file changed, 18 insertions(+), 30 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index b7d60903a3e..81c1d138ddb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16371,6 +16371,16 @@
       "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
       "license": "MIT"
     },
+    "node_modules/rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.8.15"
+      }
+    },
     "node_modules/rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -16434,16 +16444,6 @@
         "node": "*"
       }
     },
-    "node_modules/rgbcolor": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
-      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
-      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
-      "optional": true,
-      "engines": {
-        "node": ">= 0.8.15"
-      }
-    },
     "node_modules/roarr": {
       "version": "2.15.4",
       "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
@@ -16967,18 +16967,6 @@
       "license": "MIT",
       "optional": true
     },
-    "node_modules/simple-get": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
-      "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "decompress-response": "^4.2.0",
-        "once": "^1.3.1",
-        "simple-concat": "^1.0.0"
-      }
-    },
     "node_modules/simple-git": {
       "version": "3.27.0",
       "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz",
@@ -17924,14 +17912,6 @@
       "devOptional": true,
       "license": "MIT"
     },
-    "node_modules/text-table": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-      "dev": true,
-      "license": "MIT",
-      "peer": true
-    },
     "node_modules/text-segmentation": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
@@ -17942,6 +17922,14 @@
         "utrie": "^1.0.2"
       }
     },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true
+    },
     "node_modules/thenify": {
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",