self-sign
This commit is contained in:
commit
3b08c04463
|
|
@ -0,0 +1,63 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { MdKeyboardArrowDown } from 'react-icons/md';
|
||||||
|
|
||||||
|
interface DocumentPagesInterface {
|
||||||
|
selectedDocuments: DocumentType[];
|
||||||
|
setDropDownTogglePage: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
dropDownTogglePage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DocumentPages = ({ selectedDocuments, setDropDownTogglePage, dropDownTogglePage }: DocumentPagesInterface) => {
|
||||||
|
return (
|
||||||
|
<div className='col-span-2 bg-white h-full p-4 overflow-y-auto'>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
{selectedDocuments && selectedDocuments.length && selectedDocuments.map((document, indx) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={indx}
|
||||||
|
// tabIndex={1}
|
||||||
|
// onBlur={() => setDropDownTogglePage('')}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onClick={() => (`${(dropDownTogglePage === 'pageDropDown' + indx) ? '' : 'pageDropDown' + indx}`)}
|
||||||
|
className={`p-2 ${(dropDownTogglePage === 'pageDropDown' + indx) ? "bg-[var(--primary)]" : "bg-slate-200"} flex flex-col justify-center items-center gap-2 rounded`}>
|
||||||
|
{
|
||||||
|
document.images != undefined && <img
|
||||||
|
key={indx}
|
||||||
|
className='rounded-sm shadow'
|
||||||
|
src={document.images[0].src}
|
||||||
|
alt="" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`flex items-center justify-between w-full text-xs rounded-sm cursor-pointer ${(dropDownTogglePage === 'pageDropDown' + indx) ? "text-slate-100" : "text-slate-600"}`}>
|
||||||
|
<p className={`whitespace-nowrap overflow-hidden text-ellipsis max-w-[18ch]`}>{document.name}</p>
|
||||||
|
<MdKeyboardArrowDown className={`${(dropDownTogglePage === 'pageDropDown' + indx) ? 'rotate-180' : ''}`} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
dropDownTogglePage === 'pageDropDown' + indx &&
|
||||||
|
<div className='my-1 flex justify-center items-center gap-1 flex-wrap'>
|
||||||
|
{document.images != undefined && document.images.map((img, indx) => (
|
||||||
|
<a
|
||||||
|
href={"#" + document.documentId + indx}
|
||||||
|
className='max-w-max px-4 py-2 shadow cursor-pointer border-1 rounded-sm border-slate-200 hover:border-[var(--primary)] transition-all duration-300 bg-slate-300'
|
||||||
|
>
|
||||||
|
<p className='text-center text-xs text-slate-600'>{indx + 1}</p>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DocumentPages
|
||||||
|
|
@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
|
||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
import { RootState } from "../../store/store";
|
import { RootState } from "../../store/store";
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom"
|
||||||
import { DroppedItem } from "../../utlity/types";
|
import { DroppedItem, DroppedItemsObj } from "../../utlity/types";
|
||||||
|
|
||||||
import Loader from "../dashboard/Loader";
|
import Loader from "../dashboard/Loader";
|
||||||
import SignCon from "../signature/SignCon";
|
import SignCon from "../signature/SignCon";
|
||||||
|
|
@ -11,7 +11,7 @@ import { Bounce, toast } from "react-toastify";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
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 } from 'react-icons/fa'
|
import { FaRegImage, FaFileAlt, FaSignature, FaStamp, FaCheck, FaQuestionCircle } from 'react-icons/fa'
|
||||||
import { IoIosDocument } from 'react-icons/io'
|
import { IoIosDocument } 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";
|
||||||
|
|
@ -20,6 +20,10 @@ import dayjs from "dayjs";
|
||||||
import maskUtils from "../../utlity/maskUtils";
|
import maskUtils from "../../utlity/maskUtils";
|
||||||
import StampUpload from "../stamp/StampUpload";
|
import StampUpload from "../stamp/StampUpload";
|
||||||
import TermsModal from "./TermsModal";
|
import TermsModal from "./TermsModal";
|
||||||
|
import DocumentPages from "./DocumentPages";
|
||||||
|
import FieldList from "../process/processStepTwo/FieldList";
|
||||||
|
import typeToIconMap from "../../helper/iconMap";
|
||||||
|
import { droppedTagsDefaultField } from "../process/processStepTwo/DocumentContainer";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -139,9 +143,13 @@ const SignDocument = () => {
|
||||||
const [tagJson, setTagJson] = useState<DroppedItem[] | []>([]);
|
const [tagJson, setTagJson] = useState<DroppedItem[] | []>([]);
|
||||||
const [transaction, setTransaction] = useState<TransactionType | null>(null);
|
const [transaction, setTransaction] = useState<TransactionType | null>(null);
|
||||||
const [recSignStatus, setRecSignStatus] = useState<string | null>(null);
|
const [recSignStatus, setRecSignStatus] = useState<string | null>(null);
|
||||||
|
const [droppedItems, setDroppedItems] = useState([]);
|
||||||
|
const[signTagId , setSignTagId] = useState<number>(0)
|
||||||
|
|
||||||
const [stamp, setStamp] = useState<StampTypeObj>({ open: false, blob: "" });
|
const [stamp, setStamp] = useState<StampTypeObj>({ open: false, blob: "" });
|
||||||
|
|
||||||
|
console.log(recipient, "recipient Line 145")
|
||||||
|
|
||||||
// Handling Date Opacity
|
// Handling Date Opacity
|
||||||
const [dateValues, setDateValues] = useState<{ [key: string]: string }>({});
|
const [dateValues, setDateValues] = useState<{ [key: string]: string }>({});
|
||||||
const [isDateOpen, setIsDateOpen] = useState<string | null>(null);
|
const [isDateOpen, setIsDateOpen] = useState<string | null>(null);
|
||||||
|
|
@ -171,8 +179,12 @@ const SignDocument = () => {
|
||||||
initial: null,
|
initial: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const [signConfObj, setSignConfObj] = useState<SignConfTypeObj | {}>({});
|
const [signConfObj, setSignConfObj] = useState<SignConfTypeObj | {}>({});
|
||||||
|
|
||||||
|
console.log("signConfObj",signConfObj)
|
||||||
|
|
||||||
const zoom = (percentage: number, contentClass: string) => {
|
const zoom = (percentage: number, contentClass: string) => {
|
||||||
const content = document.querySelector(`.${contentClass}`);
|
const content = document.querySelector(`.${contentClass}`);
|
||||||
if (content) {
|
if (content) {
|
||||||
|
|
@ -195,11 +207,11 @@ const SignDocument = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!focusElement) {
|
if (!focusElement) {
|
||||||
if (tagJson && tagJson.length) {
|
if (droppedItems && droppedItems.length) {
|
||||||
setFocusElement({ ...tagJson[0], focusElementIndx: 0 });
|
setFocusElement({ ...droppedItems[0], focusElementIndx: 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [tagJson])
|
}, [droppedItems])
|
||||||
|
|
||||||
console.log(saved, "Line 162")
|
console.log(saved, "Line 162")
|
||||||
|
|
||||||
|
|
@ -232,7 +244,9 @@ const SignDocument = () => {
|
||||||
}
|
}
|
||||||
}, [saved])
|
}, [saved])
|
||||||
|
|
||||||
const handleSignClick = (index: number) => {
|
const handleSignClick = (index: number , id:number) => {
|
||||||
|
console.log("IDNumber" , id)
|
||||||
|
setSignTagId(id)
|
||||||
if (saved.save) {
|
if (saved.save) {
|
||||||
if (index in signConfObj) {
|
if (index in signConfObj) {
|
||||||
setOpenSign(true);
|
setOpenSign(true);
|
||||||
|
|
@ -256,8 +270,11 @@ const SignDocument = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setSignConfObj({ ...newObj })
|
setSignConfObj({ ...newObj })
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleStampClick = (index: number) => {
|
const handleStampClick = (index: number) => {
|
||||||
console.log("Stamp Clicked", index)
|
console.log("Stamp Clicked", index)
|
||||||
setStamp({
|
setStamp({
|
||||||
|
|
@ -282,9 +299,12 @@ const SignDocument = () => {
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.dir(res)
|
console.dir(res)
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
|
|
||||||
|
console.log(res, "Line 288")
|
||||||
|
|
||||||
setSelectedDocuments(res.data.documents)
|
setSelectedDocuments(res.data.documents)
|
||||||
setRecipient(res.data.recipient)
|
setRecipient(res.data.recipient)
|
||||||
setTagJson(res.data.tagJsons)
|
setDroppedItems(res.data.tagJsons)
|
||||||
setTransaction(res.data.transaction)
|
setTransaction(res.data.transaction)
|
||||||
setRecSignStatus(res.data.status)
|
setRecSignStatus(res.data.status)
|
||||||
|
|
||||||
|
|
@ -301,7 +321,7 @@ const SignDocument = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
console.log(tagJson, "Line 261")
|
console.log(droppedItems, "Line 261")
|
||||||
|
|
||||||
const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -309,7 +329,7 @@ const SignDocument = () => {
|
||||||
tags: []
|
tags: []
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tagJson) return;
|
if (!droppedItems) return;
|
||||||
|
|
||||||
// const form = e.currentTarget;
|
// const form = e.currentTarget;
|
||||||
// const formData = new FormData(form);
|
// const formData = new FormData(form);
|
||||||
|
|
@ -321,8 +341,8 @@ const SignDocument = () => {
|
||||||
// });
|
// });
|
||||||
|
|
||||||
let signInitialsCount = 0;
|
let signInitialsCount = 0;
|
||||||
for (let i = 0; i < tagJson.length; i++) {
|
for (let i = 0; i < droppedItems.length; i++) {
|
||||||
if (tagJson[i].type === "SIGNATURE" || tagJson[i].type === "INITIALS") {
|
if (droppedItems[i].type === "SIGNATURE" || droppedItems[i].type === "INITIALS") {
|
||||||
signInitialsCount += 1;
|
signInitialsCount += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +364,7 @@ const SignDocument = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const tag of tagJson) {
|
for (const tag of droppedItems) {
|
||||||
console.log(tag, "Tag Data")
|
console.log(tag, "Tag Data")
|
||||||
|
|
||||||
// if ((tag.type === "SIGNATURE" || tag.subType === "INITIALS") && !tag.value) {
|
// if ((tag.type === "SIGNATURE" || tag.subType === "INITIALS") && !tag.value) {
|
||||||
|
|
@ -492,11 +512,12 @@ const SignDocument = () => {
|
||||||
|
|
||||||
const fetchSignatureData = async (signatureId: string) => {
|
const fetchSignatureData = async (signatureId: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${import.meta.env.VITE_BASE_URI}/api/sign/signatures/${signatureId}`, {
|
const response = await axios.get(`${import.meta.env.VITE_BASE_URI}/api/sign/signatures/${signatureId}?recipientId=${recipientId}`, {
|
||||||
headers: { "ngrok-skip-browser-warning": "69420" }
|
headers: { "ngrok-skip-browser-warning": "69420" }
|
||||||
});
|
});
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
return response.data.signature;
|
console.log("line 516" , response.data)
|
||||||
|
return response.data;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching signature data:", error);
|
console.error("Error fetching signature data:", error);
|
||||||
|
|
@ -506,21 +527,21 @@ const SignDocument = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (tagJson) {
|
if (droppedItems) {
|
||||||
for (const tag of tagJson) {
|
for (const tag of droppedItems) {
|
||||||
if (tag.type === "SIGNATURE" && "value" in tag) {
|
if (tag.type === "SIGNATURE" && "value" in tag) {
|
||||||
const signatureData = await fetchSignatureData(tag.value);
|
const signatureData = await fetchSignatureData(tag.value);
|
||||||
console.log(signatureData);
|
console.log("Currnet Signature",signatureData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
}, [tagJson])
|
}, [droppedItems])
|
||||||
|
|
||||||
|
|
||||||
const handleTagUpdate = (updateIndx: number, updateValue: string) => {
|
const handleTagUpdate = (updateIndx: number, updateValue: string) => {
|
||||||
if (tagJson && tagJson.length) {
|
if (droppedItems && droppedItems.length) {
|
||||||
const updatedTag = tagJson.map((val, indx) => {
|
const updatedTag = droppedItems.map((val, indx) => {
|
||||||
if (indx === updateIndx) {
|
if (indx === updateIndx) {
|
||||||
return {
|
return {
|
||||||
...val,
|
...val,
|
||||||
|
|
@ -529,7 +550,7 @@ const SignDocument = () => {
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
})
|
})
|
||||||
setTagJson(updatedTag);
|
setDroppedItems(updatedTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setTagJson((prev) => {
|
// setTagJson((prev) => {
|
||||||
|
|
@ -541,6 +562,198 @@ const SignDocument = () => {
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// HANDLE DROP - START
|
||||||
|
const handleDrop = (event: React.DragEvent<HTMLDivElement>, docId: string, documentId: number, pageIndex: number) => {
|
||||||
|
console.log("// HANDLE DROP - START")
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const data = window.dragElemData;
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
const dragElemData = JSON.parse(data); // Get the dropped label
|
||||||
|
|
||||||
|
const field = { ...dragElemData }
|
||||||
|
if (!field.label) return;
|
||||||
|
|
||||||
|
// const field = fields.find((item) => item.label === dragElemData.label); // Find corresponding field
|
||||||
|
// if (!field) return; // If not found, exit
|
||||||
|
|
||||||
|
const dropZone = event.currentTarget.getBoundingClientRect();
|
||||||
|
const x = event.clientX - dropZone.left - dragElemData.offsetX;
|
||||||
|
const y = event.clientY - dropZone.top - dragElemData.offsetY;
|
||||||
|
|
||||||
|
const key = `${docId}_${pageIndex}`;
|
||||||
|
// const IconComponent = typeToIconMap[field.type] || <FaQuestionCircle />;
|
||||||
|
|
||||||
|
let prepData = {
|
||||||
|
properties: data.properties,
|
||||||
|
icon: typeToIconMap[field.label.toUpperCase()] || <FaQuestionCircle />,
|
||||||
|
type: dragElemData.label.toUpperCase(),
|
||||||
|
subType: (dragElemData.label in droppedTagsDefaultField) ? droppedTagsDefaultField[dragElemData.label] : '',
|
||||||
|
label: dragElemData.label,
|
||||||
|
dimensions: {
|
||||||
|
left: x,
|
||||||
|
top: y,
|
||||||
|
width: dragElemData.width,
|
||||||
|
height: dragElemData.height,
|
||||||
|
},
|
||||||
|
styles: dragElemData.label === "text" ? {
|
||||||
|
"font": "Great Vibes",
|
||||||
|
"italic": false,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"color": "black",
|
||||||
|
"textSize": 14.0
|
||||||
|
} : null,
|
||||||
|
documentId: docId,
|
||||||
|
pageIndex: pageIndex,
|
||||||
|
recipientId: dragElemData.recipientId,
|
||||||
|
recipientIndx: dragElemData.recipientIndx,
|
||||||
|
update: true,
|
||||||
|
isDeleted: false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("group" in dragElemData) {
|
||||||
|
prepData.group = dragElemData.group;
|
||||||
|
prepData.isGroupExist = false;
|
||||||
|
|
||||||
|
// if(uniqGroupIds.includes(dragElemData.group)) {
|
||||||
|
// prepData.isGroupExist = true;
|
||||||
|
// } else {
|
||||||
|
// prepData.isGroupExist = false;
|
||||||
|
// setUniqGroupIds([...uniqGroupIds, dragElemData.group]);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prepData.type === "temporal") {
|
||||||
|
prepData.currentTimeStamp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prepData.type.toLowerCase() === "number") {
|
||||||
|
prepData.decimalPlace = 0;
|
||||||
|
prepData.isCurrency = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const dataToSet: DroppedItemsObj = {
|
||||||
|
// ...droppedItems,
|
||||||
|
// [key]: [...(droppedItems[key] || []),
|
||||||
|
// prepData],
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const dataToSet: DroppedItemsObj = {
|
||||||
|
// ...droppedItems,
|
||||||
|
// [key]: [...(droppedItems[key] || []),
|
||||||
|
// {
|
||||||
|
// ...prepData,
|
||||||
|
// radioGroups: dragElemData.label === "radio" ?
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// ...prepData,
|
||||||
|
// dimensions: {
|
||||||
|
// ...prepData.dimensions, top: 8, left: 10
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// ...prepData, dimensions: {
|
||||||
|
// ...prepData.dimensions,
|
||||||
|
// top: 8,
|
||||||
|
// left: 10
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// :
|
||||||
|
// []
|
||||||
|
// }],
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (dragElemData.label === "radio") {
|
||||||
|
// setDroppedItems(dataToSet);
|
||||||
|
// } else {
|
||||||
|
// setDroppedItems(dataToSet);
|
||||||
|
// }
|
||||||
|
|
||||||
|
setDroppedItems((prev) => [...prev, prepData]);
|
||||||
|
// setDroppedItemsCounter((prev) => prev + 1);
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// const tagIndex = key in droppedItems ? droppedItems[key].length : 0;
|
||||||
|
// handleTagClick(key, tagIndex)
|
||||||
|
// }, 0)
|
||||||
|
};
|
||||||
|
// HANDLE DROP - END
|
||||||
|
|
||||||
|
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
event.preventDefault(); // Allows the drop event to work
|
||||||
|
};
|
||||||
|
|
||||||
|
// HANDLE TAG MOUSE DOWN - START
|
||||||
|
const handleTagMouseDown = (event: React.MouseEvent<HTMLDivElement>, key: string, index: number) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
let targetContainer = event?.currentTarget?.parentElement?.parentElement;
|
||||||
|
let targetElement = event?.currentTarget;
|
||||||
|
|
||||||
|
if (!targetContainer || !targetElement) return;
|
||||||
|
|
||||||
|
const containerRect = targetContainer.getBoundingClientRect();
|
||||||
|
const elementRect = targetElement.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Calculate the initial offset (where the mouse was clicked inside the element)
|
||||||
|
const offsetX = event.clientX - elementRect.left;
|
||||||
|
const offsetY = event.clientY - elementRect.top;
|
||||||
|
|
||||||
|
const conScrollWidth = targetContainer?.scrollWidth;
|
||||||
|
const conScrollHeight = targetContainer?.scrollHeight;
|
||||||
|
|
||||||
|
let isGroupAttr = event.currentTarget.hasAttribute("group");
|
||||||
|
let groupId = null;
|
||||||
|
if (isGroupAttr) {
|
||||||
|
groupId = event.currentTarget.getAttribute("group");
|
||||||
|
}
|
||||||
|
|
||||||
|
let groupElements: NodeListOf<HTMLElement> | null = null
|
||||||
|
if (isGroupAttr && groupId) {
|
||||||
|
groupElements = document.querySelectorAll(`div[group="${groupId}"]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
|
// Get new X and Y positions relative to the container
|
||||||
|
let left = event.clientX - containerRect.left - offsetX;
|
||||||
|
let top = event.clientY - containerRect.top - offsetY;
|
||||||
|
|
||||||
|
|
||||||
|
// **Restrict movement within container bounds**
|
||||||
|
left = Math.max(0, Math.min(left, conScrollWidth - elementRect.width));
|
||||||
|
top = Math.max(0, Math.min(top, conScrollHeight - elementRect.height));
|
||||||
|
|
||||||
|
console.log(left, top, "LEFTTOP")
|
||||||
|
|
||||||
|
if (groupElements != null && groupElements.length) handleGroupBorderPosition(groupElements, containerRect, offsetX, offsetY);
|
||||||
|
|
||||||
|
// Apply the movement to the element
|
||||||
|
setDroppedItems(
|
||||||
|
droppedItems.map((item, i) =>
|
||||||
|
i === index ? { ...item, dimensions: { ...item.dimensions, left, top }, update: true } : item
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
document.removeEventListener("pointermove", handleMouseMove);
|
||||||
|
document.removeEventListener("pointerup", handleMouseUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
document.addEventListener("pointermove", handleMouseMove);
|
||||||
|
document.addEventListener("pointerup", handleMouseUp);
|
||||||
|
};
|
||||||
|
// HANDLE TAG MOUSE DOWN - END
|
||||||
|
|
||||||
|
|
||||||
|
console.log(droppedItems, "DROPPED ITEMS LINE 680")
|
||||||
|
|
||||||
// const [showTerms, setShowTerms] = useState<boolean>(true);
|
// const [showTerms, setShowTerms] = useState<boolean>(true);
|
||||||
return (
|
return (
|
||||||
<div className={`w-full h-screen overflow-hidden relative ${(globalLoader.isLoading) ? 'pointer-events-none overflow-hidden' : ''}`}>
|
<div className={`w-full h-screen overflow-hidden relative ${(globalLoader.isLoading) ? 'pointer-events-none overflow-hidden' : ''}`}>
|
||||||
|
|
@ -642,9 +855,6 @@ const SignDocument = () => {
|
||||||
|
|
||||||
<p>{recipient && recipient.firstName} {recipient && recipient.lastName}</p>
|
<p>{recipient && recipient.firstName} {recipient && recipient.lastName}</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/* Right Side - ENDS */}
|
{/* Right Side - ENDS */}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -655,65 +865,23 @@ const SignDocument = () => {
|
||||||
|
|
||||||
{/* Left Side pages start */}
|
{/* Left Side pages start */}
|
||||||
{/* <div className="lg:col-span-2 bg-slate-100 h-full p-4 overflow-y-auto"></div> */}
|
{/* <div className="lg:col-span-2 bg-slate-100 h-full p-4 overflow-y-auto"></div> */}
|
||||||
|
|
||||||
<div className='col-span-2 bg-white h-full p-4 overflow-y-auto'>
|
<div className='col-span-2 bg-white h-full p-4 overflow-y-auto'>
|
||||||
|
{recipientId && <FieldList color={"#8f87f1"} recipientId={Number(recipientId)} recipientIndx={0} acntId={"1"} />}
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
{selectedDocuments && selectedDocuments.length && selectedDocuments.map((document, indx) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={indx}
|
|
||||||
// tabIndex={1}
|
|
||||||
// onBlur={() => setDropDownTogglePage('')}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
onClick={() => setDropDownTogglePage(`${(dropDownTogglePage === 'pageDropDown' + indx) ? '' : 'pageDropDown' + indx}`)}
|
|
||||||
className={`p-2 ${(dropDownTogglePage === 'pageDropDown' + indx) ? "bg-[var(--primary)]" : "bg-slate-200"} flex flex-col justify-center items-center gap-2 rounded`}>
|
|
||||||
{
|
|
||||||
document.images != undefined && <img
|
|
||||||
key={indx}
|
|
||||||
className='rounded-sm shadow'
|
|
||||||
src={document.images[0].src}
|
|
||||||
alt="" />
|
|
||||||
}
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`flex items-center justify-between w-full text-xs rounded-sm cursor-pointer ${(dropDownTogglePage === 'pageDropDown' + indx) ? "text-slate-100" : "text-slate-600"}`}>
|
|
||||||
<p className={`whitespace-nowrap overflow-hidden text-ellipsis max-w-[18ch]`}>{document.name}</p>
|
|
||||||
<MdKeyboardArrowDown className={`${(dropDownTogglePage === 'pageDropDown' + indx) ? 'rotate-180' : ''}`} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
dropDownTogglePage === 'pageDropDown' + indx &&
|
|
||||||
<div className='my-1 flex justify-center items-center gap-1 flex-wrap'>
|
|
||||||
{document.images != undefined && document.images.map((img, indx) => (
|
|
||||||
<a
|
|
||||||
href={"#" + document.documentId + indx}
|
|
||||||
className='max-w-max px-4 py-2 shadow cursor-pointer border-1 rounded-sm border-slate-200 hover:border-[var(--primary)] transition-all duration-300 bg-slate-300'
|
|
||||||
>
|
|
||||||
<p className='text-center text-xs text-slate-600'>{indx + 1}</p>
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{/* Pages - END */}
|
{/* Pages - END */}
|
||||||
|
|
||||||
{/* Main container */}
|
{/* Main container */}
|
||||||
<div
|
<div
|
||||||
id="doc-con"
|
id="doc-con"
|
||||||
className="zoom-con relative col-span-10 px-4 bg-slate-100 h-full w-full overflow-auto scroll-smooth"
|
className="zoom-con relative col-span-8 px-4 bg-slate-100 h-full w-full overflow-auto scroll-smooth"
|
||||||
>
|
>
|
||||||
|
|
||||||
{
|
{
|
||||||
selectedDocuments && selectedDocuments.length > 0 && selectedDocuments.map((doc) => {
|
selectedDocuments && selectedDocuments.length > 0 && selectedDocuments.map((doc) => {
|
||||||
console.log(tagJson, "tagJsontagJsontagJson")
|
console.log(droppedItems, "tagJsontagJsontagJson")
|
||||||
return (
|
return (
|
||||||
<div key={doc.documentId} className='flex flex-col'>
|
<div key={doc.documentId} className='flex flex-col'>
|
||||||
<div className='py-2 text-sm'>
|
<div className='py-2 text-sm'>
|
||||||
|
|
@ -722,16 +890,20 @@ const SignDocument = () => {
|
||||||
|
|
||||||
<div className='flex flex-col gap-3 max-w-max relative left-[50%] translate-x-[-50%]'>
|
<div className='flex flex-col gap-3 max-w-max relative left-[50%] translate-x-[-50%]'>
|
||||||
{
|
{
|
||||||
tagJson && tagJson.length > 0 && doc.images && doc.images.length > 0 && doc.images.map((page, indx) => {
|
doc.images && doc.images.length > 0 && doc.images.map((page, indx) => {
|
||||||
const key = `${doc.documentId}_${page.index}`;
|
const key = `${doc.documentId}_${page.index}`;
|
||||||
const currDocTags = tagJson.filter((val) => val.pageIndex === page.index)
|
console.log(droppedItems, "line 820")
|
||||||
console.log(currDocTags, tagJson, page, doc, "innnnnnnnnnnnn")
|
// const tagJsonData = [...droppedItems];
|
||||||
|
// console.log(tagJsonData, "Line 821")
|
||||||
|
|
||||||
|
const currDocTags = droppedItems.filter((val) => val.pageIndex === page.index)
|
||||||
|
console.log(currDocTags, droppedItems, page, doc, "innnnnnnnnnnnn")
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={indx}
|
key={indx}
|
||||||
id={doc.documentId + indx}
|
id={doc.documentId + indx}
|
||||||
// onDrop={(e) => handleDrop(e, doc.documentId, doc.documentId, page.index)}
|
onDrop={(e) => handleDrop(e, doc.documentId, doc.documentId, page.index)}
|
||||||
// onDragOver={handleDragOver}
|
onDragOver={(e) => handleDragOver(e)}
|
||||||
className='drop-page-in shadow-md relative'
|
className='drop-page-in shadow-md relative'
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
@ -739,13 +911,15 @@ const SignDocument = () => {
|
||||||
|
|
||||||
|
|
||||||
{currDocTags.map((item, index) => {
|
{currDocTags.map((item, index) => {
|
||||||
|
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 })}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
draggable="false"
|
// draggable="false"
|
||||||
|
onPointerDown={(e) => handleTagMouseDown(e, key, index)}
|
||||||
className="absolute rounded dropped-item text-sm"
|
className="absolute rounded dropped-item text-sm"
|
||||||
// onClick={() => handleTagClick(key, index)}
|
// onClick={() => handleTagClick(key, index)}
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -849,7 +1023,7 @@ const SignDocument = () => {
|
||||||
<div
|
<div
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
id={item.id}
|
id={item.id}
|
||||||
onClick={() => handleSignClick(index)}
|
onClick={() => handleSignClick(index , item.id)}
|
||||||
className={`flex justify-center items-center h-full w-full rounded cursor-pointer ${transparentTags || hideTags ? "pointer-events-none bg-transparent" : "bg-slate-200 shadow-sm border-slate-100 opacity-80"}`}
|
className={`flex justify-center items-center h-full w-full rounded cursor-pointer ${transparentTags || hideTags ? "pointer-events-none bg-transparent" : "bg-slate-200 shadow-sm border-slate-100 opacity-80"}`}
|
||||||
// style={{ height: item.dimensions.height + "px" }}
|
// style={{ height: item.dimensions.height + "px" }}
|
||||||
>
|
>
|
||||||
|
|
@ -865,7 +1039,9 @@ const SignDocument = () => {
|
||||||
width: `${item.dimensions.width}px`,
|
width: `${item.dimensions.width}px`,
|
||||||
height: `${item.dimensions.height}px`,
|
height: `${item.dimensions.height}px`,
|
||||||
}}
|
}}
|
||||||
src={saved.signature as string} />
|
// src={saved.signature as string} />
|
||||||
|
src={`data:image/png;base64,${saved.signature}`}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
</div>}
|
</div>}
|
||||||
{/* SIGNATURE FIELD - END */}
|
{/* SIGNATURE FIELD - END */}
|
||||||
|
|
@ -876,7 +1052,7 @@ const SignDocument = () => {
|
||||||
<div
|
<div
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
id={item.id}
|
id={item.id}
|
||||||
onClick={() => handleSignClick(index)}
|
onClick={() => handleSignClick(index , item.id)}
|
||||||
className={`flex justify-center items-center h-full w-full rounded cursor-pointer ${transparentTags || hideTags ? "pointer-events-none" : "bg-slate-200 shadow-sm border-slate-100 opacity-80"}`}
|
className={`flex justify-center items-center h-full w-full rounded cursor-pointer ${transparentTags || hideTags ? "pointer-events-none" : "bg-slate-200 shadow-sm border-slate-100 opacity-80"}`}
|
||||||
// style={{ height: item.dimensions.height + "px" }}
|
// style={{ height: item.dimensions.height + "px" }}
|
||||||
>
|
>
|
||||||
|
|
@ -889,7 +1065,9 @@ const SignDocument = () => {
|
||||||
height: `${item.dimensions.height}px`,
|
height: `${item.dimensions.height}px`,
|
||||||
}}
|
}}
|
||||||
className="w-[100%] h-full"
|
className="w-[100%] h-full"
|
||||||
src={saved.initial as string} />
|
// src={saved.initial as string}
|
||||||
|
src={`data:image/png;base64,${saved.initial}`}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
</div>}
|
</div>}
|
||||||
{/* INITIALS FIELD - END */}
|
{/* INITIALS FIELD - END */}
|
||||||
|
|
@ -1074,6 +1252,10 @@ const SignDocument = () => {
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<DocumentPages selectedDocuments={selectedDocuments} setDropDownTogglePage={setDropDownTogglePage} dropDownTogglePage={dropDownTogglePage} />
|
||||||
|
|
||||||
|
|
||||||
{/* Right Side - START */}
|
{/* Right Side - START */}
|
||||||
{/* <div className="col-span-2 bg-slate-100 h-full p-4 overflow-y-auto">
|
{/* <div className="col-span-2 bg-slate-100 h-full p-4 overflow-y-auto">
|
||||||
{
|
{
|
||||||
|
|
@ -1091,7 +1273,7 @@ const SignDocument = () => {
|
||||||
|
|
||||||
|
|
||||||
<div style={{ display: `${openSign ? 'block' : 'none'}` }}>
|
<div style={{ display: `${openSign ? 'block' : 'none'}` }}>
|
||||||
<SignCon recipientId={recipientId as string} setOpenSign={setOpenSign} saved={saved} setSaved={setSaved} />
|
<SignCon recipientId={recipientId as string} setOpenSign={setOpenSign} saved={saved} setSaved={setSaved} signTagId={signTagId}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: `${stamp.open ? 'block' : 'none'}` }}>
|
<div style={{ display: `${stamp.open ? 'block' : 'none'}` }}>
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import typeToIconMap from '../../../helper/iconMap';
|
||||||
import { IoAdd } from 'react-icons/io5';
|
import { IoAdd } from 'react-icons/io5';
|
||||||
import Loader from '../../dashboard/Loader';
|
import Loader from '../../dashboard/Loader';
|
||||||
import { TRANSACTION_TEMPLATE_TOGGLE } from "../../../store/slices/selectedRecipientsSlice";
|
import { TRANSACTION_TEMPLATE_TOGGLE } from "../../../store/slices/selectedRecipientsSlice";
|
||||||
|
import { handleGroupBorderPosition } from '../../../utlity/tagGroupConUtils';
|
||||||
|
|
||||||
export interface DroppedItemsObj {
|
export interface DroppedItemsObj {
|
||||||
[key: string]: DroppedItem[]
|
[key: string]: DroppedItem[]
|
||||||
|
|
@ -27,7 +28,7 @@ interface DroppedTagsDefaultFieldType {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const droppedTagsDefaultField: DroppedTagsDefaultFieldType = {
|
export const droppedTagsDefaultField: DroppedTagsDefaultFieldType = {
|
||||||
text: "paragraph",
|
text: "paragraph",
|
||||||
temporal: "date",
|
temporal: "date",
|
||||||
number: "integer",
|
number: "integer",
|
||||||
|
|
@ -64,6 +65,8 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
// 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)
|
||||||
|
|
||||||
|
// const [uniqGroupIds, setUniqGroupIds] = useState<string[]>([]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
|
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
|
||||||
|
|
@ -143,7 +146,7 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
// debugger
|
// debugger
|
||||||
|
|
||||||
for (const [recipientId, tags] of Object.entries(tagsData)) {
|
for (const [recipientId, tags] of Object.entries(tagsData)) {
|
||||||
console.log(recipientId, tags, "line 133")
|
// console.log(recipientId, tags, "line 133")
|
||||||
const updateTags = []
|
const updateTags = []
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
if ("update" in tag && tag.update) {
|
if ("update" in tag && tag.update) {
|
||||||
|
|
@ -202,7 +205,7 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
let mask = null
|
let mask = null
|
||||||
|
|
||||||
|
|
||||||
console.log(dropTag, "line 132")
|
// console.log(dropTag, "line 132")
|
||||||
|
|
||||||
// if (dropTag.subType?.toLowerCase() === "password") {
|
// if (dropTag.subType?.toLowerCase() === "password") {
|
||||||
// console.log(dropTag)
|
// console.log(dropTag)
|
||||||
|
|
@ -212,7 +215,7 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
console.log(dropTag, "line 204")
|
// console.log(dropTag, "line 204")
|
||||||
|
|
||||||
const isDeleted = "isDeleted" in dropTag ? dropTag.isDeleted : false
|
const isDeleted = "isDeleted" in dropTag ? dropTag.isDeleted : false
|
||||||
|
|
||||||
|
|
@ -289,6 +292,7 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { status: "SENT" })
|
const res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { status: "SENT" })
|
||||||
|
// const res = await api.put(`/api/accounts/${accountId}/transactions/${transactionId}`, { status: "SENT" })
|
||||||
console.log(res, "Check123")
|
console.log(res, "Check123")
|
||||||
})()
|
})()
|
||||||
}, [isSend])
|
}, [isSend])
|
||||||
|
|
@ -349,6 +353,18 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
isDeleted: false
|
isDeleted: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("group" in dragElemData) {
|
||||||
|
prepData.group = dragElemData.group;
|
||||||
|
prepData.isGroupExist = false;
|
||||||
|
|
||||||
|
// if(uniqGroupIds.includes(dragElemData.group)) {
|
||||||
|
// prepData.isGroupExist = true;
|
||||||
|
// } else {
|
||||||
|
// prepData.isGroupExist = false;
|
||||||
|
// setUniqGroupIds([...uniqGroupIds, dragElemData.group]);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
if (prepData.type === "temporal") {
|
if (prepData.type === "temporal") {
|
||||||
prepData.currentTimeStamp = true;
|
prepData.currentTimeStamp = true;
|
||||||
}
|
}
|
||||||
|
|
@ -361,36 +377,44 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
const dataToSet: DroppedItemsObj = {
|
const dataToSet: DroppedItemsObj = {
|
||||||
...droppedItems,
|
...droppedItems,
|
||||||
[key]: [...(droppedItems[key] || []),
|
[key]: [...(droppedItems[key] || []),
|
||||||
{
|
prepData],
|
||||||
...prepData,
|
|
||||||
radioGroups: dragElemData.label === "radio" ?
|
|
||||||
[
|
|
||||||
{
|
|
||||||
...prepData,
|
|
||||||
dimensions: {
|
|
||||||
...prepData.dimensions, top: 8, left: 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...prepData, dimensions: {
|
|
||||||
...prepData.dimensions,
|
|
||||||
top: 8,
|
|
||||||
left: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
:
|
|
||||||
[]
|
|
||||||
}],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dragElemData.label === "radio") {
|
// const dataToSet: DroppedItemsObj = {
|
||||||
setDroppedItems(dataToSet);
|
// ...droppedItems,
|
||||||
} else {
|
// [key]: [...(droppedItems[key] || []),
|
||||||
setDroppedItems(dataToSet);
|
// {
|
||||||
}
|
// ...prepData,
|
||||||
|
// radioGroups: dragElemData.label === "radio" ?
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// ...prepData,
|
||||||
|
// dimensions: {
|
||||||
|
// ...prepData.dimensions, top: 8, left: 10
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// ...prepData, dimensions: {
|
||||||
|
// ...prepData.dimensions,
|
||||||
|
// top: 8,
|
||||||
|
// left: 10
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// :
|
||||||
|
// []
|
||||||
|
// }],
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (dragElemData.label === "radio") {
|
||||||
|
// setDroppedItems(dataToSet);
|
||||||
|
// } else {
|
||||||
|
// setDroppedItems(dataToSet);
|
||||||
|
// }
|
||||||
|
|
||||||
|
setDroppedItems(dataToSet);
|
||||||
setDroppedItemsCounter((prev) => prev + 1);
|
setDroppedItemsCounter((prev) => prev + 1);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const tagIndex = key in droppedItems ? droppedItems[key].length : 0;
|
const tagIndex = key in droppedItems ? droppedItems[key].length : 0;
|
||||||
handleTagClick(key, tagIndex)
|
handleTagClick(key, tagIndex)
|
||||||
|
|
@ -403,6 +427,9 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
let targetContainer = event?.currentTarget?.parentElement?.parentElement;
|
let targetContainer = event?.currentTarget?.parentElement?.parentElement;
|
||||||
|
|
||||||
|
console.log(targetContainer, "targetContainer line 421")
|
||||||
|
|
||||||
let targetElement = event?.currentTarget?.parentElement;
|
let targetElement = event?.currentTarget?.parentElement;
|
||||||
|
|
||||||
if (!targetContainer || !targetElement) return;
|
if (!targetContainer || !targetElement) return;
|
||||||
|
|
@ -417,16 +444,29 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
const conScrollWidth = targetContainer?.scrollWidth;
|
const conScrollWidth = targetContainer?.scrollWidth;
|
||||||
const conScrollHeight = targetContainer?.scrollHeight;
|
const conScrollHeight = targetContainer?.scrollHeight;
|
||||||
|
|
||||||
|
let isGroupAttr = event.currentTarget.hasAttribute("group");
|
||||||
|
let groupId = null;
|
||||||
|
if (isGroupAttr) {
|
||||||
|
groupId = event.currentTarget.getAttribute("group");
|
||||||
|
}
|
||||||
|
|
||||||
|
let groupElements: NodeListOf<HTMLElement> | null = null
|
||||||
|
if (isGroupAttr && groupId) {
|
||||||
|
groupElements = document.querySelectorAll(`div[group="${groupId}"]`);
|
||||||
|
}
|
||||||
|
|
||||||
const handleMouseMove = (event: MouseEvent) => {
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
// Get new X and Y positions relative to the container
|
// Get new X and Y positions relative to the container
|
||||||
let left = event.clientX - containerRect.left - offsetX;
|
let left = event.clientX - containerRect.left - offsetX;
|
||||||
let top = event.clientY - containerRect.top - offsetY;
|
let top = event.clientY - containerRect.top - offsetY;
|
||||||
|
|
||||||
|
|
||||||
// **Restrict movement within container bounds**
|
// **Restrict movement within container bounds**
|
||||||
left = Math.max(0, Math.min(left, conScrollWidth - elementRect.width));
|
left = Math.max(0, Math.min(left, conScrollWidth - elementRect.width));
|
||||||
top = Math.max(0, Math.min(top, conScrollHeight - elementRect.height));
|
top = Math.max(0, Math.min(top, conScrollHeight - elementRect.height));
|
||||||
|
|
||||||
|
if (groupElements != null && groupElements.length) handleGroupBorderPosition(groupElements, containerRect, offsetX, offsetY);
|
||||||
|
|
||||||
// Apply the movement to the element
|
// Apply the movement to the element
|
||||||
setDroppedItems({
|
setDroppedItems({
|
||||||
...droppedItems,
|
...droppedItems,
|
||||||
|
|
@ -534,334 +574,365 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleAddRadioClick = (key: string) => {
|
const handleAddRadioClick = (key: string) => {
|
||||||
console.log("Handle Radio Clicled", key)
|
console.log("Handle Radio Clicled", key)
|
||||||
console.log(droppedItems, "line 525")
|
console.log(droppedItems, "line 525")
|
||||||
|
// const handleAddRadioClick = (key: string) => {
|
||||||
|
// console.log("Handle Radio Clicled", key)
|
||||||
|
// console.log(droppedItems, "line 525")
|
||||||
|
// }
|
||||||
|
|
||||||
|
const handleAddGroupItemClicked = (key: string, item) => {
|
||||||
|
|
||||||
|
|
||||||
|
const groupId = item.group;
|
||||||
|
|
||||||
|
item = { ...item, dimensions: { ...item.dimensions, top: item.dimensions.top + item.dimensions.height + 20 } }
|
||||||
|
|
||||||
|
// dimensions: { ...item.dimensions, left: newLeft, top: newTop }
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
handleIGroupBorderPosition(item.group)
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
setDroppedItems({
|
||||||
|
...droppedItems,
|
||||||
|
[key]: [...droppedItems[key], { ...item, isGroupExist: true }],
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const handleAddRadio = (e: React.MouseEvent<HTMLElement>, key: string, index: number) => {
|
// const handleAddRadio = (e: React.MouseEvent<HTMLElement>, key: string, index: number) => {
|
||||||
// // const dataToSet: DroppedItemsObj = {
|
// // const dataToSet: DroppedItemsObj = {
|
||||||
// // ...droppedItems,
|
// // ...droppedItems,
|
||||||
// // [key]: [...(droppedItems[key] || []),
|
// // [key]: [...(droppedItems[key] || []),
|
||||||
// // {
|
// // {
|
||||||
// // ...prepData,
|
// // ...prepData,
|
||||||
// // radioGroups: dragElemData.label === "radio" ? [{ ...prepData }] : []
|
// // radioGroups: dragElemData.label === "radio" ? [{ ...prepData }] : []
|
||||||
// // }],
|
// // }],
|
||||||
// // }
|
// // }
|
||||||
|
|
||||||
// // const lastRadioElemRect = e.currentTarget?.parentElement.previousSibling.getBoundingClientRect();
|
// // const lastRadioElemRect = e.currentTarget?.parentElement.previousSibling.getBoundingClientRect();
|
||||||
// // console.log(lastRadioElemRect, "lastRadioElemRect")
|
// // console.log(lastRadioElemRect, "lastRadioElemRect")
|
||||||
|
|
||||||
// const setNewData = droppedItems;
|
// const setNewData = droppedItems;
|
||||||
|
|
||||||
// if (Array.isArray(setNewData[key][index].radioGroups) && setNewData[key][index].radioGroups?.length > 0) {
|
// if (Array.isArray(setNewData[key][index].radioGroups) && setNewData[key][index].radioGroups?.length > 0) {
|
||||||
// setNewData[key][index].radioGroups?.push(setNewData[key][index].radioGroups[0])
|
// setNewData[key][index].radioGroups?.push(setNewData[key][index].radioGroups[0])
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// setDroppedItems(setNewData);
|
// setDroppedItems(setNewData);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// const handleRadioTagMouseDown = (event: React.MouseEvent<HTMLDivElement>, key: string, index: number, radioIndex: number) => {
|
// const handleRadioTagMouseDown = (event: React.MouseEvent<HTMLDivElement>, key: string, index: number, radioIndex: number) => {
|
||||||
|
|
||||||
// event.preventDefault();
|
// event.preventDefault();
|
||||||
|
|
||||||
// let targetContainer = event?.currentTarget?.parentElement;
|
// let targetContainer = event?.currentTarget?.parentElement;
|
||||||
// let targetElement = event?.currentTarget;
|
// let targetElement = event?.currentTarget;
|
||||||
|
|
||||||
// if (!targetContainer || !targetElement) return;
|
// if (!targetContainer || !targetElement) return;
|
||||||
|
|
||||||
// const containerRect = targetContainer.getBoundingClientRect();
|
// const containerRect = targetContainer.getBoundingClientRect();
|
||||||
// const elementRect = targetElement.getBoundingClientRect();
|
// const elementRect = targetElement.getBoundingClientRect();
|
||||||
|
|
||||||
// // Calculate the initial offset (where the mouse was clicked inside the element)
|
// // Calculate the initial offset (where the mouse was clicked inside the element)
|
||||||
// const offsetX = event.clientX - elementRect.left;
|
// const offsetX = event.clientX - elementRect.left;
|
||||||
// const offsetY = event.clientY - elementRect.top;
|
// const offsetY = event.clientY - elementRect.top;
|
||||||
|
|
||||||
// const handleMouseMove = (event: PointerEvent) => {
|
// const handleMouseMove = (event: PointerEvent) => {
|
||||||
// // Get new X and Y positions relative to the container
|
// // Get new X and Y positions relative to the container
|
||||||
// // let x = offsetX;
|
// // let x = offsetX;
|
||||||
// // let y = offsetY;
|
// // let y = offsetY;
|
||||||
|
|
||||||
// let x = event.clientX - elementRect.left;
|
// let x = event.clientX - elementRect.left;
|
||||||
// let y = event.clientY - elementRect.top;
|
// let y = event.clientY - elementRect.top;
|
||||||
|
|
||||||
// const newData = droppedItems;
|
// const newData = droppedItems;
|
||||||
|
|
||||||
// if (newData[key][index].radioGroups && newData[key][index].radioGroups.length > 0) {
|
// if (newData[key][index].radioGroups && newData[key][index].radioGroups.length > 0) {
|
||||||
// newData[key][index].radioGroups[radioIndex].dimensions.left = x;
|
// newData[key][index].radioGroups[radioIndex].dimensions.left = x;
|
||||||
// newData[key][index].radioGroups[radioIndex].dimensions.top = y;
|
// newData[key][index].radioGroups[radioIndex].dimensions.top = y;
|
||||||
|
|
||||||
// let topMin = Number.POSITIVE_INFINITY;
|
// let topMin = Number.POSITIVE_INFINITY;
|
||||||
// let topMax = Number.NEGATIVE_INFINITY;
|
// let topMax = Number.NEGATIVE_INFINITY;
|
||||||
// let leftMin = Number.POSITIVE_INFINITY;
|
// let leftMin = Number.POSITIVE_INFINITY;
|
||||||
// let leftMax = Number.NEGATIVE_INFINITY;
|
// let leftMax = Number.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
// for (const radio of newData[key][index].radioGroups) {
|
// for (const radio of newData[key][index].radioGroups) {
|
||||||
// if (radio.dimensions.left < leftMin) {
|
// if (radio.dimensions.left < leftMin) {
|
||||||
// leftMin = radio.dimensions.left;
|
// leftMin = radio.dimensions.left;
|
||||||
// }
|
// }
|
||||||
// if (radio.dimensions.left > leftMax) {
|
// if (radio.dimensions.left > leftMax) {
|
||||||
// leftMax = radio.dimensions.left;
|
// leftMax = radio.dimensions.left;
|
||||||
// }
|
// }
|
||||||
// if (radio.dimensions.top < topMin) {
|
// if (radio.dimensions.top < topMin) {
|
||||||
// topMin = radio.dimensions.top;
|
// topMin = radio.dimensions.top;
|
||||||
// }
|
// }
|
||||||
// if (radio.dimensions.top > topMax) {
|
// if (radio.dimensions.top > topMax) {
|
||||||
// topMax = radio.dimensions.top;
|
// topMax = radio.dimensions.top;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// newData[key][index].radioPosition = {
|
// newData[key][index].radioPosition = {
|
||||||
// topMin: topMin,
|
// topMin: topMin,
|
||||||
// topMax: topMax,
|
// topMax: topMax,
|
||||||
// leftMin: leftMin,
|
// leftMin: leftMin,
|
||||||
// leftMax: leftMax,
|
// leftMax: leftMax,
|
||||||
// width: leftMax - leftMin,
|
// width: leftMax - leftMin,
|
||||||
// height: topMax - topMin
|
// height: topMax - topMin
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// newData[key][index].dimensions.left = x;
|
// newData[key][index].dimensions.left = x;
|
||||||
// newData[key][index].dimensions.top = y;
|
// newData[key][index].dimensions.top = y;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// setDroppedItems({ ...newData });
|
// setDroppedItems({ ...newData });
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// const handleMouseUp = () => {
|
// const handleMouseUp = () => {
|
||||||
// document.removeEventListener("pointermove", handleMouseMove);
|
// document.removeEventListener("pointermove", handleMouseMove);
|
||||||
// document.removeEventListener("pointerup", handleMouseUp);
|
// document.removeEventListener("pointerup", handleMouseUp);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// // Add event listeners
|
// // Add event listeners
|
||||||
// document.addEventListener("pointermove", handleMouseMove);
|
// document.addEventListener("pointermove", handleMouseMove);
|
||||||
// document.addEventListener("pointerup", handleMouseUp);
|
// document.addEventListener("pointerup", handleMouseUp);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
// NEW DIRECTIONAL MOVEMENT HANDLER - START
|
// NEW DIRECTIONAL MOVEMENT HANDLER - START
|
||||||
const handleDirectionalMove = (direction: 'up' | 'down' | 'left' | 'right', stepSize: number = 5) => {
|
const handleDirectionalMove = (direction: 'up' | 'down' | 'left' | 'right', stepSize: number = 5) => {
|
||||||
if (!selectedTag) return;
|
if (!selectedTag) return;
|
||||||
|
|
||||||
const { key, index } = selectedTag;
|
const { key, index } = selectedTag;
|
||||||
const currentItem = droppedItems[key]?.[index];
|
const currentItem = droppedItems[key]?.[index];
|
||||||
|
|
||||||
if (!currentItem) return;
|
if (!currentItem) return;
|
||||||
|
|
||||||
let newLeft = currentItem.dimensions.left;
|
let newLeft = currentItem.dimensions.left;
|
||||||
let newTop = currentItem.dimensions.top;
|
let newTop = currentItem.dimensions.top;
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 'up':
|
case 'up':
|
||||||
newTop = Math.max(0, newTop - stepSize);
|
newTop = Math.max(0, newTop - stepSize);
|
||||||
break;
|
break;
|
||||||
case 'down':
|
case 'down':
|
||||||
newTop = newTop + stepSize;
|
newTop = newTop + stepSize;
|
||||||
break;
|
break;
|
||||||
case 'left':
|
case 'left':
|
||||||
newLeft = Math.max(0, newLeft - stepSize);
|
newLeft = Math.max(0, newLeft - stepSize);
|
||||||
break;
|
break;
|
||||||
case 'right':
|
case 'right':
|
||||||
newLeft = newLeft + stepSize;
|
newLeft = newLeft + stepSize;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDroppedItems({
|
||||||
|
...droppedItems,
|
||||||
|
[key]: Array.isArray(droppedItems[key])
|
||||||
|
? droppedItems[key].map((item, i) =>
|
||||||
|
i === index
|
||||||
|
? { ...item, dimensions: { ...item.dimensions, left: newLeft, top: newTop }, update: true }
|
||||||
|
: item
|
||||||
|
)
|
||||||
|
: [],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a wrapper that matches DirectionalControls' expected signature
|
||||||
|
const directionalControlsHandler = (direction: 'up' | 'down' | 'left' | 'right') => {
|
||||||
|
handleDirectionalMove(direction, 5); // Use default stepSize of 5
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function handleIGroupBorderPosition(groupId: string) {
|
||||||
|
|
||||||
|
const groupElements: NodeListOf<HTMLElement> = document.querySelectorAll(`div[group="${groupId}"]`);
|
||||||
|
|
||||||
|
let targetContainer = groupElements[0].parentElement?.parentElement;
|
||||||
|
console.log(targetContainer, "targetContainer line 421")
|
||||||
|
let targetElement = groupElements[0].parentElement;
|
||||||
|
|
||||||
|
if (!targetContainer || !targetElement) return;
|
||||||
|
const containerRect = targetContainer.getBoundingClientRect();
|
||||||
|
|
||||||
|
handleGroupBorderPosition(groupElements, containerRect, 40, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
setDroppedItems({
|
|
||||||
...droppedItems,
|
|
||||||
[key]: Array.isArray(droppedItems[key])
|
|
||||||
? droppedItems[key].map((item, i) =>
|
|
||||||
i === index
|
|
||||||
? { ...item, dimensions: { ...item.dimensions, left: newLeft, top: newTop }, update: true }
|
|
||||||
: item
|
|
||||||
)
|
|
||||||
: [],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a wrapper that matches DirectionalControls' expected signature
|
return (
|
||||||
const directionalControlsHandler = (direction: 'up' | 'down' | 'left' | 'right') => {
|
<>
|
||||||
handleDirectionalMove(direction, 5); // Use default stepSize of 5
|
{/* Center Doc Container - START */}
|
||||||
};
|
<div id="doc-con" className='zoom-con col-span-8 bg-slate-100 h-full w-full overflow-auto scroll-smooth'>
|
||||||
|
|
||||||
|
{
|
||||||
|
selectedDocuments.length > 0 ? selectedDocuments.map((doc, indxDoc) => {
|
||||||
|
return (
|
||||||
|
<div key={indxDoc} className='flex flex-col'>
|
||||||
|
<div className='py-2 text-sm'>
|
||||||
|
<p className='text-center'>{doc.name}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex flex-col gap-3 max-w-max relative left-[50%] translate-x-[-50%]'>
|
||||||
|
{
|
||||||
|
doc.images && doc.images.length > 0 && doc.images.map((page, indx) => {
|
||||||
|
const key = `${doc.id}_${page.index}`;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={indx}
|
||||||
|
|
||||||
|
id={`${doc.id}${indx}`}
|
||||||
|
onDrop={(e) => handleDrop(e, doc.id, indxDoc, page.index)}
|
||||||
|
onDragOver={handleDragOver}
|
||||||
|
className='drop-page-in shadow-md relative'
|
||||||
|
>
|
||||||
|
|
||||||
|
{/* DROPPED ITEMS - Render only the dropped items for this specific docId and page - STARTS */}
|
||||||
|
{droppedItems[key]?.map((item, index) => {
|
||||||
|
if (item.isDeleted) return;
|
||||||
|
|
||||||
|
const type = item.type.toUpperCase();
|
||||||
|
const IconComponent = typeToIconMap[type] || <FaQuestionCircle />;
|
||||||
|
const selectedRecipient = selectedRecipients.filter((obj, indx) => obj.id === item.recipientId);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
draggable="false"
|
||||||
|
className="absolute rounded dropped-item"
|
||||||
|
onClick={() => handleTagClick(key, index)}
|
||||||
|
style={{
|
||||||
|
left: `${item.dimensions.left}px`,
|
||||||
|
top: `${item.dimensions.top}px`,
|
||||||
|
width: item.type === "radio" ? `${item.dimensions.width + 20}px` : `${item.dimensions.width}px`,
|
||||||
|
height: item.type === "radio" ? `max-content` : `${item.dimensions.height}px`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
|
||||||
return (
|
{/* If Selected Tag Recipient Info- START */}
|
||||||
<>
|
{selectedTag?.key && selectedTag.key === key && selectedTag.index === index &&
|
||||||
{/* Center Doc Container - START */}
|
<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 id="doc-con" className='zoom-con col-span-8 bg-slate-100 h-full w-full overflow-auto scroll-smooth'>
|
<div className='flex justify-center items-center gap-1 bg-white px-2 shadow'>
|
||||||
|
<p className='w-2.5 h-2.5 rounded'
|
||||||
{
|
|
||||||
selectedDocuments.length > 0 ? selectedDocuments.map((doc, indxDoc) => {
|
|
||||||
return (
|
|
||||||
<div key={indxDoc} className='flex flex-col'>
|
|
||||||
<div className='py-2 text-sm'>
|
|
||||||
<p className='text-center'>{doc.name}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='flex flex-col gap-3 max-w-max relative left-[50%] translate-x-[-50%]'>
|
|
||||||
{
|
|
||||||
doc.images && doc.images.length > 0 && doc.images.map((page, indx) => {
|
|
||||||
const key = `${doc.id}_${page.index}`;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={indx}
|
|
||||||
|
|
||||||
id={`${doc.id}${indx}`}
|
|
||||||
onDrop={(e) => handleDrop(e, doc.id, indxDoc, page.index)}
|
|
||||||
onDragOver={handleDragOver}
|
|
||||||
className='drop-page-in shadow-md relative'
|
|
||||||
>
|
|
||||||
|
|
||||||
{/* DROPPED ITEMS - Render only the dropped items for this specific docId and page - STARTS */}
|
|
||||||
{droppedItems[key]?.map((item, index) => {
|
|
||||||
if (item.isDeleted) return;
|
|
||||||
const type = item.type.toUpperCase();
|
|
||||||
const IconComponent = typeToIconMap[type] || <FaQuestionCircle />;
|
|
||||||
const selectedRecipient = selectedRecipients.filter((obj, indx) => obj.id === item.recipientId);
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
draggable="false"
|
|
||||||
className="absolute rounded dropped-item"
|
|
||||||
onClick={() => handleTagClick(key, index)}
|
|
||||||
style={{
|
|
||||||
left: `${item.dimensions.left}px`,
|
|
||||||
top: `${item.dimensions.top}px`,
|
|
||||||
width: item.type === "radio" ? `${item.dimensions.width + 20}px` : `${item.dimensions.width}px`,
|
|
||||||
height: item.type === "radio" ? `max-content` : `${item.dimensions.height}px`
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
|
|
||||||
{/* If Selected Tag Recipient Info- START */}
|
|
||||||
{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: selectedRecipient[0]?.color }}
|
|
||||||
></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>}
|
|
||||||
{/* If Selected Tag Recipient Info- END */}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Expand Circle - STARTS */}
|
|
||||||
{item.type !== "radio" && <div
|
|
||||||
onPointerDown={(e) => handleExpandTag(e, key, index)}
|
|
||||||
className='w-2.5 h-2.5 absolute bg-red-400 rounded-full bottom-[-8px] right-[-8px] cursor-nw-resize hover:bg-blue-400'>
|
|
||||||
</div>}
|
|
||||||
{/* Expand Circle - ENDS */}
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
item.type !== "radio" ?
|
|
||||||
<div
|
|
||||||
onPointerDown={(e) => handleTagMouseDown(e, key, index)}
|
|
||||||
// style={{ width: `${item.width}px !important` }}
|
|
||||||
className='p-2 rounded-sm h-full shadow opacity-40 cursor-grab w-full'
|
|
||||||
style={{ background: selectedRecipient[0]?.color }}
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
className={`flex justify-center items-center w-full text-xl text-white h-full`}
|
|
||||||
// style={{ color: selectedRecipients[item.recipientIndx]?.color }}
|
|
||||||
>
|
|
||||||
{IconComponent}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
{/* Radio - Container - START */}
|
|
||||||
<div>
|
|
||||||
|
|
||||||
{/* Radio- Item - START */}
|
|
||||||
<div
|
|
||||||
onPointerDown={(e) => handleTagMouseDown(e, key, index)}
|
|
||||||
// style={{ width: `${item.width}px !important` }}
|
|
||||||
className='p-2 rounded-sm h-full shadow opacity-40 cursor-grab w-full'
|
|
||||||
style={{ background: selectedRecipient[0]?.color }}
|
style={{ background: selectedRecipient[0]?.color }}
|
||||||
>
|
></p>
|
||||||
<p
|
<p
|
||||||
className={`flex justify-center items-center w-full text-xl text-white h-full`}
|
className=''>{IconComponent}
|
||||||
// style={{ color: selectedRecipients[item.recipientIndx]?.color }}
|
</p>
|
||||||
>
|
<p className='capitalize text-ellipsis whitespace-nowrap'>{item.label}</p>
|
||||||
{IconComponent}
|
<IoMdClose onClick={(e) => {
|
||||||
</p>
|
e.stopPropagation();
|
||||||
</div>
|
handleRemoveTag(key, index)
|
||||||
{/* Radio- Item - END */}
|
}} className='cursor-pointer' />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/* Radio - Container - END */}
|
</div>}
|
||||||
|
{/* If Selected Tag Recipient Info- END */}
|
||||||
|
|
||||||
|
|
||||||
<IoAdd onClick={() => handleAddRadioClick(key)} className='ml-[50%] translate-x-[-50%] cursor-pointer' />
|
|
||||||
|
|
||||||
|
{/* Expand Circle - STARTS */}
|
||||||
|
{item.type !== "radio" && <div
|
||||||
|
onPointerDown={(e) => handleExpandTag(e, key, index)}
|
||||||
|
className='w-2.5 h-2.5 absolute bg-red-400 rounded-full bottom-[-8px] right-[-8px] cursor-nw-resize hover:bg-blue-400'>
|
||||||
|
</div>}
|
||||||
|
{/* Expand Circle - ENDS */}
|
||||||
|
|
||||||
|
{/* Tag - START */}
|
||||||
|
{
|
||||||
|
<div
|
||||||
|
{...("group" in item && item.group ? { "group": item.group } : {})}
|
||||||
|
onPointerDown={(e) => handleTagMouseDown(e, key, index)}
|
||||||
|
className='p-2 rounded-sm h-full shadow opacity-40 cursor-grab w-full'
|
||||||
|
style={{ background: selectedRecipient[0]?.color }}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
className={`flex justify-center items-center w-full text-xl text-white h-full`}
|
||||||
|
// style={{ color: selectedRecipients[item.recipientIndx]?.color }}
|
||||||
|
>
|
||||||
|
{IconComponent}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
{/* Tag - END */}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
"group" in item && item.group && "isGroupExist" in item && !item.isGroupExist &&
|
||||||
|
<>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="group-border" border-group={item.group} border-pos="top"></div>
|
||||||
|
<div className="group-border" border-group={item.group} border-pos="right"></div>
|
||||||
|
<div className="group-border bottom-border" border-group={item.group} border-pos="bottom">
|
||||||
|
<div onClick={() => handleAddGroupItemClicked(key, item)}><IoAdd /></div>
|
||||||
|
</div>
|
||||||
|
<div className="group-border" border-group={item.group} border-pos="left"></div>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
}
|
}
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
)}
|
</>
|
||||||
{/* Render only the dropped items for this specific docId and page - ENDS */}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
<img
|
)}
|
||||||
style={{ "minWidth": page.width, "minHeight": page.height, "maxWidth": page.width, "maxHeight": page.height }}
|
{/* Render only the dropped items for this specific docId and page - ENDS */}
|
||||||
draggable="false"
|
|
||||||
width={page.width}
|
<img
|
||||||
height={page.height}
|
style={{ "minWidth": page.width, "minHeight": page.height, "maxWidth": page.width, "maxHeight": page.height }}
|
||||||
src={page.src}
|
draggable="false"
|
||||||
loading='lazy'
|
width={page.width}
|
||||||
/>
|
height={page.height}
|
||||||
|
src={page.src}
|
||||||
|
loading='lazy'
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* 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.images && doc.images.length}
|
page {indx + 1} of {doc.images && doc.images.length}
|
||||||
</p>
|
</p>
|
||||||
{/* <p className='absolute top-[50%] translate-y-[-50%] rotate-[-90deg] text-xs right-[-140px] text-slate-600'>
|
{/* <p className='absolute top-[50%] translate-y-[-50%] rotate-[-90deg] text-xs right-[-140px] text-slate-600'>
|
||||||
Document {indxDoc + 1} {doc.name}
|
Document {indxDoc + 1} {doc.name}
|
||||||
</p> */}
|
</p> */}
|
||||||
{/* Side details of documents Pages and document Name - END */}
|
{/* Side details of documents Pages and document Name - END */}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
}) : <Loader />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div >
|
||||||
)
|
|
||||||
}) : <Loader />
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{selectedTag && <RightSideBar selectedTag={droppedItems[selectedTag.key][selectedTag.index]} setDroppedItems={setDroppedItems} selTagKey={selectedTag.key} selTagIndx={selectedTag.index} DirectionalControlsProps={{
|
||||||
|
onMove: directionalControlsHandler,
|
||||||
|
disabled: false,
|
||||||
|
stepSize: 5,
|
||||||
|
className: ''
|
||||||
|
}} />}
|
||||||
|
{/* Center Doc Container - END */}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
export default DocumentContainer;
|
||||||
|
|
||||||
{selectedTag && <RightSideBar selectedTag={droppedItems[selectedTag.key][selectedTag.index]} setDroppedItems={setDroppedItems} selTagKey={selectedTag.key} selTagIndx={selectedTag.index} DirectionalControlsProps={{
|
|
||||||
onMove: directionalControlsHandler,
|
|
||||||
disabled: false,
|
|
||||||
stepSize: 5,
|
|
||||||
className: ''
|
|
||||||
}} />}
|
|
||||||
{/* Center Doc Container - END */}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DocumentContainer;
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import fields from '../../../helper/fieldsListData';
|
import fields from '../../../helper/fieldsListData';
|
||||||
import api from '../../../config/api';
|
// import api from '../../../config/api';
|
||||||
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 } from '../../../utlity/types';
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const handlePointerDown = (event: React.DragEvent<HTMLDivElement>, label: string, recipientId: number, recipientIndx: number, tagsProperties: TagsProperties) => {
|
const handlePointerDown = (event: React.DragEvent<HTMLDivElement>, label: string, recipientId: number, recipientIndx: number, tagsProperties: TagsProperties) => {
|
||||||
const dragElemRect = event.currentTarget.getBoundingClientRect();
|
const dragElemRect = event.currentTarget.getBoundingClientRect();
|
||||||
|
|
@ -31,6 +33,8 @@ const handlePointerDown = (event: React.DragEvent<HTMLDivElement>, label: string
|
||||||
properties: tagsProperties
|
properties: tagsProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj.label.toLowerCase() === "radio" || obj.label.toLowerCase() === "checkbox") obj.group = uuidv4();
|
||||||
|
|
||||||
window.dragElemData = JSON.stringify(obj);
|
window.dragElemData = JSON.stringify(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,21 +42,31 @@ interface FieldListProps {
|
||||||
color: string;
|
color: string;
|
||||||
recipientId: number;
|
recipientId: number;
|
||||||
recipientIndx: number;
|
recipientIndx: number;
|
||||||
|
acntId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx }) => {
|
const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx, acntId = null }) => {
|
||||||
|
|
||||||
const [tagsData, setTagsData] = useState<TagsProperties[]>([]);
|
const [tagsData, setTagsData] = useState<TagsProperties[]>([]);
|
||||||
|
|
||||||
const { accountId } = useParams<{ accountId: string }>();
|
let { accountId } = useParams<{ accountId: string }>();
|
||||||
|
|
||||||
|
if(acntId) {
|
||||||
|
accountId = acntId;
|
||||||
|
}
|
||||||
|
|
||||||
if (!accountId) {
|
if (!accountId) {
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api
|
axios
|
||||||
.get(`/api/accounts/${accountId}/tags`)
|
.get(`${import.meta.env.VITE_BASE_URI}/api/accounts/${accountId}/tags`, {
|
||||||
|
headers: {
|
||||||
|
"ngrok-skip-browser-warning": "69420",
|
||||||
|
}
|
||||||
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const priorityOrder = ['SIGNATURE', 'INITIALS', 'STAMP'];
|
const priorityOrder = ['SIGNATURE', 'INITIALS', 'STAMP'];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ const RightSideBar: React.FC<DroppedItemProps> = ({ selectedTag, setDroppedItems
|
||||||
|
|
||||||
const selectedType = selectedTag.type in enumMap && enumMap[selectedTag.type as keyof typeof enumMap];
|
const selectedType = selectedTag.type in enumMap && enumMap[selectedTag.type as keyof typeof enumMap];
|
||||||
|
|
||||||
console.log("selectedTag", selectedTag, selectedType)
|
// console.log("selectedTag", selectedTag, selectedType)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,14 @@ import React, { useEffect, useState } from 'react';
|
||||||
// import api from '../../config/api';
|
// import api from '../../config/api';
|
||||||
import DrawSignatureCanvas from '../setting/Signature/DrawSignatureCanvas';
|
import DrawSignatureCanvas from '../setting/Signature/DrawSignatureCanvas';
|
||||||
import { AiOutlineUpload, AiOutlineEdit } from 'react-icons/ai';
|
import { AiOutlineUpload, AiOutlineEdit } from 'react-icons/ai';
|
||||||
import { MdCloudUpload } from 'react-icons/md';
|
import { MdCloudUpload } from 'react-icons/md';
|
||||||
import { FaSpinner } from "react-icons/fa";
|
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 { CiSaveDown1 } from 'react-icons/ci';
|
||||||
|
import api from '../../config/api';
|
||||||
|
|
||||||
interface Signature {
|
interface Signature {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -44,9 +47,15 @@ interface Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AddSignatureModalProps {
|
interface AddSignatureModalProps {
|
||||||
setShowAddSignature?: (value: boolean) => void;
|
// setShowAddSignature?: (value: boolean) => void;
|
||||||
getAllSignatures: () => Promise<void>;
|
// getAllSignatures: () => Promise<void>;
|
||||||
editingSignature?: Signature | null;
|
// editingSignature?: Signature | null;
|
||||||
|
|
||||||
|
recipientId?: string;
|
||||||
|
setOpenSign: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
saved: SaveType;
|
||||||
|
setSaved: React.Dispatch<React.SetStateAction<SaveType>>;
|
||||||
|
signTagId: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Account {
|
interface Account {
|
||||||
|
|
@ -70,11 +79,15 @@ interface SelectStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
setShowAddSignature,
|
setOpenSign,
|
||||||
getAllSignatures,
|
recipientId,
|
||||||
editingSignature
|
saved,
|
||||||
|
setSaved,
|
||||||
|
signTagId
|
||||||
}) => {
|
}) => {
|
||||||
const [activeTab, setActiveTab] = useState<'SELECT' | 'DRAW' | 'UPLOAD'>('SELECT');
|
|
||||||
|
console.log("savedModal", saved)
|
||||||
|
const [activeTab, setActiveTab] = useState<'TYPED' | 'DRAW' | 'UPLOAD' | 'SAVED'>('TYPED');
|
||||||
const [fullName, setFullName] = useState('');
|
const [fullName, setFullName] = useState('');
|
||||||
const [initials, setInitials] = useState('');
|
const [initials, setInitials] = useState('');
|
||||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||||
|
|
@ -92,18 +105,6 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
{ id: 6, name: 'classic', initials: 'LA', style: 'classic' },
|
{ id: 6, name: 'classic', initials: 'LA', style: 'classic' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const [selectedSignature, setSelectedSignature] = useState<SelectStyle>(
|
|
||||||
signatureOptions.length > 0 ? { id: signatureOptions[0].id, style: signatureOptions[0].style } : { id: 0, style: "" }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Store the actual file
|
|
||||||
const [file1, setFile1] = useState<File | null>(null);
|
|
||||||
const [file2, setFile2] = useState<File | null>(null);
|
|
||||||
|
|
||||||
// Store the preview URL
|
|
||||||
const [preview1, setPreview1] = useState<string | null>(null);
|
|
||||||
const [preview2, setPreview2] = useState<string | null>(null);
|
|
||||||
|
|
||||||
// User data
|
// User data
|
||||||
const [user, setUser] = useState<UserData>({
|
const [user, setUser] = useState<UserData>({
|
||||||
id: "",
|
id: "",
|
||||||
|
|
@ -118,48 +119,52 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const isEditMode = !!editingSignature;
|
console.log("User data", user)
|
||||||
|
|
||||||
|
const [selectedSignature, setSelectedSignature] = useState<SelectStyle>(
|
||||||
|
signatureOptions.length > 0 ? { id: signatureOptions[0].id, style: signatureOptions[0].style } : { id: 0, style: "" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Store the actual file
|
||||||
|
const [file1, setFile1] = useState<File | null>(null);
|
||||||
|
const [file2, setFile2] = useState<File | null>(null);
|
||||||
|
|
||||||
|
// Store the preview URL
|
||||||
|
const [preview1, setPreview1] = useState<string | null>(null);
|
||||||
|
const [preview2, setPreview2] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const [preSaveSignatures, setPreSaveSignatures] = useState([])
|
||||||
|
|
||||||
|
|
||||||
// Navigation items
|
// Navigation items
|
||||||
const navigationItems = [
|
const navigationItems = [
|
||||||
{ id: 'SELECT', label: 'SELECT', icon: <GrCheckboxSelected className="w-4 h-4" /> },
|
{ id: 'TYPED', label: 'TYPED', icon: <GrCheckboxSelected className="w-4 h-4" /> },
|
||||||
{ id: 'DRAW', label: 'DRAW', icon: <AiOutlineEdit className="w-5 h-5" /> },
|
{ id: 'DRAW', label: 'DRAW', icon: <AiOutlineEdit className="w-5 h-5" /> },
|
||||||
{ id: 'UPLOAD', label: 'UPLOAD', icon: <AiOutlineUpload className="w-5 h-5" /> },
|
{ id: 'UPLOAD', label: 'UPLOAD', icon: <AiOutlineUpload className="w-5 h-5" /> },
|
||||||
|
{ id: 'SAVED', label: 'SAVED', icon: <CiSaveDown1 className="w-5 h-5" /> },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Initialize form with editing signature data
|
|
||||||
useEffect(() => {
|
|
||||||
if (editingSignature) {
|
|
||||||
setFullName(`${editingSignature.firstName} ${editingSignature.lastName}`);
|
|
||||||
setInitials(`${editingSignature.firstName.slice(0, 1)}${editingSignature.lastName.slice(0, 1)}`);
|
|
||||||
setActiveTab(editingSignature.signatureType as 'SELECT' | 'DRAW' | 'UPLOAD');
|
|
||||||
|
|
||||||
// Set font for SELECT tab
|
|
||||||
const fontOption = signatureOptions.find(option => option.style === editingSignature.font);
|
|
||||||
if (fontOption) {
|
|
||||||
setSelectedSignature({ id: fontOption.id, style: fontOption.style });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set signature blobs for all tabs
|
|
||||||
if (editingSignature.signatureBlob && editingSignature.initialsBlob) {
|
|
||||||
setSignatures({
|
|
||||||
fullSignature: `data:image/png;base64,${editingSignature.signatureBlob}`,
|
|
||||||
initials: `data:image/png;base64,${editingSignature.initialsBlob}`
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set preview URLs for UPLOAD tab
|
|
||||||
if (editingSignature.signatureType === 'UPLOAD') {
|
|
||||||
setPreview1(`data:image/png;base64,${editingSignature.signatureBlob}`);
|
|
||||||
setPreview2(`data:image/png;base64,${editingSignature.initialsBlob}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [editingSignature]);
|
|
||||||
|
|
||||||
const handleSignatureChange = (data: { fullSignature: string | null; initials: string | null }) => {
|
const handleSignatureChange = (data: { fullSignature: string | null; initials: string | null }) => {
|
||||||
setSignatures(data);
|
setSignatures(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Getting Signatures - START
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const res = await axios.get(`${import.meta.env.VITE_BASE_URI}/api/sign/signatures?recipientId=${recipientId}`, {
|
||||||
|
headers: {
|
||||||
|
"ngrok-skip-browser-warning": "69420"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res?.data) {
|
||||||
|
let preSavedSignatures = res?.data
|
||||||
|
setPreSaveSignatures(preSavedSignatures)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [])
|
||||||
|
// Getting Signatures - END
|
||||||
|
|
||||||
// Cleanup preview URLs when component unmounts or image changes
|
// Cleanup preview URLs when component unmounts or image changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -202,7 +207,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
|
console.log("handleSubmit Called")
|
||||||
if (!signatures.fullSignature || !signatures.initials) {
|
if (!signatures.fullSignature || !signatures.initials) {
|
||||||
alert('Please provide both signature and initials');
|
alert('Please provide both signature and initials');
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
|
|
@ -211,62 +216,52 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
signatureType: activeTab,
|
tagId: signTagId,
|
||||||
signatureBase64: signatures.fullSignature,
|
// signatureId: signatureId,
|
||||||
initialsBase64: signatures.initials,
|
type: activeTab,
|
||||||
firstName: fullName.split(' ')[0] || user.firstName,
|
firstName: fullName.split(' ')[0] || user.firstName,
|
||||||
lastName: fullName.split(' ')[1] || user.lastName,
|
lastName: fullName.split(' ')[1] || user.lastName,
|
||||||
|
initials: "",
|
||||||
|
initialsBase64: signatures.initials,
|
||||||
|
signatureBase64: signatures.fullSignature,
|
||||||
font: selectedSignature.style
|
font: selectedSignature.style
|
||||||
};
|
};
|
||||||
|
|
||||||
let res;
|
console.log("payload", payload)
|
||||||
if (isEditMode && editingSignature) {
|
// if (isEditMode && editingSignature) {
|
||||||
// Update existing signature
|
// // Update existing signature
|
||||||
const updatePayload = {
|
// const updatePayload = {
|
||||||
...payload,
|
// ...payload,
|
||||||
signatureId: editingSignature.id
|
// signatureId: editingSignature.id
|
||||||
};
|
// };
|
||||||
res = await axios.put(`${import.meta.env.VITE_BASE_URI}/api/user/signatures`, updatePayload);
|
// res = await axios.put(`${import.meta.env.VITE_BASE_URI}/api/user/signatures`, updatePayload);
|
||||||
console.log("handleUpdate", res);
|
// console.log("handleUpdate", res);
|
||||||
|
|
||||||
toast.success("Signature Updated Successfully", {
|
// toast.success("Signature Updated Successfully", {
|
||||||
position: "top-center",
|
// position: "top-center",
|
||||||
autoClose: 500,
|
// autoClose: 500,
|
||||||
hideProgressBar: false,
|
// hideProgressBar: false,
|
||||||
closeOnClick: false,
|
// closeOnClick: false,
|
||||||
pauseOnHover: true,
|
// pauseOnHover: true,
|
||||||
draggable: true,
|
// draggable: true,
|
||||||
progress: undefined,
|
// progress: undefined,
|
||||||
theme: "light",
|
// theme: "light",
|
||||||
transition: Bounce,
|
// transition: Bounce,
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// Create new signature
|
||||||
|
let res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/sign/signatures?recipientId=${recipientId}`,
|
||||||
|
payload,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"ngrok-skip-browser-warning": "69420"
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
console.log("handleSubmit", res);
|
||||||
// Create new signature
|
|
||||||
res = await api.post(`/api/user/signatures`, payload);
|
|
||||||
console.log("handleSubmit", res);
|
|
||||||
|
|
||||||
toast.success("Signature Created Successfully", {
|
toast.success("Signature Created Successfully", {
|
||||||
position: "top-center",
|
|
||||||
autoClose: 500,
|
|
||||||
hideProgressBar: false,
|
|
||||||
closeOnClick: false,
|
|
||||||
pauseOnHover: true,
|
|
||||||
draggable: true,
|
|
||||||
progress: undefined,
|
|
||||||
theme: "light",
|
|
||||||
transition: Bounce,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res?.data) {
|
|
||||||
await getAllSignatures();
|
|
||||||
setShowAddSignature?.(false);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error submitting signature:", error);
|
|
||||||
toast.error(isEditMode ? "Failed to update signature" : "Failed to create signature", {
|
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
autoClose: 2000,
|
autoClose: 500,
|
||||||
hideProgressBar: false,
|
hideProgressBar: false,
|
||||||
closeOnClick: false,
|
closeOnClick: false,
|
||||||
pauseOnHover: true,
|
pauseOnHover: true,
|
||||||
|
|
@ -275,6 +270,35 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
theme: "light",
|
theme: "light",
|
||||||
transition: Bounce,
|
transition: Bounce,
|
||||||
});
|
});
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (res?.data) {
|
||||||
|
setSignatures({
|
||||||
|
fullSignature:"",
|
||||||
|
initials:"",
|
||||||
|
})
|
||||||
|
setSaved({
|
||||||
|
saveType: res.data.signatureType ?? null,
|
||||||
|
save: true,
|
||||||
|
signature: res.data.signatureBlob ?? null,
|
||||||
|
initial: res.data.initialsBlob ?? null,
|
||||||
|
});
|
||||||
|
setOpenSign(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error submitting signature:", error);
|
||||||
|
// toast.error(isEditMode ? "Failed to update signature" : "Failed to create signature", {
|
||||||
|
// position: "top-center",
|
||||||
|
// autoClose: 2000,
|
||||||
|
// hideProgressBar: false,
|
||||||
|
// closeOnClick: false,
|
||||||
|
// pauseOnHover: true,
|
||||||
|
// draggable: true,
|
||||||
|
// progress: undefined,
|
||||||
|
// theme: "light",
|
||||||
|
// transition: Bounce,
|
||||||
|
// });
|
||||||
} finally {
|
} finally {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
}
|
}
|
||||||
|
|
@ -282,7 +306,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
switch (activeTab) {
|
switch (activeTab) {
|
||||||
case 'SELECT':
|
case 'TYPED':
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col ">
|
<div className="h-full flex flex-col ">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
|
|
@ -340,7 +364,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
return (
|
return (
|
||||||
<DrawSignatureCanvas
|
<DrawSignatureCanvas
|
||||||
onSignatureChange={handleSignatureChange}
|
onSignatureChange={handleSignatureChange}
|
||||||
initialSignatures={isEditMode ? signatures : undefined}
|
// initialSignatures={isEditMode ? signatures : undefined}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -402,6 +426,78 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
case 'SAVED':
|
||||||
|
return (
|
||||||
|
<div className="h-full flex flex-col ">
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900 mb-2">Saved Signature's</h2>
|
||||||
|
{/* <p className="text-sm text-gray-600">Select from pre-designed signature styles</p> */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 overflow-y-auto">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{preSaveSignatures.map((signature) => (
|
||||||
|
<div key={signature?.id} className="grid grid-cols-12 gap-4 px-6 py-9 hover:bg-gray-50 transition-colors duration-150">
|
||||||
|
{/* Signature Column */}
|
||||||
|
<div className="col-span-5">
|
||||||
|
<div className="flex flex-col space-y-2 relative ps-6 border-l-3 border-blue-600 rounded-bl-2xl rounded-tl-2xl">
|
||||||
|
<div className="text-sm text-gray-600 font-medium mb-1">
|
||||||
|
Signed by:
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Signature Image or Fallback Text */}
|
||||||
|
<div className="bg-white rounded-lg p-1 flex items-center justify-center">
|
||||||
|
{signature?.signatureBlob ? (
|
||||||
|
<img
|
||||||
|
src={`data:${signature?.signatureMimeType || "image/png"};base64,${signature?.signatureBlob}`}
|
||||||
|
className="h-[50px] w-[250px] object-contain"
|
||||||
|
alt="Signature"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="text-gray-400 italic text-sm">No Signature</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Name */}
|
||||||
|
<div className="text-xs text-gray-500 truncate">
|
||||||
|
{signature?.signatureHash ?? ' '}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Initial Column */}
|
||||||
|
<div className="col-span-5">
|
||||||
|
<div className="flex flex-col space-y-2 relative ps-6 border-l-3 border-green-600 rounded-bl-2xl rounded-tl-2xl">
|
||||||
|
<div className="text-sm text-gray-600 font-medium mb-1">
|
||||||
|
Initials
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Initials Image */}
|
||||||
|
<div className="bg-white rounded-lg p-1 flex items-center justify-center">
|
||||||
|
{signature?.initialsBlob ? (
|
||||||
|
<img
|
||||||
|
src={`data:image/png;base64,${signature?.initialsBlob}`}
|
||||||
|
className="h-[50px] object-contain"
|
||||||
|
alt="Initials"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="text-gray-400 italic text-sm">No Initials</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Optional initials hash or font */}
|
||||||
|
<div className="text-xs text-gray-500 truncate">
|
||||||
|
{signature?.initialsHash || " "}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -415,11 +511,8 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
let currUser = res?.data;
|
let currUser = res?.data;
|
||||||
setUser(currUser);
|
setUser(currUser);
|
||||||
|
|
||||||
// Only set default values if not in edit mode
|
setFullName(currUser.firstName + " " + currUser.lastName);
|
||||||
if (!isEditMode) {
|
setInitials(currUser.firstName.slice(0, 1) + currUser.lastName.slice(0, 1));
|
||||||
setFullName(currUser.firstName + " " + currUser.lastName);
|
|
||||||
setInitials(currUser.firstName.slice(0, 1) + currUser.lastName.slice(0, 1));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching user details:", error);
|
console.error("Error fetching user details:", error);
|
||||||
}
|
}
|
||||||
|
|
@ -439,7 +532,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
<div className="px-4 py-4 border-b border-gray-200">
|
<div className="px-4 py-4 border-b border-gray-200">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<div className='px-1 py-1'>
|
<div className='px-1 py-1'>
|
||||||
<h3 className="text-md font-semibold text-gray-900">Add Signature</h3>
|
<h3 className="text-md font-semibold text-gray-900">Add Signature Sign</h3>
|
||||||
<p className="text-xs text-gray-500">Create your digital signature</p>
|
<p className="text-xs text-gray-500">Create your digital signature</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -482,7 +575,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
{navigationItems.map((item) => (
|
{navigationItems.map((item) => (
|
||||||
<button
|
<button
|
||||||
key={item.id}
|
key={item.id}
|
||||||
onClick={() => setActiveTab(item.id as 'SELECT' | 'DRAW' | 'UPLOAD')}
|
onClick={() => setActiveTab(item.id as 'TYPED' | 'DRAW' | 'UPLOAD' | 'SAVED')}
|
||||||
className={`w-full flex items-center space-x-3 px-2 py-2 text-sm font-medium rounded-lg cursor-pointer transition-colors ${activeTab === item.id
|
className={`w-full flex items-center space-x-3 px-2 py-2 text-sm font-medium rounded-lg cursor-pointer transition-colors ${activeTab === item.id
|
||||||
? 'bg-blue-50 text-blue-700 border border-blue-200'
|
? 'bg-blue-50 text-blue-700 border border-blue-200'
|
||||||
: 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'
|
: 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'
|
||||||
|
|
@ -519,7 +612,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
<div className="p-4 border-t border-gray-200 flex justify-end gap-3">
|
<div className="p-4 border-t border-gray-200 flex justify-end gap-3">
|
||||||
<button
|
<button
|
||||||
className="cursor-pointer px-4 py-2 text-sm font-medium rounded-md border border-gray-300 text-gray-700 hover:bg-gray-50 transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
|
className="cursor-pointer px-4 py-2 text-sm font-medium rounded-md border border-gray-300 text-gray-700 hover:bg-gray-50 transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
|
||||||
onClick={() => setShowAddSignature?.(false)}
|
onClick={() => setOpenSign?.(false)}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
>
|
>
|
||||||
CANCEL
|
CANCEL
|
||||||
|
|
@ -532,10 +625,13 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
{isSubmitting ? (
|
{isSubmitting ? (
|
||||||
<>
|
<>
|
||||||
<FaSpinner className="animate-spin" />
|
<FaSpinner className="animate-spin" />
|
||||||
{isEditMode ? 'UPDATING...' : 'CREATING...'}
|
{/* {isEditMode ? 'UPDATING...' : 'CREATING...'} */}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
isEditMode ? 'UPDATE SIGNATURE' : 'CREATE SIGNATURE'
|
<>
|
||||||
|
CREATE SIGNATURE
|
||||||
|
{/* isEditMode ? 'UPDATE SIGNATURE' : 'CREATE SIGNATURE' */}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@
|
||||||
|
|
||||||
--processStepOneTextHead: #000000;
|
--processStepOneTextHead: #000000;
|
||||||
|
|
||||||
--modalSubmitBG:#1919d7;
|
--modalSubmitBG: #1919d7;
|
||||||
--modalSubmitBGHover:#395ee1;
|
--modalSubmitBGHover: #395ee1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -62,37 +62,64 @@
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
-ms-touch-action: none; /* For older IE/Edge */
|
-ms-touch-action: none;
|
||||||
|
/* For older IE/Edge */
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes textColorChange {
|
@keyframes textColorChange {
|
||||||
0%, 100% {
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
color: #41644A; /* Tailwind blue-500 */
|
color: #41644A;
|
||||||
|
/* Tailwind blue-500 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.animate-text {
|
.animate-text {
|
||||||
animation: textColorChange 2s infinite ease-in-out;
|
animation: textColorChange 2s infinite ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
|
||||||
.no-scrollbar::-webkit-scrollbar {
|
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||||
display: none;
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
}
|
display: none;
|
||||||
/* Hide scrollbar for IE, Edge and Firefox */
|
|
||||||
.no-scrollbar {
|
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hide scrollbar for IE, Edge and Firefox */
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
/* IE and Edge */
|
||||||
|
scrollbar-width: none;
|
||||||
|
/* Firefox */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Group Border - START */
|
||||||
|
.group-border {
|
||||||
|
position: absolute;
|
||||||
|
border: 1px dashed var(--primary);
|
||||||
|
/* pointer-events: none; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-border>div {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 50;
|
||||||
|
background-color: var(--primary);
|
||||||
|
color: var(--primaryLight);
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
/* Loader CSS */
|
/* Loader CSS */
|
||||||
/* From Uiverse.io by Juanes200122 */
|
/* From Uiverse.io by Juanes200122 */
|
||||||
.pl {
|
.pl {
|
||||||
|
|
@ -299,3 +326,15 @@ canvas {
|
||||||
stroke-dashoffset: -440;
|
stroke-dashoffset: -440;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
=======
|
||||||
|
.bottom-border>div:hover {
|
||||||
|
background-color: var(--primaryLight2) ;
|
||||||
|
opacity: 0.9;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Group Border - END */
|
||||||
|
|
||||||
|
/* Loader CSS */
|
||||||
|
>>>>>>> 313217eded9cceb45db39bd86d6886f199fec226
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
interface Dimension {
|
||||||
|
maxTop: number | null;
|
||||||
|
minTop: number | null;
|
||||||
|
maxLeft: number | null;
|
||||||
|
minLeft: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getGroupDimension = (
|
||||||
|
group: NodeListOf<HTMLElement>,
|
||||||
|
containerRect: DOMRect,
|
||||||
|
offsetX: number,
|
||||||
|
offsetY: number
|
||||||
|
) => {
|
||||||
|
let dimension: Dimension = { maxTop: null, minTop: null, maxLeft: null, minLeft: null };
|
||||||
|
|
||||||
|
group.forEach((element: HTMLElement) => {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
dimension.minTop = Math.min(dimension.minTop ?? Infinity, rect.top);
|
||||||
|
dimension.maxTop = Math.max(dimension.maxTop ?? 0, rect.bottom);
|
||||||
|
|
||||||
|
dimension.minLeft = Math.min(dimension.minLeft ?? Infinity, rect.left);
|
||||||
|
dimension.maxLeft = Math.max(dimension.maxLeft ?? 0, rect.right);
|
||||||
|
});
|
||||||
|
|
||||||
|
dimension.maxTop = dimension.maxTop !== null ? dimension.maxTop - containerRect.top + (offsetY - 10) : null;
|
||||||
|
dimension.minTop = dimension.minTop !== null ? dimension.minTop - containerRect.top - (offsetY - 10) : null;
|
||||||
|
|
||||||
|
dimension.maxLeft = dimension.maxLeft !== null ? dimension.maxLeft - containerRect.left + (offsetX - 10) : null;
|
||||||
|
dimension.minLeft = dimension.minLeft !== null ? dimension.minLeft - containerRect.left - (offsetX - 10) : null;
|
||||||
|
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handleGroupBorderPosition = (groupElements: NodeListOf<HTMLElement>, containerRect: DOMRect, offsetX: number, offsetY: number) => {
|
||||||
|
const dimension = getGroupDimension(groupElements, containerRect, offsetX, offsetY);
|
||||||
|
const borderTop: HTMLElement | null = document.querySelector("[border-group='" + groupElements[0].getAttribute("group") + "'][border-pos='top']");
|
||||||
|
const borderRight: HTMLElement | null = document.querySelector("[border-group='" + groupElements[0].getAttribute("group") + "'][border-pos='right']");
|
||||||
|
const borderBottom: HTMLElement | null = document.querySelector("[border-group='" + groupElements[0].getAttribute("group") + "'][border-pos='bottom']");
|
||||||
|
const borderLeft: HTMLElement | null = document.querySelector("[border-group='" + groupElements[0].getAttribute("group") + "'][border-pos='left']");
|
||||||
|
|
||||||
|
if (borderTop !== null && dimension.maxLeft !== null && dimension.minLeft !== null) {
|
||||||
|
borderTop.style.width = (dimension.maxLeft - dimension.minLeft) + "px";
|
||||||
|
borderTop.style.height = "1px";
|
||||||
|
borderTop.style.top = dimension.minTop + "px";
|
||||||
|
borderTop.style.left = dimension.minLeft + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borderRight !== null && dimension.maxTop !== null && dimension.minTop !== null) {
|
||||||
|
borderRight.style.width = "1px";
|
||||||
|
borderRight.style.height = (dimension.maxTop - dimension.minTop) + "px";
|
||||||
|
borderRight.style.top = dimension.minTop + "px";
|
||||||
|
borderRight.style.left = dimension.maxLeft + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borderBottom !== null && dimension.maxLeft !== null && dimension.minLeft !== null) {
|
||||||
|
borderBottom.style.width = (dimension.maxLeft - dimension.minLeft) + "px";
|
||||||
|
borderBottom.style.height = "1px";
|
||||||
|
borderBottom.style.top = dimension.maxTop + "px";
|
||||||
|
borderBottom.style.left = dimension.minLeft + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borderLeft !== null && dimension.maxTop !== null && dimension.minTop !== null) {
|
||||||
|
borderLeft.style.width = "1px";
|
||||||
|
borderLeft.style.height = (dimension.maxTop - dimension.minTop) + "px";
|
||||||
|
borderLeft.style.top = dimension.minTop + "px";
|
||||||
|
borderLeft.style.left = dimension.minLeft + "px";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const handleTargetBorderEventListener = (groupId: string, containerRect: DOMRect) => {
|
||||||
|
// console.log("handleTargetBorderEventListener called for groupId:", groupId);
|
||||||
|
// if (groupId) {
|
||||||
|
// const groupElements: NodeListOf<HTMLElement> = document.querySelectorAll(`div[group="${groupId}"]`);
|
||||||
|
// handleGroupBorderPosition(groupElements, containerRect);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
const handleInitialGroupBorderPosition = (groupElements: NodeListOf<HTMLElement>, containerRect: DOMRect, offsetX: number, offsetY: number) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
handleGroupBorderPosition(groupElements, containerRect, offsetX, offsetY)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getGroupDimension,
|
||||||
|
handleGroupBorderPosition,
|
||||||
|
handleInitialGroupBorderPosition
|
||||||
|
// handleTargetBorderEventListener
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue