MultiSign

This commit is contained in:
=bhagwanSingh 2025-08-01 19:35:02 +05:30
parent 09e7f85e29
commit e7a7bfbed1
7 changed files with 228 additions and 130 deletions

View File

@ -19,6 +19,8 @@ import {
FaCalendarAlt FaCalendarAlt
} from 'react-icons/fa'; } from 'react-icons/fa';
import TransactionDataTable from "./TransactionDataTable"; import TransactionDataTable from "./TransactionDataTable";
import { useSelector } from "react-redux";
import { RootState } from "../../store/store";
interface Transaction { interface Transaction {
id: number; id: number;
@ -121,6 +123,8 @@ const Account = () => {
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const userData = useSelector((state: RootState) => state.user);
// const getUserDetails = async () => { // const getUserDetails = async () => {
// try { // try {
// let res = await api.get('/api/user/details') // let res = await api.get('/api/user/details')
@ -170,7 +174,7 @@ const Account = () => {
}; };
try { try {
const res = await api.get('/api/dashboard', { params: payload }); const res = await api.get(`/api/accounts/${userData.account.id}/dashboard`, { params: payload });
console.log("Dashboard Data:", res.data); console.log("Dashboard Data:", res.data);
const cardDataArray = mapApiDataToCards(res.data); const cardDataArray = mapApiDataToCards(res.data);
setCards(cardDataArray); setCards(cardDataArray);
@ -249,7 +253,7 @@ const Account = () => {
<Cards type="transactions" onOpenModal={handleOpenModal} cards={cards} <Cards type="transactions" onOpenModal={handleOpenModal} cards={cards}
isLoading={isLoading} /> isLoading={isLoading} />
<TransactionDataTable /> <TransactionDataTable />
{isModalOpen && <AddInviteModal onClose={() => setIsModalOpen(false)} onInvite={handleInvite} inviteLoading={inviteLoading} {isModalOpen && <AddInviteModal onClose={() => setIsModalOpen(false)} onInvite={handleInvite} inviteLoading={inviteLoading}
accountOptions={accountsData} />} accountOptions={accountsData} />}

View File

@ -14,6 +14,8 @@ import {
FaFilter, FaFilter,
FaCalendarAlt FaCalendarAlt
} from 'react-icons/fa'; } from 'react-icons/fa';
import { useSelector } from 'react-redux';
import { RootState } from '../../store/store';
interface CardData { interface CardData {
title: string; title: string;
@ -82,6 +84,8 @@ const Home = () => {
const [cards, setCards] = useState<CardData[]>([]); const [cards, setCards] = useState<CardData[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const userData = useSelector((state : RootState) => state.user);
console.log("activeAccountId", activeAccountId); console.log("activeAccountId", activeAccountId);
console.log("cards", cards); console.log("cards", cards);
@ -94,7 +98,7 @@ const Home = () => {
}; };
try { try {
const res = await api.get('/api/dashboard', { params: payload }); const res = await api.get(`/api/accounts/${userData.account.id}/dashboard`, { params: payload });
setDashboardData(res.data); setDashboardData(res.data);
console.log("Dashboard Data:", res.data); console.log("Dashboard Data:", res.data);
const cardDataArray = mapApiDataToCards(res.data); const cardDataArray = mapApiDataToCards(res.data);

View File

@ -19,7 +19,8 @@ import { Link, useNavigate, useParams } from "react-router-dom";
import Loader from "../../dashboard/Loader"; import Loader from "../../dashboard/Loader";
import confetti from 'canvas-confetti' import confetti from 'canvas-confetti'
import { IoClose } from "react-icons/io5"; import { IoClose } from "react-icons/io5";
import { IoMdHome } from "react-icons/io"; import { IoMdClose, IoMdHome } from "react-icons/io";
import { Bounce, toast } from "react-toastify";
type Signer = { type Signer = {
id: number; id: number;
@ -222,6 +223,19 @@ const DocumentCompletionScreen = () => {
}, []) }, [])
useEffect(() => { useEffect(() => {
// toast.dismiss();
// toast.success("Your document has been successfully sent for signature.", {
// position: "top-center",
// autoClose: 1500,
// hideProgressBar: false,
// closeOnClick: false,
// pauseOnHover: true,
// draggable: true,
// progress: undefined,
// theme: "light",
// transition: Bounce,
// });
if (showConfetti) { if (showConfetti) {
const duration = 3000; const duration = 3000;
const end = Date.now() + duration; const end = Date.now() + duration;
@ -233,76 +247,63 @@ const DocumentCompletionScreen = () => {
} }
confetti({ confetti({
particleCount: 80, // more particles particleCount: 5, // fewer particles per burst for smoothness
angle: Math.random() * 360, // fire in random direction angle: 90, // falling straight down
spread: 220, // wider spread spread: 30, // slight spread
startVelocity: 15, // more power startVelocity: 8, // gentle falling speed
scalar: 1.2, // bigger pieces (default is 1)
origin: { origin: {
x: Math.random(), x: Math.random(), // random horizontal position across the top
y: Math.random() * 0.6, y: 0,
}, },
scalar: 1,
zIndex: 9999, zIndex: 9999,
}); });
}, 350); // fire every 150ms }, 50); // fire every 50ms for continuous effect
return () => clearInterval(interval);
} }
}, [showConfetti]); }, [showConfetti]);
return ( return (
<> <>
<>
{
showConfetti && (
<div className="absolute top-0 left-0 w-full h-full z-[9999] bg-white/80 backdrop-blur-sm flex items-center justify-center">
{/* <Confetti width={width} height={height} /> */}
<div className="relative bg-white bg-opacity-90 backdrop-blur-lg border border-green-200 shadow-xl rounded-md px-8 py-6 w-[90%] max-w-sm text-center animate-fade-in-up">
{/* Close Icon */}
<button
onClick={() => setShowConfetti(false)} // or whatever logic hides the modal
className="absolute top-2 right-2 text-gray-500 hover:text-gray-700"
aria-label="Close"
>
<IoClose className="text-2xl" />
</button>
{/* Success Icon */}
<FaCheckCircle className="text-green-500 text-5xl mb-4 mx-auto drop-shadow-lg" />
{/* Message */}
<h2 className="text-2xl font-semibold text-gray-800 mb-1">Transaction Successful</h2>
<p className="text-gray-600 text-sm">Your transaction has been created and saved successfully.</p>
</div>
</div>
)
}
</>
<div className="min-h-screen bg-[var(--mainViewBg)]"> <div className="min-h-screen bg-[var(--mainViewBg)]">
{/* Top Banner */} {/* Top Banner */}
<div className='fixed top-0 w-full flex items-center justify-between bg-white shadow z-50 px-4 py-3'>
<div className='flex items-center gap-2'>
<Link to={"/"}>
<IoMdHome
className='text-2xl text-slate-500 cursor-pointer hover:text-[var(--primary)] transition'
/>
</Link>
<p className="text-base font-normal text-gray-700 border-l pl-4">🎉 Awesome! The document’s been sent for signature. 🎉</p>
</div>
<div
id="add-tags-btn-step-one"
className='flex items-center gap-3'>
<Link to={`/accounts/${accountId}/transactions/${transactionId}`} className="flex items-center gap-2 cursor-pointer text-xs px-4 py-2 ml-3 rounded-sm bg-[var(--primary)]">
<FaPen className=" text-white text-md" />
<span className="tracking-wide text-white">Edit</span>
</Link>
{/* <button
onClick={() => handleNextClick(false)}
className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer"
>
{signType === SignTypeEnum.selfSign ? "Sign" : "Next"}
</button> */}
<div className="w-full px-6 py-2 bg-white border-b rounded-sm border-gray-200">
<div className="max-w-[97vw] mx-auto px-2 py-2.5">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Link to='/' className="w-5 h-5 text-green-700 rounded-full flex items-center justify-center">
<IoMdHome className="h-10 w-10" />
</Link>
{/* <div className="w-5 h-5 bg-white text-green-800 rounded-full flex items-center justify-center">
<FaCheck className="text-sm" />
</div> */}
<div>
<h2 className="text-md font-semibold text-gray-900">Awesome! Your document is sent for signature</h2>
</div>
</div>
<Link to={`/accounts/${accountId}/transactions/${transactionId}`} className="flex items-center gap-2 cursor-pointer text-xs px-4 py-2 ml-3 rounded-sm bg-[var(--primary)]">
<FaPen className=" text-white text-md" />
<span className="tracking-wide text-white">Edit</span>
</Link>
</div>
</div> </div>
</div> </div>
{(selectedRecipients.length > 0 && selectedDocuments.length > 0) ? {(selectedRecipients.length > 0 && selectedDocuments.length > 0) ?
<div className="p-3"> <div className="p-3 mt-[55px]">
<div className="max-w-[97vw] mx-auto"> <div className="max-w-[97vw] mx-auto">
{/* Header */} {/* Header */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-2"> <div className="grid grid-cols-1 lg:grid-cols-12 gap-2">

View File

@ -168,6 +168,7 @@ const ProcessStepOne = () => {
const recipientsData = selectedRecipients.map((recipient, index) => ({ const recipientsData = selectedRecipients.map((recipient, index) => ({
id: "id" in recipient ? recipient.id : null, id: "id" in recipient ? recipient.id : null,
routingOrder: "routingOrder" in recipient && recipient.routingOrder ? recipient.routingOrder : 1, routingOrder: "routingOrder" in recipient && recipient.routingOrder ? recipient.routingOrder : 1,
provideOwnTags: userData.email === recipient.email ? true : false,
type: recipient.type, type: recipient.type,
firstName: recipient.firstName, firstName: recipient.firstName,
lastName: recipient.lastName, lastName: recipient.lastName,
@ -225,18 +226,15 @@ const ProcessStepOne = () => {
} }
} else { } else {
dispatch(addRecipientAsync({ recipientsData: recipientsDataTemp, accountId, transactionId })); await dispatch(addRecipientAsync({ recipientsData: recipientsDataTemp, accountId, transactionId }));
} }
dispatch(showLoader("Processing Message...")); dispatch(showLoader("Processing Message..."));
console.log(`1/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`)
let res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { let res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, {
subject: emailDtls.subject, message: emailDtls.message, subject: emailDtls.subject, message: emailDtls.message,
status: "CREATED" status: "CREATED"
}) })
console.log("Line 158", res.data)
if (isSendNow) { if (isSendNow) {
dispatch(updateTransactionStatus(TRANSACTION_STATUS_ENUMS.TRANSACTION_SEND_SUCCESS)); dispatch(updateTransactionStatus(TRANSACTION_STATUS_ENUMS.TRANSACTION_SEND_SUCCESS));
setTimeout(() => { setTimeout(() => {

View File

@ -20,6 +20,7 @@ import Loader from '../../dashboard/Loader';
// import { TRANSACTION_TEMPLATE_TOGGLE } from "../../../store/slices/selectedRecipientsSlice"; // import { TRANSACTION_TEMPLATE_TOGGLE } from "../../../store/slices/selectedRecipientsSlice";
import { handleGroupBorderPosition } from '../../../utlity/tagGroupConUtils'; import { handleGroupBorderPosition } from '../../../utlity/tagGroupConUtils';
import { hideLoader, showLoader } from '../../../store/slices/loaderSlice'; import { hideLoader, showLoader } from '../../../store/slices/loaderSlice';
import { IsSendInterface } from './ProcessStepTwo';
export interface DroppedItemsObj { export interface DroppedItemsObj {
[key: string]: DroppedItem[] [key: string]: DroppedItem[]
@ -74,9 +75,12 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId })); selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId }));
}, []) }, [])
console.log(droppedItems, "line 78")
// FETCHING TAG - START // FETCHING TAG - START
useEffect(() => { useEffect(() => {
if (selectedRecipients.length === 0) return; if (selectedRecipients.length === 0) return;
const fetchTags = async () => { const fetchTags = async () => {
try { try {
const requests = selectedRecipients.map((recipient) => const requests = selectedRecipients.map((recipient) =>
@ -176,17 +180,22 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
return [recipientId, tags.map(tag => ({ ...tag, update: false }))]; return [recipientId, tags.map(tag => ({ ...tag, update: false }))];
}) })
) )
console.log(droppedItemsUpdateFalse, "Line 182")
setDroppedItems(droppedItemsUpdateFalse); setDroppedItems(droppedItemsUpdateFalse);
} catch (error) { } catch (error) {
console.error("Error submitting recipient tags:", error); console.error("Error submitting recipient tags:", error);
} }
}; };
// Save Tags - START
useEffect(() => {
if (isSend === null) return;
dispatch(showLoader("Loading ...")) const handleTransactionProcess = async (save: boolean = false) => {
console.log(droppedItems, "called Line 189");
if (!save && isSend === null) return;
!save && dispatch(showLoader("Loading ..."))
let updatedTags = { ...droppedItems } let updatedTags = { ...droppedItems }
@ -291,17 +300,37 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
tagsData = groupByRecipientId(tagsData); tagsData = groupByRecipientId(tagsData);
sendTagsToRecipients(tagsData, accountId, transactionId); console.log(tagsData, "Line 302");
(async () => { await sendTagsToRecipients(tagsData, accountId, transactionId);
const res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { status: "SENT" })
// const res = await api.put(`/api/accounts/${accountId}/transactions/${transactionId}`, { status: "SENT" })
console.log(res, "Check123") // SENDING Transaction - START
dispatch(hideLoader()) // if (!save) {
})() // const res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { status: "SENT" })
// // const res = await api.put(`/api/accounts/${accountId}/transactions/${transactionId}`, { status: "SENT" })
// console.log(res, "Check123")
// dispatch(hideLoader())
// }
// SENDING Transaction - END
}
// Save Tags - START
useEffect(() => {
handleTransactionProcess()
}, [isSend]) }, [isSend])
// Save Tags - END // Save Tags - END
// useEffect(() => {
// setTimeout(() => {
// setInterval(async () => {
// await handleTransactionProcess(true);
// }, 8000)
// }, 8000)
// }, [])
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => { const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault(); // Allows the drop event to work event.preventDefault(); // Allows the drop event to work
}; };
@ -1026,9 +1055,9 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
const IconComponent = typeToIconMap[type] || <FaQuestionCircle />; const IconComponent = typeToIconMap[type] || <FaQuestionCircle />;
const selectedRecipient = selectedRecipients.filter((obj, indx) => obj.id === item.recipientId); const selectedRecipient = selectedRecipients.filter((obj, indx) => obj.id === item.recipientId);
return ( return (
<> <React.Fragment key={index}>
<div <div
key={index} // key={index}
draggable="false" draggable="false"
className="absolute rounded dropped-item" className="absolute rounded dropped-item"
onClick={() => handleTagClick(key, index)} onClick={() => handleTagClick(key, index)}
@ -1090,20 +1119,22 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
</div> </div>
{ <>
"group" in item && item.group && "isGroupExist" in item && !item.isGroupExist && {
<> "group" in item && item.group && "isGroupExist" in item && !item.isGroupExist &&
<div className="group-border" border-group={item.group} border-pos="top"></div> <>
<div className="group-border" border-group={item.group} border-pos="right"></div> <div className="group-border" border-group={item.group} border-pos="top"></div>
<div className="group-border bottom-border" border-group={item.group} border-pos="bottom"> <div className="group-border" border-group={item.group} border-pos="right"></div>
<div onClick={() => handleAddGroupItemClicked(key, item)}><IoAdd /></div> <div className="group-border bottom-border" border-group={item.group} border-pos="bottom">
</div> <div onClick={() => handleAddGroupItemClicked(key, item)}><IoAdd /></div>
<div className="group-border" border-group={item.group} border-pos="left"></div> </div>
</> <div className="group-border" border-group={item.group} border-pos="left"></div>
</>
} }
</>
</> </React.Fragment>
) )
} }
@ -1146,7 +1177,11 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
</div > </div >
{selectedTag && <RightSideBar selectedTag={droppedItems[selectedTag.key][selectedTag.index]} setDroppedItems={setDroppedItems} selTagKey={selectedTag.key} selTagIndx={selectedTag.index} DirectionalControlsProps={{ {
console.log(selectedTag, droppedItems, "Line 1175")
}
{selectedTag && selectedTag !== null && "key" in selectedTag && "index" in selectedTag && <RightSideBar selectedTag={droppedItems[selectedTag.key][selectedTag.index]} setDroppedItems={setDroppedItems} selTagKey={selectedTag.key} selTagIndx={selectedTag.index} DirectionalControlsProps={{
onMove: directionalControlsHandler, onMove: directionalControlsHandler,
onPositionChange: handleDirectPositionChange, onPositionChange: handleDirectPositionChange,
disabled: false, disabled: false,

View File

@ -7,7 +7,7 @@ import { FaCheck, FaSignature } from 'react-icons/fa'
import { IoIosDocument } from 'react-icons/io' import { IoIosDocument } from 'react-icons/io'
import { LuTableOfContents } from 'react-icons/lu' import { LuTableOfContents } from 'react-icons/lu'
import { MdKeyboardArrowDown } from 'react-icons/md' import { MdKeyboardArrowDown } from 'react-icons/md'
import { RiResetLeftLine, RiResetRightLine } from 'react-icons/ri' import { RiResetRightLine } from 'react-icons/ri'
import { fetchRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE } from '../../../store/slices/selectedRecipientsSlice' import { fetchRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE } from '../../../store/slices/selectedRecipientsSlice'
import { fetchDocuments } from '../../../store/slices/documentSlice' import { fetchDocuments } from '../../../store/slices/documentSlice'
import { useNavigate, useParams } from 'react-router-dom' import { useNavigate, useParams } from 'react-router-dom'
@ -66,42 +66,83 @@ const NavTwo: React.FC<NavTwoProps> = ({ isFields, setIsFields, isSend, setIsSen
const [isFitDd, setIsFitDd] = useState<boolean>(false) const [isFitDd, setIsFitDd] = useState<boolean>(false)
const [selFitIndx, setSelFitIndx] = useState<number>(0); const [selFitIndx, setSelFitIndx] = useState<number>(0);
const [selfUserSign, setSelfUserSign] = useState({ sign: false, recipientId: 0 });
const navigate = useNavigate() const navigate = useNavigate()
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients) const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients)
const selectedDocuments = useSelector((state: RootState) => state.documents.documents) const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
const userDetails = useSelector((state: RootState) => state.user);
useEffect(() => { useEffect(() => {
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId })); if (selectedRecipients.length || selectedDocuments.length) return;
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId })); (async () => {
selectedRecipients.length === 0 && await dispatch(fetchRecipients({ accountId, transactionId }));
selectedDocuments.length === 0 && await dispatch(fetchDocuments({ accountId, transactionId }));
})()
}, []) }, [])
useEffect(() => {
if (selectedRecipients.length > 0) {
let minRoutingOrder: number = Infinity;
let userEmailPresent = {
present: false,
routingOrder: 0,
recipientId: 0
};
// Getting Minimum RoutingOrder
for (let i = 0; i < selectedRecipients.length; i++) {
const recipient = selectedRecipients[i]
if (recipient.routingOrder < minRoutingOrder) {
minRoutingOrder = recipient.routingOrder;
}
if (recipient.email === userDetails.email) {
userEmailPresent.present = true;
userEmailPresent.routingOrder = recipient.routingOrder;
userEmailPresent.recipientId = recipient.id;
}
}
if (userEmailPresent.present && userEmailPresent.routingOrder === minRoutingOrder) {
setSelfUserSign({ sign: true, recipientId: userEmailPresent.recipientId })
}
}
}, [selectedRecipients])
const [nav2RecToggle, setNav2RecToggle] = useState<boolean>(false); const [nav2RecToggle, setNav2RecToggle] = useState<boolean>(false);
const [nav2DocToggle, setNav2DocToggle] = useState<boolean>(false); const [nav2DocToggle, setNav2DocToggle] = useState<boolean>(false);
function handleSend() { function handleSend(isSignSend: boolean = false) {
// dispatch(showLoader("Loading ...")); // dispatch(showLoader("Loading ..."));
if (isSend === null) { if (isSend === null) {
setIsSend(false); setIsSend(false);
} }
setIsSend(!isSend) setIsSend(!isSend);
if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS) {
navigate(`/document-completion-screen/${accountId}/${transactionId}`) setTimeout(() => {
} else { if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS) {
navigate(`/templates`); if (isSignSend) {
toast.success("Template Saved...!", { navigate(`./../../../sign/${selfUserSign.recipientId}`);
position: "top-center", }
autoClose: 1500, // else {
hideProgressBar: false, // navigate(`/document-completion-screen/${accountId}/${transactionId}`)
closeOnClick: false, // }
pauseOnHover: true, } else {
draggable: true, navigate(`/templates`);
progress: undefined, toast.success("Template Saved...!", {
theme: "light", position: "top-center",
transition: Bounce, autoClose: 1500,
}); hideProgressBar: false,
} closeOnClick: false,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
transition: Bounce,
});
}
}, 0)
} }
const handleSetIsFields = (setTo: boolean) => { const handleSetIsFields = (setTo: boolean) => {
@ -123,24 +164,24 @@ const NavTwo: React.FC<NavTwoProps> = ({ isFields, setIsFields, isSend, setIsSen
zoom(Number(indx), 'zoom-con') zoom(Number(indx), 'zoom-con')
}, [selFitIndx]) }, [selFitIndx])
useEffect(() => { // useEffect(() => {
let timeoutId: number; // let timeoutId: number;
const timeOutIn = 8000; // const timeOutIn = 8000;
const updateLabel = () => { // const updateLabel = () => {
if (document.visibilityState === 'visible') { // if (document.visibilityState === 'visible') {
setTransactionSaving(true); // setTransactionSaving(true);
setTimeout(() => { // setTimeout(() => {
setTransactionSaving(false); // setTransactionSaving(false);
}, 4000) // }, 4000)
} // }
timeoutId = setTimeout(updateLabel, timeOutIn); // timeoutId = setTimeout(updateLabel, timeOutIn);
}; // };
timeoutId = setTimeout(updateLabel, timeOutIn); // timeoutId = setTimeout(updateLabel, timeOutIn);
// Cleanup on unmount // // Cleanup on unmount
return () => clearTimeout(timeoutId); // return () => clearTimeout(timeoutId);
}, []); // }, []);
useEffect(() => { useEffect(() => {
if (!transactionSaving) return; if (!transactionSaving) return;
@ -286,6 +327,15 @@ const NavTwo: React.FC<NavTwoProps> = ({ isFields, setIsFields, isSend, setIsSen
</p> </p>
<FaSignature className='text-white text-md' /> <FaSignature className='text-white text-md' />
</div> </div>
{transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && selfUserSign.sign && <div
id='send-and-sign-dash-btn'
onClick={() => handleSend(selfUserSign.sign)}
className='flex items-center gap-2 cursor-pointer text-xs px-4 py-2 ml-3 rounded-sm bg-[var(--primary)]'>
<p className='tracking-wide text-white'>
Sign & Send
</p>
<FaSignature className='text-white text-md' />
</div>}

View File

@ -9,10 +9,16 @@ import { RootState } from '../../../store/store';
import Loader from '../../dashboard/Loader'; import Loader from '../../dashboard/Loader';
import { hideLoader } from '../../../store/slices/loaderSlice'; import { hideLoader } from '../../../store/slices/loaderSlice';
export interface IsSendInterface {
send: boolean | null;
save: boolean;
}
const ProcessStepTwo = () => { const ProcessStepTwo = () => {
const [isFields, setIsFields] = useState(true); const [isFields, setIsFields] = useState(true);
const [selectedRecipient, setSelectedRecipient] = useState(0); const [selectedRecipient, setSelectedRecipient] = useState(0);
const [isSend, setIsSend] = useState<boolean | null>(null); const [isSend, setIsSend] = useState<boolean | null>(null);
const globalLoader = useSelector((state: RootState) => state.loader) const globalLoader = useSelector((state: RootState) => state.loader)
const dispatch = useDispatch(); const dispatch = useDispatch();