Default Sign Fill Done

This commit is contained in:
=bhagwanSingh 2025-08-05 13:03:25 +05:30
parent 479ad820be
commit 444de539f4
4 changed files with 207 additions and 40 deletions

View File

@ -12,7 +12,7 @@ import { useDispatch, useSelector } from "react-redux";
import { hideLoader, showLoader } from "../../store/slices/loaderSlice"; import { hideLoader, showLoader } from "../../store/slices/loaderSlice";
import { FaRegImage, FaFileAlt, FaSignature, FaStamp, FaCheck, FaQuestionCircle } from 'react-icons/fa' import { FaRegImage, FaFileAlt, FaSignature, FaStamp, FaCheck, FaQuestionCircle } from 'react-icons/fa'
import { IoIosDocument } from 'react-icons/io' import { IoIosDocument, IoMdClose } from 'react-icons/io'
import { MdKeyboardArrowDown } from 'react-icons/md' import { MdKeyboardArrowDown } from 'react-icons/md'
import { TbChevronsDownLeft, TbSignature } from "react-icons/tb"; import { TbChevronsDownLeft, TbSignature } from "react-icons/tb";
import { BsFileArrowDownFill } from "react-icons/bs"; import { BsFileArrowDownFill } from "react-icons/bs";
@ -139,6 +139,8 @@ const SignDocument = () => {
// Signer data - START // Signer data - START
const [selectedDocuments, setSelectedDocuments] = useState<DocumentType[] | null>(null); const [selectedDocuments, setSelectedDocuments] = useState<DocumentType[] | null>(null);
const [selectedTag, setSelectedTag] = useState<{ key: string, index: number } | null>(null);
const [recipient, setRecipient] = useState<RecipientType | null>(null); const [recipient, setRecipient] = useState<RecipientType | null>(null);
const [tagJson, setTagJson] = useState<DroppedItem[] | []>([]); const [tagJson, setTagJson] = useState<DroppedItem[] | []>([]);
const [transaction, setTransaction] = useState<TransactionType | null>(null); const [transaction, setTransaction] = useState<TransactionType | null>(null);
@ -194,6 +196,10 @@ const SignDocument = () => {
} }
} }
const handleTagClick = (key: string, index: number) => {
setSelectedTag({ key, index })
}
useEffect(() => { useEffect(() => {
let indx = fitObj[selFitIndx].value let indx = fitObj[selFitIndx].value
if (indx === "FIT") { if (indx === "FIT") {
@ -680,6 +686,17 @@ const SignDocument = () => {
// setDroppedItems(dataToSet); // setDroppedItems(dataToSet);
// } // }
if (prepData.type.toLowerCase() === TagsTypes.SIGNATURE || prepData.type.toLowerCase() === TagsTypes.INITIALS) {
const currDocTags = droppedItems.filter((val) => val.pageIndex === prepData.pageIndex)
setSignConfObj({
...signConfObj,
[currDocTags.length]: {
accepted: true,
index: currDocTags.length
}
})
}
setDroppedItems((prev) => [...prev, prepData]); setDroppedItems((prev) => [...prev, prepData]);
// setDroppedItemsCounter((prev) => prev + 1); // setDroppedItemsCounter((prev) => prev + 1);
@ -696,6 +713,8 @@ const SignDocument = () => {
// HANDLE TAG MOUSE DOWN - START // HANDLE TAG MOUSE DOWN - START
const handleTagMouseDown = (event: React.MouseEvent<HTMLDivElement>, key: string, index: number) => { const handleTagMouseDown = (event: React.MouseEvent<HTMLDivElement>, key: string, index: number) => {
setSelectedTag({ key, index })
event.preventDefault(); event.preventDefault();
let targetContainer = event?.currentTarget?.parentElement?.parentElement; let targetContainer = event?.currentTarget?.parentElement?.parentElement;
@ -759,6 +778,99 @@ const SignDocument = () => {
// HANDLE TAG MOUSE DOWN - END // HANDLE TAG MOUSE DOWN - END
// Updated handleRemoveTag function with your existing API logic and group handling
const handleRemoveTag = (key: string, targetIndex: number) => {
console.log(droppedItems, "Line 784")
const tag = droppedItems[key][targetIndex];
const recipientId = tag.recipientId;
(async () => {
if ("id" in tag) {
try {
const response = await api.delete(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/recipients/${recipientId}/tags/${tag.id}`)
if (response.status !== 200) throw "Tag Deletion error"
} catch (err) {
console.error("Tag Deletion error")
return;
}
}
setSelectedTag(null);
// Check if this item has a group for special group handling
if ('group' in tag && tag.group) {
const groupId = tag.group;
// Find all items in the same group
const groupItems = droppedItems[key]
.map((item, idx) => ({ item, index: idx }))
.filter(({ item }) => 'group' in item && item.group === groupId && !item.isDeleted);
// Sort group items by their top position to identify the parent (top-most)
groupItems.sort((a, b) => a.item.dimensions.top - b.item.dimensions.top);
// Check if the item being removed is the parent (top-most item)
const isParentItem = groupItems.length > 0 && groupItems[0].index === targetIndex;
if (isParentItem && groupItems.length > 1) {
// If removing the parent and there are child items, mark all items in the group as deleted
console.log(`Removing parent item and all children for group: ${groupId}`);
// Get indices of all group items to mark as deleted
const indicesToDelete = groupItems.map(({ index }) => index);
setDroppedItems(prevState => ({
...prevState,
[key]: prevState[key].map((item, index) =>
indicesToDelete.includes(index) ? { ...item, isDeleted: true } : item
)
}));
// Remove group border elements after state update
// setTimeout(() => {
// removeGroupBorders(groupId);
// }, 100);
} else {
// If removing a child item or the only item in group, just mark this item as deleted
console.log(`Removing individual item from group: ${groupId}`);
setDroppedItems(prevState => ({
...prevState,
[key]: prevState[key].map((item, index) =>
index === targetIndex ? { ...item, isDeleted: true } : item
)
}));
// Check if this was the last item in the group after state update
// setTimeout(() => {
// const remainingGroupItems = droppedItems[key].filter(item =>
// 'group' in item && item.group === groupId && !item.isDeleted
// );
// if (remainingGroupItems.length === 0) {
// // Remove group borders if no items left
// removeGroupBorders(groupId);
// } else {
// // Update group borders for remaining items
// handleIGroupBorderPosition(groupId);
// }
// }, 100);
}
} else {
// Handle non-group item removal (your existing logic)
setDroppedItems(prevState => ({
...prevState,
[key]: prevState[key].map((item, index) =>
index === targetIndex ? { ...item, isDeleted: true } : item
)
}));
}
})()
};
console.log(droppedItems, "DROPPED ITEMS LINE 680") console.log(droppedItems, "DROPPED ITEMS LINE 680")
// const [showTerms, setShowTerms] = useState<boolean>(true); // const [showTerms, setShowTerms] = useState<boolean>(true);
@ -928,6 +1040,7 @@ const SignDocument = () => {
console.log(item, "micCheck 842") console.log(item, "micCheck 842")
if (item.pageIndex !== page.index) return; if (item.pageIndex !== page.index) return;
return ( return (
<div <div
tabIndex={1} tabIndex={1}
onFocus={() => setFocusElement({ ...item, focusElementIndx: index })} onFocus={() => setFocusElement({ ...item, focusElementIndx: index })}
@ -946,8 +1059,29 @@ const SignDocument = () => {
}} }}
> >
<>
{selectedTag?.key && selectedTag.key === key && selectedTag.index === index &&
<div className='absolute flex justify-between items-center w-full max-w-max bg-white top-[-22px] shadow z-20 text-sm rounded-t-sm' >
<div className='flex justify-center items-center gap-1 bg-white px-2 shadow'>
<p className='w-2.5 h-2.5 rounded'
style={{ "background": "#2d2d2d" }}
>
</p>
{/* <p
className=''>{IconComponent}
</p> */}
<p className='capitalize text-ellipsis whitespace-nowrap'>{item.label}</p>
<IoMdClose onClick={(e) => {
e.stopPropagation();
handleRemoveTag(key, index)
}} className='cursor-pointer' />
</div>
</div>}
</>
{/* TEXT FIELD - START */} {/* TEXT FIELD - START */}
{item.type === "TEXT" && {
item.type === "TEXT" &&
<div <div
id={item.id} id={item.id}
tabIndex={1} tabIndex={1}
@ -1012,12 +1146,14 @@ const SignDocument = () => {
className="outline-none whitespace-nowrap w-full max-h-max" className="outline-none whitespace-nowrap w-full max-h-max"
></p> ></p>
} }
</div>} </div>
}
{/* TEXT FIELD - END */} {/* TEXT FIELD - END */}
{/* CHECKBOX FIELD - START */} {/* CHECKBOX FIELD - START */}
{item.type === "CHECKBOX" && {
item.type === "CHECKBOX" &&
<div <div
id={item.id} id={item.id}
className={`h-full w-full rounded flex justify-center items-center ${transparentTags || hideTags ? "pointer-events-none" : "bg-slate-200 shadow-sm border-slate-100 opacity-80"}`} className={`h-full w-full rounded flex justify-center items-center ${transparentTags || hideTags ? "pointer-events-none" : "bg-slate-200 shadow-sm border-slate-100 opacity-80"}`}
@ -1028,12 +1164,14 @@ const SignDocument = () => {
// style={{ height: item.dimensions.height + "px" }} // style={{ height: item.dimensions.height + "px" }}
className="w-full px-2 outline-none" className="w-full px-2 outline-none"
type="checkbox" /> type="checkbox" />
</div>} </div>
}
{/* CHECKBOX FIELD - END */} {/* CHECKBOX FIELD - END */}
{/* SIGNATURE FIELD - START */} {/* SIGNATURE FIELD - START */}
{item.type === "SIGNATURE" && {
item.type === "SIGNATURE" &&
<div <div
tabIndex={1} tabIndex={1}
id={item.id} id={item.id}
@ -1057,12 +1195,14 @@ const SignDocument = () => {
src={`data:image/png;base64,${saved.signature}`} src={`data:image/png;base64,${saved.signature}`}
/> />
} }
</div>} </div>
}
{/* SIGNATURE FIELD - END */} {/* SIGNATURE FIELD - END */}
{/* INITIALS FIELD - START */} {/* INITIALS FIELD - START */}
{item.type === "INITIALS" && {
item.type === "INITIALS" &&
<div <div
tabIndex={1} tabIndex={1}
id={item.id} id={item.id}
@ -1083,12 +1223,14 @@ const SignDocument = () => {
src={`data:image/png;base64,${saved.initial}`} src={`data:image/png;base64,${saved.initial}`}
/> />
} }
</div>} </div>
}
{/* INITIALS FIELD - END */} {/* INITIALS FIELD - END */}
{/* STAMP FIELD - START */} {/* STAMP FIELD - START */}
{item.type === "STAMP" && {
item.type === "STAMP" &&
<div <div
tabIndex={1} tabIndex={1}
id={item.id} id={item.id}
@ -1101,11 +1243,13 @@ const SignDocument = () => {
: :
<img className="w-[100%] h-full" src={saved.initial as string} /> <img className="w-[100%] h-full" src={saved.initial as string} />
} }
</div>} </div>
}
{/* STAMP FIELD - END */} {/* STAMP FIELD - END */}
{/* IMAGE FIELD - START */} {/* IMAGE FIELD - START */}
{item.type === "FILE" && {
item.type === "FILE" &&
<div <div
tabIndex={1} tabIndex={1}
id={item.id} id={item.id}
@ -1118,12 +1262,14 @@ const SignDocument = () => {
: :
<img className="w-[100%] h-full" src={saved.initial as string} /> <img className="w-[100%] h-full" src={saved.initial as string} />
} }
</div>} </div>
}
{/* IMAGE FIELD - END */} {/* IMAGE FIELD - END */}
{/* SELECT FIELD - START */} {/* SELECT FIELD - START */}
{item.type === "SELECT" && {
item.type === "SELECT" &&
<div <div
id={item.id} id={item.id}
tabIndex={1} tabIndex={1}
@ -1146,7 +1292,8 @@ const SignDocument = () => {
}) })
} }
</select> </select>
</div>} </div>
}
{/* SELECT FIELD - END */} {/* SELECT FIELD - END */}
@ -1154,7 +1301,8 @@ const SignDocument = () => {
{/* TEMPORAL FIELD - START */} {/* TEMPORAL FIELD - START */}
{item.type === "TEMPORAL" && {
item.type === "TEMPORAL" &&
<div <div
id={item.id} id={item.id}
tabIndex={1} tabIndex={1}
@ -1192,13 +1340,15 @@ const SignDocument = () => {
type={`${item.subType?.toLowerCase() === "date" ? "date" : (item.subType?.toLowerCase() === "time" ? "time" : "datetime-local")}`} type={`${item.subType?.toLowerCase() === "date" ? "date" : (item.subType?.toLowerCase() === "time" ? "time" : "datetime-local")}`}
/> />
</div>} </div>
}
{/* TEMPORAL FIELD - END */} {/* TEMPORAL FIELD - END */}
{/* Attachment Field - START */} {/* Attachment Field - START */}
{item.type.toLowerCase() === TagsTypes.ATTACHMENT && {
item.type.toLowerCase() === TagsTypes.ATTACHMENT &&
<div <div
tabIndex={1} tabIndex={1}
id={item.id} id={item.id}
@ -1219,13 +1369,15 @@ const SignDocument = () => {
</p> </p>
) )
} }
</div>} </div>
}
{/* Attachment Field - END */} {/* Attachment Field - END */}
{/* Focus Show Element */} {/* Focus Show Element */}
{(!transparentTags && !hideTags) && (focusElement && focusElement.documentId === item.documentId && focusElement.focusElementIndx === index) && {
(!transparentTags && !hideTags) && (focusElement && focusElement.documentId === item.documentId && focusElement.focusElementIndx === index) &&
<> <>
<div <div
className="absolute left-0 z-50 bg-blue-900 text-xs text-slate-100 px-2 py-[2px] rounded-sm whitespace-nowrap" className="absolute left-0 z-50 bg-blue-900 text-xs text-slate-100 px-2 py-[2px] rounded-sm whitespace-nowrap"
@ -1244,6 +1396,7 @@ const SignDocument = () => {
</> </>
} }
</div> </div>
) )
}) })
} }
@ -1260,7 +1413,7 @@ const SignDocument = () => {
{/* Side details of documents Pages and document Name - START */} {/* Side details of documents Pages and document Name - START */}
<p className='absolute top-[50%] translate-y-[-50%] rotate-[-90deg] text-xs left-[-60px] text-slate-600'> < p className='absolute top-[50%] translate-y-[-50%] rotate-[-90deg] text-xs left-[-60px] text-slate-600' >
page {indx + 1} of {doc.pages && doc.pages.length} page {indx + 1} of {doc.pages && doc.pages.length}
</p> </p>
{/* Side details of documents Pages and document Name - END */} {/* Side details of documents Pages and document Name - END */}
@ -1333,7 +1486,7 @@ const SignDocument = () => {
<InitialCon openInitial={openInitial} setOpenInitial={setOpenInitial} savedInitial={savedInitial} setSavedInitial={setSavedInitial} /> */} <InitialCon openInitial={openInitial} setOpenInitial={setOpenInitial} savedInitial={savedInitial} setSavedInitial={setSavedInitial} /> */}
{globalLoader.isLoading && <Loader />} {globalLoader.isLoading && <Loader />}
</div> </div >
) )
} }

View File

@ -363,19 +363,6 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
const key = `${docId}_${pageIndex}`; const key = `${docId}_${pageIndex}`;
// const IconComponent = typeToIconMap[field.type] || <FaQuestionCircle />; // const IconComponent = typeToIconMap[field.type] || <FaQuestionCircle />;
// Handling Initia Width and height of Some tags - START
if (dragElemData.label === TagsTypes.STAMP) {
dragElemData.width = 160
dragElemData.height = 160
} else if (dragElemData.label === TagsTypes.SIGNATURE) {
dragElemData.width = 200
dragElemData.height = 75
} else if (dragElemData.label === TagsTypes.INITIALS) {
dragElemData.width = 85
dragElemData.height = 75
}
// Handling Initia Width and height of Some tags - END
let prepData = { let prepData = {
properties: data.properties, properties: data.properties,
icon: typeToIconMap[field.label.toUpperCase()] || <FaQuestionCircle />, icon: typeToIconMap[field.label.toUpperCase()] || <FaQuestionCircle />,

View File

@ -4,7 +4,7 @@ import fields from '../../../helper/fieldsListData';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import typeToIconMap from '../../../helper/iconMap'; import typeToIconMap from '../../../helper/iconMap';
import { FaQuestionCircle } from 'react-icons/fa'; import { FaQuestionCircle } from 'react-icons/fa';
import { TagsProperties } from '../../../utlity/types'; import { TagsProperties, TagsTypes } from '../../../utlity/types';
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import axios from 'axios'; import axios from 'axios';
@ -13,12 +13,25 @@ const handlePointerDown = (event: React.DragEvent<HTMLDivElement>, label: string
let width = dragElemRect.width let width = dragElemRect.width
let height = dragElemRect.height let height = dragElemRect.height
if (label === "radio" || label === "checkbox") { if (label === TagsTypes.RADIO || label === TagsTypes.CHECKBOX) {
const innerIconConRect = event.currentTarget.children[0].getBoundingClientRect(); const innerIconConRect = event.currentTarget.children[0].getBoundingClientRect();
width = innerIconConRect.width + 10 width = innerIconConRect.width + 10
height = innerIconConRect.height + 10 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
}
// Handling Initia Width and height of Some tags - END
const offsetX = event.clientX - dragElemRect.left; const offsetX = event.clientX - dragElemRect.left;
const offsetY = event.clientY - dragElemRect.top; const offsetY = event.clientY - dragElemRect.top;
@ -46,12 +59,12 @@ interface FieldListProps {
} }
const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx, acntId = null }) => { const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx, acntId = null }) => {
const [tagsData, setTagsData] = useState<TagsProperties[]>([]); const [tagsData, setTagsData] = useState<TagsProperties[]>([]);
let { accountId } = useParams<{ accountId: string }>(); let { accountId } = useParams<{ accountId: string }>();
if(acntId) { if (acntId) {
accountId = acntId; accountId = acntId;
} }

View File

@ -26,7 +26,7 @@ import { FaSpinner } from "react-icons/fa";
import { GrCheckboxSelected } from "react-icons/gr"; import { GrCheckboxSelected } from "react-icons/gr";
import { Bounce, toast } from "react-toastify"; import { Bounce, toast } from "react-toastify";
import axios from 'axios'; import axios from 'axios';
import { SaveType } from '../client/SignDocument'; import { SaveType, SaveTypeEnum } from '../client/SignDocument';
import { CiSaveDown1 } from 'react-icons/ci'; import { CiSaveDown1 } from 'react-icons/ci';
import api from '../../config/api'; import api from '../../config/api';
@ -160,6 +160,20 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
}) })
if (res?.data) { if (res?.data) {
let preSavedSignatures = res?.data let preSavedSignatures = res?.data
if (res.data.length) {
const defaultVal = res.data.filter((obj, indx) => "default" in obj && obj.default);
const { initialsBlob, signatureBlob } = defaultVal[0];
if (initialsBlob && signatureBlob) {
setSaved({
saveType: SaveTypeEnum.DRAW,
save: true,
signature: signatureBlob,
initial: initialsBlob,
});
console.log("saved Called Line 174")
}
}
setPreSaveSignatures(preSavedSignatures) setPreSaveSignatures(preSavedSignatures)
} }
})() })()