551 lines
25 KiB
TypeScript
551 lines
25 KiB
TypeScript
import React, { useEffect, useState } from 'react'
|
|
|
|
import { useDispatch, useSelector } from 'react-redux'
|
|
import { RootState } from '../../../store/store'
|
|
|
|
import { FaAngleRight, FaCheck, FaChevronRight, FaPaste, FaRegCopy, FaSave, FaSignature } from 'react-icons/fa'
|
|
import { IoIosDocument, IoMdArrowRoundBack, IoMdHome } from 'react-icons/io'
|
|
import { LuRedo2, LuTableOfContents, LuUndo2 } from 'react-icons/lu'
|
|
import { MdKeyboardArrowDown, MdOutlineKeyboardBackspace } 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 { Link, useNavigate, useParams } from 'react-router-dom'
|
|
import { Bounce, toast } from 'react-toastify'
|
|
import { FiChevronDown } from 'react-icons/fi'
|
|
import RecipientsCon from '../processStepOne/RecipientsCon'
|
|
import MessageCon from '../processStepOne/MessageCon'
|
|
import { IoArrowBackSharp, IoCopy } from 'react-icons/io5'
|
|
import { FaRegPaste } from 'react-icons/fa6'
|
|
import ConfirmSendModal from './TransactionSendConfirmationModal'
|
|
import { RxDividerVertical } from 'react-icons/rx'
|
|
import CloseConfirmationModal from './CloseCofirmationModal'
|
|
|
|
interface NavTwoProps {
|
|
transactionSaving?: boolean;
|
|
// setTransactionSaving: React.Dispatch<React.SetStateAction<boolean>>
|
|
isFields?: boolean;
|
|
setIsFields?: React.Dispatch<React.SetStateAction<boolean>>
|
|
isPages?: boolean;
|
|
setIsPages?: React.Dispatch<React.SetStateAction<boolean>>
|
|
isSend?: boolean | null;
|
|
setIsSend?: React.Dispatch<React.SetStateAction<boolean | null>>
|
|
isPreview?: boolean
|
|
aId?: string | null
|
|
tId?: string | null
|
|
onSendClick?: (isSave?: boolean, navigate?: boolean, navigateTo?: string) => void;
|
|
}
|
|
|
|
|
|
interface FIT {
|
|
label: string,
|
|
value: number | null
|
|
}
|
|
|
|
const fitObj = [
|
|
{
|
|
label: "Fit",
|
|
value: "FIT"
|
|
},
|
|
{
|
|
label: "50%",
|
|
value: "50"
|
|
},
|
|
{
|
|
label: "150%",
|
|
value: "150"
|
|
},
|
|
{
|
|
label: "200%",
|
|
value: "200"
|
|
},
|
|
]
|
|
|
|
const NavTwo: React.FC<NavTwoProps> = ({
|
|
transactionSaving = false,
|
|
isFields,
|
|
setIsFields,
|
|
isPages,
|
|
setIsPages,
|
|
isSend,
|
|
setIsSend,
|
|
isPreview = false,
|
|
aId = null,
|
|
tId = null,
|
|
onSendClick,
|
|
}) => {
|
|
let transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS;
|
|
const dispatch = useDispatch();
|
|
|
|
const [showActionsDropDown, setShowActionsDropDown] = useState<boolean>(false);
|
|
const [editRecipientsModal, setEditRecipientsModal] = useState<boolean>(false);
|
|
const [messageModal, setMessageModal] = useState<boolean>(false);
|
|
const [confirmSendModalOpen, setConfirmSendModalOpen] = useState({
|
|
"open": false,
|
|
"confirm": false,
|
|
"loading": false
|
|
});
|
|
|
|
console.log(editRecipientsModal)
|
|
|
|
const params = useParams<{ accountId?: string; transactionId?: string; templateId?: string }>();
|
|
let accountId = params.accountId;
|
|
let transactionId = params.transactionId
|
|
if (!transactionId) {
|
|
transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES;
|
|
transactionId = params.templateId;
|
|
dispatch(toggleToTemplates());
|
|
}
|
|
if (!accountId || !transactionId) {
|
|
window.location.href = "/";
|
|
return null;
|
|
}
|
|
|
|
// If is preview is enable
|
|
if (isPreview && aId != null && tId != null) {
|
|
accountId = aId;
|
|
transactionId = tId;
|
|
}
|
|
|
|
// const [transactionSaving, setTransactionSaving] = useState<boolean>(false);
|
|
const [dotCount, setDotCount] = useState(0);
|
|
|
|
const [closePage, setClosePage] = useState(false);
|
|
|
|
const [isFitDd, setIsFitDd] = useState<boolean>(false)
|
|
const [selFitIndx, setSelFitIndx] = useState<number>(0);
|
|
const [selfUserSign, setSelfUserSign] = useState({ sign: false, recipientId: 0 });
|
|
|
|
const navigate = useNavigate()
|
|
|
|
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients)
|
|
const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
|
|
const userDetails = useSelector((state: RootState) => state.user);
|
|
|
|
useEffect(() => {
|
|
if (selectedRecipients.length || selectedDocuments.length) return;
|
|
(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,
|
|
type: recipientType.CC
|
|
};
|
|
// 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;
|
|
userEmailPresent.type = recipient.type;
|
|
}
|
|
}
|
|
|
|
if (userEmailPresent.present && userEmailPresent.routingOrder == minRoutingOrder && userEmailPresent.type != recipientType.CC && userEmailPresent.type != recipientType.INPERSONSIGNER) {
|
|
setSelfUserSign({ sign: true, recipientId: userEmailPresent.recipientId })
|
|
}
|
|
}
|
|
}, [selectedRecipients])
|
|
|
|
const [nav2RecToggle, setNav2RecToggle] = useState<boolean>(false);
|
|
const [nav2DocToggle, setNav2DocToggle] = useState<boolean>(false);
|
|
|
|
|
|
const transactionSendValidation = () => {
|
|
|
|
const transactionSendValidationObj = {
|
|
oneSignerIsRequiredError: true
|
|
}
|
|
|
|
// One Signer is required - Validation
|
|
for (const recipient of selectedRecipients) {
|
|
if (recipient.type == recipientType.SIGNER || recipient.type == recipientType.INPERSONSIGNER) {
|
|
transactionSendValidationObj.oneSignerIsRequiredError = false; break
|
|
};
|
|
}
|
|
|
|
if (!transactionSendValidationObj.oneSignerIsRequiredError) return false;
|
|
return transactionSendValidationObj;
|
|
}
|
|
|
|
function handleSend(isSignSend: boolean = false) {
|
|
// dispatch(showLoader("Loading ..."));
|
|
if (onSendClick === undefined) return;
|
|
|
|
const transactionSendValidationObj = transactionSendValidation()
|
|
if (transactionSendValidationObj.oneSignerIsRequiredError) {
|
|
return
|
|
}
|
|
|
|
// if (isSend == null) {
|
|
// setIsSend(false);
|
|
// }
|
|
// setIsSend(!isSend);
|
|
|
|
// setTimeout(() => {
|
|
setConfirmSendModalOpen({ open: false, confirm: false, loading: false })
|
|
if (transactionTemplateToggle == TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS) {
|
|
if (isSignSend) {
|
|
// SELF SIGN CHECK HERE
|
|
window.open(`./../../../sign/${selfUserSign.recipientId}`, "_self");
|
|
}
|
|
else {
|
|
onSendClick(false); // false for not a save action
|
|
}
|
|
} else {
|
|
onSendClick(true, true, "/templates"); // true for save action
|
|
}
|
|
// }, 1000)
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (confirmSendModalOpen.confirm) handleSend()
|
|
}, [confirmSendModalOpen])
|
|
|
|
const zoom = (percentage: number, contentClass: string) => {
|
|
const content = document.querySelector(`.${contentClass}`);
|
|
if (content) {
|
|
(content as HTMLElement).style.zoom = `${percentage}%`;
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
let indx = fitObj[selFitIndx].value
|
|
if (indx == "FIT") {
|
|
indx = "100";
|
|
}
|
|
zoom(Number(indx), 'zoom-con')
|
|
}, [selFitIndx])
|
|
|
|
useEffect(() => {
|
|
if (!transactionSaving) return;
|
|
|
|
const interval = setInterval(() => {
|
|
setDotCount((prev) => (prev + 1) % 4); // Cycle through 0, 1, 2, 3
|
|
}, 500); // Update every 0.5s
|
|
|
|
return () => clearInterval(interval);
|
|
}, [transactionSaving]);
|
|
|
|
const dots = '. '.repeat(dotCount);
|
|
|
|
return (
|
|
<>
|
|
{closePage && <CloseConfirmationModal
|
|
open={closePage}
|
|
onClose={() => setClosePage(false)} // Cancel not closing
|
|
onConfirm={() => navigate("/")}
|
|
/>}
|
|
|
|
<ConfirmSendModal
|
|
confirmSendModalOpen={confirmSendModalOpen.open}
|
|
confirmSendModalOnClose={() => { setConfirmSendModalOpen({ open: false, confirm: false, loading: false }) }}
|
|
confirmSendModalOnConfirm={() => { setConfirmSendModalOpen({ open: true, confirm: true, loading: true }) }}
|
|
confirmSendModalLoading={confirmSendModalOpen.loading}
|
|
documents={selectedDocuments}
|
|
recipients={selectedRecipients}
|
|
/>
|
|
{/* Nav Two - Oprions - START */}
|
|
<div className='relative flex justify-between items-center px-4 py-1 bg-white'>
|
|
|
|
{/* Left Side */}
|
|
<div className='flex justify-start items-center gap-2'>
|
|
|
|
{/* <div>
|
|
<Link to={"/"}>
|
|
<img width={120} src="/sme-colored.png" alt="Sign Made Easy" />
|
|
</Link>
|
|
</div> */}
|
|
|
|
|
|
<div className='flex items-center gap-3'>
|
|
<div className='flex gap-4 text-xl text-slate-600'>
|
|
<button
|
|
className='hover:text-[var(--primary)] durartion-300 cursor-pointer'
|
|
onClick={() => setClosePage(true)}
|
|
>
|
|
<IoMdHome />
|
|
{/* <img width={120} src="/sme-colored.png" alt="Sign Made Easy" /> */}
|
|
</button>
|
|
<button
|
|
className='hover:text-[var(--primary)] durartion-300 cursor-pointer'
|
|
onClick={() => navigate(-1)}
|
|
>
|
|
<IoArrowBackSharp />
|
|
</button>
|
|
</div>
|
|
|
|
<div className='w-[1px] h-[28px] bg-slate-200'></div>
|
|
|
|
|
|
<div className='flex items-center gap-2 text-xs'>
|
|
<button
|
|
onClick={() => navigate(-1)}
|
|
className='underline font-thin cursor-pointer'>
|
|
Set Up Transaction
|
|
</button>
|
|
<FaAngleRight className='font-thin' />
|
|
<p className='font-normal'>Add Fields</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div
|
|
tabIndex={1}
|
|
onBlur={() => setIsFitDd(false)}
|
|
className='absolute gap-2 flex items-center left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] z-50'
|
|
>
|
|
|
|
<div className='flex'>
|
|
<p className='p-2 hover:bg-slate-100 cursor-pointer rounded-sm'>
|
|
<LuUndo2 className='text-sm text-slate-600' />
|
|
</p>
|
|
<p className='p-2 hover:bg-slate-100 cursor-pointer rounded-sm'>
|
|
<LuRedo2 className='text-sm text-slate-600' />
|
|
</p>
|
|
</div>
|
|
|
|
<div className='w-full h-[20px] border-[1px] border-slate-200'></div>
|
|
|
|
<div className='flex'>
|
|
<p className='p-2 hover:bg-slate-100 cursor-pointer rounded-sm'>
|
|
<FaRegCopy className='text-sm text-slate-600' />
|
|
</p>
|
|
<p className='p-2 hover:bg-slate-100 cursor-pointer rounded-sm'>
|
|
<FaRegPaste className='text-sm text-slate-600' />
|
|
</p>
|
|
</div>
|
|
|
|
<div className='w-full h-[20px] border-[1px] border-slate-200'></div>
|
|
|
|
<div className='border border-slate-400 rounded-sm ml-1'>
|
|
<div
|
|
onClick={() => setIsFitDd(!isFitDd)}
|
|
className='hidden sm:flex md:flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'
|
|
>
|
|
<p className='tracking-wide'>{fitObj[selFitIndx]?.label}</p>
|
|
<MdKeyboardArrowDown style={{ transform: `${isFitDd ? "rotate(180deg)" : ""}` }} />
|
|
</div>
|
|
|
|
{isFitDd && <div className='absolute bg-white rounded-sm z-[1000] shadow'>
|
|
{fitObj.map((val, indx) => {
|
|
return (<div
|
|
key={indx}
|
|
onClick={() => setSelFitIndx(indx)}
|
|
className='flex z-50 items-center justify-between gap-2 w-[70px] p-2 text-xs cursor-default hover:bg-slate-100'>
|
|
<div
|
|
|
|
className='flex items-center justify-between w-full'>
|
|
<p className='whitespace-nowrap overflow-hidden text-ellipsis max-w-[12ch]'>{val.label}</p>
|
|
{selFitIndx == indx && <FaCheck className='text-sm text-slate-400' />}
|
|
</div>
|
|
</div>)
|
|
})
|
|
}
|
|
</div>}
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
{/* {!isPreview && <div className='hidden sm:flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
|
|
<RiResetRightLine
|
|
className={`${transactionSaving ? "animate-spin" : ""} transition duration-300`}
|
|
/>
|
|
<p className="tracking-wide transition-all">{transactionSaving ? `Saving ${dots}` : "Save"}</p>
|
|
</div>} */}
|
|
|
|
</div>
|
|
|
|
|
|
{/* Right Side - STARTS */}
|
|
<div className='flex justify-center items-center'>
|
|
|
|
<div
|
|
className="relative inline-block text-left">
|
|
{/* Trigger */}
|
|
<button
|
|
onClick={() => setShowActionsDropDown((prev) => !prev)}
|
|
className="flex justify-center items-center bg-white px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50 cursor-pointer">
|
|
<p className='tracking-wide mr-1'>Actions</p>
|
|
<MdKeyboardArrowDown />
|
|
</button>
|
|
|
|
{/* Menu */}
|
|
{showActionsDropDown && <div
|
|
className="absolute right-0 mt-2 w-48 rounded-md bg-white shadow-sm ring-1 ring-black/5 z-10">
|
|
<div
|
|
className="py-1">
|
|
{/* <button className="w-full text-left px-4 py-2 text-sm hover:bg-gray-100">
|
|
Save & Close
|
|
</button> */}
|
|
<button
|
|
onClick={() => {
|
|
if (onSendClick !== undefined) onSendClick(true, false); // true for save action
|
|
setShowActionsDropDown(false)
|
|
}}
|
|
className="cursor-pointer w-full text-left px-4 py-2 text-sm hover:bg-gray-100">
|
|
Save Changes
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
if (onSendClick !== undefined) onSendClick(true, true, transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES ? "/templates" : "/"); // true for save action
|
|
setShowActionsDropDown(false);
|
|
}}
|
|
className="cursor-pointer w-full text-left px-4 py-2 text-sm hover:bg-gray-100">
|
|
Save & Exit
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
setMessageModal(true)
|
|
setShowActionsDropDown(false)
|
|
}}
|
|
className="cursor-pointer w-full text-left px-4 py-2 text-sm hover:bg-gray-100">
|
|
Edit Message
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
setEditRecipientsModal(true)
|
|
setShowActionsDropDown(false)
|
|
}}
|
|
className="cursor-pointer w-full text-left px-4 py-2 text-sm hover:bg-gray-100">
|
|
Edit Recipients
|
|
</button>
|
|
{/* <button
|
|
onClick={() => {
|
|
setEditRecipientsModal(true)
|
|
setShowActionsDropDown(false)
|
|
}}
|
|
className="w-full text-left px-4 py-2 text-sm hover:bg-gray-100">
|
|
Edit Documents
|
|
</button>
|
|
<button className="w-full text-left px-4 py-2 text-sm hover:bg-gray-100">
|
|
Advanced Options
|
|
</button> */}
|
|
</div>
|
|
</div>}
|
|
</div>
|
|
|
|
{/* Document Nav */}
|
|
<div className='hidden sm:block'
|
|
tabIndex={1} onBlur={() => setNav2DocToggle(false)}>
|
|
<div onClick={() => setNav2DocToggle(!nav2DocToggle)} className='flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
|
|
<p className='tracking-wide'>{selectedDocuments.length} Documents</p>
|
|
<MdKeyboardArrowDown className={`${nav2DocToggle ? 'rotate-180' : ''} transition-all`} />
|
|
</div>
|
|
|
|
<div
|
|
className={`absolute max-w-max shadow rounded-md mt-1 px-2 py-1 z-20 bg-white ${nav2DocToggle ? '' : 'hidden'}`}>
|
|
|
|
{selectedDocuments.length && selectedDocuments.map((document, indx) => {
|
|
return (<div key={indx} className='flex items-center justify-between gap-2 w-full p-2 text-xs rounded-sm cursor-default'>
|
|
<div className='flex items-center gap-1'>
|
|
{/* <p className='w-3 h-3 rounded-sm' style={{ background: recipient.color }}></p> */}
|
|
<IoIosDocument className='text-slate-600 text-lg' />
|
|
<p className='whitespace-nowrap overflow-hidden text-ellipsis max-w-[15ch]'>{document.name}</p>
|
|
</div>
|
|
</div>)
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Recipients Nav */}
|
|
<div className='hidden sm:block relative' tabIndex={1} onBlur={() => setNav2RecToggle(false)}>
|
|
<div onClick={() => setNav2RecToggle(!nav2RecToggle)} className='flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
|
|
<p className='tracking-wide'>{selectedRecipients.length} Recipients</p>
|
|
<MdKeyboardArrowDown className={`${nav2RecToggle ? 'rotate-180' : ''} transition-all`} />
|
|
</div>
|
|
|
|
|
|
<div
|
|
className={`absolute max-w-max shadow rounded-md mt-1 px-2 py-1 z-20 bg-white ${nav2RecToggle ? '' : 'hidden'}`}>
|
|
|
|
{selectedRecipients.length && selectedRecipients.map((recipient, indx) => {
|
|
return (<div key={indx} className='flex items-center justify-between gap-2 w-full p-2 text-xs rounded-sm cursor-default'>
|
|
<div className='flex items-center gap-1.5'>
|
|
<p className='w-3 h-3 rounded-sm' style={{ background: recipient.color }}></p>
|
|
<p className='whitespace-nowrap overflow-hidden text-ellipsis max-w-[22ch]'>{recipient.type + " | "} {recipient.firstName} {recipient.lastName}</p>
|
|
</div>
|
|
</div>)
|
|
})}
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{/* Send */}
|
|
{!isPreview && <>
|
|
<div
|
|
id='send-sign-dash-btn'
|
|
onClick={() => setConfirmSendModalOpen({ open: true, confirm: false, loading: false })}
|
|
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'>
|
|
{transactionTemplateToggle == TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES ? "Save" : "Send"}
|
|
</p>
|
|
<FaSignature className='text-white text-md' />
|
|
</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>} */}
|
|
</>}
|
|
|
|
|
|
{editRecipientsModal && accountId && transactionId && <>
|
|
<div className="w-full h-[100vh] absolute top-0 left-0 z-[1000] flex justify-center items-center">
|
|
{/* <div className="w-full h-full bg-slate-100 opacity-40 blur-2xl absolute top-0 left-0"></div> */}
|
|
<div className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50" />
|
|
<div className="z-50 bg-white p-4 rounded-sm shadow-md">
|
|
<RecipientsCon
|
|
transactionTemplateToggle={transactionTemplateToggle}
|
|
accountId={accountId}
|
|
transactionId={transactionId}
|
|
userData={userDetails}
|
|
setEditRecipientsModal={setEditRecipientsModal}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</>}
|
|
|
|
{messageModal && accountId && transactionId && <>
|
|
<div className="w-full h-[100vh] absolute top-0 left-0 z-[1000] flex justify-center items-center">
|
|
{/* <div className="w-full h-full bg-slate-100 opacity-40 blur-2xl absolute top-0 left-0"></div> */}
|
|
<div className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50" />
|
|
<div className="z-50 bg-white p-4 rounded-sm shadow-md">
|
|
<MessageCon
|
|
transactionTemplateToggle={transactionTemplateToggle}
|
|
accountId={accountId}
|
|
transactionId={transactionId}
|
|
messageModal={messageModal}
|
|
setMessageModal={setMessageModal}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</>}
|
|
|
|
</div>
|
|
{/* Right Side - ENDS */}
|
|
</div>
|
|
{/* Nav Two - Oprions - End */}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default NavTwo |