Compare commits

..

No commits in common. "204d41cdc473ea0f623022ddf9efca92efc41ebe" and "0cf16a05f013a3eb8716dd27d07e754fb56a285c" have entirely different histories.

16 changed files with 457 additions and 706 deletions

View File

@ -204,7 +204,7 @@ const Cards: React.FC<CardsProps> = ({ type = 'dashboard', onOpenModal, onDateRa
// } // }
return ( return (
<div className="w-full px-3 rounded-md"> <div className="w-full px-4 py-3 mt-2 rounded-md">
{/* Header */} {/* Header */}
<div className="flex flex-col lg:flex-row items-start lg:items-center justify-between mb-2 gap-4"> <div className="flex flex-col lg:flex-row items-start lg:items-center justify-between mb-2 gap-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@ -212,12 +212,12 @@ const Cards: React.FC<CardsProps> = ({ type = 'dashboard', onOpenModal, onDateRa
<FaFilter className="text-white text-lg" /> <FaFilter className="text-white text-lg" />
</div> */} </div> */}
<div> <div>
{/* <h2 className="text-lg font-semibold text-gray-800">Overview</h2> */} <h2 className="text-lg font-semibold text-gray-800">Overview</h2>
{/* <p className="text-gray-600 text-sm">Monitor performance metrics</p> */} {/* <p className="text-gray-600 text-sm">Monitor performance metrics</p> */}
</div> </div>
</div> </div>
</div> </div>
{/* Cards */} {/* Cards */}
@ -231,11 +231,11 @@ const Cards: React.FC<CardsProps> = ({ type = 'dashboard', onOpenModal, onDateRa
</div> </div>
</div> </div>
</div> : </div> :
<div className="flex flex-wrap gap-2 justify-between"> <div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4">
{cards.map((card, index) => ( {cards.map((card, index) => (
<div <div
key={card.title} key={card.title}
className={`group relative overflow-hidden rounded-lg ${card.gradient} border border-white/40 px-3 py-1 transition-all duration-300 hover:scale-105 hover:shadow-lg ${card.shadowColor} cursor-pointer backdrop-blur-sm min-w-[200px] max-w-[220px]`} className={`group relative overflow-hidden rounded-xl ${card.gradient} border border-white/40 p-4 transition-all duration-300 hover:scale-105 hover:shadow-lg ${card.shadowColor} cursor-pointer backdrop-blur-sm`}
style={{ style={{
animationDelay: `${index * 100}ms` animationDelay: `${index * 100}ms`
}} }}
@ -247,20 +247,24 @@ const Cards: React.FC<CardsProps> = ({ type = 'dashboard', onOpenModal, onDateRa
</div> </div>
{/* Content */} {/* Content */}
<div className="relative flex justify-between items-center z-10"> <div className="relative z-10">
<div className="flex items-center gap-2"> <div className="flex items-center justify-between mb-2">
<div className={`p-2 rounded-lg border ${card.iconBg} group-hover:scale-110 transition-transform duration-200`}> <div className={`p-2 rounded-lg border ${card.iconBg} group-hover:scale-110 transition-transform duration-200`}>
{card.icon} {card.icon}
</div> </div>
<h3 className="text-sm font-medium text-gray-600 group-hover:text-gray-700 transition-colors"> {renderTrendIndicator(card.trend, card.percentage)}
{card.title}
</h3>
</div> </div>
<div className="flex items-center"> <div className="space-y-1">
<p className={`text-xl font-bold ${card.textColor} group-hover:scale-105 transition-transform duration-200 leading-none mb-1`}> <h3 className="text-xs font-medium text-gray-600 group-hover:text-gray-700 transition-colors">
{card.count} {card.title}
</p> </h3>
<div className="flex items-baseline gap-1">
<p className={`text-xl font-bold ${card.textColor} group-hover:scale-105 transition-transform duration-200`}>
{card.count}
</p>
<span className="text-[10px] text-gray-500">items</span>
</div>
</div> </div>
</div> </div>

View File

@ -33,7 +33,7 @@ const Home = () => {
{ {
title: 'Action Needed', title: 'Action Needed',
count: data.actionNeeded || 0, count: data.actionNeeded || 0,
icon: <FaTasks size={15} className="text-indigo-600" />, icon: <FaTasks size={18} className="text-indigo-600" />,
gradient: 'bg-gradient-to-br from-indigo-50 to-indigo-100', gradient: 'bg-gradient-to-br from-indigo-50 to-indigo-100',
shadowColor: 'shadow-indigo-200/50', shadowColor: 'shadow-indigo-200/50',
iconBg: 'bg-indigo-100 border-indigo-200', iconBg: 'bg-indigo-100 border-indigo-200',
@ -43,7 +43,7 @@ const Home = () => {
{ {
title: 'Expiring Soon', title: 'Expiring Soon',
count: data.expiring || 0, count: data.expiring || 0,
icon: <FaHourglassHalf size={15} className="text-rose-600" />, icon: <FaHourglassHalf size={18} className="text-rose-600" />,
gradient: 'bg-gradient-to-br from-rose-50 to-rose-100', gradient: 'bg-gradient-to-br from-rose-50 to-rose-100',
shadowColor: 'shadow-rose-200/50', shadowColor: 'shadow-rose-200/50',
iconBg: 'bg-rose-100 border-rose-200', iconBg: 'bg-rose-100 border-rose-200',
@ -53,7 +53,7 @@ const Home = () => {
{ {
title: 'Completed', title: 'Completed',
count: data.completed || 0, count: data.completed || 0,
icon: <FaCheckCircle size={15} className="text-teal-600" />, icon: <FaCheckCircle size={18} className="text-teal-600" />,
gradient: 'bg-gradient-to-br from-teal-50 to-teal-100', gradient: 'bg-gradient-to-br from-teal-50 to-teal-100',
shadowColor: 'shadow-teal-200/50', shadowColor: 'shadow-teal-200/50',
iconBg: 'bg-teal-100 border-teal-200', iconBg: 'bg-teal-100 border-teal-200',
@ -63,7 +63,7 @@ const Home = () => {
{ {
title: 'Draft', title: 'Draft',
count: data.draft || 0, count: data.draft || 0,
icon: <FaClock size={15} className="text-stone-600" />, icon: <FaClock size={18} className="text-stone-600" />,
gradient: 'bg-gradient-to-br from-blue-50 to-blue-100', gradient: 'bg-gradient-to-br from-blue-50 to-blue-100',
shadowColor: 'shadow-blue-200/50', shadowColor: 'shadow-blue-200/50',
iconBg: 'bg-blue-100 border-blue-200', iconBg: 'bg-blue-100 border-blue-200',

View File

@ -48,7 +48,7 @@ const SignersList: React.FC<{ signers: Signer[] }> = ({ signers }) => {
{signers.map((signer) => ( {signers.map((signer) => (
<div key={signer.id} className="flex items-center gap-4 p-3 bg-white/40 rounded-lg"> <div key={signer.id} className="flex items-center gap-4 p-3 bg-white/40 rounded-lg">
<div className="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center text-blue-600 font-medium"> <div className="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center text-blue-600 font-medium">
{signer.name.length > 2 ? signer.name.split(" ").map(n => n[0].toUpperCase()).join("") : signer.email.split("").map(n => n[0].toUpperCase()).join("")} {signer.name.split(" ").map(n => n[0].toUpperCase()).join("")}
</div> </div>
<div className="flex-1"> <div className="flex-1">
<div className="font-medium text-gray-800">{signer.name}</div> <div className="font-medium text-gray-800">{signer.name}</div>

View File

@ -7,17 +7,15 @@ import api from "../../../config/api";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../../../store/store"; import { RootState } from "../../../store/store";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useNavigate, useParams, useSearchParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import { setImages } from "../../../store/slices/selectedDocsSlice"; import { setImages } from "../../../store/slices/selectedDocsSlice";
import { addRecipient, addRecipientAsync, fetchRecipients, recipientType, removeAllRecipients, removeRecipientAsync, resetRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE, updateRecipientIds } from "../../../store/slices/selectedRecipientsSlice"; import { addRecipient, addRecipientAsync, fetchRecipients, recipientType, resetRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE, updateRecipientIds } from "../../../store/slices/selectedRecipientsSlice";
import { setTransactionId, TRANSACTION_STATUS_ENUMS, updateTransactionStatus } from "../../../store/slices/transactionSlice"; import { setTransactionId, TRANSACTION_STATUS_ENUMS, updateTransactionStatus } from "../../../store/slices/transactionSlice";
import { hideLoader, showLoader } from "../../../store/slices/loaderSlice"; import { hideLoader, showLoader } from "../../../store/slices/loaderSlice";
import Loader from "../../dashboard/Loader"; import Loader from "../../dashboard/Loader";
import { Bounce, toast } from "react-toastify"; import { Bounce, toast } from "react-toastify";
import { fetchDocuments, resetDocuments, setDocuments, uploadDocuments } from "../../../store/slices/documentSlice"; import { fetchDocuments, resetDocuments, setDocuments, uploadDocuments } from "../../../store/slices/documentSlice";
import { SignTypeEnum } from "../../../utlity/types"; import { SignTypeEnum } from "../../../utlity/types";
import { RiPencilFill } from "react-icons/ri";
import SelfSignWarnModal from "./SelfSignWarnModal";
const ProcessStepOne = () => { const ProcessStepOne = () => {
interface EmailDtls { interface EmailDtls {
@ -30,9 +28,6 @@ const ProcessStepOne = () => {
const signType = useParams<{ signType: string }>().signType; const signType = useParams<{ signType: string }>().signType;
const templateId = useParams<{ templateId: string }>().templateId; const templateId = useParams<{ templateId: string }>().templateId;
let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>(); let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>();
const [searchParams] = useSearchParams();
console.log("searchParams", searchParams.get('useTemplate'))
const isTamplate = searchParams.get('useTemplate')
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -59,29 +54,10 @@ const ProcessStepOne = () => {
const selectedDocuments = useSelector((state: RootState) => state.documents.documents) const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients) const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients)
const [showSelfSignWarnModal, setShowSelfSignWarnModal] = useState(false)
console.log()
const userData = useSelector((state: RootState) => state.user) const userData = useSelector((state: RootState) => state.user)
// ProcessStepOne.tsx // ProcessStepOne.tsx
const topRef = useRef<HTMLDivElement | null>(null); const topRef = useRef<HTMLDivElement | null>(null);
const [templateName, setTemplateName] = useState('Untitled');
const [isTyping, setIsTyping] = useState(false);
// Optional: use a timer to detect pause in typing
let typingTimeout = null;
const handleChange = (e) => {
setTemplateName(e.target.value);
setIsTyping(true);
clearTimeout(typingTimeout);
typingTimeout = setTimeout(() => {
setIsTyping(false);
}, 5000); // hide icon while typing, show it again after 500ms of no input
};
// const userData = useSelector((state: RootState) => state.user) // const userData = useSelector((state: RootState) => state.user)
const [transactionDetails, setTransactionDetails] = useState<any>([]); const [transactionDetails, setTransactionDetails] = useState<any>([]);
@ -95,24 +71,23 @@ const ProcessStepOne = () => {
try { try {
const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`); const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`);
setTransactionDetails(res.data) setTransactionDetails(res.data)
// console.log("setTransactionDetails",res.data)
} catch (e) { } catch (e) {
console.log("Error - transactions details") console.log("Error - transactions details")
} }
})() })()
// Fetching Transaction Details - END // Fetching Transaction Details - END
// ======= // =======
// (async () => { // (async () => {
// const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) // const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`)
// console.log(res.data); // console.log(res.data);
// })() // })()
// >>>>>>> origin/main // >>>>>>> origin/main
// (async () => { // (async () => {
// const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) // const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`)
// console.log(res.data); // console.log(res.data);
// })() // })()
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId })); selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId })); selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId }));
@ -129,48 +104,45 @@ const ProcessStepOne = () => {
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const handleNextClick = async (isSendNow: boolean, saveAndClose: boolean = false) => { const handleNextClick = async (isSendNow: boolean) => {
let formError = { let formError = {
documents: false, documents: false,
recipients: false, recipients: false,
subject: false subject: false
} }
if (transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) { if (!selectedDocuments.length) {
if (!selectedDocuments.length) { formError.documents = true
formError.documents = true }
} if (!selectedRecipients.length) {
if (!selectedRecipients.length) { formError.recipients = true
formError.recipients = true }
} if (!emailDtls.subject.length) {
if (!emailDtls.subject.length) { formError.subject = true
formError.subject = true
}
if (SignTypeEnum.selfSign === signType) formError.recipients = false;
if (formError.documents || formError.recipients || formError.subject) {
console.log(selectedDocuments, 'line 193')
toast.dismiss();
toast.error(`${formError.documents ? "Add Document" : ""}
${(formError.documents && formError.recipients) ? " | " : ""}
${formError.recipients ? "Add Recipient" : ""}
${(formError.documents || formError.recipients) ? " | " : ""}
${formError.subject ? "Add Subject" : ""}`, {
position: "top-center",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
transition: Bounce,
});
return;
}
} }
if (SignTypeEnum.selfSign === signType) formError.recipients = false;
if (formError.documents || formError.recipients || formError.subject) {
console.log(selectedDocuments, 'line 193')
toast.dismiss();
toast.error(`${formError.documents ? "Add Document" : ""}
${(formError.documents && formError.recipients) ? " | " : ""}
${formError.recipients ? "Add Recipient" : ""}
${(formError.documents || formError.recipients) ? " | " : ""}
${formError.subject ? "Add Subject" : ""}`, {
position: "top-center",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
transition: Bounce,
});
return;
}
try { try {
dispatch(showLoader("Processing Documents...")); dispatch(showLoader("Processing Documents..."));
@ -221,17 +193,6 @@ const ProcessStepOne = () => {
let recipientId = null; let recipientId = null;
if (signType === SignTypeEnum.selfSign) { if (signType === SignTypeEnum.selfSign) {
dispatch(removeAllRecipients());
await Promise.all(
selectedRecipients.map((recipient) => dispatch(removeRecipientAsync({
recipientId: recipient.id,
email: recipient.email,
accountId,
transactionId,
}))
)
);
recipientsDataTemp = [{ recipientsDataTemp = [{
id: null, id: null,
routingOrder: 1, routingOrder: 1,
@ -271,7 +232,6 @@ const ProcessStepOne = () => {
console.log(`1/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) 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}`, {
name: templateName,
subject: emailDtls.subject, message: emailDtls.message, subject: emailDtls.subject, message: emailDtls.message,
status: "CREATED" status: "CREATED"
}) })
@ -290,11 +250,7 @@ const ProcessStepOne = () => {
dispatch(hideLoader()); dispatch(hideLoader());
if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) { if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) {
console.log(`/process-step-two/${accountId}/template/${transactionId}`) console.log(`/process-step-two/${accountId}/template/${transactionId}`)
if (!saveAndClose) { navigate(`/process-step-two/${accountId}/template/${transactionId}`)
navigate(`/process-step-two/${accountId}/template/${transactionId}`)
} else {
navigate(`/templates`)
}
} else { } else {
if (signType === SignTypeEnum.selfSign) { if (signType === SignTypeEnum.selfSign) {
(async () => { (async () => {
@ -339,7 +295,6 @@ const ProcessStepOne = () => {
const handleSelfSignCb = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSelfSignCb = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.currentTarget.checked) { if (e.currentTarget.checked) {
navigate("self_sign"); navigate("self_sign");
setShowSelfSignWarnModal((prev) => !prev)
} else { } else {
navigate("./../"); navigate("./../");
} }
@ -358,42 +313,18 @@ const ProcessStepOne = () => {
onClick={handleClose} onClick={handleClose}
className='text-2xl text-slate-500 cursor-pointer hover:text-[var(--primary)] transition' className='text-2xl text-slate-500 cursor-pointer hover:text-[var(--primary)] transition'
/> />
<p className="text-base font-normal text-gray-700 border-l pl-4 relative"> <p className="text-base font-normal text-gray-700 border-l pl-4">Add Recipient and Message</p>
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES ?
<>
<input
value={templateName}
onChange={handleChange}
className="w-full px-4 py-1.5 border-2 border-dashed rounded-md text-sm focus:outline-none transition border-gray-300 focus:ring-2 focus:border-dashed focus:ring-[var(--primary)]"
/>
{!isTyping && (
<RiPencilFill className="absolute top-2.5 right-2 text-[17px]" />
)}
</> :
"Add Recipient and Message"
}
</p>
</div> </div>
<div <div
id="add-tags-btn-step-one" id="add-tags-btn-step-one"
className='flex items-center gap-3'> className='flex items-center gap-3'>
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && <button
onClick={() => handleNextClick(false, true)}
className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer"
>
Save & Close
</button>}
<button <button
onClick={() => handleNextClick(false)} onClick={() => handleNextClick(false)}
className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer" className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition"
> >
{signType === SignTypeEnum.selfSign ? "Sign" : "Next"} {signType === SignTypeEnum.selfSign ? "Sign" : "Next"}
</button> </button>
</div> </div>
</div> </div>
@ -409,7 +340,7 @@ const ProcessStepOne = () => {
{/* Recipients */} {/* Recipients */}
<section className="mt-8"> <section className="mt-8">
{!isTamplate && {
transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES &&
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className="text-lg font-medium mb-4 pt-6 border-t text-[var(--processStepOneTextHead)]">Signers</h2> <h2 className="text-lg font-medium mb-4 pt-6 border-t text-[var(--processStepOneTextHead)]">Signers</h2>
@ -425,9 +356,9 @@ const ProcessStepOne = () => {
} }
{ {
(signType !== SignTypeEnum.selfSign || showSelfSignWarnModal) && signType !== SignTypeEnum.selfSign &&
<div className="flex flex-col gap-4 align-start"> <div className="flex flex-col gap-4 align-start">
<RecipientCards transactionTemplateToggle={transactionTemplateToggle} setEditRecipient={setEditRecipient} setEditCase={setEditCase} /> <RecipientCards transactionTemplateToggle={transactionTemplateToggle} setEditRecipient={setEditRecipient} setEditCase={setEditCase} />
{/* {signType !== "self-sign" && <RecipientAddCard />} */} {/* {signType !== "self-sign" && <RecipientAddCard />} */}
<div <div
@ -475,7 +406,6 @@ const ProcessStepOne = () => {
</div> </div>
{globalLoader.isLoading && <Loader />} {globalLoader.isLoading && <Loader />}
{showSelfSignWarnModal && <SelfSignWarnModal setShowSelfSignWarnModal={setShowSelfSignWarnModal} />}
</div > </div >
</> </>
); );

View File

@ -1,8 +1,8 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { FaPlus } from "react-icons/fa"; import { FaPlus } from "react-icons/fa";
import { addRecipient, Recipient, recipientType, TRANSACTION_TEMPLATE_TOGGLE, updateRecipient } from "../../../store/slices/selectedRecipientsSlice"; import { addRecipient, Recipient, recipientType, updateRecipient } from "../../../store/slices/selectedRecipientsSlice";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch } from "react-redux";
import { AppDispatch, RootState } from "../../../store/store"; import { AppDispatch } from "../../../store/store";
import api from "../../../config/api"; import api from "../../../config/api";
import ContactModal from "./ContactModal"; import ContactModal from "./ContactModal";
import useDebouncedEffect from "../../../utlity/useDebounce"; import useDebouncedEffect from "../../../utlity/useDebounce";
@ -29,8 +29,6 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
JSON.parse(sessionStorage.getItem('activeAccountId') || 'null') JSON.parse(sessionStorage.getItem('activeAccountId') || 'null')
); );
const recipients = useSelector((state: RootState) => state.selectedRecipients.recipients);
console.log("recipients.length in AddCase", recipients)
const [contactData, setContactData] = useState<ContactTypeObj>({ type: "", contacts: [] }); const [contactData, setContactData] = useState<ContactTypeObj>({ type: "", contacts: [] });
const [openContactModal, setOpenContactModal] = useState(false); const [openContactModal, setOpenContactModal] = useState(false);
@ -38,7 +36,7 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const formRef = useRef<HTMLFormElement | null>(null); const formRef = useRef<HTMLFormElement | null>(null);
const [recipient, setRecipients] = useState<Recipient>({ uuid: null, newOne: false, firstName: "", lastName: "", email: "", hostName: "", hostEmail: "", roleName: "", type: recipientType.SIGNER, allowSenderToEdit: true, allowSenderToDelete: true }); const [recipient, setRecipients] = useState<Recipient>({ uuid: null, newOne: false, firstName: "", lastName: "", email: "", hostName: "", hostEmail: "", roleName: "", type: recipientType.SIGNER, allowSenderToEdit: false, allowSenderToDelete: false });
const [showAdvanceSettings, setShowAdvanceSettings] = useState(false) const [showAdvanceSettings, setShowAdvanceSettings] = useState(false)
@ -49,14 +47,6 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
const [lastQuery, setLastQuery] = useState<string | null>(null); const [lastQuery, setLastQuery] = useState<string | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null); const containerRef = useRef<HTMLDivElement | null>(null);
const [manualFocusTriggered, setManualFocusTriggered] = useState(false); const [manualFocusTriggered, setManualFocusTriggered] = useState(false);
const [errors, setErrors] = useState({
roleName: false,
lastName: false,
email: false,
emailFormat: false,
type: false,
});
console.log(recipient) console.log(recipient)
@ -72,37 +62,7 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
}, [openContactModal]); }, [openContactModal]);
useEffect(() => { useEffect(() => {
// Check if the recipient exists in the list (using uuid or id or email)
const exists = recipients.some((r) => {
return (
(r.uuid && r.uuid === editRecipient?.uuid) ||
(r.id && r.id === editRecipient?.id) ||
(r.email && r.email === editRecipient?.email)
);
});
console.log("Line 83", exists)
if (editCase === "Edit" && editRecipient) { if (editCase === "Edit" && editRecipient) {
console.log("editRecipientAdd", editRecipient)
if (!exists) {
// Recipient was deleted -> reset
setEditCase('');
setEditRecipient(null);
setRecipients({
firstName: "",
lastName: "",
email: "",
hostName: "",
hostEmail: "",
roleName: "",
type: recipientType.SIGNER,
allowSenderToEdit: true,
allowSenderToDelete: true,
uuid: "",
newOne: false,
});
return;
}
setRecipients({ setRecipients({
// id:editRecipient.id, // id:editRecipient.id,
firstName: editRecipient.firstName || "", firstName: editRecipient.firstName || "",
@ -112,141 +72,106 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
hostEmail: editRecipient.hostEmail || "", hostEmail: editRecipient.hostEmail || "",
roleName: editRecipient.roleName || "", roleName: editRecipient.roleName || "",
type: editRecipient.type || recipientType.SIGNER, type: editRecipient.type || recipientType.SIGNER,
allowSenderToEdit: editRecipient.allowSenderToEdit ?? true, allowSenderToEdit: editRecipient.allowSenderToEdit ?? false,
allowSenderToDelete: editRecipient.allowSenderToDelete ?? true, allowSenderToDelete: editRecipient.allowSenderToDelete ?? false,
uuid: String(editRecipient?.id ?? editRecipient?.uuid ?? ''), uuid: String(editRecipient?.id ?? editRecipient?.uuid ?? ''),
newOne: editRecipient.newOne ?? false newOne: editRecipient.newOne ?? false
}); });
} }
}, [editCase, editRecipient, recipients]); }, [editCase, editRecipient]);
const handleRecipientAdd = (e: React.FormEvent<HTMLFormElement>) => { const handleRecipientAdd = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
const newErrors = { console.log("recipientrecipient", recipient)
roleName: false,
lastName: false,
email: false,
emailFormat: false,
type: false,
};
const roleNameFilled = recipient.roleName.trim(); if (!recipient.lastName || !recipient.email || !recipient.type) return;
const lastNameFilled = recipient.lastName.trim();
const emailFilled = recipient.email.trim();
const firstNameFilled = recipient.firstName.trim()
// ✅ Email format validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(recipient.email)) {
// 🔹 Check if we're in TRANSACTIONS mode console.log("Invalid email format");
if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS) {
if (lastNameFilled || emailFilled) {
if (lastNameFilled && !emailFilled) {
setErrors({ ...newErrors, email: true });
return;
}
if (!lastNameFilled && emailFilled) {
setErrors({ ...newErrors, lastName: true });
return;
}
if (!emailRegex.test(emailFilled)) {
setErrors({ ...newErrors, emailFormat: true });
return;
}
submitForm();
return;
}
// Neither lastName nor email is filled — treat as invalid
setErrors({ ...newErrors, lastName: true, email: true });
return; return;
} }
if (editCase === 'Edit') {
dispatch(updateRecipient(recipient));
// // 1. If either lastName or email is filled, validate their presence mutually } else {
// if ( emailFilled) { dispatch(addRecipient({
...recipient,
// // if (lastNameFilled && !emailFilled) { uuid: uuidv4(),
// // setErrors({ ...newErrors, email: true }); newOne: true
// // return; }));
// // }
// // if (!lastNameFilled && emailFilled) {
// // setErrors({ ...newErrors, lastName: true });
// // return;
// // }
// // // Both lastName and email are filled — check email format
// if (!emailRegex.test(emailFilled)) {
// setErrors({ ...newErrors, emailFormat: true });
// return;
// }
// // Passed validation, submit
// submitForm();
// return;
// }
if (roleNameFilled || lastNameFilled || emailFilled || firstNameFilled) {
submitForm()
return
} }
// 2. If both lastName and email empty, validate roleName only setRecipients({
if (!roleNameFilled) { firstName: "",
setErrors({ ...newErrors, roleName: true }); lastName: "",
return; email: "",
} hostName: "",
hostEmail: "",
roleName: "",
type: recipientType.SIGNER,
allowSenderToEdit: false,
allowSenderToDelete: false,
uuid: "",
newOne: false
});
// roleName filled, submit immediately // setRecipients(null),
submitForm(); setEditCase("")
setManualFocusTriggered(false)
function submitForm() { formRef.current?.reset();
if (editCase === 'Edit') {
dispatch(updateRecipient(recipient));
} else {
dispatch(addRecipient({
...recipient,
uuid: uuidv4(),
newOne: true,
}));
}
setRecipients({
firstName: "",
lastName: "",
email: "",
hostName: "",
hostEmail: "",
roleName: "",
type: recipientType.SIGNER,
allowSenderToEdit: true,
allowSenderToDelete: true,
uuid: "",
newOne: false,
});
setErrors({
roleName: false,
lastName: false,
email: false,
emailFormat: false,
type: false,
});
setEditCase("");
setManualFocusTriggered(false);
formRef.current?.reset();
}
}; };
// useEffect(() => {
// if (!recipient.firstName.length) return;
// const handler = setTimeout(() => {
// api.get(`/api/contact?firstName=${recipient.firstName}`)
// .then(res => {
// setContactData({ type: "firstName", contacts: res.data.content });
// })
// .catch(err => console.log(err));
// }, 500); // wait 500ms after the last change
// return () => {
// clearTimeout(handler); // cancel previous timeout if effect runs again
// };
// }, [recipient.firstName]);
// useDebouncedEffect(() => {
// if (!recipient.firstName.length) return;
// api.get(`/api/contact?firstName=${recipient.firstName}`)
// .then(res => {
// setContactData({ type: "firstName", contacts: res.data.content });
// })
// .catch(err => console.log(err));
// }, [recipient.firstName], 500);
// useDebouncedEffect(() => {
// if (!recipient.lastName.length) return
// api.get(`/api/contact?lastName=${recipient.lastName}`)
// .then(res => {
// setContactData({ type: "lastName", contacts: res.data.content });
// })
// .catch(err => console.log(err))
// }, [recipient.lastName], 500);
// useDebouncedEffect(() => {
// if (!recipient.email.length) return
// api.get(`/api/contact?email=${recipient.email}`)
// .then(res => {
// setContactData({ type: "email", contacts: res.data.content });
// })
// .catch(err => console.log(err))
// }, [recipient.email], 500);
const handleContactModalBlur = () => { const handleContactModalBlur = () => {
setTimeout(() => { setTimeout(() => {
setOpenContactModal(false) setOpenContactModal(false)
@ -320,138 +245,131 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
} }
}, [recipient.firstName, recipient.lastName, recipient.email], 300); }, [recipient.firstName, recipient.lastName, recipient.email], 300);
useEffect(() => { useEffect(() => {
const handleClickOutside = (e: MouseEvent | FocusEvent) => { const handleClickOutside = (e: MouseEvent | FocusEvent) => {
if ( if (
containerRef.current && containerRef.current &&
!containerRef.current.contains(e.target as Node) !containerRef.current.contains(e.target as Node)
) { ) {
setOpenContactModal(false); setOpenContactModal(false);
} }
}; };
document.addEventListener("mousedown", handleClickOutside); document.addEventListener("mousedown", handleClickOutside);
document.addEventListener("focusin", handleClickOutside); // Also handles tabbing out document.addEventListener("focusin", handleClickOutside); // Also handles tabbing out
return () => { return () => {
document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("mousedown", handleClickOutside);
document.removeEventListener("focusin", handleClickOutside); document.removeEventListener("focusin", handleClickOutside);
}; };
}, []); }, []);
return ( return (
<div ref={containerRef}> <div ref={containerRef}>
<form <form
ref={formRef} ref={formRef}
onSubmit={handleRecipientAdd} onSubmit={handleRecipientAdd}
id="add-recipient-step-one" id="add-recipient-step-one"
className="w-full bg-white border border-gray-200 rounded-lg shadow-md px-6 py-4 space-y-3 relative" className="w-full bg-white border border-gray-200 rounded-lg shadow-md px-6 py-4 space-y-3 relative"
> >
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && ( {transactionTemplateToggle === 'templates' && (
<div className="space-y-1"> <div className="space-y-1">
{/* Top Row: Role Input + Settings */} {/* Top Row: Role Input + Settings */}
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
{/* Role Name Input */} {/* Role Name Input */}
{/* Role Name Input */} <input
<div className="w-64"> required
<input type="text"
type="text" onFocus={() => setOpenContactModal(true)}
value={recipient.roleName} onBlur={handleContactModalBlur}
placeholder="Role name" value={recipient.roleName}
className={`w-full px-3 py-2 border rounded-md text-sm focus:outline-none transition placeholder="Role name"
${errors.roleName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} className="w-64 px-3 py-2 me-3 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
onChange={(e) => { onChange={(e) => setRecipients({ ...recipient, roleName: e.target.value })}
setRecipients({ ...recipient, roleName: e.target.value }); />
setErrors(prev => ({ ...prev, roleName: false }));
}}
/>
{errors.roleName && (
<p className="text-red-500 text-xs mt-1">Role is required.</p>
)}
</div>
{/* Settings + Permissions */}
{/* Settings + Permissions */} <div className="flex items-center">
<div className="flex items-center"> <div className="flex justify-between">
<div className="flex justify-between w-full"> {/* Permission Status Text - Always Visible when settings open */}
{/* Permission Status Text - Always Visible */} <div
<div className="max-h-10 opacity-100 me-3 overflow-hidden"> className={`transition-all duration-600 ease-in-out ${showAdvanceSettings ? 'max-h-10 opacity-100 me-3' : 'max-h-0 opacity-0 '
<div className="text-sm text-gray-600 pt-0.5"> } overflow-hidden`}
{/* {recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Full permissions granted"} >
{recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "Edit permission granted"} <div className="text-sm text-gray-600">
{!recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Delete permission granted"} {recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Full permissions granted"}
{!recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "No permissions granted"} */} {recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "Edit permission granted"}
Permissions granted : {!recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Delete permission granted"}
</div> {!recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "No permissions granted"}
</div> </div>
</div>
{/* Permission Controls - Always Visible */} {/* Animated Permission Controls */}
<div className="max-w-80 opacity-100 overflow-visible"> <div className={`overflow-visible transition-all duration-900 ease-in-out ${showAdvanceSettings ? 'max-w-80 opacity-100' : 'max-w-0 opacity-0'
<div className="flex items-center space-x-3 pr-1.5"> }`}>
{/* Edit Permission */} <div className="flex items-center space-x-3 pr-1.5">
<div className="relative group"> {/* Edit Permission */}
<label <div className="relative group">
className={`relative flex items-center justify-center w-12 h-7 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToEdit <label
? 'bg-blue-100 border-blue-500 shadow-md' className={`relative flex items-center justify-center w-6 h-6 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToEdit
: 'bg-white border-gray-300 hover:border-blue-400 text-gray-400' ? 'bg-blue-100 border-blue-500 shadow-lg'
: 'bg-white border-gray-300 hover:border-blue-400'
}`}
>
<input
type="checkbox"
checked={recipient.allowSenderToEdit}
onChange={(e) =>
setRecipients({ ...recipient, allowSenderToEdit: e.target.checked })
}
onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur}
className="absolute w-full h-full opacity-0 cursor-pointer"
/>
<FiEdit
className={`w-3 h-3 pointer-events-none transition-all duration-300 ${recipient.allowSenderToEdit ? 'text-blue-600' : 'text-gray-400'
}`} }`}
> />
<input </label>
type="checkbox" {/* Tooltip */}
checked={recipient.allowSenderToEdit} <div className="absolute bottom-0 -translate-y-full left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-20">
onChange={(e) => <div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
setRecipients({ ...recipient, allowSenderToEdit: e.target.checked }) Allow Edit Permission
} <div className="absolute bottom-[-5px] left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-800"></div>
onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur}
className="absolute w-full h-full opacity-0 cursor-pointer"
/>
<FiEdit
className={`w-2.5 h-2.5 pointer-events-none transition-all duration-300 ${recipient.allowSenderToEdit ? 'text-blue-600' : 'text-gray-400'
}`}
/><span className="ms-0.5 text-[12px]">Edit</span>
</label>
{/* Tooltip */}
<div className="absolute bottom-0 -translate-y-full left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-20">
<div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
Edit Permission
<div className="absolute bottom-[-5px] left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-800"></div>
</div>
</div> </div>
</div> </div>
</div>
{/* Delete Permission */} {/* Delete Permission */}
<div className="relative group"> <div className="relative group">
<label <label
className={`relative flex items-center justify-center w-15 h-7 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToDelete className={`relative flex items-center justify-center w-6 h-6 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToDelete
? 'bg-red-100 border-red-500 shadow-md' ? 'bg-red-100 border-red-500 shadow-lg'
: 'bg-white border-gray-300 hover:border-red-400 text-gray-400' : 'bg-white border-gray-300 hover:border-red-400'
}`}
>
<input
type="checkbox"
checked={recipient.allowSenderToDelete}
onChange={(e) =>
setRecipients({ ...recipient, allowSenderToDelete: e.target.checked })
}
onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur}
className="absolute w-full h-full opacity-0 cursor-pointer"
/>
<FiTrash
className={`w-3 h-3 pointer-events-none transition-all duration-300 ${recipient.allowSenderToDelete ? 'text-red-600' : 'text-gray-400'
}`} }`}
> />
<input </label>
type="checkbox" {/* Tooltip */}
checked={recipient.allowSenderToDelete} <div className="absolute bottom-0 -translate-y-full left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-20">
onChange={(e) => <div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
setRecipients({ ...recipient, allowSenderToDelete: e.target.checked }) Allow Delete Permission
} <div className="absolute bottom-[-5px] left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-800"></div>
onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur}
className="absolute w-full h-full opacity-0 cursor-pointer"
/>
<FiTrash
className={`w-3 h-3 pointer-events-none transition-all duration-300 ${recipient.allowSenderToDelete ? 'text-red-600' : 'text-gray-400'
}`}
/><span className="ms-0.5 text-[12px]">Delete</span>
</label>
{/* Tooltip */}
<div className="absolute bottom-0 -translate-y-full left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-20">
<div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
Delete Permission
<div className="absolute bottom-[-5px] left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-800"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -459,142 +377,137 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
</div> </div>
</div> </div>
{/* Settings Icon */}
<div className="relative group">
<p
className="text-blue-600 hover:text-blue-700 cursor-pointer transition-colors duration-200 p-2 rounded-full hover:bg-blue-50"
onClick={() => setShowAdvanceSettings((prev) => !prev)}
>
<IoIosSettings
className={`h-6 w-6 transition-transform duration-300 ${showAdvanceSettings ? 'rotate-90' : 'rotate-0'
}`}
/>
</p>
{/* Tooltip */}
<div className="absolute top-0 -translate-y-full left-1/2 transform -translate-x-1/2 mb-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-20">
<div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
Advanced Settings
<div className="absolute bottom-[-6px] left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-800"></div>
</div>
</div>
</div>
</div> </div>
</div> </div>
)} </div>
)}
{/* Name Inputs */} {/* Name Inputs */}
<div className="grid grid-cols-12 gap-4 mt-3"> <div className="grid grid-cols-12 gap-4 mt-3">
<div className="col-span-4"> <input
<input type="text"
type="text" onFocus={() => handleFocus("firstName")}
onFocus={() => handleFocus("firstName")} onBlur={handleContactModalBlur}
onBlur={handleContactModalBlur} value={recipient.firstName}
value={recipient.firstName} placeholder="First Name"
placeholder="First Name" className="col-span-4 w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
className={` w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition onChange={(e) => setRecipients({ ...recipient, firstName: e.target.value })}
${errors.firstName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} />
onChange={(e) => { <input
setRecipients({ ...recipient, firstName: e.target.value }); required
// setErrors((prev) => ({ ...prev, firstName: false })); type="text"
}} onFocus={() => handleFocus("lastName")}
/> onBlur={handleContactModalBlur}
</div> value={recipient.lastName}
{/* {errors.firstName && ( placeholder="Last Name"
<p className="text-red-500 text-xs mt-1">First Name is required</p> className="col-span-4 w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
)} */} onChange={(e) => setRecipients({ ...recipient, lastName: e.target.value })}
<div className="col-span-4"> />
<input <input
type="text" required
onFocus={() => handleFocus("lastName")} type="email"
onBlur={handleContactModalBlur} onFocus={() => handleFocus("email")}
value={recipient.lastName} onBlur={handleContactModalBlur}
placeholder="Last Name" value={recipient.email}
className={` w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition placeholder="Recipient Email"
${errors.lastName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} className="col-span-4 w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
onChange={(e) => { onChange={(e) => setRecipients({ ...recipient, email: e.target.value })}
setRecipients({ ...recipient, lastName: e.target.value }); />
setErrors((prev) => ({ ...prev, lastName: false })); </div>
}}
/>
{errors.lastName && ( {recipient.type === recipientType.INPERSONSIGNER && <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<p className="text-red-500 text-xs mt-1">Last Name is required</p> <input
)} required
</div> type="text"
<div className="col-span-4"> onFocus={() => setOpenContactModal(true)}
<input onBlur={handleContactModalBlur}
type="email" value={recipient.hostName}
onFocus={() => handleFocus("email")} placeholder="Host Name"
onBlur={handleContactModalBlur} className="w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
value={recipient.email} onChange={(e) => setRecipients({ ...recipient, hostName: e.target.value })}
placeholder="Recipient Email" />
className={`w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition <input
${errors.email ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} required
onChange={(e) => { type="email"
setRecipients({ ...recipient, email: e.target.value }); onFocus={() => setOpenContactModal(true)}
setErrors((prev) => ({ ...prev, email: false })); onBlur={handleContactModalBlur}
}} value={recipient.hostEmail}
/> placeholder="Host Email"
{errors.email && ( className="w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
<p className="text-red-500 text-xs mt-1">Email is required</p> onChange={(e) => setRecipients({ ...recipient, hostEmail: e.target.value })}
)} />
</div> </div>}
{/* Contact Modal */}
{openContactModal && contactData.contacts.length > 0 && (
<div className="absolute z-50 mt-1 w-2/3 max-h-[50vh] bg-white shadow-lg rounded-md p-3 border border-gray-100 overflow-y-auto no-scrollbar">
<ContactModal
contactData={contactData}
inpFirstName={recipient.firstName}
inpLastName={recipient.lastName}
inpEmail={recipient.email}
openContactModal={openContactModal}
setRecipients={setRecipients}
setOpenContactModal={setOpenContactModal}
topRef={topRef}
setManualFocusTriggered={setManualFocusTriggered}
/>
</div>
)}
{/* Signing options + Add button in one line */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div className="flex flex-wrap gap-6">
{[
{ label: "Signer", value: recipientType.SIGNER },
{ label: "In Person Signer", value: recipientType.INPERSONSIGNER },
{ label: "CC", value: recipientType.CC },
].map((option) => (
<label key={option.value} className="flex items-center gap-2 text-gray-700 text-sm cursor-pointer">
<input
type="radio"
name="recipient-type"
value={option.value}
defaultChecked={option.value === recipientType.SIGNER}
onClick={(e) => setRecipients({ ...recipient, type: e.target.value })}
className="accent-[var(--primary)] cursor-pointer"
/>
{option.label}
</label>
))}
</div> </div>
<button
{recipient.type === recipientType.INPERSONSIGNER && <div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> type="submit"
<input className="inline-flex items-center gap-2 bg-[var(--primary)] hover:bg-[var(--primaryLight2)] text-white text-sm font-semibold px-5 py-2 rounded-md transition"
required={transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES} >
type="text" <FaPlus size={14} /> {editCase === "Edit" ? "Edit Recipient" : "Add Recipient"}
onFocus={() => setOpenContactModal(true)} </button>
onBlur={handleContactModalBlur} </div>
value={recipient.hostName} </form>
placeholder="Host Name" </div>
className="w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
onChange={(e) => setRecipients({ ...recipient, hostName: e.target.value })}
/>
<input
required={transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES}
type="email"
onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur}
value={recipient.hostEmail}
placeholder="Host Email"
className="w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
onChange={(e) => setRecipients({ ...recipient, hostEmail: e.target.value })}
/>
</div>}
{/* Contact Modal */}
{openContactModal && contactData.contacts.length > 0 && (
<div className="absolute z-50 mt-1 w-2/3 max-h-[50vh] bg-white shadow-lg rounded-md p-3 border border-gray-100 overflow-y-auto no-scrollbar">
<ContactModal
contactData={contactData}
inpFirstName={recipient.firstName}
inpLastName={recipient.lastName}
inpEmail={recipient.email}
openContactModal={openContactModal}
setRecipients={setRecipients}
setOpenContactModal={setOpenContactModal}
topRef={topRef}
setManualFocusTriggered={setManualFocusTriggered}
/>
</div>
)}
{/* Signing options + Add button in one line */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div className="flex flex-wrap gap-6">
{[
{ label: "Signer", value: recipientType.SIGNER },
{ label: "In Person Signer", value: recipientType.INPERSONSIGNER },
{ label: "CC", value: recipientType.CC },
].map((option) => (
<label key={option.value} className="flex items-center gap-2 text-gray-700 text-sm cursor-pointer">
<input
type="radio"
name="recipient-type"
value={option.value}
defaultChecked={option.value === recipientType.SIGNER}
onClick={(e) => setRecipients({ ...recipient, type: e.target.value })}
className="accent-[var(--primary)] cursor-pointer"
/>
{option.label}
</label>
))}
</div>
<button
type="submit"
className="inline-flex items-center gap-2 bg-[var(--primary)] hover:bg-[var(--primaryLight2)] text-white text-sm font-semibold px-5 py-2 rounded-md transition"
>
<FaPlus size={14} /> {editCase === "Edit" ? "Edit Recipient" : "Add Recipient"}
</button>
</div>
</form>
</div>
); );
}; };

View File

@ -3,7 +3,7 @@ import {
removeRecipientAsync, removeRecipientAsync,
removeSelectedRecipient, removeSelectedRecipient,
// setSigningOrder, // setSigningOrder,
updateRecipientOrder, updateRecipientOrder, // 👈 You need to define this in your slice
} from "../../../store/slices/selectedRecipientsSlice"; } from "../../../store/slices/selectedRecipientsSlice";
import { AppDispatch, RootState } from "../../../store/store"; import { AppDispatch, RootState } from "../../../store/store";
@ -14,7 +14,6 @@ import SigningOrderDiagram from "../../../SigningOrderDiagram ";
import { IoCloseOutline } from "react-icons/io5"; import { IoCloseOutline } from "react-icons/io5";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { FiEdit } from "react-icons/fi"; import { FiEdit } from "react-icons/fi";
import { RiPencilFill } from "react-icons/ri";
const getInitials = (name: string) => { const getInitials = (name: string) => {
if (!name) return ""; if (!name) return "";
@ -31,7 +30,7 @@ type CardsData = {
transactionTemplateToggle: string transactionTemplateToggle: string
}; };
const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateToggle , editRecipient ,editCase }: CardsData) => { const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateToggle }: CardsData) => {
const templateId = useParams<{ templateId: string }>().templateId; const templateId = useParams<{ templateId: string }>().templateId;
let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>(); let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>();
@ -60,6 +59,7 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
const handleRemoveRecipient = (recipient) => { const handleRemoveRecipient = (recipient) => {
if (!accountId || !transactionId) return; if (!accountId || !transactionId) return;
// <<<<<<< HEAD
// dispatch(removeSelectedRecipient(recipient)) // dispatch(removeSelectedRecipient(recipient))
// dispatch(removeRecipientAsync([{ // dispatch(removeRecipientAsync([{
// recipientId: recipient.id, // recipientId: recipient.id,
@ -67,7 +67,7 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
// accountId: accountId, // accountId: accountId,
// transactionId: transactionId, // transactionId: transactionId,
// }])) // }]))
// ======= // =======
if (recipient.uuid) { if (recipient.uuid) {
dispatch(removeSelectedRecipient(recipient)) dispatch(removeSelectedRecipient(recipient))
} else { } else {
@ -78,6 +78,7 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
transactionId: transactionId, transactionId: transactionId,
})) }))
} }
// >>>>>>> origin/main
if (recipients.length === 2) { if (recipients.length === 2) {
let leftRecipient = recipients.filter((obj) => { let leftRecipient = recipients.filter((obj) => {
if ("id" in obj && "id" in recipient) { if ("id" in obj && "id" in recipient) {
@ -134,28 +135,24 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
> >
<div className="flex items-center gap-3 min-w-0"> <div className="flex items-center gap-3 min-w-0">
{/* {signingOrder && ( */} {/* {signingOrder && ( */}
{recipients.length > 1 ? <div className="relative"> {recipients.length > 1 ? <input
<input type="number"
type="number" value={recipient.routingOrder || 1}
value={recipient.routingOrder || 1} min={1}
min={1} onChange={(e) =>
onChange={(e) => handleOrderChange(recipient.id || recipient.email, Number(e.target.value))
handleOrderChange(recipient.id || recipient.email, Number(e.target.value)) }
} className="w-8 text-center rounded text-sm text-gray-700 border-none focus:outline-none focus:ring-[var(--primary)]"
className="w-10 h-6 text-center rounded text-sm text-gray-600 focus:outline-none focus:ring-[var(--primary)] border border-dashed border-gray-400 bg-slate-100" /> : <input
/> type="number"
{/* <RiPencilFill className="absolute top-1.5 right-0 text-[14px] text-gray-500" /> */} disabled
</div> value={recipient.routingOrder || 1}
: <input min={1}
type="number" onChange={(e) =>
disabled handleOrderChange(recipient.id || recipient.email, Number(e.target.value))
value={recipient.routingOrder || 1} }
min={1} className="w-8 text-center rounded text-sm text-gray-700 border-none focus:outline-none focus:ring-[var(--primary)]"
onChange={(e) => />}
handleOrderChange(recipient.id || recipient.email, Number(e.target.value))
}
className="w-8 text-center rounded text-sm text-gray-700 border-none focus:outline-none focus:ring-[var(--primary)]"
/>}
{/* )} */} {/* )} */}
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--primary)] text-white flex items-center justify-center font-semibold text-xs select-none"> <div className="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--primary)] text-white flex items-center justify-center font-semibold text-xs select-none">
@ -223,10 +220,11 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
</div> </div>
)} )}
{signingOrderModal.open && {signingOrderModal.open &&
<div className="fixed top-0 left-0 inset-0 z-50 bg-black/50 backdrop-blur-sm flex justify-center items-center"> <div className="fixed top-0 left-0 inset-0 z-50 bg-black/50 backdrop-blur-sm flex justify-center items-center">
<div className="flex-col relative justify-center items-center max-w-[80%] max-h-[60vh] h-full overflow-auto"> <div className="flex-col relative justify-center items-center max-w-[80%] max-h-[60vh] h-full overflow-auto">
<div className="p-2 rounded-t-lg text-white flex justify-between items-center bg-[var(--primary)]"> <div className="pb-2 text-white flex justify-between items-center">
<p className="font-semibold">Signing Order</p> <p className="font-semibold">Signing Order</p>
<div <div
onClick={() => setSigningOrderModal({ ...signingOrderModal, open: false })} onClick={() => setSigningOrderModal({ ...signingOrderModal, open: false })}

View File

@ -1,44 +0,0 @@
import { useNavigate } from "react-router-dom";
type PropsType = {
setShowSelfSignWarnModal: (val: boolean) => void;
onConfirm: () => void;
};
const SelfSignWarnModal = ({ setShowSelfSignWarnModal }: PropsType) => {
const navigate = useNavigate()
return (
<div className="fixed inset-0 backdrop-blur-sm flex items-center justify-center z-50">
<div className="bg-white rounded-lg shadow-xl p-6 w-100">
<h3 className="text-lg font-medium text-gray-800 mb-4">Confirm Self Sign</h3>
<p className="text-gray-600 mb-6">
Are you sure you want to proceed with self sign? This will remove all the recipient that you added.
</p>
<div className="flex justify-end gap-3">
<button
onClick={() => {
setShowSelfSignWarnModal(false);
navigate("./../");
}}
className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-md transition-colors"
>
No
</button>
<button
onClick={() => {
// onConfirm();
setShowSelfSignWarnModal(false);
}}
className="px-4 py-2 bg-red-600 text-white hover:bg-red-700 rounded-md transition-colors"
>
Yes
</button>
</div>
</div>
</div>
);
};
export default SelfSignWarnModal;

View File

@ -65,8 +65,13 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients); const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients);
// const selectedDocuments = useSelector((state: RootState) => state.selectedDocuments.selectedDocuments) // const selectedDocuments = useSelector((state: RootState) => state.selectedDocuments.selectedDocuments)
const selectedDocuments = useSelector((state: RootState) => state.documents.documents) const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
console.log("selectedDocuments", selectedDocuments)
const [droppedItems, setDroppedItems] = useState<DroppedItemsObj>({}); const [droppedItems, setDroppedItems] = useState<DroppedItemsObj>({});
console.log("droppedItems", droppedItems)
// const [uniqGroupIds, setUniqGroupIds] = useState<string[]>([]);
useEffect(() => { useEffect(() => {

View File

@ -11,7 +11,6 @@ import { RiResetLeftLine, 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'
import { Bounce, toast } from 'react-toastify'
interface NavTwoProps { interface NavTwoProps {
isFields: boolean; isFields: boolean;
@ -86,22 +85,7 @@ const NavTwo: React.FC<NavTwoProps> = ({ isFields, setIsFields, isSend, setIsSen
setIsSend(false); setIsSend(false);
} }
setIsSend(!isSend) setIsSend(!isSend)
if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS) { navigate(`/document-completion-screen/${accountId}/${transactionId}`)
navigate(`/document-completion-screen/${accountId}/${transactionId}`)
} else {
navigate(`/templates`);
toast.success("Template Saved...!", {
position: "top-center",
autoClose: 1500,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
transition: Bounce,
});
}
} }
const handleSetIsFields = (setTo: boolean) => { const handleSetIsFields = (setTo: boolean) => {
@ -281,9 +265,7 @@ const NavTwo: React.FC<NavTwoProps> = ({ isFields, setIsFields, isSend, setIsSen
id='send-sign-dash-btn' id='send-sign-dash-btn'
onClick={() => handleSend()} onClick={() => handleSend()}
className='flex items-center gap-2 cursor-pointer text-xs px-4 py-2 ml-3 rounded-sm bg-[var(--primary)]'> 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'> <p className='tracking-wide text-white'>Send</p>
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES ? "Save" : "Send"}
</p>
<FaSignature className='text-white text-md' /> <FaSignature className='text-white text-md' />
</div> </div>

View File

@ -152,7 +152,7 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
{/* Middle Row: Left - Center (Inputs) - Right */} {/* Middle Row: Left - Center (Inputs) - Right */}
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{/* Left Button */} {/* Left Button */}
{/* <div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<button <button
onClick={() => handleMove('left')} onClick={() => handleMove('left')}
disabled={disabled} disabled={disabled}
@ -163,12 +163,12 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
<FaArrowLeft size={12} /> <FaArrowLeft size={12} />
</button> </button>
<span className="mt-1">Left</span> <span className="mt-1">Left</span>
</div> */} </div>
{/* Center Panel */} {/* Center Panel */}
<div className="relative flex items-center justify-center bg-white rounded-lg px-1 py-2 w-24 "> <div className="relative flex items-center justify-center bg-white rounded-lg px-1 py-2 w-24 ">
{/* Floating dimensions tooltip */} {/* Floating dimensions tooltip */}
{/* <div className="absolute -top-2 left-1/2 -translate-x-1/2 px-2 py-[1px] text-[10px] font-mono text-black z-10 rounded-sm flex items-center gap-[2px]"> <div className="absolute -top-2 left-1/2 -translate-x-1/2 px-2 py-[1px] text-[10px] font-mono text-black z-10 rounded-sm flex items-center gap-[2px]">
<input <input
type="number" type="number"
value={leftValue} value={leftValue}
@ -188,12 +188,12 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
disabled={disabled} disabled={disabled}
className="w-[40px] h-[16px] text-[10px] text-center border-none focus:outline-none text-black font-mono" className="w-[40px] h-[16px] text-[10px] text-center border-none focus:outline-none text-black font-mono"
/> />
</div> */} </div>
</div> </div>
{/* Right Button */} {/* Right Button */}
{/* <div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<button <button
onClick={() => handleMove('right')} onClick={() => handleMove('right')}
disabled={disabled} disabled={disabled}
@ -204,11 +204,11 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
<FaArrowRight size={12} /> <FaArrowRight size={12} />
</button> </button>
<span className="mt-1">Right</span> <span className="mt-1">Right</span>
</div> */} </div>
</div> </div>
{/* Bottom Button */} {/* Bottom Button */}
{/* <div className="flex justify-center me-4"> <div className="flex justify-center me-4">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<button <button
onClick={() => handleMove('down')} onClick={() => handleMove('down')}
@ -221,7 +221,7 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
</button> </button>
<span className="mt-1">Bottom</span> <span className="mt-1">Bottom</span>
</div> </div>
</div> */} </div>
</div> </div>
); );
}; };

View File

@ -40,7 +40,7 @@ const Templates = () => {
const getAllTemplates = async () => { const getAllTemplates = async () => {
setLoading(true) setLoading(true)
try { try {
let res = await api.get(`/api/accounts/${activeAccountId}/templates?sortBy=lastModifiedAt desc`) let res = await api.get(`/api/accounts/${activeAccountId}/templates`)
let templateData = res?.data let templateData = res?.data
setTemplates(templateData) setTemplates(templateData)
} catch (error) { } catch (error) {
@ -78,16 +78,13 @@ const Templates = () => {
let res = await api.post(`/api/accounts/${activeAccountId}/transactions`, payload) let res = await api.post(`/api/accounts/${activeAccountId}/transactions`, payload)
console.log("handleUseClick", res.data) console.log("handleUseClick", res.data)
// /process-step-one/:accountId/:transactionId // /process-step-one/:accountId/:transactionId
navigate(`/process-step-one/${activeAccountId}/${res?.data?.id}?useTemplate=true`); navigate(`/process-step-one/${activeAccountId}/${res?.data?.id}`);
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
} }
const handleEditClick = (templateId: string) => {
setShowMenu(null);
navigate(`/process-step-one/${accountId}/template/${templateId}`);
}
return ( return (
<div className="p-3 text-sm"> <div className="p-3 text-sm">
@ -157,7 +154,7 @@ const Templates = () => {
{/* <FaCheck className="text-purple-600 text-xs" /> */} {/* <FaCheck className="text-purple-600 text-xs" /> */}
</div> </div>
</td> </td>
<td className="px-4 py-2 text-sm text-center">{item.name || 'Untitled'}</td> <td className="px-4 py-2 text-sm text-center">{item.name || 'Dummy'}</td>
<td className="px-4 py-2 text-sm text-center">{formatDate(item.createdAt)}</td> <td className="px-4 py-2 text-sm text-center">{formatDate(item.createdAt)}</td>
<td className="px-4 py-2 text-sm text-center">{formatDate(item.lastModifiedAt)}</td> <td className="px-4 py-2 text-sm text-center">{formatDate(item.lastModifiedAt)}</td>
<td className="px-4 py-2 text-sm text-center" onClick={() => handleUseClick(item)}><span className="bg-[var(--lightGreyCol)] cursor-pointer border-gray-300 text-gray-600 hover:bg-gray-100 px-3 py-1 rounded-lg font-semibold text-[12px]">Use</span></td> <td className="px-4 py-2 text-sm text-center" onClick={() => handleUseClick(item)}><span className="bg-[var(--lightGreyCol)] cursor-pointer border-gray-300 text-gray-600 hover:bg-gray-100 px-3 py-1 rounded-lg font-semibold text-[12px]">Use</span></td>
@ -183,7 +180,10 @@ const Templates = () => {
> >
<button <button
className="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" className="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
onClick={() => handleEditClick(item.id)} onClick={() => {
setShowMenu(null);
navigate(`/process-step-two/${accountId}/template/${item.id}`);
}}
> >
Edit Edit
</button> </button>

View File

@ -135,7 +135,7 @@ const TransactionView = () => {
<AiFillSignature className='absolute left-[-30px] text-[1rem]' /> <AiFillSignature className='absolute left-[-30px] text-[1rem]' />
<p className='text-black font-semibold'>{recipient.status}</p> <p className='text-black font-semibold'>{recipient.status}</p>
</div> </div>
{recipient.email === user.email && recipient.status !== "COMPLETED" && {recipient.email === user.email &&
<p <p
onClick={() => handleNavigateToSign(recipient.id)} onClick={() => handleNavigateToSign(recipient.id)}
className='text-white rounded-sm bg-[var(--primary)] px-3 py-1 font-semibold'> className='text-white rounded-sm bg-[var(--primary)] px-3 py-1 font-semibold'>

View File

@ -100,18 +100,6 @@ canvas {
} }
} }
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
-moz-appearance: textfield;
}
/* Group Border - START */ /* Group Border - START */
.group-border { .group-border {
position: absolute; position: absolute;

View File

@ -213,13 +213,7 @@ export const fetchDocuments = createAsyncThunk<
`/api/accounts/${accountId}/${toggle}/${transactionId}/documents?include_images=true` `/api/accounts/${accountId}/${toggle}/${transactionId}/documents?include_images=true`
); );
const data = response.data as Document[]; return response.data as Document[];
if (data.length === 0 && window.location.pathname.includes('/process-step-two')) {
window.location.href = window.location.href.replace("process-step-two", "process-step-one") // ✅ navigate using window
}
return data;
} catch (error: any) { } catch (error: any) {
return rejectWithValue(error.response?.data || 'Failed to fetch documents'); return rejectWithValue(error.response?.data || 'Failed to fetch documents');
} }

View File

@ -437,8 +437,6 @@ export const removeRecipientAsync = createAsyncThunk<
const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`; const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`;
console.log(`Line 440 : ${basePath}/${recipientId}`)
// return
if (recipientId) { if (recipientId) {
await api.delete(`${basePath}/${recipientId}`); await api.delete(`${basePath}/${recipientId}`);
return recipientId; return recipientId;
@ -465,13 +463,7 @@ export const fetchRecipients = createAsyncThunk<
const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`; const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`;
const response = await api.get(basePath); const response = await api.get(basePath);
const data = response.data as Recipient[]; return response.data as Recipient[];
if (data.length === 0 && window.location.pathname.includes('/process-step-two')) {
window.location.href = window.location.href.replace("process-step-two", "process-step-one") // ✅ navigate using window
}
return data as Recipient[];
} catch (err: any) { } catch (err: any) {
return rejectWithValue(err.response?.data || "Failed to fetch recipients"); return rejectWithValue(err.response?.data || "Failed to fetch recipients");
} }
@ -483,20 +475,17 @@ const selectedRecipientsSlice = createSlice({
initialState, initialState,
reducers: { reducers: {
addRecipient: (state, action: PayloadAction<Recipient>) => { addRecipient: (state, action: PayloadAction<Recipient>) => {
for (const recipient of state.recipients) {
// Checking if meail already exist - START if (recipient.email === action.payload.email) {
// for (const recipient of state.recipients) { toast.dismiss();
// if (recipient.email === action.payload.email) { toast.error("Email already exists !", {
// toast.dismiss(); position: "bottom-right",
// toast.error("Email already exists !", { autoClose: 5000,
// position: "bottom-right", theme: "light",
// autoClose: 5000, });
// theme: "light", return state;
// }); }
// return state; }
// }
// }
// Checking if meail already exist - END
if (action.payload.type === recipientType.INPERSONSIGNER) { if (action.payload.type === recipientType.INPERSONSIGNER) {
state.signingOrder = true; state.signingOrder = true;
@ -535,9 +524,6 @@ const selectedRecipientsSlice = createSlice({
removeSelectedRecipient: (state, action: PayloadAction<Recipient>) => { removeSelectedRecipient: (state, action: PayloadAction<Recipient>) => {
state.recipients = state.recipients.filter((recipient) => recipient.uuid !== action.payload.uuid); state.recipients = state.recipients.filter((recipient) => recipient.uuid !== action.payload.uuid);
}, },
removeAllRecipients: (state) => {
state.recipients = [];
},
addColorsToRecipient: (state) => { addColorsToRecipient: (state) => {
for (const [index, recipient] of state.recipients.entries()) { for (const [index, recipient] of state.recipients.entries()) {
recipient.color = colors[index]; recipient.color = colors[index];
@ -644,7 +630,6 @@ export const {
setSelectedRecipients, setSelectedRecipients,
toggleToTemplates, toggleToTemplates,
removeSelectedRecipient, removeSelectedRecipient,
removeAllRecipients,
setSigningOrder, setSigningOrder,
addColorsToRecipient, addColorsToRecipient,
updateRecipientIds, updateRecipientIds,

View File

@ -49,6 +49,7 @@ const JoyrideController = () => {
), ),
placement: "left", placement: "left",
disableBeacon: true, disableBeacon: true,
}, },
{ {
target: "#start-now-upload-con", target: "#start-now-upload-con",
@ -62,6 +63,7 @@ const JoyrideController = () => {
), ),
placement: "top", placement: "top",
disableBeacon: true, disableBeacon: true,
}, },
]; ];
} else if (location.pathname.includes("/process-step-one")) { } else if (location.pathname.includes("/process-step-one")) {
@ -198,12 +200,6 @@ const JoyrideController = () => {
} }
}; };
if(window.location.href.includes("template")) {
return (<></>)
} else {
return (<></>)
}
return ( return (
<Joyride <Joyride
steps={steps} steps={steps}