From 14ede77a1681ad00cacd6ea22c4cc9007eb28bb6 Mon Sep 17 00:00:00 2001 From: =bhagwanSingh <=bhagwan.r@hicglobalsolutions.com> Date: Fri, 26 Sep 2025 19:56:38 +0530 Subject: [PATCH] upd 26 sep --- .env | 6 +- public/sme-colored.png | Bin 0 -> 6306 bytes src/App.tsx | 2 + src/components/accounts/DownloadDocument.tsx | 73 ++ .../accounts/TransactionDataTable.tsx | 71 +- src/components/auth/LoginForm.tsx | 4 +- .../client/ClientDownloadDocument.tsx | 78 ++ src/components/client/CompletionScreen.tsx | 42 +- src/components/client/DocumentPages.tsx | 3 - src/components/client/SessionExpired.tsx | 19 + src/components/client/SignButton.tsx | 24 +- src/components/client/SignDocument.tsx | 413 +++++-- src/components/client/TagsCon.tsx | 86 +- src/components/client/TermsModal.tsx | 2 +- src/components/dashboard/SendForSign.tsx | 13 +- .../process/CompletionScreen/SignerList.tsx | 24 +- .../TransactionSentSuccess.tsx | 106 +- .../process/processStepOne/DocumentCard.tsx | 2 +- .../process/processStepOne/ProcessStepOne.tsx | 5 +- .../processStepTwo/DocumentContainer.tsx | 12 +- .../process/processStepTwo/FieldList.tsx | 2 +- .../process/processStepTwo/LeftSideBar.tsx | 26 +- .../process/processStepTwo/NavTwo.tsx | 61 +- .../process/processStepTwo/ProcessStepTwo.tsx | 23 +- .../routes_helper/ProtectedRoute.tsx | 7 +- .../setting/Signature/AddSignatureModal.tsx | 533 +++------ .../setting/Signature/DrawSignatureCanvas.tsx | 126 +- .../setting/Signature/Signature.tsx | 23 +- src/components/signature/ClientSignCon.tsx | 890 ++++++++++++++ src/components/signature/SignCon.tsx | 1042 ----------------- src/components/signature_pad/SignatureCon.tsx | 2 +- .../transactions/TransactionView.tsx | 3 +- src/config/api.tsx | 46 +- src/config/useAxios.tsx | 2 +- src/store/slices/documentSlice.ts | 2 +- src/utlity/signSessionRedirect.ts | 9 + vite.config.ts | 19 +- 37 files changed, 2008 insertions(+), 1793 deletions(-) create mode 100644 public/sme-colored.png create mode 100644 src/components/accounts/DownloadDocument.tsx create mode 100644 src/components/client/ClientDownloadDocument.tsx create mode 100644 src/components/client/SessionExpired.tsx create mode 100644 src/components/signature/ClientSignCon.tsx delete mode 100644 src/components/signature/SignCon.tsx create mode 100644 src/utlity/signSessionRedirect.ts diff --git a/.env b/.env index a0b511c..639667a 100644 --- a/.env +++ b/.env @@ -1,8 +1,10 @@ -VITE_BASE_URI="https://glider-precious-similarly.ngrok-free.app" +# VITE_BASE_URI="https://glider-precious-similarly.ngrok-free.app" # VITE_BASE_URI="https://wired-terminally-muskrat.ngrok-free.app" # VITE_BASE_URI="https://officially-powerful-goat.ngrok-free.app" # VITE_BASE_URI="https://python-amused-adder.ngrok-free.app" # VITE_BASE_URI="https://concrete-gladly-mullet.ngrok-free.app" +# VITE_BASE_URI="https://smashing-albacore-engaging.ngrok-free.app" +VITE_BASE_URI="https://basically-polished-yeti.ngrok-free.app" -# VITE_BASE_URI="http://192.168.2.176:8083" \ No newline at end of file +# VITE_BASE_URI="http://10.10.1.248:8083" \ No newline at end of file diff --git a/public/sme-colored.png b/public/sme-colored.png new file mode 100644 index 0000000000000000000000000000000000000000..2cc81c10b483a68963de0a022526abe7a576bd82 GIT binary patch literal 6306 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 Y0ewS(#*rmbNdN!<07*qoM6N<$g7;r`YXATM literal 0 HcmV?d00001 diff --git a/src/App.tsx b/src/App.tsx index 38d1023..5a4eb38 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -24,6 +24,7 @@ import JoyrideController from "./utlity/JoyRideTour"; import Contacts from "./components/contacts/Contacts"; import TransactionSentSuccess from "./components/process/CompletionScreen/TransactionSentSuccess"; import CompletionScreen from "./components/client/CompletionScreen"; +import SessionExpired from "./components/client/SessionExpired"; const App = () => { return ( @@ -108,6 +109,7 @@ const App = () => { } /> } /> } /> + } /> {/* Links work wothout Login */} diff --git a/src/components/accounts/DownloadDocument.tsx b/src/components/accounts/DownloadDocument.tsx new file mode 100644 index 0000000..878bb6b --- /dev/null +++ b/src/components/accounts/DownloadDocument.tsx @@ -0,0 +1,73 @@ +import React from 'react' +import { IoMdClose } from 'react-icons/io' +import downloadDocumentUtils from '../../utlity/downloadDocumentsUtils'; +import { DownloadTypesEnum } from './TransactionDataTable'; + +interface DownloadDocumentInt { + showMenu: { open: boolean, transactionId: string | null }, + setShowMenu: React.Dispatch<{ open: boolean, transactionId: string | null }>, + accountId: string +} + +const DownloadDocument: React.FC = ({ showMenu, setShowMenu, accountId }) => { + + + function handleDownloadFormSubmit(e) { + e.preventDefault(); + + const formData = new FormData(e.target); + const docType = formData.get('download-doc-type'); + const includeCertificate = formData.get('download-doc-type-include-cert'); + + downloadDocumentUtils(accountId, showMenu.transactionId as string, docType as string, includeCertificate as string | null) + } + + + return ( + <> + {showMenu.open && ( +
handleDownloadFormSubmit(e)} className='fixed inset-0 z-50'> +
setShowMenu({ open: false, transactionId: null })}>
+
+
+

