From 204d41cdc473ea0f623022ddf9efca92efc41ebe Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Fri, 1 Aug 2025 19:35:47 +0530 Subject: [PATCH] template&assessment-self-sign-first-form --- src/components/home/Cards.tsx | 32 +- src/components/home/Home.tsx | 8 +- .../process/processStepOne/ProcessStepOne.tsx | 130 +++- .../processStepOne/RecipientAddCard.tsx | 713 ++++++++++-------- .../process/processStepOne/RecipientCards.tsx | 52 +- .../processStepOne/SelfSignWarnModal.tsx | 44 ++ src/components/templates/Templates.tsx | 2 +- src/index.css | 12 + src/store/slices/selectedRecipientsSlice.tsx | 8 +- src/utlity/JoyRideTour.tsx | 2 - 10 files changed, 600 insertions(+), 403 deletions(-) create mode 100644 src/components/process/processStepOne/SelfSignWarnModal.tsx diff --git a/src/components/home/Cards.tsx b/src/components/home/Cards.tsx index 06fa7d2..7ce4bcf 100644 --- a/src/components/home/Cards.tsx +++ b/src/components/home/Cards.tsx @@ -204,7 +204,7 @@ const Cards: React.FC = ({ type = 'dashboard', onOpenModal, onDateRa // } return ( -
+
{/* Header */}
@@ -212,12 +212,12 @@ const Cards: React.FC = ({ type = 'dashboard', onOpenModal, onDateRa
*/}
-

Overview

+ {/*

Overview

*/} {/*

Monitor performance metrics

*/}
- +
{/* Cards */} @@ -231,11 +231,11 @@ const Cards: React.FC = ({ type = 'dashboard', onOpenModal, onDateRa
: -
+
{cards.map((card, index) => (
= ({ type = 'dashboard', onOpenModal, onDateRa
{/* Content */} -
-
+
+
{card.icon}
- {renderTrendIndicator(card.trend, card.percentage)} -
- -
-

+

{card.title}

-
-

- {card.count} -

- items -
+
+ +
+

+ {card.count} +

diff --git a/src/components/home/Home.tsx b/src/components/home/Home.tsx index c9769b7..1ab4b7a 100644 --- a/src/components/home/Home.tsx +++ b/src/components/home/Home.tsx @@ -33,7 +33,7 @@ const Home = () => { { title: 'Action Needed', count: data.actionNeeded || 0, - icon: , + icon: , gradient: 'bg-gradient-to-br from-indigo-50 to-indigo-100', shadowColor: 'shadow-indigo-200/50', iconBg: 'bg-indigo-100 border-indigo-200', @@ -43,7 +43,7 @@ const Home = () => { { title: 'Expiring Soon', count: data.expiring || 0, - icon: , + icon: , gradient: 'bg-gradient-to-br from-rose-50 to-rose-100', shadowColor: 'shadow-rose-200/50', iconBg: 'bg-rose-100 border-rose-200', @@ -53,7 +53,7 @@ const Home = () => { { title: 'Completed', count: data.completed || 0, - icon: , + icon: , gradient: 'bg-gradient-to-br from-teal-50 to-teal-100', shadowColor: 'shadow-teal-200/50', iconBg: 'bg-teal-100 border-teal-200', @@ -63,7 +63,7 @@ const Home = () => { { title: 'Draft', count: data.draft || 0, - icon: , + icon: , gradient: 'bg-gradient-to-br from-blue-50 to-blue-100', shadowColor: 'shadow-blue-200/50', iconBg: 'bg-blue-100 border-blue-200', diff --git a/src/components/process/processStepOne/ProcessStepOne.tsx b/src/components/process/processStepOne/ProcessStepOne.tsx index a6eda9b..1efc51d 100644 --- a/src/components/process/processStepOne/ProcessStepOne.tsx +++ b/src/components/process/processStepOne/ProcessStepOne.tsx @@ -7,15 +7,17 @@ import api from "../../../config/api"; import { useDispatch, useSelector } from "react-redux"; import { RootState } from "../../../store/store"; import { useEffect, useRef, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate, useParams, useSearchParams } from "react-router-dom"; import { setImages } from "../../../store/slices/selectedDocsSlice"; -import { addRecipient, addRecipientAsync, fetchRecipients, recipientType, resetRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE, updateRecipientIds } from "../../../store/slices/selectedRecipientsSlice"; +import { addRecipient, addRecipientAsync, fetchRecipients, recipientType, removeAllRecipients, removeRecipientAsync, resetRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE, updateRecipientIds } from "../../../store/slices/selectedRecipientsSlice"; import { setTransactionId, TRANSACTION_STATUS_ENUMS, updateTransactionStatus } from "../../../store/slices/transactionSlice"; import { hideLoader, showLoader } from "../../../store/slices/loaderSlice"; import Loader from "../../dashboard/Loader"; import { Bounce, toast } from "react-toastify"; import { fetchDocuments, resetDocuments, setDocuments, uploadDocuments } from "../../../store/slices/documentSlice"; import { SignTypeEnum } from "../../../utlity/types"; +import { RiPencilFill } from "react-icons/ri"; +import SelfSignWarnModal from "./SelfSignWarnModal"; const ProcessStepOne = () => { interface EmailDtls { @@ -28,6 +30,9 @@ const ProcessStepOne = () => { const signType = useParams<{ signType: string }>().signType; const templateId = useParams<{ templateId: string }>().templateId; 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 dispatch = useDispatch(); @@ -54,10 +59,29 @@ const ProcessStepOne = () => { const selectedDocuments = useSelector((state: RootState) => state.documents.documents) const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients) + const [showSelfSignWarnModal, setShowSelfSignWarnModal] = useState(false) + + console.log() const userData = useSelector((state: RootState) => state.user) // ProcessStepOne.tsx const topRef = useRef(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 [transactionDetails, setTransactionDetails] = useState([]); @@ -71,6 +95,7 @@ const ProcessStepOne = () => { try { const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`); setTransactionDetails(res.data) + // console.log("setTransactionDetails",res.data) } catch (e) { console.log("Error - transactions details") } @@ -111,38 +136,41 @@ const ProcessStepOne = () => { subject: false } - if (!selectedDocuments.length) { - formError.documents = true - } - if (!selectedRecipients.length) { - formError.recipients = true - } - if (!emailDtls.subject.length) { - formError.subject = true + if (transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) { + if (!selectedDocuments.length) { + formError.documents = true + } + if (!selectedRecipients.length) { + formError.recipients = true + } + if (!emailDtls.subject.length) { + 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 { dispatch(showLoader("Processing Documents...")); @@ -193,6 +221,17 @@ const ProcessStepOne = () => { let recipientId = null; if (signType === SignTypeEnum.selfSign) { + dispatch(removeAllRecipients()); + await Promise.all( + selectedRecipients.map((recipient) => dispatch(removeRecipientAsync({ + recipientId: recipient.id, + email: recipient.email, + accountId, + transactionId, + })) + ) + ); + recipientsDataTemp = [{ id: null, routingOrder: 1, @@ -232,6 +271,7 @@ const ProcessStepOne = () => { console.log(`1/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) let res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { + name: templateName, subject: emailDtls.subject, message: emailDtls.message, status: "CREATED" }) @@ -250,7 +290,7 @@ const ProcessStepOne = () => { dispatch(hideLoader()); if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) { console.log(`/process-step-two/${accountId}/template/${transactionId}`) - if(!saveAndClose) { + if (!saveAndClose) { navigate(`/process-step-two/${accountId}/template/${transactionId}`) } else { navigate(`/templates`) @@ -299,6 +339,7 @@ const ProcessStepOne = () => { const handleSelfSignCb = (e: React.ChangeEvent) => { if (e.currentTarget.checked) { navigate("self_sign"); + setShowSelfSignWarnModal((prev) => !prev) } else { navigate("./../"); } @@ -317,7 +358,21 @@ const ProcessStepOne = () => { onClick={handleClose} className='text-2xl text-slate-500 cursor-pointer hover:text-[var(--primary)] transition' /> -

Add Recipient and Message

+

+ {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES ? + <> + + {!isTyping && ( + + )} + : + "Add Recipient and Message" + } +

{ {/* Recipients */}
- { + {!isTamplate && transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES &&

Signers

@@ -370,9 +425,9 @@ const ProcessStepOne = () => { } { - signType !== SignTypeEnum.selfSign && + (signType !== SignTypeEnum.selfSign || showSelfSignWarnModal) &&
- + {/* {signType !== "self-sign" && } */}
{
{globalLoader.isLoading && } + {showSelfSignWarnModal && }
); diff --git a/src/components/process/processStepOne/RecipientAddCard.tsx b/src/components/process/processStepOne/RecipientAddCard.tsx index c260f59..b0bb3cc 100644 --- a/src/components/process/processStepOne/RecipientAddCard.tsx +++ b/src/components/process/processStepOne/RecipientAddCard.tsx @@ -1,8 +1,8 @@ import { useEffect, useRef, useState } from "react"; import { FaPlus } from "react-icons/fa"; import { addRecipient, Recipient, recipientType, TRANSACTION_TEMPLATE_TOGGLE, updateRecipient } from "../../../store/slices/selectedRecipientsSlice"; -import { useDispatch } from "react-redux"; -import { AppDispatch } from "../../../store/store"; +import { useDispatch, useSelector } from "react-redux"; +import { AppDispatch, RootState } from "../../../store/store"; import api from "../../../config/api"; import ContactModal from "./ContactModal"; import useDebouncedEffect from "../../../utlity/useDebounce"; @@ -29,6 +29,8 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase, 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({ type: "", contacts: [] }); const [openContactModal, setOpenContactModal] = useState(false); @@ -47,6 +49,14 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase, const [lastQuery, setLastQuery] = useState(null); const containerRef = useRef(null); const [manualFocusTriggered, setManualFocusTriggered] = useState(false); + const [errors, setErrors] = useState({ + roleName: false, + lastName: false, + email: false, + emailFormat: false, + type: false, + }); + console.log(recipient) @@ -62,7 +72,37 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase, }, [openContactModal]); 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) { + 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({ // id:editRecipient.id, firstName: editRecipient.firstName || "", @@ -78,104 +118,135 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase, newOne: editRecipient.newOne ?? false }); } - }, [editCase, editRecipient]); + }, [editCase, editRecipient, recipients]); const handleRecipientAdd = (e: React.FormEvent) => { e.preventDefault(); - console.log("recipientrecipient", recipient) + const newErrors = { + roleName: false, + lastName: false, + email: false, + emailFormat: false, + type: false, + }; - if(transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS) { - if (!recipient.lastName || !recipient.email || !recipient.type) return; + const roleNameFilled = recipient.roleName.trim(); + const lastNameFilled = recipient.lastName.trim(); + const emailFilled = recipient.email.trim(); + const firstNameFilled = recipient.firstName.trim() - // ✅ Email format validation - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(recipient.email)) { - console.log("Invalid email format"); + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + + // 🔹 Check if we're in TRANSACTIONS mode + 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; } - if (editCase === 'Edit') { - dispatch(updateRecipient(recipient)); - } else { - dispatch(addRecipient({ - ...recipient, - uuid: uuidv4(), - newOne: true - })); + + // // 1. If either lastName or email is filled, validate their presence mutually + // if ( emailFilled) { + + // // if (lastNameFilled && !emailFilled) { + // // setErrors({ ...newErrors, email: 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 } - setRecipients({ - firstName: "", - lastName: "", - email: "", - hostName: "", - hostEmail: "", - roleName: "", - type: recipientType.SIGNER, - allowSenderToEdit: true, - allowSenderToDelete: true, - uuid: "", - newOne: false - }); + // 2. If both lastName and email empty, validate roleName only + if (!roleNameFilled) { + setErrors({ ...newErrors, roleName: true }); + return; + } - // setRecipients(null), - setEditCase("") -setManualFocusTriggered(false) - formRef.current?.reset(); + // roleName filled, submit immediately + submitForm(); + + function submitForm() { + 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 = () => { setTimeout(() => { setOpenContactModal(false) @@ -249,131 +320,138 @@ setManualFocusTriggered(false) } }, [recipient.firstName, recipient.lastName, recipient.email], 300); -useEffect(() => { - const handleClickOutside = (e: MouseEvent | FocusEvent) => { - if ( - containerRef.current && - !containerRef.current.contains(e.target as Node) - ) { - setOpenContactModal(false); - } - }; + useEffect(() => { + const handleClickOutside = (e: MouseEvent | FocusEvent) => { + if ( + containerRef.current && + !containerRef.current.contains(e.target as Node) + ) { + setOpenContactModal(false); + } + }; - document.addEventListener("mousedown", handleClickOutside); - document.addEventListener("focusin", handleClickOutside); // Also handles tabbing out + document.addEventListener("mousedown", handleClickOutside); + document.addEventListener("focusin", handleClickOutside); // Also handles tabbing out - return () => { - document.removeEventListener("mousedown", handleClickOutside); - document.removeEventListener("focusin", handleClickOutside); - }; -}, []); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + document.removeEventListener("focusin", handleClickOutside); + }; + }, []); return (
-
- {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && ( -
- {/* Top Row: Role Input + Settings */} -
- {/* Role Name Input */} - setOpenContactModal(true)} - onBlur={handleContactModalBlur} - value={recipient.roleName} - placeholder="Role name" - 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) => setRecipients({ ...recipient, roleName: e.target.value })} - /> + + {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && ( +
+ {/* Top Row: Role Input + Settings */} +
+ {/* Role Name Input */} + {/* Role Name Input */} +
+ { + setRecipients({ ...recipient, roleName: e.target.value }); + setErrors(prev => ({ ...prev, roleName: false })); + }} + /> + {errors.roleName && ( +

Role is required.

+ )} +
- {/* Settings + Permissions */} -
-
- {/* Permission Status Text - Always Visible when settings open */} -
-
- {recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Full permissions granted"} - {recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "Edit permission granted"} - {!recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Delete permission granted"} - {!recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "No permissions granted"} + + {/* Settings + Permissions */} +
+
+ {/* Permission Status Text - Always Visible */} +
+
+ {/* {recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Full permissions granted"} + {recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "Edit permission granted"} + {!recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Delete permission granted"} + {!recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "No permissions granted"} */} + Permissions granted : +
-
- {/* Animated Permission Controls */} -
-
- {/* Edit Permission */} -
-
+ )} + + {/* Name Inputs */} +
+
+ handleFocus("firstName")} + onBlur={handleContactModalBlur} + value={recipient.firstName} + placeholder="First Name" + className={` w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition + ${errors.firstName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} + onChange={(e) => { + setRecipients({ ...recipient, firstName: e.target.value }); + // setErrors((prev) => ({ ...prev, firstName: false })); + }} + /> +
+ {/* {errors.firstName && ( +

First Name is required

+ )} */} +
+ handleFocus("lastName")} + onBlur={handleContactModalBlur} + value={recipient.lastName} + placeholder="Last Name" + className={` w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition + ${errors.lastName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} + onChange={(e) => { + setRecipients({ ...recipient, lastName: e.target.value }); + setErrors((prev) => ({ ...prev, lastName: false })); + }} + /> + {errors.lastName && ( +

Last Name is required

+ )} +
+
+ handleFocus("email")} + onBlur={handleContactModalBlur} + value={recipient.email} + placeholder="Recipient Email" + className={`w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition + ${errors.email ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} + onChange={(e) => { + setRecipients({ ...recipient, email: e.target.value }); + setErrors((prev) => ({ ...prev, email: false })); + }} + /> + {errors.email && ( +

Email is required

+ )} +
- )} - - {/* Name Inputs */} -
- handleFocus("firstName")} - onBlur={handleContactModalBlur} - value={recipient.firstName} - 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" - onChange={(e) => setRecipients({ ...recipient, firstName: e.target.value })} - /> - handleFocus("lastName")} - onBlur={handleContactModalBlur} - value={recipient.lastName} - placeholder="Last 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" - onChange={(e) => setRecipients({ ...recipient, lastName: e.target.value })} - /> - handleFocus("email")} - onBlur={handleContactModalBlur} - value={recipient.email} - placeholder="Recipient Email" - 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, email: e.target.value })} - /> -
- {recipient.type === recipientType.INPERSONSIGNER &&
- setOpenContactModal(true)} - onBlur={handleContactModalBlur} - value={recipient.hostName} - placeholder="Host Name" - 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 })} - /> - 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 })} - /> -
} - - {/* Contact Modal */} - {openContactModal && contactData.contacts.length > 0 && ( -
- + setOpenContactModal(true)} + onBlur={handleContactModalBlur} + value={recipient.hostName} + placeholder="Host Name" + 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 })} /> + 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 })} + /> +
} + + {/* Contact Modal */} + {openContactModal && contactData.contacts.length > 0 && ( +
+ +
+ )} + + + + {/* Signing options + Add button in one line */} +
+
+ {[ + { label: "Signer", value: recipientType.SIGNER }, + { label: "In Person Signer", value: recipientType.INPERSONSIGNER }, + { label: "CC", value: recipientType.CC }, + ].map((option) => ( + + ))} +
+ +
- )} - - - - {/* Signing options + Add button in one line */} -
-
- {[ - { label: "Signer", value: recipientType.SIGNER }, - { label: "In Person Signer", value: recipientType.INPERSONSIGNER }, - { label: "CC", value: recipientType.CC }, - ].map((option) => ( - - ))} -
- - -
- -
+ +
); }; diff --git a/src/components/process/processStepOne/RecipientCards.tsx b/src/components/process/processStepOne/RecipientCards.tsx index cecb18d..9e017f5 100644 --- a/src/components/process/processStepOne/RecipientCards.tsx +++ b/src/components/process/processStepOne/RecipientCards.tsx @@ -3,7 +3,7 @@ import { removeRecipientAsync, removeSelectedRecipient, // setSigningOrder, - updateRecipientOrder, // 👈 You need to define this in your slice + updateRecipientOrder, } from "../../../store/slices/selectedRecipientsSlice"; import { AppDispatch, RootState } from "../../../store/store"; @@ -14,6 +14,7 @@ import SigningOrderDiagram from "../../../SigningOrderDiagram "; import { IoCloseOutline } from "react-icons/io5"; import { useParams } from "react-router-dom"; import { FiEdit } from "react-icons/fi"; +import { RiPencilFill } from "react-icons/ri"; const getInitials = (name: string) => { if (!name) return ""; @@ -30,7 +31,7 @@ type CardsData = { transactionTemplateToggle: string }; -const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateToggle }: CardsData) => { +const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateToggle , editRecipient ,editCase }: CardsData) => { const templateId = useParams<{ templateId: string }>().templateId; let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>(); @@ -59,7 +60,6 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg const handleRemoveRecipient = (recipient) => { if (!accountId || !transactionId) return; -// <<<<<<< HEAD // dispatch(removeSelectedRecipient(recipient)) // dispatch(removeRecipientAsync([{ // recipientId: recipient.id, @@ -67,7 +67,7 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg // accountId: accountId, // transactionId: transactionId, // }])) -// ======= + // ======= if (recipient.uuid) { dispatch(removeSelectedRecipient(recipient)) } else { @@ -78,7 +78,6 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg transactionId: transactionId, })) } -// >>>>>>> origin/main if (recipients.length === 2) { let leftRecipient = recipients.filter((obj) => { if ("id" in obj && "id" in recipient) { @@ -135,24 +134,28 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg >
{/* {signingOrder && ( */} - {recipients.length > 1 ? - 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)]" - /> : - 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)]" - />} + {recipients.length > 1 ?
+ + handleOrderChange(recipient.id || recipient.email, Number(e.target.value)) + } + 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" + /> + {/* */} +
+ : + 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)]" + />} {/* )} */}
@@ -220,11 +223,10 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
)} - {signingOrderModal.open &&
-
+

Signing Order

setSigningOrderModal({ ...signingOrderModal, open: false })} diff --git a/src/components/process/processStepOne/SelfSignWarnModal.tsx b/src/components/process/processStepOne/SelfSignWarnModal.tsx new file mode 100644 index 0000000..fc83e0c --- /dev/null +++ b/src/components/process/processStepOne/SelfSignWarnModal.tsx @@ -0,0 +1,44 @@ +import { useNavigate } from "react-router-dom"; + +type PropsType = { + setShowSelfSignWarnModal: (val: boolean) => void; + onConfirm: () => void; +}; + +const SelfSignWarnModal = ({ setShowSelfSignWarnModal }: PropsType) => { + const navigate = useNavigate() + + return ( +
+
+

Confirm Self Sign

+

+ Are you sure you want to proceed with self sign? This will remove all the recipient that you added. +

+
+ + +
+
+
+ ); +}; + +export default SelfSignWarnModal; diff --git a/src/components/templates/Templates.tsx b/src/components/templates/Templates.tsx index 140abf1..46a0c91 100644 --- a/src/components/templates/Templates.tsx +++ b/src/components/templates/Templates.tsx @@ -78,7 +78,7 @@ const Templates = () => { let res = await api.post(`/api/accounts/${activeAccountId}/transactions`, payload) console.log("handleUseClick", res.data) // /process-step-one/:accountId/:transactionId - navigate(`/process-step-one/${activeAccountId}/${res?.data?.id}`); + navigate(`/process-step-one/${activeAccountId}/${res?.data?.id}?useTemplate=true`); } catch (error) { console.log(error) } diff --git a/src/index.css b/src/index.css index e4f589e..e9927b4 100644 --- a/src/index.css +++ b/src/index.css @@ -100,6 +100,18 @@ 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 { position: absolute; diff --git a/src/store/slices/selectedRecipientsSlice.tsx b/src/store/slices/selectedRecipientsSlice.tsx index f7a3d02..e1a0957 100644 --- a/src/store/slices/selectedRecipientsSlice.tsx +++ b/src/store/slices/selectedRecipientsSlice.tsx @@ -437,6 +437,8 @@ export const removeRecipientAsync = createAsyncThunk< const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`; + console.log(`Line 440 : ${basePath}/${recipientId}`) + // return if (recipientId) { await api.delete(`${basePath}/${recipientId}`); return recipientId; @@ -481,7 +483,7 @@ const selectedRecipientsSlice = createSlice({ initialState, reducers: { addRecipient: (state, action: PayloadAction) => { - + // Checking if meail already exist - START // for (const recipient of state.recipients) { // if (recipient.email === action.payload.email) { @@ -533,6 +535,9 @@ const selectedRecipientsSlice = createSlice({ removeSelectedRecipient: (state, action: PayloadAction) => { state.recipients = state.recipients.filter((recipient) => recipient.uuid !== action.payload.uuid); }, + removeAllRecipients: (state) => { + state.recipients = []; + }, addColorsToRecipient: (state) => { for (const [index, recipient] of state.recipients.entries()) { recipient.color = colors[index]; @@ -639,6 +644,7 @@ export const { setSelectedRecipients, toggleToTemplates, removeSelectedRecipient, + removeAllRecipients, setSigningOrder, addColorsToRecipient, updateRecipientIds, diff --git a/src/utlity/JoyRideTour.tsx b/src/utlity/JoyRideTour.tsx index 685f167..68c42c5 100644 --- a/src/utlity/JoyRideTour.tsx +++ b/src/utlity/JoyRideTour.tsx @@ -49,7 +49,6 @@ const JoyrideController = () => { ), placement: "left", disableBeacon: true, - }, { target: "#start-now-upload-con", @@ -63,7 +62,6 @@ const JoyrideController = () => { ), placement: "top", disableBeacon: true, - }, ]; } else if (location.pathname.includes("/process-step-one")) {