- {/* Order Number */}
- {recipients.length > 1 ? (
-
-
- handleOrderChange(
- recipient.id || recipient.uuid,
- Number(e.target.value)
- )
- }
- className="w-8 sm: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"
- />
- {idx === 0 && recipients.length > 1 &&
-
+
+ r.id || r.uuid)}
+ strategy={verticalListSortingStrategy}
+ >
+
+ {recipients.map((recipient, idx) => (
+
+
+ {/* Main Content Section */}
+
+ {/* Order Number */}
+ {recipients.length > 1 ? (
+
+
{
+ const value = e.target.value;
+ if (/^\d*$/.test(value)) {
+ const num = Number(value);
+ handleOrderChange(recipient.id || recipient.uuid, num);
+ }
+ }}
+ onKeyDown={(e) => {
+ if (!/[0-9]/.test(e.key) && e.key !== "Backspace" && e.key !== "Tab") {
+ e.preventDefault();
+ }
+ }}
+ className="w-8 sm: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"
+ />
+ {idx === 0 && recipients.length > 1 &&
+
- {/* Tooltip */}
-
- Signing order: Recipients receive emails one after another.
- Same order means they all receive at once.
-
-
}
-
- ) : (
-
- handleOrderChange(
- recipient.id || recipient.uuid,
- Number(e.target.value)
- )
- }
- className="w-6 sm:w-8 text-center rounded text-sm text-gray-700 border-none focus:outline-none focus:ring-[var(--primary)] flex-shrink-0"
- />
- )}
+ {/* Tooltip */}
+
+ Signing order: Recipients receive emails one after another.
+ Same order means they all receive at once.
+
+ }
+
+ ) : (
+
+ handleOrderChange(
+ recipient.id || recipient.uuid,
+ Number(e.target.value)
+ )
+ }
+ className="w-6 sm:w-8 text-center rounded text-sm text-gray-700 border-none focus:outline-none focus:ring-[var(--primary)] flex-shrink-0"
+ />
+ )}
- {/* Avatar */}
- {/*
+ {/* Avatar */}
+ {/*
{getInitials(`${recipient.firstName} ${recipient.lastName || ""}`)}
*/}
- {/* Form Fields Section */}
-
- {/* Role Name and Permissions Row */}
-
- {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES &&
-
- {renderEditableField(recipient, "roleName", "Role name")}
-
-
}
+ {/* Form Fields Section */}
+
+ {/* Role Name and Permissions Row */}
+
+ {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES &&
+
+ {renderEditableField(recipient, "roleName", "Role name")}
+
+
}
- {/* Permissions - Mobile: Below role, Desktop: Right side */}
-
- {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && (
-
-
+
+ {/* Name and Email Fields */}
+
+ {/* Mobile: Stack vertically, Tablet+: Side by side */}
+
+
+
+
+ {renderEditableField(recipient, "firstName", "First Name")}
+
+
+
+
+ {renderEditableField(recipient, "lastName", "Last Name")}
+
+
+
+
+
+ {renderEditableField(recipient, "email", "Recipient Email", "", "email")}
+
+
+
+
+
+ {/* Host Fields (for In-Person Signers) */}
+ {recipient.type === recipientType.INPERSONSIGNER && (
+
+
+
+
+ {renderEditableField(recipient, "hostName", "Host Name")}
+
+
+
+
+ {renderEditableField(recipient, "hostEmail", "Host Email", "", "email")}
+
+
+
+
+ )}
+
+ {/* Recipient Type Radio Buttons */}
+
+
-
-
- )}
-
-
-
- {/* Name and Email Fields */}
-
- {/* Mobile: Stack vertically, Tablet+: Side by side */}
-
-
-
-
- {renderEditableField(recipient, "firstName", "First Name")}
-
-
-
-
- {renderEditableField(recipient, "lastName", "Last Name")}
-
-
-
-
-
- {renderEditableField(recipient, "email", "Recipient Email", "", "email")}
-
-
- {/* Host Fields (for In-Person Signers) */}
- {recipient.type === recipientType.INPERSONSIGNER && (
-
-
-
-
- {renderEditableField(recipient, "hostName", "Host Name")}
-
-
-
-
- {renderEditableField(recipient, "hostEmail", "Host Email", "", "email")}
-
-
+ {/* Action Buttons */}
+ {signType !== "self-sign" && (
+
+
-
- )}
-
- {/* Recipient Type Radio Buttons */}
-
-
- handleTypeChange(recipient, recipientType.SIGNER)}
- onBlur={() => setEditingField(null)}
- className="accent-[var(--primary)] w-3 h-3"
- disabled={!isEditable(recipient)}
- />
- Signer
-
-
- handleTypeChange(recipient, recipientType.INPERSONSIGNER)}
- onBlur={() => setEditingField(null)}
- className="accent-[var(--primary)] w-3 h-3"
- disabled={!isEditable(recipient)}
- />
- In Person Signer
-
-
- handleTypeChange(recipient, recipientType.CC)}
- onBlur={() => setEditingField(null)}
- className="accent-[var(--primary)] w-3 h-3"
- disabled={!isEditable(recipient)}
- />
- CC
-
+ )}
-
-
- {/* Action Buttons */}
- {signType !== "self-sign" && (
-
-
-
- )}
+
+ ))}
- ))}
-
+
+ DndContext>
>
) : (
@@ -488,4 +643,85 @@ const RecipientCards = ({
);
};
-export default RecipientCards;
\ No newline at end of file
+export default RecipientCards;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//
+// r.id || r.uuid)}
+// strategy={verticalListSortingStrategy}
+// >
+//
+// {recipients.map((recipient, idx) => (
+//
+// {/* 🔹 your existing recipient card content goes here */}
+//
+// ))}
+//
+//
+//
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/process/processStepOne/RecipientsCon.tsx b/src/components/process/processStepOne/RecipientsCon.tsx
new file mode 100644
index 0000000..690213c
--- /dev/null
+++ b/src/components/process/processStepOne/RecipientsCon.tsx
@@ -0,0 +1,179 @@
+import { useRef, useState } from "react";
+import RecipientAddCard from "./RecipientAddCard"
+import RecipientCards from "./RecipientCards"
+import { useParams } from "react-router-dom";
+import { SignTypeEnum } from "../../../utlity/types";
+import { useDispatch, useSelector } from "react-redux";
+import { AppDispatch, RootState } from "../../../store/store";
+import { IoMdClose } from "react-icons/io";
+import getMinRoutingOrder from "../../../utlity/commonUtils";
+import { addRecipientAsync, recipientType, removeAllRecipients, removeRecipientAsync } from "../../../store/slices/selectedRecipientsSlice";
+import { UserState } from "../../../store/slices/userSlice";
+import api from "../../../config/api";
+import { FormSubmitInt } from "./ProcessStepOne";
+
+interface RecipientsConIntProps {
+ transactionTemplateToggle: string;
+ accountId: string | undefined;
+ transactionId: string | undefined;
+ userData: UserState;
+ isModal: boolean;
+ submitError?: FormSubmitInt;
+ setEditRecipientsModal?: React.Dispatch
+}
+
+const RecipientsCon: React.FC = ({ transactionTemplateToggle, accountId, transactionId, userData, submitError, isModal = true, setEditRecipientsModal }) => {
+ const dispatch = useDispatch()
+
+ const topRef = useRef(null);
+ const signType = useParams<{ signType: string }>().signType;
+ const [showSelfSignWarnModal, setShowSelfSignWarnModal] = useState(false)
+ const [editRecipient, setEditRecipient] = useState({})
+ const [editRecipientCurrentEmail, setEditRecipientCurrentEmail] = useState('')
+ const [editCase, setEditCase] = useState("")
+
+ const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients)
+
+ const globalLoader = useSelector((state: RootState) => state.loader)
+
+
+ // Handle Recipient Process - START
+ const handleRecipientAdd = async () => {
+ let minRoutingOrder = getMinRoutingOrder({ recipients: selectedRecipients });
+
+ const recipientsData = selectedRecipients.map((recipient, index) => ({
+ id: "id" in recipient ? recipient.id : null,
+ routingOrder: "routingOrder" in recipient && recipient.routingOrder ? recipient.routingOrder : 1,
+ provideOwnTags: userData.email === recipient.email && (recipient.routingOrder ?? 1) === minRoutingOrder ? true : false,
+ type: recipient.type,
+ firstName: recipient.firstName,
+ lastName: recipient.lastName,
+ authType: "NONE",
+ deliveryMethod: "EMAIL",
+ email: recipient.email,
+ hostName: recipient.hostName,
+ hostEmail: recipient.hostEmail,
+ company: "",
+ title: "",
+ website: "",
+ phone: "",
+ accessCode: "",
+ accessCodeDelivery: true,
+ language: "en",
+ name: `${recipient.firstName} ${recipient.lastName}`,
+ roleName: recipient.roleName,
+ allowSenderToEdit: recipient.allowSenderToEdit,
+ allowSenderToDelete: recipient.allowSenderToDelete,
+ }));
+
+ let recipientsDataTemp = recipientsData;
+ let recipientId = null;
+
+ if (signType === SignTypeEnum.selfSign) {
+ dispatch(removeAllRecipients());
+ await Promise.all(
+ selectedRecipients.map((recipient) => dispatch(removeRecipientAsync({
+ recipientId: recipient.id,
+ accountId,
+ transactionId,
+ email: recipient.email,
+ })))
+ );
+
+ recipientsDataTemp = [{
+ id: null,
+ routingOrder: 1,
+ provideOwnTags: true,
+ type: recipientType.SIGNER,
+ firstName: userData.firstName,
+ lastName: userData.lastName,
+ authType: "NONE",
+ deliveryMethod: "EMAIL",
+ email: userData.email,
+ hostName: "",
+ hostEmail: "",
+ company: "",
+ title: "",
+ website: "",
+ phone: "",
+ accessCode: "",
+ accessCodeDelivery: true,
+ language: userData.language ? userData.language : "en",
+ name: `${userData.firstName} ${userData.lastName}`,
+ roleName: "",
+ allowSenderToEdit: true,
+ allowSenderToDelete: true,
+ }]
+
+ try {
+ const basePath = `/api/accounts/${accountId}/transactions/${transactionId}/recipients`;
+ const res = await api.post(basePath, recipientsDataTemp)
+ recipientId = res.data[0].id;
+ } catch (error) {
+ console.log("Error Creating Self Sign Recipient", error.message)
+ }
+
+ } else {
+ if (!accountId || !transactionId) return;
+ dispatch(addRecipientAsync({ recipientsData: recipientsDataTemp, accountId, transactionId }));
+ }
+ }
+
+ // Handle Recipient Process - END
+
+ return (
+ <>
+ {(signType !== SignTypeEnum.selfSign || showSelfSignWarnModal) && <>
+
+ {isModal &&
+
Recipients
+
{
+ handleRecipientAdd()
+ setEditRecipientsModal(false)
+ }}
+ className="text-xl text-slate-400 cursor-pointer" />
+ }
+
+
+ {submitError && submitError.showError &&
+ {submitError.duplicateEmailSameRoutingOrder && `Each Signing order must have unique emails, ${submitError && submitError.email}`}
+ {!submitError.recipients && !submitError.duplicateEmailSameRoutingOrder && submitError.invalidRecipientEmail && `Invalid email address, ${submitError && submitError.email}`}
+ {!submitError.recipients && !submitError.duplicateEmailSameRoutingOrder && submitError.invalidRecipientLastName && `Last name cannot be empty.`}
+
}
+
+
+
+
+ {submitError && submitError.showError &&
+ {submitError.recipients && "At least one recipient is required."}
+
}
+
+
+ >}
+ >
+ )
+}
+
+export default RecipientsCon
\ No newline at end of file
diff --git a/src/components/process/processStepOne/SelectedDocuments.tsx b/src/components/process/processStepOne/SelectedDocuments.tsx
index 6dbf3b3..65aad90 100644
--- a/src/components/process/processStepOne/SelectedDocuments.tsx
+++ b/src/components/process/processStepOne/SelectedDocuments.tsx
@@ -1,35 +1,25 @@
import { useState, useRef, useEffect } from 'react';
import { ReactSortable } from 'react-sortablejs';
-import { RiDraggable } from "react-icons/ri";
-import { FaFileAlt, FaPlus, FaGoogleDrive, FaDropbox, FaMicrosoft, FaCloudUploadAlt } from "react-icons/fa";
+import { FaPlus, FaGoogleDrive, FaDropbox, FaMicrosoft, FaCloudUploadAlt } from "react-icons/fa";
import { useDispatch, useSelector } from 'react-redux';
// import { setSelectedDocuments } from '../../../store/slices/selectedDocsSlice';
-import { setDocuments, uploadDocuments } from '../../../store/slices/documentSlice';
-import { RootState, AppDispatch } from '../../../store/store';
+import { clearDocumentUploadErrors, DocumentErrorEnum, setDocuments, uploadDocuments } from '../../../store/slices/documentSlice';
+import { RootState } from '../../../store/store';
import { IoMdClose } from 'react-icons/io';
-import { Bounce, toast } from "react-toastify";
-import api from '../../../config/api';
import DocumentCard from './DocumentCard';
import { useParams } from 'react-router-dom';
-import { toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE } from '../../../store/slices/selectedRecipientsSlice';
+import { TRANSACTION_TEMPLATE_TOGGLE } from '../../../store/slices/selectedRecipientsSlice';
-const SelectedDocuments = ({ transactionTemplateToggle }) => {
- // let transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS;
-
- // const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
- // await sleep(5000);
+interface SelectedDocumentsIntProps {
+ transactionTemplateToggle: TRANSACTION_TEMPLATE_TOGGLE
+}
+const SelectedDocuments: React.FC = ({ transactionTemplateToggle }) => {
const documents = useSelector((state: RootState) => state.documents.documents);
+ const errorDocuments = useSelector((state: RootState) => state.documents.error);
const docCount = documents.length;
- useEffect(() => {
-
- console.log("Documents updated:", documents);
- }, [documents]);
-
-
-
const templateId = useParams<{ templateId: string }>().templateId;
let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>();
@@ -62,15 +52,19 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
dispatch(uploadDocuments({ formData, accountId, transactionId }))
.unwrap()
.then((res) => {
- toast.dismiss();
setFiles([]);
- setModalOpen(false);
})
.catch((err) => {
console.error("Upload failed", err);
});
};
+ useEffect(() => {
+ if (isModalOpen) {
+ if (errorDocuments[DocumentErrorEnum.FILE_SIZE_EXCEEDED].length === 0 && errorDocuments[DocumentErrorEnum.UNSUPPORTED_DOC_TYPE].length === 0) setModalOpen(false);
+ }
+ }, [documents])
+
const handleFileChange = (e: React.ChangeEvent) => {
const selectedFiles = e.target.files ? Array.from(e.target.files) : [];
if (selectedFiles.length > 0) {
@@ -90,36 +84,39 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
// Get proper Tailwind class names for upload card span
const getUploadCardSpanClass = () => {
- if (docCount === 0) {
- // Upload card takes all columns only when no docs
- return "col-span-1 sm:col-span-2 md:col-span-3 lg:col-span-4 xl:col-span-5";
- }
+ if (docCount === 0) {
+ // Upload card takes all columns only when no docs
+ return "col-span-1 sm:col-span-2 md:col-span-3 lg:col-span-4 xl:col-span-5";
+ }
- switch (docCount) {
- case 1:
- return "col-span-1 sm:col-span-1 md:col-span-2 lg:col-span-3 xl:col-span-4";
- case 2:
- return "col-span-1 sm:col-span-1 md:col-span-1 lg:col-span-2 xl:col-span-3";
- case 3:
- return "col-span-1 sm:col-span-1 md:col-span-1 lg:col-span-1 xl:col-span-2";
- case 4:
- return "col-span-1"; // balanced
- default:
- return "col-span-1";
- }
-};
+ switch (docCount) {
+ case 1:
+ return "col-span-1 sm:col-span-1 md:col-span-2 lg:col-span-3 xl:col-span-4";
+ case 2:
+ return "col-span-1 sm:col-span-1 md:col-span-1 lg:col-span-2 xl:col-span-3";
+ case 3:
+ return "col-span-1 sm:col-span-1 md:col-span-1 lg:col-span-1 xl:col-span-2";
+ case 4:
+ return "col-span-1"; // balanced
+ default:
+ return "col-span-1";
+ }
+ };
// Calculate how many documents should be in the first row
- const getFirstRowDocCount = () => {
- if (docCount === 0) return 0;
- if (docCount <= 4) return docCount; // All docs fit in first row
- return 4; // Max 4 docs in first row when upload card takes 1 column
- };
+ // const getFirstRowDocCount = () => {
+ // if (docCount === 0) return 0;
+ // if (docCount <= 4) return docCount; // All docs fit in first row
+ // return 4; // Max 4 docs in first row when upload card takes 1 column
+ // };
- const firstRowDocCount = getFirstRowDocCount();
- const remainingDocs = Math.max(0, docCount - firstRowDocCount);
+ // const firstRowDocCount = getFirstRowDocCount();
+ // const remainingDocs = Math.max(0, docCount - firstRowDocCount);
+
+
+ // console.log(errorDocuments, "errorDocuments Line 121")
return (
<>
@@ -127,23 +124,38 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
{/* Upload Document Card */}
setModalOpen(true)}
- className={`${getUploadCardSpanClass()} cursor-pointer h-[170px] flex flex-col items-center justify-center border-2 border-dashed border-gray-300 rounded-xl bg-white hover:bg-gray-50 transition shadow-sm hover:shadow-md`}
+ onDragOver={(e) => e.preventDefault()}
+ onDrop={handleDrop}
+ className={`${getUploadCardSpanClass()} cursor-pointer h-full flex flex-col items-center justify-center border-1 border-dashed border-gray-300 rounded-xl bg-white hover:bg-gray-50 transition`}
>
-
-
Upload Document
+ {/* Upload icon */}
+
+
+ {/* Compact text | Upload or drag & drop files */}
+
+
+
+
+
+ PDF, DOCX (max 10MB)
+
{/* First Row Documents */}
({ ...doc }))}
+ list={documents.map((doc) => ({ ...doc }))}
setList={(newState) => {
- const updatedDocs = [...newState, ...documents.slice(firstRowDocCount)];
+ const updatedDocs = [...newState];
dispatch(setDocuments(updatedDocs));
}}
handle=".drag-handle"
@@ -151,8 +163,8 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
ghostClass="sortable-ghost"
disabled={false}
>
- {documents.slice(0, firstRowDocCount).map((doc) => (
-
+ {documents.map((doc) => (
+
{
{/* Additional Rows */}
- {remainingDocs > 0 && (
-
({ ...doc }))}
- setList={(newState) => {
- const updatedDocs = [
- ...documents.slice(0, firstRowDocCount),
- ...newState,
- ];
- dispatch(setDocuments(updatedDocs));
- }}
- handle=".drag-handle"
- animation={200}
- ghostClass="sortable-ghost"
- disabled={false}
- >
- {documents.slice(firstRowDocCount).map((doc) => (
-
-
-
- ))}
-
- )}
+
{/* Modal */}
{isModalOpen && (
@@ -211,7 +191,10 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
{/* Close Button */}
@@ -253,10 +236,27 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
ref={fileInputRef}
className="hidden"
onChange={handleFileChange}
- accept=".pdf,.doc,.docx,.jpg,.png,.jpeg,.txt"
+ accept=".pdf"
multiple
/>
+ <>
+ {
+ (errorDocuments[DocumentErrorEnum.UNSUPPORTED_DOC_TYPE]).map((docName, indx) => {
+ return (
+
Unsupportd File Type for {docName}
+ )
+ })
+ }
+ {
+ (errorDocuments[DocumentErrorEnum.FILE_SIZE_EXCEEDED]).map((docName, indx) => {
+ return (
+
File Size Exceeded for {docName}
+ )
+ })
+ }
+ >
+
)}
{activeTab !== "Upload" && (
diff --git a/src/components/process/processStepOne/SelfSignWarnModal.tsx b/src/components/process/processStepOne/SelfSignWarnModal.tsx
index 5fd21dc..8a718ab 100644
--- a/src/components/process/processStepOne/SelfSignWarnModal.tsx
+++ b/src/components/process/processStepOne/SelfSignWarnModal.tsx
@@ -13,7 +13,7 @@ const SelfSignWarnModal = ({ setShowSelfSignWarnModal }: PropsType) => {
Confirm Self Sign
- Are you sure you want to proceed with self sign? This will remove all the recipient that you added.
+ Proceeding with self sign will make you the only signer. Other recipients will not be part of the signing process.
@@ -31,7 +31,7 @@ const SelfSignWarnModal = ({ setShowSelfSignWarnModal }: PropsType) => {
// onConfirm();
setShowSelfSignWarnModal(false);
}}
- className="px-4 py-2 bg-red-600 text-white hover:bg-red-700 rounded-md transition-colors"
+ className="px-4 py-2 cursor-pointer bg-[var(--mainPrimaryBtn)] text-white rounded-md transition-colors"
>
Yes
diff --git a/src/components/process/processStepOne/SortableRecipient.tsx b/src/components/process/processStepOne/SortableRecipient.tsx
new file mode 100644
index 0000000..f5d3c2f
--- /dev/null
+++ b/src/components/process/processStepOne/SortableRecipient.tsx
@@ -0,0 +1,49 @@
+import { CSS } from "@dnd-kit/utilities";
+import { useSortable } from "@dnd-kit/sortable";
+import { MdDragIndicator } from "react-icons/md";
+import { useSelector } from "react-redux";
+import { RootState } from "../../../store/store";
+
+const SortableRecipient = ({ recipient, idx, editRecipientCurrentEmail, children }: any) => {
+
+ const selectedRecipientsLen = useSelector((state: RootState) => state.selectedRecipients.recipients.length);
+
+ const {
+ attributes,
+ listeners,
+ setNodeRef,
+ transform,
+ transition,
+ isDragging,
+ } = useSortable({ id: recipient.id || recipient.uuid });
+
+ const style = {
+ transform: CSS.Transform.toString(transform),
+ transition,
+ opacity: isDragging ? 0.6 : 1,
+ };
+
+ return (
+
+ {/* Drag handle only on left side */}
+ {selectedRecipientsLen &&
+
+
}
+
+ {/* Your card content */}
+
{children}
+
+ );
+}
+
+export default SortableRecipient;
\ No newline at end of file
diff --git a/src/components/process/processStepTwo/DocumentContainer.tsx b/src/components/process/processStepTwo/DocumentContainer.tsx
index c53062e..be4ff16 100644
--- a/src/components/process/processStepTwo/DocumentContainer.tsx
+++ b/src/components/process/processStepTwo/DocumentContainer.tsx
@@ -47,6 +47,8 @@ interface DocumentContainerProps {
let copiedTags: DroppedItem[] = []
let selectedDoc: { [key: string]: string | null } = { key: null }
+const fetchedTags: string[] = []
+
const DocumentContainer: React.FC
= ({ transactionSaving, setTransactionSaving, isSend, isPreview = false, aId = null, tId = null }) => {
let transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS;
const dispatch = useDispatch();
@@ -87,24 +89,6 @@ const DocumentContainer: React.FC = ({ transactionSaving
hotKey?: string | null;
}
-
-
- // const hotKeysObjInitial: HotKeysObj = {
- // "CtrlA": {
- // enabled: false,
- // key: null
- // },
- // "Delete": {
- // enabled: false,
- // key: null
- // },
- // "CtrlC": {
- // enabled: false,
- // key: null,
- // tagId: null
- // }
- // }
-
const hotKeysObjInitial: HotKeysObj = {
isActive: false,
key: null,
@@ -112,11 +96,8 @@ const DocumentContainer: React.FC = ({ transactionSaving
hotKey: null
}
-
-
const [hotKeysObj, setHotKeysObj] = useState(hotKeysObjInitial);
-
useEffect(() => {
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId }));
@@ -125,12 +106,21 @@ const DocumentContainer: React.FC = ({ transactionSaving
const fetchTags = async () => {
try {
- const requests = selectedRecipients.map((recipient) =>
- api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/recipients/${recipient.id}/tags`)
- );
+ const requests = selectedRecipients.filter((recipient) => {
+ // Adding new rec doesn't have id till we click on IoMdClose or save so removing them and adding rec after click then fetching tags
+ if (!recipient.id) return false;
+ // also checking if have id but tags already fetched so to avoid same req
+ if (fetchedTags.includes(recipient.id)) return false;
+ fetchedTags.push(recipient.id)
+ return true
+ }).map((recipient) => api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/recipients/${recipient.id}/tags`));
+
+ if (!requests.length) return
+
const response = await Promise.all(requests);
let recTags = {}
for (const res of response) {
+ if (!res && !res.data) return
for (const tag of res.data) {
const key = `${tag.documentId}_${tag.pageIndex}`;
if (recTags[key]) {
@@ -188,8 +178,6 @@ const DocumentContainer: React.FC = ({ transactionSaving
// Filter Tags that needs to update
const updatedData = {}
- // debugger
-
for (const [recipientId, tags] of Object.entries(tagsData)) {
// console.log(recipientId, tags, "line 133")
const updateTags = []
@@ -206,13 +194,20 @@ const DocumentContainer: React.FC = ({ transactionSaving
updatedData[recipientId] = updateTags
}
- const requests = Object.entries(updatedData).filter(([recipientId, tags]) => {
- if (tags.length === 0) return false;
- return api.put(
- `/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/recipients/${recipientId}/tags`,
- tags
- );
- });
+ const requests = Object.entries(updatedData)
+ .filter(([_, tags]) => tags.length > 0) // filter out empty ones
+ .map(([recipientId, tags]) => {
+ const updatedTagsWithNavOrder = tags.map((tag, indx) => ({
+ ...tag,
+ navigationOrder: indx + 1,
+ }));
+
+ return api.put(
+ `/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/recipients/${recipientId}/tags`,
+ updatedTagsWithNavOrder
+ );
+ });
+
try {
const responses = await Promise.all(requests);
@@ -350,14 +345,11 @@ const DocumentContainer: React.FC = ({ transactionSaving
setTimeout(() => {
const tagIndex = key in droppedItems ? droppedItems[key].length : 0;
- console.log(tagIndex, "line 307", key);
- setSelectedTag({ key, tagIndex })
+ setSelectedTag({ key, index: tagIndex })
}, 0)
};
// HANDLE DROP - END
- console.log(selectedTag, "Line 359")
-
useEffect(() => {
if (!hotKeysObj.isActive) return
@@ -551,6 +543,7 @@ const DocumentContainer: React.FC = ({ transactionSaving
selTagKey={selectedTag.key}
selTagIndx={selectedTag.index}
signClient={false}
+ emptySelectedTag={() => setSelectedTag(null)}
/>
}
diff --git a/src/components/process/processStepTwo/DroppedItemsTagsCon.tsx b/src/components/process/processStepTwo/DroppedItemsTagsCon.tsx
index b465975..db32b33 100644
--- a/src/components/process/processStepTwo/DroppedItemsTagsCon.tsx
+++ b/src/components/process/processStepTwo/DroppedItemsTagsCon.tsx
@@ -48,17 +48,15 @@ const DroppedItemsTagsCon = forwardRef(({
const positionRef = useRef<{ left: number; top: number }>({ left: 0, top: 0 });
const handleTagClick = (key: string, index: number) => {
- console.log(index, "line 307", key);
-
setSelectedTag({ key, index })
}
const handleRemoveTag = (key: string, targetIndex: number) => {
- if(key === undefined || targetIndex === undefined) return
-
+ if (key === undefined || targetIndex === undefined) return
+
const tag = droppedItems[key][targetIndex];
const recipientId = tag.recipientId;
-
+
(async () => {
if ("id" in tag) {
try {
@@ -70,7 +68,7 @@ const DroppedItemsTagsCon = forwardRef(({
}
}
-
+
setSelectedTag(null);
@@ -570,9 +568,9 @@ const DroppedItemsTagsCon = forwardRef(({
- {IconComponent}
-
+ */}
{item.label}
{
e.stopPropagation();
@@ -599,10 +597,11 @@ const DroppedItemsTagsCon = forwardRef(({
style={{ background: selectedRecipient[0]?.color }}
>
{IconComponent}
+ {/* {item.label} */}
}
diff --git a/src/components/process/processStepTwo/FieldList.tsx b/src/components/process/processStepTwo/FieldList.tsx
index 0802340..11c98b2 100644
--- a/src/components/process/processStepTwo/FieldList.tsx
+++ b/src/components/process/processStepTwo/FieldList.tsx
@@ -19,17 +19,62 @@ const handlePointerDown = (event: React.DragEvent
, label: string
height = innerIconConRect.height + 10
}
- // Handling Initia Width and height of Some tags - START
- if (label === TagsTypes.STAMP) {
- width = 160
- height = 160
- } else if (label === TagsTypes.SIGNATURE) {
- width = 200
- height = 75
- } else if (label === TagsTypes.INITIALS) {
- width = 85
- height = 75
+ switch (label) {
+ case TagsTypes.STAMP: {
+ width = 160
+ height = 160
+ break;
+ }
+ case TagsTypes.SIGNATURE: {
+ width = 200
+ height = 75
+ break;
+ }
+ case TagsTypes.INITIALS: {
+ width = 85
+ height = 75
+ break;
+ }
+ case TagsTypes.COMPANY: {
+ width = 185
+ height = 35
+ break;
+ }
+ case TagsTypes.EMAIL: {
+ width = 185
+ height = 35
+ break;
+ }
+ case TagsTypes.NAME: {
+ width = 185
+ height = 35
+ break;
+ }
+ case TagsTypes.NUMBER: {
+ width = 185
+ height = 35
+ break;
+ }
+ case TagsTypes.SELECT: {
+ width = 185
+ height = 35
+ break;
+ }
+ case TagsTypes.TEMPORAL: {
+ width = 185
+ height = 35
+ break;
+ }
+ case TagsTypes.TEXT: {
+ width = 185
+ height = 35
+ break;
+ }
}
+
+
+
+
// Handling Initia Width and height of Some tags - END
const offsetX = event.clientX - dragElemRect.left;
@@ -110,8 +155,41 @@ const FieldList: React.FC = ({ color, recipientId, recipientIndx
});
}, []);
+ // return (
+ //
+ // {tagsData.map((field, index) => {
+
+ // const IconComponent = typeToIconMap[field.type] ||
;
+ // // Optional: skip unknown types
+ // if (!IconComponent) return null;
+
+ // return (
+ // //
handleDragStart(e, field.label, recipientId)} className="p-1 flex justify-start items-center gap-2 rounded-sm cursor-grab hover:bg-slate-200 transition-all duration-300">
+ //
handlePointerDown(e, field.type.toLowerCase(), recipientId, recipientIndx, field)}
+ // className="p-1 flex justify-start items-center gap-2 rounded-sm cursor-grab hover:bg-slate-200 transition-all duration-300">
+ //
+ // {IconComponent}
+ //
+ //
+ // {field.type.toLowerCase()}
+ //
+ //
+ // )
+ // }
+
+
+ // )}
+ //
+ // );
+
return (
-
+
{tagsData.map((field, index) => {
const IconComponent = typeToIconMap[field.type] ||
;
@@ -124,10 +202,14 @@ const FieldList: React.FC
= ({ color, recipientId, recipientIndx
draggable={true}
key={index}
onPointerDown={(e) => handlePointerDown(e, field.type.toLowerCase(), recipientId, recipientIndx, field)}
- className="p-1 flex justify-start items-center gap-2 rounded-sm cursor-grab hover:bg-slate-200 transition-all duration-300">
+ className={`border-[1px] flex flex-col justify-center bg-white p-2 w-[75px] h-[75px] items-center gap-2 rounded-sm cursor-grab hover:bg-slate-200 transition-all duration-300`}
+ style={{ borderColor: color }}
+ >
+
+ className={`p-1 rounded-sm text-white`}
+ // style={{ background: color }}
+ >
{IconComponent}
>
}
-const LeftSideBar: React.FC = ({ isFields, selectedRecipientIndx, setSelectedRecipient }) => {
+const LeftSideBar: React.FC = ({ isFields, isPages, selectedRecipientIndx, setSelectedRecipient }) => {
+
let transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS;
const dispatch = useDispatch();
const params = useParams<{ accountId?: string; transactionId?: string; templateId?: string }>();
@@ -64,12 +66,28 @@ const LeftSideBar: React.FC = ({ isFields, selectedRecipientIn
}
}, [])
+
+ useEffect(() => {
+ if (selectedRecipient && selectedRecipient.type === recipientType.CC) {
+ for (const [indx, recip] of selectedRecipients.entries()) {
+ if (recip.type !== recipientType.CC) {
+ setSelectedRecipient(indx);
+ break;
+ }
+ }
+ };
+ }, [selectedRecipient])
+
+ if(selectedRecipient && selectedRecipient.type === recipientType.CC){
+ return ;
+ }
+
return (
<>
{/* Left Side Bar - START */}
{
- selectedRecipients.length > 0 &&
- {isFields && <>
+
+ {selectedRecipients.length > 0 && isFields && <>
{/* Fields List and Recipeint - Start */}
{/* Side Bar showing Recipients */}
= ({ isFields, selectedRecipientIn
{/* Fields List and Recipeint - End */}
>}
-
-
- {!isFields && <>
+ {isPages && <>
{/* Pages - START */}
{selectedDocuments.length && selectedDocuments.map((document, indx) => {
@@ -190,7 +206,7 @@ const LeftSideBar: React.FC = ({ isFields, selectedRecipientIn
onChange={(e) => {
const newPage = Number(e.target.value);
setCurrentPage(newPage);
- window.location.hash = document.id +""+ newPage;
+ window.location.hash = document.id + "" + newPage;
}}
>
{document.pages != undefined && document.pages.map((_, pageIndex) => (
@@ -226,18 +242,7 @@ const LeftSideBar: React.FC = ({ isFields, selectedRecipientIn
{/* Pages - END */}
>}
-
-
-
-
-
-
-
-
-
-
-
-
+
}
{/* Left Side Bar - END */}
diff --git a/src/components/process/processStepTwo/NavTwo.tsx b/src/components/process/processStepTwo/NavTwo.tsx
index 7bddf98..b38bf18 100644
--- a/src/components/process/processStepTwo/NavTwo.tsx
+++ b/src/components/process/processStepTwo/NavTwo.tsx
@@ -13,12 +13,16 @@ import { fetchDocuments } from '../../../store/slices/documentSlice'
import { useNavigate, useParams } from 'react-router-dom'
import { Bounce, toast } from 'react-toastify'
import { FiChevronDown } from 'react-icons/fi'
+import RecipientsCon from '../processStepOne/RecipientsCon'
+import MessageCon from '../processStepOne/MessageCon'
interface NavTwoProps {
transactionSaving?: boolean;
// setTransactionSaving: React.Dispatch
>
isFields?: boolean;
setIsFields?: React.Dispatch>
+ isPages?: boolean;
+ setIsPages?: React.Dispatch>
isSend?: boolean | null;
setIsSend?: React.Dispatch>
isPreview?: boolean
@@ -51,9 +55,27 @@ const fitObj = [
},
]
-const NavTwo: React.FC = ({ transactionSaving = false, isFields, setIsFields, isSend, setIsSend, isPreview = false, aId = null, tId = null }) => {
+const NavTwo: React.FC = ({
+ transactionSaving = false,
+ isFields,
+ setIsFields,
+ isPages,
+ setIsPages,
+ isSend,
+ setIsSend,
+ isPreview = false,
+ aId = null,
+ tId = null
+}) => {
let transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS;
const dispatch = useDispatch();
+
+ const [showActionsDropDown, setShowActionsDropDown] = useState(false);
+ const [editRecipientsModal, setEditRecipientsModal] = useState(false);
+ const [messageModal, setMessageModal] = useState(false);
+
+ console.log(editRecipientsModal)
+
const params = useParams<{ accountId?: string; transactionId?: string; templateId?: string }>();
let accountId = params.accountId;
let transactionId = params.transactionId
@@ -160,7 +182,20 @@ const NavTwo: React.FC = ({ transactionSaving = false, isFields, se
}
const handleSetIsFields = (setTo: boolean) => {
- if (setTo !== isFields) setIsFields(setTo);
+ if (setTo !== undefined && setTo !== isFields) {
+ setIsFields(setTo)
+ if(setTo === true) {
+ setIsPages(false)
+ }
+ };
+ }
+ const handleSetIsPages = (setTo: boolean) => {
+ if (setTo !== undefined && setTo !== isPages) {
+ setIsPages(setTo)
+ if(setTo === true) {
+ setIsFields(false)
+ }
+ };
}
const zoom = (percentage: number, contentClass: string) => {
@@ -200,15 +235,15 @@ const NavTwo: React.FC = ({ transactionSaving = false, isFields, se
handleSetIsFields(true)}
+ onClick={() => handleSetIsFields(!isFields)}
className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${isFields ? 'bg-slate-100' : ''}`}>
Fields
handleSetIsFields(false)}
- className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${!isFields ? 'bg-slate-100' : ''}`}>
+ onClick={() => handleSetIsPages(!isPages)}
+ className={`flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm ${isPages ? 'bg-slate-100' : ''}`}>
Pages
@@ -219,7 +254,7 @@ const NavTwo: React.FC
= ({ transactionSaving = false, isFields, se
>
setIsFitDd(!isFitDd)}
- className='flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
+ className='hidden sm:flex md:flex items-center gap-1 cursor-pointer text-xs px-2 py-1 rounded-sm'>
Fit
@@ -243,7 +278,7 @@ const NavTwo: React.FC = ({ transactionSaving = false, isFields, se
- {!isPreview &&
+ {!isPreview &&
@@ -256,34 +291,58 @@ const NavTwo: React.FC
= ({ transactionSaving = false, isFields, se
{/* Right Side - STARTS */}
-
+
{/* Trigger */}
-