Download Document

+ +
+
+
+ Choose file to download +
+ + + + + +
+
+
+ + +
+
+
+
+ )} + + ) +} + +export default DownloadDocument \ No newline at end of file diff --git a/src/components/accounts/TransactionDataTable.tsx b/src/components/accounts/TransactionDataTable.tsx index 2c4f83d..06b1364 100644 --- a/src/components/accounts/TransactionDataTable.tsx +++ b/src/components/accounts/TransactionDataTable.tsx @@ -8,6 +8,7 @@ import logoRecord from '../../assets/record.svg'; import { MdOutlineFileDownload } from 'react-icons/md'; import downloadDocumentUtils from '../../utlity/downloadDocumentsUtils'; import { IoMdClose } from 'react-icons/io'; +import DownloadDocument from './DownloadDocument'; const formatDate = (timestamp: number) => { return new Date(timestamp * 1000).toLocaleString(); @@ -20,6 +21,12 @@ const statusColorMap = { EXPIRED: "bg-red-100 text-red-600", }; +export enum DownloadTypesEnum { + ALL = "archived", + COMBINED = "combined", + CERTIFICATE = "certificate" +} + const TransactionDataTable = ({ activeAccountId }) => { const navigate = useNavigate() @@ -34,11 +41,7 @@ const TransactionDataTable = ({ activeAccountId }) => { }); const [loading, setLoading] = useState(false) - enum DownloadTypesEnum { - ALL = "archived", - COMBINED = "combined", - CERTIFICATE = "certificate" - } + const [downloadDocumentType, setDownloadDocumentType] = useState({ type: DownloadTypesEnum.ALL, @@ -98,7 +101,7 @@ const TransactionDataTable = ({ activeAccountId }) => { function handleDownloadFormSubmit(e) { e.preventDefault(); - + const formData = new FormData(e.target); const docType = formData.get('download-doc-type'); const includeCertificate = formData.get('download-doc-type-include-cert'); @@ -106,8 +109,6 @@ const TransactionDataTable = ({ activeAccountId }) => { downloadDocumentUtils(activeAccountId, showMenu.transactionId as string, docType as string, includeCertificate as string | null) } - - return ( <> @@ -148,7 +149,7 @@ const TransactionDataTable = ({ activeAccountId }) => { {transactions.map((tx, idx) => ( handleTransactionClick(tx.id)} + // onClick={() => handleTransactionClick(tx.id)} >
{ {showMenu.open && ( -
handleDownloadFormSubmit(e)} className='fixed inset-0 z-50'> -
setShowMenu({open: false, transactionId: null})}>
-
-
-

Download Document

- -
-
-
- Choose file to download -
- - - - {/* */} - -
-
-
- - -
-
-
-
+ )} diff --git a/src/components/auth/LoginForm.tsx b/src/components/auth/LoginForm.tsx index 3177b27..710faac 100644 --- a/src/components/auth/LoginForm.tsx +++ b/src/components/auth/LoginForm.tsx @@ -8,6 +8,7 @@ import OAuthGoogle from "./OAuthGoogle"; // import Cookies from "js-cookie"; import { BsEye } from "react-icons/bs"; import { FiEyeOff } from "react-icons/fi"; +import { TokenStorage } from "../../config/api"; // import api from "../../config/api"; interface FormDataState { @@ -115,8 +116,9 @@ const LoginForm = ({ onSwitchToRegister }) => { ); if (res.status === 200) { - navigate("/"); + TokenStorage.setTokens(res.data.accessToken, res.data.refreshToken) formErrorRef.current = { message: "Login Successfully", error: false } + navigate("/"); } } catch (err) { if (err.response?.status === 400 || err.response?.status === 401) { diff --git a/src/components/client/ClientDownloadDocument.tsx b/src/components/client/ClientDownloadDocument.tsx new file mode 100644 index 0000000..7664162 --- /dev/null +++ b/src/components/client/ClientDownloadDocument.tsx @@ -0,0 +1,78 @@ +import React from 'react' +import { IoMdClose } from 'react-icons/io' +import downloadDocumentUtils from '../../utlity/downloadDocumentsUtils'; + +interface DownloadDocumentInt { + showMenuDownload: { open: boolean, transactionId: string | null }, + setShowMenuDownload: React.Dispatch<{ open: boolean, transactionId: string | null }>, + accountId: string +} + +enum DownloadTypesEnum { + ALL = "archived", + COMBINED = "combined", + CERTIFICATE = "certificate" +} + +const ClientDownloadDocument: React.FC = ({ showMenuDownload, setShowMenuDownload, accountId }) => { + + + function handleDownloadFormSubmit(e) { + e.preventDefault(); + + const formData = new FormData(e.target); + const docType = formData.get('download-doc-type'); + const includeCertificate = formData.get('download-doc-type-include-cert'); + + downloadDocumentUtils(accountId, showMenuDownload.transactionId as string, docType as string, includeCertificate as string | null) + } + + + return ( + <> + {showMenuDownload.open && ( +
handleDownloadFormSubmit(e)} className='fixed inset-0 z-50'> +
setShowMenuDownload({ open: false, transactionId: null })}>
+
+
+

Download Document

+ +
+
+
+ Choose file to download +
+ + + + + +
+
+
+ + +
+
+
+
+ )} + + ) +} + +export default ClientDownloadDocument \ No newline at end of file diff --git a/src/components/client/CompletionScreen.tsx b/src/components/client/CompletionScreen.tsx index 8beace7..d360607 100644 --- a/src/components/client/CompletionScreen.tsx +++ b/src/components/client/CompletionScreen.tsx @@ -23,10 +23,10 @@ const CompletionScreen: React.FC = ({
{/* Header */} -
+
- + Sign made easy
@@ -34,10 +34,10 @@ const CompletionScreen: React.FC = ({ {/* Main content */}
-

+

{hit}{title}

-

+

{message}

@@ -49,42 +49,42 @@ const CompletionScreen: React.FC = ({ {/* */} -

+

Access your documents anytime — just Login

{/* Illustration placeholder */} -
+
{textColorSuccess ? Document completed : Document completed}
{/* Apps Section */} -
-

+
+

Boost Efficiency with Our Apps

-
+
{/* Forms Made Easy */} -
+
-

+

Generate Forms with Ease

- Docs Made Easy -
@@ -94,15 +94,15 @@ const CompletionScreen: React.FC = ({
{/* Docs Made Easy */} -
+
-

+

Generate Documents (Invoices, Reports, Quotes)

- Docs Made Easy -
@@ -116,8 +116,8 @@ const CompletionScreen: React.FC = ({

{/* Footer */} -