diff --git a/src/components/client/CompletionScreen.tsx b/src/components/client/CompletionScreen.tsx index b01ced3..10f9227 100644 --- a/src/components/client/CompletionScreen.tsx +++ b/src/components/client/CompletionScreen.tsx @@ -66,7 +66,7 @@ const CompletionScreen: React.FC = ({ Sign made easy */} - + @@ -81,7 +81,7 @@ const CompletionScreen: React.FC = ({

{ handleDownloadDocument(recipientId || "") }} - className="text-white bg-[var(--mainPrimaryBtn)] px-3 py-1 rounded-sm mt-4 cursor-pointer"> + className="text-white bg-[var(--mainPrimaryBtn)] px-3 py-2 rounded-sm mt-4 cursor-pointer"> Download Signed Documents

@@ -113,7 +113,8 @@ const CompletionScreen: React.FC = ({ {/* Apps Section */} -
+ {/*
*/} +

Boost Efficiency with Our Apps

@@ -128,7 +129,9 @@ const CompletionScreen: React.FC = ({
Docs Made Easy -
@@ -146,7 +149,9 @@ const CompletionScreen: React.FC = ({
Docs Made Easy -
diff --git a/src/components/client/DocumentPages.tsx b/src/components/client/DocumentPages.tsx index 93e6fb3..8bcd1fa 100644 --- a/src/components/client/DocumentPages.tsx +++ b/src/components/client/DocumentPages.tsx @@ -1,103 +1,150 @@ -import React, { useState } from 'react' -import { MdKeyboardArrowDown, MdOutlineNavigateNext } from 'react-icons/md'; +import React, { useEffect, useState } from 'react' +import { MdKeyboardArrowUp, MdMoreVert } from 'react-icons/md'; import { DocumentType } from './SignDocument'; -import { GrFormPrevious } from 'react-icons/gr'; +import { DroppedItem } from '../../utlity/types'; +import { PiTagSimpleFill } from 'react-icons/pi'; interface DocumentPagesInterface { selectedDocuments: DocumentType[] | null; setDropDownTogglePage: React.Dispatch>; dropDownTogglePage: string; + droppedItems: Record | null; } -const DocumentPages = ({ selectedDocuments, setDropDownTogglePage, dropDownTogglePage }: DocumentPagesInterface) => { +const DocumentPages = ({ selectedDocuments, setDropDownTogglePage, dropDownTogglePage, droppedItems }: DocumentPagesInterface) => { + + const [activePage, setActivePage] = useState( + selectedDocuments?.[0] ? `${selectedDocuments[0].documentId}_0` : null + ) + + const [documentPagesTagsMapping, setDocumentPagesTagsMapping] = useState>>({}) + + useEffect(() => { + const documentId = selectedDocuments?.[0] ? `${selectedDocuments[0].documentId}_0` : null + if (documentId === null) return; + + const key = 'pageDropDown' + 0; + setDropDownTogglePage(dropDownTogglePage === key ? '' : key); + setActivePage(`${documentId}_0`); + window.location.hash = documentId + "0"; + }, [selectedDocuments]) + + const toggleDoc = (indx: number, documentId: string) => { + const key = 'pageDropDown' + indx; + setDropDownTogglePage(dropDownTogglePage === key ? '' : key); + setActivePage(`${documentId}_0`); + window.location.hash = documentId + "0"; + } + + const goToPage = (documentId: string, pageIndex: number) => { + const key = `${documentId}_${pageIndex}`; + setActivePage(key); + window.location.hash = documentId + "" + pageIndex; + } + + + useEffect(() => { + setTimeout(() => { + let documentPagesTagsMappingLocal: Record> = {} + + droppedItems && Object.keys(droppedItems).length > 0 && droppedItems.forEach(item => { + + const documentId = item.documentId; + const pageIndex = item.pageIndex; + + if (!documentPagesTagsMappingLocal[documentId]) { + documentPagesTagsMappingLocal[documentId] = {}; + } + + documentPagesTagsMappingLocal[documentId][pageIndex] = documentPagesTagsMappingLocal[documentId][pageIndex] ? [documentPagesTagsMappingLocal[documentId][pageIndex][0] + 1, "#005AB5"] : [1, "#005AB5"] + }) + + setDocumentPagesTagsMapping(documentPagesTagsMappingLocal) + }, 300) + }, [droppedItems]) - const [currentPage, setCurrentPage] = useState(0); return ( -
- {selectedDocuments && selectedDocuments.length && selectedDocuments.map((document, indx) => { +
+ {selectedDocuments && selectedDocuments.length > 0 && selectedDocuments.map((document, indx) => { + const isOpen = dropDownTogglePage === 'pageDropDown' + indx; + return ( -
- // tabIndex={1} - // onBlur={() => setDropDownTogglePage('')} - > + {/* Document Header */}
{ - setDropDownTogglePage(`${(dropDownTogglePage == 'pageDropDown' + indx) ? '' : 'pageDropDown' + indx}`); - setCurrentPage(0); - window.location.hash = document.documentId + "" + 0; - } - } - className={`p-2 ${(dropDownTogglePage == 'pageDropDown' + indx) ? "bg-[var(--primary)]" : "bg-slate-200"} flex flex-col justify-center items-center gap-2 rounded`}> - { - document.pages != undefined && - } - -
-

{document.name}

- + onClick={() => toggleDoc(indx, document.documentId)} + className="flex items-start justify-between px-3 py-2.5 cursor-pointer hover:bg-slate-50 transition-colors" + > +
+

+ {document.name} +

+

+ {document.pages?.length} {document.pages?.length === 1 ? 'page' : 'pages'} +

+
+ {/* Page Thumbnails - DocuSign style */} + {isOpen && ( +
+ {document.pages?.map((page, pageIndex) => { + const key = `${document.documentId}_${pageIndex}`; + const isActive = activePage === key; - { - dropDownTogglePage == 'pageDropDown' + indx && -
- {/* Prev Button */} - { - if (currentPage == 0) e.preventDefault(); - else setCurrentPage(currentPage - 1); - }} - > - - + return ( +
goToPage(document.documentId, pageIndex)} + className="flex flex-col items-center py-2 px-1 rounded-md cursor-pointer hover:bg-slate-50 transition-colors" + > + {/* Big Thumbnail */} +
+ {`Page - {/* Page Selector */} - + {/* Page number + dots */} +
+ {pageIndex + 1} + { + // <> + // + // + } +
- - / {document.pages?.length} - + {documentPagesTagsMapping[document.documentId]?.[pageIndex] && ( +
+ {/* + {documentPagesTagsMapping[document.documentId][pageIndex][0]} + */} + +
+ )} - {/* Next Button */} - { - if (currentPage == document.pages?.length - 1) e.preventDefault(); - else setCurrentPage(currentPage + 1); - }} - > - - +
+
+ ) + })}
- } + )}
) diff --git a/src/components/client/SignDocument.tsx b/src/components/client/SignDocument.tsx index 0431611..8ecbd16 100644 --- a/src/components/client/SignDocument.tsx +++ b/src/components/client/SignDocument.tsx @@ -23,7 +23,7 @@ import DocumentPages from "./DocumentPages"; import FieldList from "../process/processStepTwo/FieldList"; import typeToIconMap from "../../helper/iconMap"; -import RightSideBar from "../process/processStepTwo/rightSideBar/RightSideBar"; +import TagProperties from "../process/processStepTwo/tagProperties/TagProperties"; import TagsCon from "./TagsCon"; import ConsentScreen from "./ConsentScreen"; import SignButton from "./SignButton"; @@ -165,13 +165,14 @@ const SignDocument = () => { const [tagJson, setTagJson] = useState([]); const [transaction, setTransaction] = useState(null); const [recSignStatus, setRecSignStatus] = useState(null); + const [droppedItems, setDroppedItems] = useState([]); + const [signTagId, setSignTagId] = useState(0) const [showConfetti, setShowConfetti] = useState(false) const [pageScales, setPageScales] = useState>({}); - const [requiredFilled, setRequiredFilled] = useState(false); const [horizontalFormLoader, setHorizontalFormLoader] = useState<{ requiredFilled: number, totalRequired: number | null }>({ requiredFilled: 0, totalRequired: null }); @@ -1036,7 +1037,7 @@ const SignDocument = () => { {/*
*/}
+ className={`${isPages ? "block" : "hidden"} bg-slate-100 sm:block absolute w-[220px] left-0 top-[42px] border-r-2 sm:border-none border-slate-200 z-10 sm:static sm:w-auto sm:col-span-2 h-full overflow-y-auto ${recipient?.type != "CC" ? "bg-slate-100" : ""} ${!provideTags && isFields ? "hidden" : ""}`}>
{ + dropDownTogglePage={dropDownTogglePage} + droppedItems={droppedItems} + />
{/* Pages - END */} @@ -1222,7 +1225,7 @@ const SignDocument = () => { {provideTags && selectedTag && selectedTag != null && "key" in selectedTag && "index" in selectedTag &&
{/* Right Side Attributes Section if providedTags - START */} - { @@ -141,11 +147,11 @@ const StartNow = () => { }} />}
fileInputRef.current?.click()} + // onClick={() => fileInputRef.current?.click()} onDrop={handleDrop} onDragOver={handleDragOver} id='start-now-upload-con' - className="group col-span-1 cursor-pointer border-1 border-dashed border-[#D3D3D3] rounded-lg bg-[var(--documentUploadBg)] transition-all duration-200 p-4 flex flex-col items-center justify-center gap-2 text-center shadow-sm hover:shadow-md"> + className="group col-span-1 cursor-pointer border-1 border-dashed border-[#D3D3D3] rounded-lg bg-[var(--documentUploadBg)] transition-all duration-200 p-4 flex flex-col items-center justify-center gap-2 text-center shadow-sm"> {/* Upload icon */} @@ -163,11 +169,71 @@ const StartNow = () => { PDF, DOCX (max 10MB)

- + */} + + +
+ + + + {/* Dropdown */} +
+ + + +
+
{filesError && {filesError}} diff --git a/src/components/process/CompletionScreen/TransactionSentSuccess.tsx b/src/components/process/CompletionScreen/TransactionSentSuccess.tsx index adc1730..8583ec8 100644 --- a/src/components/process/CompletionScreen/TransactionSentSuccess.tsx +++ b/src/components/process/CompletionScreen/TransactionSentSuccess.tsx @@ -91,83 +91,380 @@ const TransactionSentSuccess = () => {
{/* Content */} -
-
- {/* Success banner */} -
- {/*
- -
*/} +
+
- - - - - - + {/* Success Hero */} + {/* Success Hero */} +
- - -
-

- Your Document is sent for signature -

-

All signers will be notified via email

-
-
- - {/* Main two-column layout */} -
- {/* Left: Document Preview */} -
-
-
-

Quick Preview

-
-
- -
-
-
- - {/* Right: Signers list + actions */} + {/* subtle background */}
-
+ className=" + absolute + right-[-80px] + top-[-80px] + w-[220px] + h-[220px] + bg-emerald-50 + rounded-full + blur-3xl + opacity-70 + " + /> -
- +
+ + {/* Left */} +
+ + {/* success badge */} +
+ +
+ +
+ + + Transaction Sent Successfully +
-
- + Your document has been sent for signature + + + {/* description */} +

+ All recipients will receive an email notification with + secure access to review and sign the document. +

+ + {/* actions */} +
+ + {/* */} + + + + {selfUserSign.sign && ( -

signSessionRedirect(accountId, transactionId, selfUserSign.recipientId + "")} - className="flex-1 p-2 text-center rounded-md bg-[var(--mainPrimaryBtn)] text-white hover:shadow-sm transition-all duration-150 cursor-pointer" + )}

-
+ {/* Right */} +
- {/* Optional: Signing Order */} - {/*
- -
*/} +
+ + + +
+
+
+
+ + {/* Main Section */} +
+ + {/* Preview */} +
+ + {/* Header */} +
+ +
+

+ Document Preview +

+ +

+ Review the final document before signing +

+
+
+ + {/* Preview Body */} +
+ +
+ + { + selectedRecipients.length > 0 && + selectedDocuments.length > 0 && ( + + ) + } + +
+
+
+ + {/* Right Sidebar */} +
+ +
+ + {/* Header */} +
+ +

+ Signers +

+ +

+ Recipients who will receive this document +

+ +
+ + {/* Body */} +
+ + + +
+
diff --git a/src/components/process/processStepOne/ProcessStepOne.tsx b/src/components/process/processStepOne/ProcessStepOne.tsx index 814d950..dbc572c 100644 --- a/src/components/process/processStepOne/ProcessStepOne.tsx +++ b/src/components/process/processStepOne/ProcessStepOne.tsx @@ -5,7 +5,7 @@ import { RootState } from "../../../store/store"; import { useEffect, useRef, useState } from "react"; import { useNavigate, useParams, useSearchParams } from "react-router-dom"; -import { addRecipientAsync, fetchRecipients, recipientType, removeAllRecipients, removeRecipientAsync, resetRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE, updateRecipientOrder } from "../../../store/slices/selectedRecipientsSlice"; +import { addRecipientAsync, fetchRecipients, recipientType, removeAllRecipients, removeRecipientAsync, resetRecipients, setSigningOrder, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE, updateRecipientOrder } from "../../../store/slices/selectedRecipientsSlice"; import { TRANSACTION_STATUS_ENUMS, updateTransactionStatus } from "../../../store/slices/transactionSlice"; import { hideLoader, showLoader } from "../../../store/slices/loaderSlice"; import Loader from "../../dashboard/Loader"; @@ -78,6 +78,8 @@ const ProcessStepOne = () => { const selectedDocuments = useSelector((state: RootState) => state.documents.documents) const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients) + const signingOrder = useSelector((state: RootState) => state.selectedRecipients.signingOrder) + const [showSelfSignWarnModal, setShowSelfSignWarnModal] = useState(false) const [editRecipientCurrentEmail, setEditRecipientCurrentEmail] = useState('') @@ -87,7 +89,6 @@ const ProcessStepOne = () => { const [templateName, setTemplateName] = useState('Untitled'); const [isTyping, setIsTyping] = useState(false); - const [signingOrder, setSigningOrder] = useState(false) // Optional: use a timer to detect pause in typing let typingTimeout = null; @@ -142,6 +143,12 @@ const ProcessStepOne = () => { if (submitError.duplicateEmailSameRoutingOrder) setSubmitError(prev => ({ ...prev, duplicateEmailSameRoutingOrder: false })) if (submitError.documents) setSubmitError(prev => ({ ...prev, documents: false })) if (submitError.recipients) setSubmitError(prev => ({ ...prev, recipients: false })) + + // Handle Signing Order for template and for transction - fill on refresh based on recipients routing order or prefill - START + let isSigningOrder = signingOrder; + selectedRecipients && selectedRecipients.length > 1 && selectedRecipients.some(recipient => recipient.routingOrder && recipient.routingOrder > 1) ? isSigningOrder = true : ""; + isSigningOrder && handleSigningOrderChange(isSigningOrder); + // Handle Signing Order for template and for transction - fill on refresh based on recipients routing order or prefill - END }, [selectedRecipients]) const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -392,6 +399,9 @@ const ProcessStepOne = () => { useEffect(() => { validationCheck() + selectedRecipients.forEach((recipient, index) => { + + }) }, [selectedDocuments, selectedRecipients, emailDtls]) const handleSelfSignCb = (e: React.ChangeEvent) => { @@ -415,10 +425,10 @@ const ProcessStepOne = () => { ) } - function handleSigningOrderChange() { - setSigningOrder(!signingOrder) + function handleSigningOrderChange(checked?: boolean) { + dispatch(setSigningOrder(checked ?? !signingOrder)) - if (!signingOrder) { + if (checked ?? !signingOrder) { selectedRecipients.forEach((recipient, index) => { const id = recipient.id || recipient.uuid || "1" dispatch(updateRecipientOrder({ id, routingOrder: index + 1 })); @@ -431,7 +441,6 @@ const ProcessStepOne = () => { } } - return ( <>
@@ -538,7 +547,8 @@ const ProcessStepOne = () => { {selectedRecipients.length > 1 &&
handleSigningOrderChange(e.target.checked)} + checked={signingOrder} id="default-checkbox" type="checkbox" value="" className="w-4 h-4 checked:bg-[var(--mainPrimaryBtn)] bg-gray-100 border-gray-300 rounded-sm outline-none" />