+
{hit}{title}
-
+
{message}
@@ -49,42 +49,42 @@ const CompletionScreen: React.FC+
Access your documents anytime — just Login
{/* Illustration placeholder */} -
:
}
+
+
Boost Efficiency with Our Apps
-
+
{/* Forms Made Easy */}
-
+
-
+
Generate Forms with Ease
-
-
@@ -94,15 +94,15 @@ const CompletionScreen: React.FC = ({
{/* Docs Made Easy */}
-
+
-
+
Generate Documents (Invoices, Reports, Quotes)
-
-
+
+
Try Now
@@ -116,8 +116,8 @@ const CompletionScreen: React.FC = ({
{/* Footer */}
-
+
+
+
+
+
+
+
+ {showMenuDownload.open && (
+
+ )}
>
);
}
diff --git a/src/components/client/SignDocument.tsx b/src/components/client/SignDocument.tsx
index 03bab51..0532391 100644
--- a/src/components/client/SignDocument.tsx
+++ b/src/components/client/SignDocument.tsx
@@ -6,14 +6,14 @@ import { Link, useNavigate, useParams } from "react-router-dom"
import { DroppedItem, TagsTypes } from "../../utlity/types";
import Loader from "../dashboard/Loader";
-import SignCon from "../signature/SignCon";
+import ClientSignCon from "../signature/ClientSignCon";
import { Bounce, toast } from "react-toastify";
import { useDispatch, useSelector } from "react-redux";
import { hideLoader, showLoader } from "../../store/slices/loaderSlice";
import { FaSignature, FaCheck, FaQuestionCircle, FaDownload, FaAngleLeft, FaAngleRight } from 'react-icons/fa'
import { IoIosDocument, IoMdHome } from 'react-icons/io'
-import { MdKeyboardArrowDown } from 'react-icons/md'
+import { MdKeyboardArrowDown, MdLabel } from 'react-icons/md'
import confetti from 'canvas-confetti'
import dayjs from "dayjs";
@@ -33,6 +33,8 @@ import ReassignModal from "./ReassignModal";
import { ImCancelCircle } from "react-icons/im";
import ReassignSuccess from "./ReassignSuccess";
import CompletionScreen from "./CompletionScreen";
+import { BsPrinter } from "react-icons/bs";
+import { GrPrint } from "react-icons/gr";
@@ -95,6 +97,7 @@ export interface SaveType {
save: boolean;
signature: string | null;
initial: string | null;
+ isDefaultAndClicked?: boolean;
}
interface TagsSubmitDataObj {
tags: TagSubmitData[];
@@ -161,6 +164,11 @@ const SignDocument = () => {
const [signTagId, setSignTagId] = useState(0)
const [showConfetti, setShowConfetti] = useState(false)
+ const [pageScales, setPageScales] = useState>({});
+
+
+ const [requiredFilled, setRequiredFilled] = useState(false);
+
const [stamp, setStamp] = useState({ open: false, blob: "" });
const [signerConsent, setSignerConsent] = useState<{ consent: boolean; decline: boolean }>({
@@ -200,6 +208,14 @@ const SignDocument = () => {
initial: null,
});
+ enum NavigationTagPosEnum {
+ ABOVE = "above",
+ BELOW = "below",
+ VISIBLE = "VISIBLE"
+ }
+
+ const [navigationTagPos, setNavigationTagPos] = useState(NavigationTagPosEnum.VISIBLE);
+
const navigate = useNavigate();
@@ -238,17 +254,17 @@ const SignDocument = () => {
if (focusElement === null || !("focusElementIndx" in focusElement)) return;
- const docCon = document.getElementById("doc-con");
- document.addEventListener("keydown", (e) => {
- if (e.key === "Tab") {
- e.preventDefault();
+ // const docCon = document.getElementById("doc-con");
+ // document.addEventListener("keydown", (e) => {
+ // if (e.key === "Tab") {
+ // e.preventDefault();
- console.log("Listening Tab Key Press")
- let focusIndx = focusElement?.focusElementIndx;
- if (focusIndx >= droppedItems.length - 1) focusIndx = -1
- setFocusElement({ ...droppedItems[++focusIndx], focusElementIndx: ++focusIndx })
- }
- })
+ // console.log("Listening Tab Key Press")
+ // let focusIndx = focusElement?.focusElementIndx;
+ // if (focusIndx >= droppedItems.length - 1) focusIndx = -1
+ // setFocusElement({ ...droppedItems[++focusIndx], focusElementIndx: ++focusIndx })
+ // }
+ // })
}
}, [droppedItems])
@@ -311,7 +327,7 @@ const SignDocument = () => {
}, [saved])
const fetchData = (isSign: boolean = false) => {
- axios.get(`${import.meta.env.VITE_BASE_URI}/api/sign?recipientId=${recipientId}`,
+ axios.get(`${import.meta.env.VITE_BASE_URI}/api/sign/${recipientId}`,
{
headers:
{ "ngrok-skip-browser-warning": "69420", }
@@ -320,7 +336,13 @@ const SignDocument = () => {
if (res.status === 200) {
setSelectedDocuments(res?.data?.documents)
setRecipient(res?.data?.details)
- setDroppedItems(res?.data?.tagJsons)
+
+ const sortedDroppedItems = res?.data?.tagJsons.sort((a, b) => a.navigationOrder - b.navigationOrder);
+ setDroppedItems(sortedDroppedItems)
+
+ setFocusElement({ ...sortedDroppedItems[0], focusElementIndx: 0 });
+
+
setTransaction(res?.data?.transaction)
setRecSignStatus(res?.data?.status)
@@ -330,7 +352,7 @@ const SignDocument = () => {
setProvideTags(true)
}
- if(windowWidth > 638) {
+ if (windowWidth > 638) {
setIsFields(false)
}
@@ -365,7 +387,7 @@ const SignDocument = () => {
});
}
- const handleFormSubmit = () => {
+ const handleFormSubmit = async () => {
const submitData: TagsSubmitDataObj = {
tags: []
}
@@ -394,9 +416,9 @@ const SignDocument = () => {
const tagData: TagSubmitData = {
id: tag.id as string,
type: tag.type,
- subType: saved.saveType as string,
+ // subType: saved.saveType as string,
signed: true,
- value: ""
+ value: saved.signatureId as string
}
submitData.tags.push(tagData)
} else {
@@ -412,20 +434,23 @@ const SignDocument = () => {
}
// return;
+ try {
+ dispatch(showLoader("Signing ..."));
+ await axios.put(`${import.meta.env.VITE_BASE_URI}/api/sign/${recipientId}/tags`, submitData, { headers: { "ngrok-skip-browser-warning": "69420", } })
+
+ const signRes = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign/${recipientId}`, {}, { headers: { "ngrok-skip-browser-warning": "69420", } })
+ dispatch(hideLoader());
+ if (signRes.status === 200) {
+ dispatch(hideLoader());
+ setTransparentTags(true)
+ setShowConfetti(true)
+ setShowCompletionScreen(true)
+ setSelectedTag(null)
+ }
+ } catch (e) {
+ dispatch(hideLoader());
+ }
- dispatch(showLoader("Signing ..."));
- axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign?recipientId=${recipientId}`, submitData, { headers: { "ngrok-skip-browser-warning": "69420", } })
- .then((res) => {
- if (res.status === 200) {
- dispatch(hideLoader());
- setTransparentTags(true)
- setShowConfetti(true)
- setShowCompletionScreen(true)
- setSelectedTag(null)
- }
- })
- .catch(() => {
- })
};
@@ -442,11 +467,11 @@ const SignDocument = () => {
// If FocusElement is present updating in Based on Next and Prev
const currFocusElemIndx = focusElement.focusElementIndx;
if (currFocusElemIndx === undefined) return;
- const updIndx = (action === "N") ? (currFocusElemIndx + 1) : (currFocusElemIndx - 1)
+ let updIndx = (action === "N") ? (currFocusElemIndx + 1) : (currFocusElemIndx - 1)
- if (updIndx >= droppedItems.length || updIndx < 0 || !droppedItems[updIndx].id) return
+ if (updIndx >= droppedItems.length || updIndx < 0 || !droppedItems[updIndx].id) updIndx = 0;
- scrollToElement(droppedItems[updIndx].id)
+ scrollToElement(droppedItems[updIndx].navigationOrder)
setFocusElement({ ...droppedItems[updIndx], focusElementIndx: updIndx })
}
@@ -462,7 +487,7 @@ const SignDocument = () => {
const fetchSignatureData = async (signatureId: string) => {
try {
- const response = await axios.get(`${import.meta.env.VITE_BASE_URI}/api/sign/signatures/${signatureId}?recipientId=${recipientId}`, {
+ const response = await axios.get(`${import.meta.env.VITE_BASE_URI}/api/sign/${recipientId}signatures/${signatureId}`, {
headers: { "ngrok-skip-browser-warning": "69420" }
});
if (response.status === 200) {
@@ -525,6 +550,17 @@ const SignDocument = () => {
}, [droppedItems.length])
+ useEffect(() => {
+ const allRequiredFields = droppedItems.filter((item, idx) => {
+ if (!item.required) return false
+ if ((item.required && item.value) || idx in signConfObj) return false
+ return true
+ })
+
+ setRequiredFilled(allRequiredFields.length ? false : true)
+ }, [droppedItems, signConfObj])
+
+
// HANDLE DROP - START
const handleDrop = (event: React.DragEvent, docId: string, documentId: number, pageIndex: number) => {
event.preventDefault();
@@ -626,7 +662,7 @@ const SignDocument = () => {
const handleDeclineConfirm = async (reason: string, comments: string) => {
try {
- await axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign/decline?recipientId=${recipientId}`, { reason: reason + ", " + comments });
+ await axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign/decline/${recipientId}`, { reason: reason + ", " + comments });
setSignerConsent((prev) => ({ ...prev, decline: true }));
setRecSignStatus("DECLINED");
setShowCompletionScreen(true);
@@ -634,7 +670,7 @@ const SignDocument = () => {
}
const handleReassignConfirm = (data: { firstName: string; lastName: string; email: string; message: string }) => {
- axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign/reassign?recipientId=${recipientId}`, {
+ axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign/reassign/${recipientId}`, {
name: data.firstName ? data.firstName + " " + data.lastName : data.lastName,
email: data.email,
message: data.message,
@@ -650,6 +686,76 @@ const SignDocument = () => {
});
}
+ // Simple throttle
+ function throttle(fn: Function, wait: number) {
+ let lastTime = 0;
+ return (...args: any[]) => {
+ const now = Date.now();
+ if (now - lastTime >= wait) {
+ lastTime = now;
+ fn(...args);
+ }
+ };
+ }
+
+ // Utility to check if element is out of viewport
+ function isOutOfViewport(el: HTMLElement) {
+ const rect = el.getBoundingClientRect();
+ const windowHeight = window.innerHeight;
+ const windowWidth = window.innerWidth;
+
+ return (
+ rect.right < 0 ||
+ rect.bottom < 0 ||
+ rect.left > windowWidth ||
+ rect.top > windowHeight
+ );
+ }
+
+ function printDocConDiv() {
+ var printContents = document.getElementById(divId).innerHTML;
+ var originalContents = document.body.innerHTML;
+
+ document.body.innerHTML = printContents;
+
+ window.print();
+
+ document.body.innerHTML = originalContents;
+ }
+
+ useEffect(() => {
+ const docCon = document.getElementById("doc-con");
+ if (!docCon) return;
+
+
+ const checkPosition = throttle(() => {
+ let el = document.getElementById("tag-navigation-btn");
+ if (!el) return;
+ const elRect = el.getBoundingClientRect();
+ const containerRect = docCon.getBoundingClientRect();
+
+ if (elRect.bottom < containerRect.top) {
+ setNavigationTagPos(NavigationTagPosEnum.ABOVE)
+ } else if (elRect.top > containerRect.bottom) {
+ setNavigationTagPos(NavigationTagPosEnum.BELOW)
+ } else {
+ setNavigationTagPos(NavigationTagPosEnum.VISIBLE)
+ }
+ }, 150);
+
+ // Initial check
+ checkPosition();
+
+ docCon.addEventListener("scroll", checkPosition);
+ window.addEventListener("resize", checkPosition); // container may resize
+
+ return () => {
+ docCon.removeEventListener("scroll", checkPosition);
+ window.removeEventListener("resize", checkPosition);
+ };
+ }, []);
+
+
if (showCompletionScreen) {
if (recSignStatus === "COMPLETED") {
return
@@ -668,40 +774,12 @@ const SignDocument = () => {
) => handleFormSubmit(e)}
>
+
+
+
{/* Nav Two - Options - START */}
-
- {/* Left Side */}
-
-
- {/* */}
- {/* */}
- {/* Sign Made Easy */}
- {/*
*/}
- {/* */}
-
-
-
- {provideTags && recipient?.type !== "CC" && handleSetIsFields(true)}
- className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${isFields ? 'bg-slate-200' : 'bg-white'}`}>
-
- Fields
- }
-
-
- handleSetIsFields(provideTags ? false : !isFields)}
- className={` flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${!isFields ? 'bg-slate-200' : 'bg-white'} ${!provideTags ? "sm:hidden" : ""}`}>
-
- Pages
-
-
-
- {/* Hi! {recipient && recipient.firstName} {recipient && recipient.lastName}
*/}
-
-
-
+
{/* Right Side - STARTS */}
@@ -713,10 +791,10 @@ const SignDocument = () => {
className=""
tabIndex={1}
onBlur={() => setNav2DocToggle(false)}>
- setNav2DocToggle(!nav2DocToggle)} className='bg-white flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
+ {/* setNav2DocToggle(!nav2DocToggle)} className='bg-white flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
{selectedDocuments && selectedDocuments.length} Documents
-
+ */}
{
}
>
- {/* FIT - START */}
- setIsFitDd(false)}
- >
- setIsFitDd(!isFitDd)}
- className='bg-white flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ml-2'>
- Fit
-
-
+ {/* PRINT _ START */}
+
+ {/* PRINT _ END */}
+
+
- {isFitDd &&
- {fitObj.map((val, indx) => {
- return ( setSelFitIndx(indx)}
- className='flex z-50 items-center justify-between gap-2 w-[70px] p-2 text-xs cursor-default hover:bg-slate-100'>
-
- {val.label}
- {selFitIndx === indx && }
-
- )
- })
- }
- }
-
- {/* FIT - END */}
{/* Send */}
{/* {(!transparentTags && !hideTags) ? {
<>
-
- {/* By Signing I agree Sign Made Easy Terms & Conditions.
*/}
-
+
+ By Signing I agree Sign Made Easy Terms & Conditions.
+ {/*
handleTagNavClick("P")}
className="bg-[var(--mainPrimaryBtn)] p-1 text-2xl text-white rounded-md" />
@@ -816,23 +872,69 @@ const SignDocument = () => {
handleTagNavClick("N")}
className="bg-[var(--mainPrimaryBtn)] p-1 text-2xl text-white rounded-md" />
-
- */}
+
+ {/* Sign
+ >Sign */}
+
+
+ {/* FIT - START */}
+ setIsFitDd(false)}
+ >
+ setIsFitDd(!isFitDd)}
+ className='bg-white flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ml-2'>
+ Fit
+
+
+
+ {isFitDd &&
+ {fitObj.map((val, indx) => {
+ return ( setSelFitIndx(indx)}
+ className='flex z-50 items-center justify-between gap-2 w-[70px] p-2 text-xs cursor-default hover:bg-slate-100'>
+
+ {val.label}
+ {selFitIndx === indx && }
+
+ )
+ })
+ }
+ }
+
+ {/* FIT - END */}
+
>
+
+ {requiredFilled && <>
+
+
+ All Set to Wrap This Up?
+ You've completed the required fields. Review your work, then select Finish.
+
+ Finish
+
+ >}
+
+
{/* Right Side - ENDS */}
{/* Nav Two - Options - End */}
-
-
-
{/* Document Container Start */}
@@ -840,7 +942,29 @@ const SignDocument = () => {
{/* */}
)
})
}
+
+ {(navigationTagPos === NavigationTagPosEnum.ABOVE || navigationTagPos === NavigationTagPosEnum.BELOW) &&
+ scrollToElement(focusElement?.navigationOrder)}
+ className={`cursor-pointer fixed ${navigationTagPos === NavigationTagPosEnum.ABOVE ? "top-[45px]" : "bottom-[45px] rotate-[180deg]"} right-[8%] flex flex-col items-center`}>
+ {/* Arrow pointing up */}
+
+
+ {/* Label box */}
+
+ Next
+
+ }
+
{provideTags && selectedTag && selectedTag !== null && "key" in selectedTag && "index" in selectedTag &&
@@ -959,7 +1126,7 @@ const SignDocument = () => {
{recipient &&
- >,
setStamp: React.Dispatch>;
setSignConfObj: React.Dispatch>;
setOpenSign: React.Dispatch>,
@@ -38,6 +40,7 @@ interface TagsConProps {
}
const TagsCon: React.FC = ({
+ scale,
currDocTags,
pageIdkey,
provideTags,
@@ -50,6 +53,8 @@ const TagsCon: React.FC = ({
droppedItems,
saved,
signConfObj,
+ recipientId,
+ setSaved,
setStamp,
setSignConfObj,
setOpenSign,
@@ -134,7 +139,7 @@ const TagsCon: React.FC = ({
(async () => {
if ("id" in tag) {
try {
- const response = await api.delete(`/api/sign/tags?recipientId=${recipientId}`, { data: [{ tagId: tag.id }] })
+ const response = await api.delete(`/api/sign/${recipientId}/tags/`, { data: [{ tagId: tag.id }] })
if (response.status !== 200) throw "Tag Deletion error"
} catch (err) {
return;
@@ -233,9 +238,24 @@ const TagsCon: React.FC = ({
// });
}
- const handleSignClick = (index: number, id: number) => {
+ const handleSignClick = async (index: number, id: number) => {
+
setSignTagId(id)
if (saved.save) {
+ if (saved.isDefaultAndClicked) {
+ try {
+ const res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign/${recipientId}/signatures`, {
+ signatureId: saved.signatureId,
+ tagId: id
+ }, { headers: { "ngrok-skip-browser-warning": "69420", } })
+
+ if (res.status === 202) {
+ setSaved({ ...saved, signatureId: res.data.id, isDefaultAndClicked: false });
+ }
+ } catch (error) { }
+ }
+
+
if (index in signConfObj) {
setOpenSign(true);
return
@@ -248,9 +268,16 @@ const TagsCon: React.FC = ({
}
})
return
+
+
}
setOpenSign(true);
-
+ // setDroppedItems((prev) => {
+ // return prev.map((obj, idx) => {
+ // if (idx === index && obj.id === id) return { ...obj, valus: saved.signatureId }
+ // return obj;
+ // })
+ // })
const newObj = {
[index]: {
"accepted": false,
@@ -258,7 +285,6 @@ const TagsCon: React.FC = ({
}
}
setSignConfObj({ ...newObj })
-
}
const handleStampClick = (index: number) => {
@@ -284,22 +310,34 @@ const TagsCon: React.FC = ({
tabIndex={index + 1}
onFocus={() => {
setSelectedTag({ key: pageIdkey, index })
- // setFocusElement({ ...item, focusElementIndx: index })
+ setFocusElement({ ...item, focusElementIndx: index })
}
}
key={index}
// onPointerDown={(e) => handleTagMouseDown(e, key, index)}
className="absolute rounded dropped-item text-sm"
// onClick={() => handleTagClick(key, index)}
+ // style={{
+ // left: `${item.dimensions.left}px`,
+ // top: `${item.dimensions.top}px`,
+ // width: `${item.dimensions.width}px`,
+ // height: `${item.dimensions.height}px`,
+ // border: `${((!hideTags && focusElement) && !transparentTags && focusElement.documentId === item.documentId && focusElement.focusElementIndx === index) ? '2px dashed #1c398e' : 'none'}`,
+ // // display: `${hideTags ? 'none' : 'block'}`
+ // }}
+
style={{
- left: `${item.dimensions.left}px`,
- top: `${item.dimensions.top}px`,
- width: `${item.dimensions.width}px`,
- height: `${item.dimensions.height}px`,
- border: `${((!hideTags && focusElement) && !transparentTags && focusElement.documentId === item.documentId && focusElement.focusElementIndx === index) ? '2px dashed #1c398e' : 'none'}`,
- // display: `${hideTags ? 'none' : 'block'}`
+ left: item.dimensions.left * scale.x,
+ top: item.dimensions.top * scale.y,
+ width: item.dimensions.width * scale.x,
+ height: item.dimensions.height * scale.y,
}}
>
+
+ {item.required && *}
+
{provideTags && !transparentTags && !hideTags && handleTagMouseDown(e, pageIdkey, index)}
// className="absolute top-[-15px] left-[-15px] w-4 h-4 bg-blue-600 rounded-tr cursor-move z-30"
@@ -319,8 +357,8 @@ const TagsCon: React.FC = ({
>
*/}
{/* {IconComponent}
-
*/}
+ className=''>{IconComponent}
+ */}
{item.label}
{provideTags && {
e.stopPropagation();
@@ -788,26 +826,26 @@ const TagsCon: React.FC = ({
>
{focusElement.label}
*/}
-
{
- handleTagNavClick("P")
- }}
+ onClick={() => {
+ handleTagNavClick("P")
+ }}
>
{focusElement.navigationOrder}/{droppedItems.length}
{
- handleTagNavClick("N")
- }}
+ onClick={() => {
+ handleTagNavClick("N")
+ }}
>
-
+ */}
>
}
diff --git a/src/components/client/TermsModal.tsx b/src/components/client/TermsModal.tsx
index 2ee8292..94cf420 100644
--- a/src/components/client/TermsModal.tsx
+++ b/src/components/client/TermsModal.tsx
@@ -12,7 +12,7 @@ interface TermsModalProps {
const TermsModal: React.FC = ({ showTerms, setShowTerms, recipientId }) => {
const onAccept = () => {
- axios.put(`${import.meta.env.VITE_BASE_URI}/api/sign/accept?recipientId=${recipientId}`, { headers: { "ngrok-skip-browser-warning": "69420" } })
+ axios.put(`${import.meta.env.VITE_BASE_URI}/api/sign/accept/${recipientId}`, { headers: { "ngrok-skip-browser-warning": "69420" } })
.then(response => {
setShowTerms(false);
console.log(response, "Accept");
diff --git a/src/components/dashboard/SendForSign.tsx b/src/components/dashboard/SendForSign.tsx
index 3d3301a..c16836b 100644
--- a/src/components/dashboard/SendForSign.tsx
+++ b/src/components/dashboard/SendForSign.tsx
@@ -24,10 +24,13 @@ const SendForSign: React.FC = ({ showSideBar }) => {
}, [sendForSignDropdown])
const user = useSelector((state: RootState) => state.user);
- if (!user.account || user.account === null) {
- window.location.href = "/login";
- return;
- }
+
+ useEffect(() => {
+ if (!user.account || user.account === null) {
+ window.location.href = "/login";
+ return;
+ }
+ }, [])
const defaultAccountId = user.account.id;
@@ -118,7 +121,7 @@ const SendForSign: React.FC = ({ showSideBar }) => {
transition-all duration-300 ease-in-out w-full
rounded
`}
- style={{ whiteSpace: "nowrap" }}
+ style={{ whiteSpace: "nowrap" }}
>
{showSideBar ? (
Send for signature
diff --git a/src/components/process/CompletionScreen/SignerList.tsx b/src/components/process/CompletionScreen/SignerList.tsx
index 05e8fe8..158e8c4 100644
--- a/src/components/process/CompletionScreen/SignerList.tsx
+++ b/src/components/process/CompletionScreen/SignerList.tsx
@@ -4,20 +4,20 @@ import { Signer } from "./DocumentCompletionScreen";
export const SignersList: React.FC<{ signers: Signer[] }> = ({ signers }) => {
return (
//
-
-
-
+
+
+
{/* */}
Recipients
- {signers.filter(s => s.completed).length} of {signers.length} signed
+ {signers.filter(s => s.completed).length}/{signers.length} Signed
-
- {signers.map((signer) => (
-
+
+ {signers.map((signer, indx) => (
+
{/* {signer.name.split(" ").length > 2 ? signer.name.split(" ").map(n => n[0].toUpperCase()).join("") : signer.name[0].toUpperCase()} */}
@@ -31,13 +31,15 @@ export const SignersList: React.FC<{ signers: Signer[] }> = ({ signers }) => {
{signer.completed ? (
-
-
+
+ {/* */}
+
Signed
) : (
-
-
+
+ {/* */}
+
Pending
)}
diff --git a/src/components/process/CompletionScreen/TransactionSentSuccess.tsx b/src/components/process/CompletionScreen/TransactionSentSuccess.tsx
index 319fe83..8b2cc33 100644
--- a/src/components/process/CompletionScreen/TransactionSentSuccess.tsx
+++ b/src/components/process/CompletionScreen/TransactionSentSuccess.tsx
@@ -9,6 +9,7 @@ import { fetchRecipients, recipientType } from '../../../store/slices/selectedRe
import { fetchDocuments } from '../../../store/slices/documentSlice'
import { SigningOrderDiagram } from './SigningOrderDiagram'
import { SignersList } from './SignerList'
+import signSessionRedirect from '../../../utlity/signSessionRedirect'
const TransactionSentSuccess = () => {
const [isVisible, setIsVisible] = useState(false)
@@ -68,43 +69,60 @@ const TransactionSentSuccess = () => {
}, [selectedRecipients])
return (
-
+
+
+
+
+
+
{/* Header */}
-
+ {/* */}
+
-
-
+ {/* */}
+ {/*
🎉 Awesome! The document’s been sent for signature. 🎉
-
+
*/}
{/* Content */}
{/* Success banner */}
-
-
+
+ {/*
-
+ */}
+
+
+
+
+
+
-
+
Your Document is sent for signature
- All signers will be notified via email
+ All signers will be notified via email
{/* Main two-column layout */}
-
+
{/* Left: Document Preview */}
-
-
+
+
Quick Preview
@@ -115,30 +133,36 @@ const TransactionSentSuccess = () => {
{/* Right: Signers list + actions */}
-
-
+
+
+
+
+
+
+
+
+ Back to Home
+
+
+ {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"
+ >
+ Sign Now
+
+ )}
+
+
+
-
- {selfUserSign.sign && (
-
- Sign Now
-
- )}
-
- Home
-
-
{/* Optional: Signing Order */}
{/*
@@ -148,6 +172,20 @@ const TransactionSentSuccess = () => {
+
+ {/* Footer */}
+
+
+ Copyright 2025 Sign Made Easy. All Rights Reserved.{" "}
+
+ Privacy Policy
+ {" "}
+ |{" "}
+
+ Reasonable Use Policy
+
+
+
)
}
diff --git a/src/components/process/processStepOne/DocumentCard.tsx b/src/components/process/processStepOne/DocumentCard.tsx
index 25476e3..6e9d057 100644
--- a/src/components/process/processStepOne/DocumentCard.tsx
+++ b/src/components/process/processStepOne/DocumentCard.tsx
@@ -40,7 +40,7 @@ const DocumentCard: React.FC = ({ id, name, isCompleted, tran
let lastUpdate = 0;
const delay = 1000;
- const docProgSSE = new EventSource(`http://192.168.2.176:8083/api/progress/${id}`);
+ const docProgSSE = new EventSource(`http://10.10.1.99:8083/api/progress/${id}`);
docProgSSE.addEventListener('progress', (event) => {
const jsonData = JSON.parse(event.data);
diff --git a/src/components/process/processStepOne/ProcessStepOne.tsx b/src/components/process/processStepOne/ProcessStepOne.tsx
index ab36ad5..b07d14b 100644
--- a/src/components/process/processStepOne/ProcessStepOne.tsx
+++ b/src/components/process/processStepOne/ProcessStepOne.tsx
@@ -23,6 +23,7 @@ import getMinRoutingOrder from "../../../utlity/commonUtils";
import MessageCon from "./MessageCon";
import RecipientsCon from "./RecipientsCon";
import { VscClose } from "react-icons/vsc";
+import signSessionRedirect from "../../../utlity/signSessionRedirect";
interface EmailDtls {
subject: string;
@@ -227,7 +228,7 @@ const ProcessStepOne = () => {
await api.patch(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/documents`, { "documents": documentsData });
- await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/documents?include_images=true`).then(res => {
+ await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/documents?include_pages=true`).then(res => {
if (res.status === 200) {
dispatch(setDocuments(res.data));
}
@@ -336,8 +337,8 @@ const ProcessStepOne = () => {
(async () => {
try {
await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { status: "SENT" })
+ if(accountId && transactionId) signSessionRedirect(accountId, transactionId, recipientId);
dispatch(hideLoader());
- navigate(`/sign/${recipientId}/self_sign`);
} catch (err) {
console.log("Error Transaction Sent", err.message);
}
diff --git a/src/components/process/processStepTwo/DocumentContainer.tsx b/src/components/process/processStepTwo/DocumentContainer.tsx
index be4ff16..d42d32f 100644
--- a/src/components/process/processStepTwo/DocumentContainer.tsx
+++ b/src/components/process/processStepTwo/DocumentContainer.tsx
@@ -195,8 +195,8 @@ const DocumentContainer: React.FC = ({ transactionSaving
}
const requests = Object.entries(updatedData)
- .filter(([_, tags]) => tags.length > 0) // filter out empty ones
- .map(([recipientId, tags]) => {
+ .filter(([_, tags]) => tags.length > 0) // filter out empty ones
+ .map(([recipientId, tags]) => {
const updatedTagsWithNavOrder = tags.map((tag, indx) => ({
...tag,
navigationOrder: indx + 1,
@@ -458,6 +458,13 @@ const DocumentContainer: React.FC = ({ transactionSaving
// return () => targetCon?.removeEventListener("keydown");
}
+
+ const handleLazyLoad = (docId: string, pageId: string) => {
+ api.get(`http://10.10.1.99:8083/api/${accountId}/transactions/${transactionId}/documents/${docId}/pages/${pageId}`).then(res => {
+ console.log(res)
+ })
+ }
+
return (
<>
{/* Center Doc Container - START */}
@@ -506,6 +513,7 @@ const DocumentContainer: React.FC = ({ transactionSaving
draggable="false"
width={page.width}
height={page.height}
+ // src={`http://10.10.1.99:8083/api/accounts/${accountId}/transactions/${transactionId}/documents/${doc.id}/pages/${page.id}`}
src={page.src}
loading='lazy'
/>
diff --git a/src/components/process/processStepTwo/FieldList.tsx b/src/components/process/processStepTwo/FieldList.tsx
index 11c98b2..6ecc7cb 100644
--- a/src/components/process/processStepTwo/FieldList.tsx
+++ b/src/components/process/processStepTwo/FieldList.tsx
@@ -129,7 +129,7 @@ const FieldList: React.FC = ({ color, recipientId, recipientIndx
const priorityOrder = ['SIGNATURE', 'INITIALS', 'STAMP'];
const data = res.data.filter((obj, indx) => {
- // if (obj.type === "STAMP" || obj.type === "RADIO" || obj.type === "CHECKBOX" || obj.type === "ATTACHMENT") return false
+ if (obj.type === "STAMP" || obj.type === "RADIO" || obj.type === "CHECKBOX" || obj.type === "ATTACHMENT") return false
return true
});
diff --git a/src/components/process/processStepTwo/LeftSideBar.tsx b/src/components/process/processStepTwo/LeftSideBar.tsx
index d13161e..011f88f 100644
--- a/src/components/process/processStepTwo/LeftSideBar.tsx
+++ b/src/components/process/processStepTwo/LeftSideBar.tsx
@@ -10,15 +10,19 @@ import { MdKeyboardArrowDown, MdOutlineNavigateNext } from 'react-icons/md'
import { useParams } from 'react-router-dom';
import { fetchDocuments } from '../../../store/slices/documentSlice';
import { GrFormPrevious } from 'react-icons/gr';
+import { LuTableOfContents } from 'react-icons/lu';
+import { IoIosDocument } from 'react-icons/io';
interface LeftSideBarProps {
isFields: boolean;
isPages: boolean;
selectedRecipientIndx: number;
setSelectedRecipient: React.Dispatch>
+ handleSetIsFields: (setTo: boolean) => void;
+ handleSetIsPages:(setTo: boolean) => void;
}
-const LeftSideBar: React.FC = ({ isFields, isPages, selectedRecipientIndx, setSelectedRecipient }) => {
+const LeftSideBar: React.FC = ({ isFields, isPages, selectedRecipientIndx, setSelectedRecipient, handleSetIsFields, handleSetIsPages }) => {
let transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS;
const dispatch = useDispatch();
@@ -78,7 +82,7 @@ const LeftSideBar: React.FC = ({ isFields, isPages, selectedRe
};
}, [selectedRecipient])
- if(selectedRecipient && selectedRecipient.type === recipientType.CC){
+ if (selectedRecipient && selectedRecipient.type === recipientType.CC) {
return ;
}
@@ -87,6 +91,24 @@ const LeftSideBar: React.FC = ({ isFields, isPages, selectedRe
{/* Left Side Bar - START */}
{
+
+
+ handleSetIsFields(!isFields)}
+ className={`flex items-center gap-1 cursor-pointer text-xs w-full justify-center py-1.5 rounded-2xl ${isFields ? 'bg-[var(--primary)] text-white' : ''} transition-all duration-300`}>
+
+ Tags
+
+
+ handleSetIsPages(!isPages)}
+ className={`flex items-center gap-1 cursor-pointer text-xs w-full justify-center py-1.5 rounded-2xl ${isPages ? 'bg-[var(--primary)] text-white' : ''} transition-all duration-300`}>
+
+ Pages
+
+
+
+
{selectedRecipients.length > 0 && isFields && <>
{/* Fields List and Recipeint - Start */}
{/* Side Bar showing Recipients */}
diff --git a/src/components/process/processStepTwo/NavTwo.tsx b/src/components/process/processStepTwo/NavTwo.tsx
index b38bf18..03df70b 100644
--- a/src/components/process/processStepTwo/NavTwo.tsx
+++ b/src/components/process/processStepTwo/NavTwo.tsx
@@ -10,7 +10,7 @@ import { MdKeyboardArrowDown } from 'react-icons/md'
import { RiResetRightLine } from 'react-icons/ri'
import { fetchRecipients, recipientType, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE } from '../../../store/slices/selectedRecipientsSlice'
import { fetchDocuments } from '../../../store/slices/documentSlice'
-import { useNavigate, useParams } from 'react-router-dom'
+import { Link, useNavigate, useParams } from 'react-router-dom'
import { Bounce, toast } from 'react-toastify'
import { FiChevronDown } from 'react-icons/fi'
import RecipientsCon from '../processStepOne/RecipientsCon'
@@ -181,22 +181,23 @@ const NavTwo: React.FC = ({
}, 1000)
}
- const handleSetIsFields = (setTo: boolean) => {
- if (setTo !== undefined && setTo !== isFields) {
- setIsFields(setTo)
- if(setTo === true) {
- setIsPages(false)
- }
- };
- }
- const handleSetIsPages = (setTo: boolean) => {
- if (setTo !== undefined && setTo !== isPages) {
- setIsPages(setTo)
- if(setTo === true) {
- setIsFields(false)
- }
- };
- }
+ // const handleSetIsFields = (setTo: boolean) => {
+ // if (setTo !== undefined && setTo !== isFields) {
+ // setIsFields(setTo)
+ // if(setTo === true) {
+ // setIsPages(false)
+ // }
+ // };
+ // }
+
+ // const handleSetIsPages = (setTo: boolean) => {
+ // if (setTo !== undefined && setTo !== isPages) {
+ // setIsPages(setTo)
+ // if(setTo === true) {
+ // setIsFields(false)
+ // }
+ // };
+ // }
const zoom = (percentage: number, contentClass: string) => {
const content = document.querySelector(`.${contentClass}`);
@@ -234,24 +235,20 @@ const NavTwo: React.FC = ({
{/* Left Side */}
- handleSetIsFields(!isFields)}
- className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${isFields ? 'bg-slate-100' : ''}`}>
-
- Fields
+
+
+
+
- handleSetIsPages(!isPages)}
- className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${isPages ? 'bg-slate-100' : ''}`}>
-
- Pages
-
setIsFitDd(false)}
>
+
+
+
setIsFitDd(!isFitDd)}
className='hidden sm:flex md:flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
@@ -259,7 +256,7 @@ const NavTwo: React.FC = ({
- {isFitDd &&
+ {isFitDd &&
{fitObj.map((val, indx) => {
return ( = ({
- {!isPreview &&
+ {/* {!isPreview &&
{transactionSaving ? `Saving ${dots}` : "Save"}
- }
+ } */}
@@ -342,7 +339,7 @@ const NavTwo: React.FC = ({
{/* Document Nav */}
setNav2DocToggle(false)}>
+ tabIndex={1} onBlur={() => setNav2DocToggle(false)}>
setNav2DocToggle(!nav2DocToggle)} className='flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
{selectedDocuments.length} Documents
diff --git a/src/components/process/processStepTwo/ProcessStepTwo.tsx b/src/components/process/processStepTwo/ProcessStepTwo.tsx
index c6d0e05..84a1eda 100644
--- a/src/components/process/processStepTwo/ProcessStepTwo.tsx
+++ b/src/components/process/processStepTwo/ProcessStepTwo.tsx
@@ -21,7 +21,7 @@ const ProcessStepTwo = () => {
const [isFields, setIsFields] = useState(windowWidth > 638 ? true : false);
const [isPages, setIsPages] = useState(false);
-
+
const [selectedRecipient, setSelectedRecipient] = useState(0);
const [transactionSaving, setTransactionSaving] = useState(false);
@@ -37,12 +37,31 @@ const ProcessStepTwo = () => {
}, 800)
}, [])
+
+ const handleSetIsFields = (setTo: boolean) => {
+ if (setTo !== undefined && setTo !== isFields) {
+ setIsFields(setTo)
+ if (setTo === true) {
+ setIsPages(false)
+ }
+ };
+ }
+
+ const handleSetIsPages = (setTo: boolean) => {
+ if (setTo !== undefined && setTo !== isPages) {
+ setIsPages(setTo)
+ if(setTo === true) {
+ setIsFields(false)
+ }
+ };
+ }
+
return (
-
+
diff --git a/src/components/routes_helper/ProtectedRoute.tsx b/src/components/routes_helper/ProtectedRoute.tsx
index 28bce20..ec98db7 100644
--- a/src/components/routes_helper/ProtectedRoute.tsx
+++ b/src/components/routes_helper/ProtectedRoute.tsx
@@ -1,13 +1,14 @@
import { JSX, useLayoutEffect } from 'react';
import { useDispatch } from "react-redux";
import { fetchUserDetails } from '../../store/slices/userSlice';
+import { AppDispatch } from '../../store/store';
const ProtectedRoute = ({ children }: { children: JSX.Element }) => {
- const dispatch = useDispatch();
+ const dispatch = useDispatch();
- useLayoutEffect(() => {
+ // useLayoutEffect(() => {
dispatch(fetchUserDetails());
- }, []);
+ // }, []);
return children;
};
diff --git a/src/components/setting/Signature/AddSignatureModal.tsx b/src/components/setting/Signature/AddSignatureModal.tsx
index 3c85cc2..8cbc314 100644
--- a/src/components/setting/Signature/AddSignatureModal.tsx
+++ b/src/components/setting/Signature/AddSignatureModal.tsx
@@ -7,6 +7,7 @@ import { FaSpinner } from "react-icons/fa";
import { GrCheckboxSelected } from "react-icons/gr";
import { Bounce, toast } from "react-toastify";
import { FiCheck } from 'react-icons/fi';
+import { IoMdClose } from 'react-icons/io';
interface Signature {
id: string;
@@ -55,7 +56,7 @@ const AddSignatureModal: React.FC = ({
getAllSignatures,
editingSignature
}) => {
- const [activeTab, setActiveTab] = useState<'SELECT' | 'DRAW' | 'UPLOAD'>('SELECT');
+ const [activeTab, setActiveTab] = useState<'SELECT' | 'DRAW' | 'UPLOAD'>('DRAW');
const [fullName, setFullName] = useState('');
const [initials, setInitials] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -196,17 +197,17 @@ const AddSignatureModal: React.FC = ({
if ((activeTab === 'DRAW' || activeTab === 'UPLOAD') &&
(!signatures.fullSignature || !signatures.initials)) {
// alert('Please provide both signature and initials');
- toast.error('Please provide both signature and initials in draw and upload case', {
- position: "top-center",
- autoClose: 2000,
- hideProgressBar: false,
- closeOnClick: false,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
+ // toast.error('Please provide both signature and initials in draw and upload case', {
+ // position: "top-center",
+ // autoClose: 2000,
+ // hideProgressBar: false,
+ // closeOnClick: false,
+ // pauseOnHover: true,
+ // draggable: true,
+ // progress: undefined,
+ // theme: "light",
+ // transition: Bounce,
+ // });
setIsSubmitting(false);
return;
}
@@ -236,32 +237,32 @@ const AddSignatureModal: React.FC = ({
};
res = await api.put(`/api/user/signatures`, updatePayload);
- toast.success("Signature Updated Successfully", {
- position: "top-center",
- autoClose: 500,
- hideProgressBar: false,
- closeOnClick: false,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
+ // toast.success("Signature Updated Successfully", {
+ // position: "top-center",
+ // autoClose: 500,
+ // hideProgressBar: false,
+ // closeOnClick: false,
+ // pauseOnHover: true,
+ // draggable: true,
+ // progress: undefined,
+ // theme: "light",
+ // transition: Bounce,
+ // });
} else {
// Create new signature
res = await api.post(`/api/user/signatures`, payload);
- toast.success("Signature Created Successfully", {
- position: "top-center",
- autoClose: 500,
- hideProgressBar: false,
- closeOnClick: false,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
+ // toast.success("Signature Created Successfully", {
+ // position: "top-center",
+ // autoClose: 500,
+ // hideProgressBar: false,
+ // closeOnClick: false,
+ // pauseOnHover: true,
+ // draggable: true,
+ // progress: undefined,
+ // theme: "light",
+ // transition: Bounce,
+ // });
}
if (res?.data) {
@@ -286,85 +287,46 @@ const AddSignatureModal: React.FC = ({
}
};
-
// Fixed renderContent function for SELECT case with proper radio button styling
const renderContent = () => {
switch (activeTab) {
case 'SELECT':
return (
-
-
- Choose Signature Style
- Select from pre-designed signature styles
-
-
-
-
- {signatureOptions.map((option) => (
- setSelectedSignature({ id: option.id, style: option.style })}
- >
- {/* Custom Radio Button */}
-
-
- {selectedSignature.id === option.id && (
-
- )}
-
-
-
- {/* Hidden native radio button for accessibility */}
- setSelectedSignature({ id: option.id, style: option.style })}
- className="sr-only"
- />
-
-
-
- Signed by:
-
- {fullName || option.name}
-
-
- dca3e646-62cd-4cc...
-
-
-
- DS
-
- {initials || option.initials}
-
-
-
-
- ))}
+ <>
+ {/* Form Inputs - Fixed */}
+
+ Confirm your name and choose signature style. *Are required fields.
+
+
+
+ setFullName(e.target.value)}
+ placeholder="Enter full name"
+ className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none"
+ />
+
+
+
+ setInitials(e.target.value)}
+ placeholder="Enter initials"
+ className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none"
+ />
+
+
-
+ >
);
case 'DRAW':
@@ -380,23 +342,34 @@ const AddSignatureModal: React.FC = ({
case 'UPLOAD':
return (
-
- Upload Signature
- Upload your signature images
+
+ Upload your Signature and confirm your name * Are required fields.
+ For best results, use an image that is 400 x 150 pixels for signature and 150 x 150 for initials
+ The maximum file size for the image is 300kb. File types supported include .png, .jpg, .jpeg
-
+
{/* Upload 1 - Full Signature */}
-
-
-
Boost Efficiency with Our Apps
-+
Generate Forms with Ease
- +
Generate Documents (Invoices, Reports, Quotes)
-
+ */} - {/* Sign Made Easy */} - {/*
*/} - {/*
-
- {provideTags && recipient?.type !== "CC" && Fields
- handleSetIsFields(provideTags ? false : !isFields)}
- className={` flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${!isFields ? 'bg-slate-200' : 'bg-white'} ${!provideTags ? "sm:hidden" : ""}`}>
-
Hi! {recipient && recipient.firstName} {recipient && recipient.lastName}
*/} -
{/* Right Side - STARTS */}
{selectedDocuments && selectedDocuments.length} Documents
Fit
-{val.label}
- {selFitIndx === indx &&By Signing I agree Sign Made Easy Terms & Conditions.
*/} -By Signing I agree Sign Made Easy Terms & Conditions.
+ {/**/} +
+ {/*Sign
+ >Sign */} + +Fit
+{val.label}
+ {selFitIndx === indx &&All Set to Wrap This Up?
+You've completed the required fields. Review your work, then select Finish.
+{IconComponent} -
*/} + className=''>{IconComponent} + */}{item.label}
{provideTags &&{focusElement.label}
{focusElement.navigationOrder}/{droppedItems.length}
{ - handleTagNavClick("N") - }} + onClick={() => { + handleTagNavClick("N") + }} >Send for signature
diff --git a/src/components/process/CompletionScreen/SignerList.tsx b/src/components/process/CompletionScreen/SignerList.tsx index 05e8fe8..158e8c4 100644 --- a/src/components/process/CompletionScreen/SignerList.tsx +++ b/src/components/process/CompletionScreen/SignerList.tsx @@ -4,20 +4,20 @@ import { Signer } from "./DocumentCompletionScreen"; export const SignersList: React.FC<{ signers: Signer[] }> = ({ signers }) => { return ( //
+
+
+
{/* */}
Recipients
- {signers.filter(s => s.completed).length} of {signers.length} signed
+ {signers.filter(s => s.completed).length}/{signers.length} Signed
-
- {signers.map((signer) => (
-
+
+ {signers.map((signer, indx) => (
+
{/* {signer.name.split(" ").length > 2 ? signer.name.split(" ").map(n => n[0].toUpperCase()).join("") : signer.name[0].toUpperCase()} */}
@@ -31,13 +31,15 @@ export const SignersList: React.FC<{ signers: Signer[] }> = ({ signers }) => {
{signer.completed ? (
-
-
+
+ {/* */}
+
Signed
) : (
-
-
+
+ {/* */}
+
Pending
)}
diff --git a/src/components/process/CompletionScreen/TransactionSentSuccess.tsx b/src/components/process/CompletionScreen/TransactionSentSuccess.tsx
index 319fe83..8b2cc33 100644
--- a/src/components/process/CompletionScreen/TransactionSentSuccess.tsx
+++ b/src/components/process/CompletionScreen/TransactionSentSuccess.tsx
@@ -9,6 +9,7 @@ import { fetchRecipients, recipientType } from '../../../store/slices/selectedRe
import { fetchDocuments } from '../../../store/slices/documentSlice'
import { SigningOrderDiagram } from './SigningOrderDiagram'
import { SignersList } from './SignerList'
+import signSessionRedirect from '../../../utlity/signSessionRedirect'
const TransactionSentSuccess = () => {
const [isVisible, setIsVisible] = useState(false)
@@ -68,43 +69,60 @@ const TransactionSentSuccess = () => {
}, [selectedRecipients])
return (
-
+
+
+
+
+
+
{/* Header */}
-
+ {/* */}
+
-
-
+ {/* */}
+ {/*
🎉 Awesome! The document’s been sent for signature. 🎉
-
+
*/}
{/* Content */}
{/* Success banner */}
-
-
+
+ {/*
-
+ */}
+
+
+
+
+
+
-
+
Your Document is sent for signature
- All signers will be notified via email
+ All signers will be notified via email
{/* Main two-column layout */}
-
+
{/* Left: Document Preview */}
-
-
+
+
Quick Preview
@@ -115,30 +133,36 @@ const TransactionSentSuccess = () => {
{/* Right: Signers list + actions */}
-
-
+
+
+
+
+
+
+
+
+ Back to Home
+
+
+ {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"
+ >
+ Sign Now
+
+ )}
+
+
+
-
- {selfUserSign.sign && (
-
- Sign Now
-
- )}
-
- Home
-
-
{/* Optional: Signing Order */}
{/*
@@ -148,6 +172,20 @@ const TransactionSentSuccess = () => {
+
+ {/* Footer */}
+
+
+ Copyright 2025 Sign Made Easy. All Rights Reserved.{" "}
+
+ Privacy Policy
+ {" "}
+ |{" "}
+
+ Reasonable Use Policy
+
+
+
)
}
diff --git a/src/components/process/processStepOne/DocumentCard.tsx b/src/components/process/processStepOne/DocumentCard.tsx
index 25476e3..6e9d057 100644
--- a/src/components/process/processStepOne/DocumentCard.tsx
+++ b/src/components/process/processStepOne/DocumentCard.tsx
@@ -40,7 +40,7 @@ const DocumentCard: React.FC = ({ id, name, isCompleted, tran
let lastUpdate = 0;
const delay = 1000;
- const docProgSSE = new EventSource(`http://192.168.2.176:8083/api/progress/${id}`);
+ const docProgSSE = new EventSource(`http://10.10.1.99:8083/api/progress/${id}`);
docProgSSE.addEventListener('progress', (event) => {
const jsonData = JSON.parse(event.data);
diff --git a/src/components/process/processStepOne/ProcessStepOne.tsx b/src/components/process/processStepOne/ProcessStepOne.tsx
index ab36ad5..b07d14b 100644
--- a/src/components/process/processStepOne/ProcessStepOne.tsx
+++ b/src/components/process/processStepOne/ProcessStepOne.tsx
@@ -23,6 +23,7 @@ import getMinRoutingOrder from "../../../utlity/commonUtils";
import MessageCon from "./MessageCon";
import RecipientsCon from "./RecipientsCon";
import { VscClose } from "react-icons/vsc";
+import signSessionRedirect from "../../../utlity/signSessionRedirect";
interface EmailDtls {
subject: string;
@@ -227,7 +228,7 @@ const ProcessStepOne = () => {
await api.patch(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/documents`, { "documents": documentsData });
- await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/documents?include_images=true`).then(res => {
+ await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/documents?include_pages=true`).then(res => {
if (res.status === 200) {
dispatch(setDocuments(res.data));
}
@@ -336,8 +337,8 @@ const ProcessStepOne = () => {
(async () => {
try {
await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { status: "SENT" })
+ if(accountId && transactionId) signSessionRedirect(accountId, transactionId, recipientId);
dispatch(hideLoader());
- navigate(`/sign/${recipientId}/self_sign`);
} catch (err) {
console.log("Error Transaction Sent", err.message);
}
diff --git a/src/components/process/processStepTwo/DocumentContainer.tsx b/src/components/process/processStepTwo/DocumentContainer.tsx
index be4ff16..d42d32f 100644
--- a/src/components/process/processStepTwo/DocumentContainer.tsx
+++ b/src/components/process/processStepTwo/DocumentContainer.tsx
@@ -195,8 +195,8 @@ const DocumentContainer: React.FC = ({ transactionSaving
}
const requests = Object.entries(updatedData)
- .filter(([_, tags]) => tags.length > 0) // filter out empty ones
- .map(([recipientId, tags]) => {
+ .filter(([_, tags]) => tags.length > 0) // filter out empty ones
+ .map(([recipientId, tags]) => {
const updatedTagsWithNavOrder = tags.map((tag, indx) => ({
...tag,
navigationOrder: indx + 1,
@@ -458,6 +458,13 @@ const DocumentContainer: React.FC = ({ transactionSaving
// return () => targetCon?.removeEventListener("keydown");
}
+
+ const handleLazyLoad = (docId: string, pageId: string) => {
+ api.get(`http://10.10.1.99:8083/api/${accountId}/transactions/${transactionId}/documents/${docId}/pages/${pageId}`).then(res => {
+ console.log(res)
+ })
+ }
+
return (
<>
{/* Center Doc Container - START */}
@@ -506,6 +513,7 @@ const DocumentContainer: React.FC = ({ transactionSaving
draggable="false"
width={page.width}
height={page.height}
+ // src={`http://10.10.1.99:8083/api/accounts/${accountId}/transactions/${transactionId}/documents/${doc.id}/pages/${page.id}`}
src={page.src}
loading='lazy'
/>
diff --git a/src/components/process/processStepTwo/FieldList.tsx b/src/components/process/processStepTwo/FieldList.tsx
index 11c98b2..6ecc7cb 100644
--- a/src/components/process/processStepTwo/FieldList.tsx
+++ b/src/components/process/processStepTwo/FieldList.tsx
@@ -129,7 +129,7 @@ const FieldList: React.FC = ({ color, recipientId, recipientIndx
const priorityOrder = ['SIGNATURE', 'INITIALS', 'STAMP'];
const data = res.data.filter((obj, indx) => {
- // if (obj.type === "STAMP" || obj.type === "RADIO" || obj.type === "CHECKBOX" || obj.type === "ATTACHMENT") return false
+ if (obj.type === "STAMP" || obj.type === "RADIO" || obj.type === "CHECKBOX" || obj.type === "ATTACHMENT") return false
return true
});
diff --git a/src/components/process/processStepTwo/LeftSideBar.tsx b/src/components/process/processStepTwo/LeftSideBar.tsx
index d13161e..011f88f 100644
--- a/src/components/process/processStepTwo/LeftSideBar.tsx
+++ b/src/components/process/processStepTwo/LeftSideBar.tsx
@@ -10,15 +10,19 @@ import { MdKeyboardArrowDown, MdOutlineNavigateNext } from 'react-icons/md'
import { useParams } from 'react-router-dom';
import { fetchDocuments } from '../../../store/slices/documentSlice';
import { GrFormPrevious } from 'react-icons/gr';
+import { LuTableOfContents } from 'react-icons/lu';
+import { IoIosDocument } from 'react-icons/io';
interface LeftSideBarProps {
isFields: boolean;
isPages: boolean;
selectedRecipientIndx: number;
setSelectedRecipient: React.Dispatch>
+ handleSetIsFields: (setTo: boolean) => void;
+ handleSetIsPages:(setTo: boolean) => void;
}
-const LeftSideBar: React.FC = ({ isFields, isPages, selectedRecipientIndx, setSelectedRecipient }) => {
+const LeftSideBar: React.FC = ({ isFields, isPages, selectedRecipientIndx, setSelectedRecipient, handleSetIsFields, handleSetIsPages }) => {
let transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS;
const dispatch = useDispatch();
@@ -78,7 +82,7 @@ const LeftSideBar: React.FC = ({ isFields, isPages, selectedRe
};
}, [selectedRecipient])
- if(selectedRecipient && selectedRecipient.type === recipientType.CC){
+ if (selectedRecipient && selectedRecipient.type === recipientType.CC) {
return ;
}
@@ -87,6 +91,24 @@ const LeftSideBar: React.FC = ({ isFields, isPages, selectedRe
{/* Left Side Bar - START */}
{
+
+
+ handleSetIsFields(!isFields)}
+ className={`flex items-center gap-1 cursor-pointer text-xs w-full justify-center py-1.5 rounded-2xl ${isFields ? 'bg-[var(--primary)] text-white' : ''} transition-all duration-300`}>
+
+ Tags
+
+
+ handleSetIsPages(!isPages)}
+ className={`flex items-center gap-1 cursor-pointer text-xs w-full justify-center py-1.5 rounded-2xl ${isPages ? 'bg-[var(--primary)] text-white' : ''} transition-all duration-300`}>
+
+ Pages
+
+
+
+
{selectedRecipients.length > 0 && isFields && <>
{/* Fields List and Recipeint - Start */}
{/* Side Bar showing Recipients */}
diff --git a/src/components/process/processStepTwo/NavTwo.tsx b/src/components/process/processStepTwo/NavTwo.tsx
index b38bf18..03df70b 100644
--- a/src/components/process/processStepTwo/NavTwo.tsx
+++ b/src/components/process/processStepTwo/NavTwo.tsx
@@ -10,7 +10,7 @@ import { MdKeyboardArrowDown } from 'react-icons/md'
import { RiResetRightLine } from 'react-icons/ri'
import { fetchRecipients, recipientType, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE } from '../../../store/slices/selectedRecipientsSlice'
import { fetchDocuments } from '../../../store/slices/documentSlice'
-import { useNavigate, useParams } from 'react-router-dom'
+import { Link, useNavigate, useParams } from 'react-router-dom'
import { Bounce, toast } from 'react-toastify'
import { FiChevronDown } from 'react-icons/fi'
import RecipientsCon from '../processStepOne/RecipientsCon'
@@ -181,22 +181,23 @@ const NavTwo: React.FC = ({
}, 1000)
}
- const handleSetIsFields = (setTo: boolean) => {
- if (setTo !== undefined && setTo !== isFields) {
- setIsFields(setTo)
- if(setTo === true) {
- setIsPages(false)
- }
- };
- }
- const handleSetIsPages = (setTo: boolean) => {
- if (setTo !== undefined && setTo !== isPages) {
- setIsPages(setTo)
- if(setTo === true) {
- setIsFields(false)
- }
- };
- }
+ // const handleSetIsFields = (setTo: boolean) => {
+ // if (setTo !== undefined && setTo !== isFields) {
+ // setIsFields(setTo)
+ // if(setTo === true) {
+ // setIsPages(false)
+ // }
+ // };
+ // }
+
+ // const handleSetIsPages = (setTo: boolean) => {
+ // if (setTo !== undefined && setTo !== isPages) {
+ // setIsPages(setTo)
+ // if(setTo === true) {
+ // setIsFields(false)
+ // }
+ // };
+ // }
const zoom = (percentage: number, contentClass: string) => {
const content = document.querySelector(`.${contentClass}`);
@@ -234,24 +235,20 @@ const NavTwo: React.FC = ({
{/* Left Side */}
- handleSetIsFields(!isFields)}
- className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${isFields ? 'bg-slate-100' : ''}`}>
-
- Fields
+
+
+
+
- handleSetIsPages(!isPages)}
- className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${isPages ? 'bg-slate-100' : ''}`}>
-
- Pages
-
setIsFitDd(false)}
>
+
+
+
setIsFitDd(!isFitDd)}
className='hidden sm:flex md:flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
@@ -259,7 +256,7 @@ const NavTwo: React.FC = ({
- {isFitDd &&
+ {isFitDd &&
{fitObj.map((val, indx) => {
return ( = ({
- {!isPreview &&
+ {/* {!isPreview &&
{transactionSaving ? `Saving ${dots}` : "Save"}
- }
+ } */}
@@ -342,7 +339,7 @@ const NavTwo: React.FC = ({
{/* Document Nav */}
setNav2DocToggle(false)}>
+ tabIndex={1} onBlur={() => setNav2DocToggle(false)}>
setNav2DocToggle(!nav2DocToggle)} className='flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
{selectedDocuments.length} Documents
diff --git a/src/components/process/processStepTwo/ProcessStepTwo.tsx b/src/components/process/processStepTwo/ProcessStepTwo.tsx
index c6d0e05..84a1eda 100644
--- a/src/components/process/processStepTwo/ProcessStepTwo.tsx
+++ b/src/components/process/processStepTwo/ProcessStepTwo.tsx
@@ -21,7 +21,7 @@ const ProcessStepTwo = () => {
const [isFields, setIsFields] = useState(windowWidth > 638 ? true : false);
const [isPages, setIsPages] = useState(false);
-
+
const [selectedRecipient, setSelectedRecipient] = useState(0);
const [transactionSaving, setTransactionSaving] = useState(false);
@@ -37,12 +37,31 @@ const ProcessStepTwo = () => {
}, 800)
}, [])
+
+ const handleSetIsFields = (setTo: boolean) => {
+ if (setTo !== undefined && setTo !== isFields) {
+ setIsFields(setTo)
+ if (setTo === true) {
+ setIsPages(false)
+ }
+ };
+ }
+
+ const handleSetIsPages = (setTo: boolean) => {
+ if (setTo !== undefined && setTo !== isPages) {
+ setIsPages(setTo)
+ if(setTo === true) {
+ setIsFields(false)
+ }
+ };
+ }
+
return (
-
+
diff --git a/src/components/routes_helper/ProtectedRoute.tsx b/src/components/routes_helper/ProtectedRoute.tsx
index 28bce20..ec98db7 100644
--- a/src/components/routes_helper/ProtectedRoute.tsx
+++ b/src/components/routes_helper/ProtectedRoute.tsx
@@ -1,13 +1,14 @@
import { JSX, useLayoutEffect } from 'react';
import { useDispatch } from "react-redux";
import { fetchUserDetails } from '../../store/slices/userSlice';
+import { AppDispatch } from '../../store/store';
const ProtectedRoute = ({ children }: { children: JSX.Element }) => {
- const dispatch = useDispatch();
+ const dispatch = useDispatch();
- useLayoutEffect(() => {
+ // useLayoutEffect(() => {
dispatch(fetchUserDetails());
- }, []);
+ // }, []);
return children;
};
diff --git a/src/components/setting/Signature/AddSignatureModal.tsx b/src/components/setting/Signature/AddSignatureModal.tsx
index 3c85cc2..8cbc314 100644
--- a/src/components/setting/Signature/AddSignatureModal.tsx
+++ b/src/components/setting/Signature/AddSignatureModal.tsx
@@ -7,6 +7,7 @@ import { FaSpinner } from "react-icons/fa";
import { GrCheckboxSelected } from "react-icons/gr";
import { Bounce, toast } from "react-toastify";
import { FiCheck } from 'react-icons/fi';
+import { IoMdClose } from 'react-icons/io';
interface Signature {
id: string;
@@ -55,7 +56,7 @@ const AddSignatureModal: React.FC = ({
getAllSignatures,
editingSignature
}) => {
- const [activeTab, setActiveTab] = useState<'SELECT' | 'DRAW' | 'UPLOAD'>('SELECT');
+ const [activeTab, setActiveTab] = useState<'SELECT' | 'DRAW' | 'UPLOAD'>('DRAW');
const [fullName, setFullName] = useState('');
const [initials, setInitials] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -196,17 +197,17 @@ const AddSignatureModal: React.FC = ({
if ((activeTab === 'DRAW' || activeTab === 'UPLOAD') &&
(!signatures.fullSignature || !signatures.initials)) {
// alert('Please provide both signature and initials');
- toast.error('Please provide both signature and initials in draw and upload case', {
- position: "top-center",
- autoClose: 2000,
- hideProgressBar: false,
- closeOnClick: false,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
+ // toast.error('Please provide both signature and initials in draw and upload case', {
+ // position: "top-center",
+ // autoClose: 2000,
+ // hideProgressBar: false,
+ // closeOnClick: false,
+ // pauseOnHover: true,
+ // draggable: true,
+ // progress: undefined,
+ // theme: "light",
+ // transition: Bounce,
+ // });
setIsSubmitting(false);
return;
}
@@ -236,32 +237,32 @@ const AddSignatureModal: React.FC = ({
};
res = await api.put(`/api/user/signatures`, updatePayload);
- toast.success("Signature Updated Successfully", {
- position: "top-center",
- autoClose: 500,
- hideProgressBar: false,
- closeOnClick: false,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
+ // toast.success("Signature Updated Successfully", {
+ // position: "top-center",
+ // autoClose: 500,
+ // hideProgressBar: false,
+ // closeOnClick: false,
+ // pauseOnHover: true,
+ // draggable: true,
+ // progress: undefined,
+ // theme: "light",
+ // transition: Bounce,
+ // });
} else {
// Create new signature
res = await api.post(`/api/user/signatures`, payload);
- toast.success("Signature Created Successfully", {
- position: "top-center",
- autoClose: 500,
- hideProgressBar: false,
- closeOnClick: false,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "light",
- transition: Bounce,
- });
+ // toast.success("Signature Created Successfully", {
+ // position: "top-center",
+ // autoClose: 500,
+ // hideProgressBar: false,
+ // closeOnClick: false,
+ // pauseOnHover: true,
+ // draggable: true,
+ // progress: undefined,
+ // theme: "light",
+ // transition: Bounce,
+ // });
}
if (res?.data) {
@@ -286,85 +287,46 @@ const AddSignatureModal: React.FC = ({
}
};
-
// Fixed renderContent function for SELECT case with proper radio button styling
const renderContent = () => {
switch (activeTab) {
case 'SELECT':
return (
-
-
- Choose Signature Style
- Select from pre-designed signature styles
-
-
-
-
- {signatureOptions.map((option) => (
- setSelectedSignature({ id: option.id, style: option.style })}
- >
- {/* Custom Radio Button */}
-
-
- {selectedSignature.id === option.id && (
-
- )}
-
-
-
- {/* Hidden native radio button for accessibility */}
- setSelectedSignature({ id: option.id, style: option.style })}
- className="sr-only"
- />
-
-
-
- Signed by:
-
- {fullName || option.name}
-
-
- dca3e646-62cd-4cc...
-
-
-
- DS
-
- {initials || option.initials}
-
-
-
-
- ))}
+ <>
+ {/* Form Inputs - Fixed */}
+
+ Confirm your name and choose signature style. *Are required fields.
+
+
+
+ setFullName(e.target.value)}
+ placeholder="Enter full name"
+ className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none"
+ />
+
+
+
+ setInitials(e.target.value)}
+ placeholder="Enter initials"
+ className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none"
+ />
+
+
-
+ >
);
case 'DRAW':
@@ -380,23 +342,34 @@ const AddSignatureModal: React.FC = ({
case 'UPLOAD':
return (
-
- Upload Signature
- Upload your signature images
+
+ Upload your Signature and confirm your name * Are required fields.
+ For best results, use an image that is 400 x 150 pixels for signature and 150 x 150 for initials
+ The maximum file size for the image is 300kb. File types supported include .png, .jpg, .jpeg
-
+
{/* Upload 1 - Full Signature */}
-
-
-
{/* */}
Recipients
- {signers.filter(s => s.completed).length} of {signers.length} signed
+ {signers.filter(s => s.completed).length}/{signers.length} Signed
+
+
-
-
+ {/* */}
+ {/*
🎉 Awesome! The document’s been sent for signature. 🎉
-
+
*/}
+
Your Document is sent for signature
-All signers will be notified via email
+All signers will be notified via email
Quick Preview
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" + > + Sign Now +
+ )} + ++ Copyright 2025 Sign Made Easy. All Rights Reserved.{" "} + + Privacy Policy + {" "} + |{" "} + + Reasonable Use Policy + +
+Tags
+Pages
+Fields
+
+
Pages
-{transactionSaving ? `Saving ${dots}` : "Save"}
-{selectedDocuments.length} Documents
Choose Signature Style
-Select from pre-designed signature styles
-Confirm your name and choose signature style. *Are required fields.
+Upload Signature
-Upload your signature images
+Upload your Signature and confirm your name * Are required fields.
+For best results, use an image that is 400 x 150 pixels for signature and 150 x 150 for initials
+The maximum file size for the image is 300kb. File types supported include .png, .jpg, .jpeg