Merge branch 'main' of http://git.hicglobalsolutions.in/BhawanSingh/SME-Web into jai
This commit is contained in:
commit
fcb7da1c68
|
|
@ -8,19 +8,13 @@ import RightSideBar, { MASKTYPE, TEXT } from './rightSideBar/RightSideBar';
|
|||
import { DroppedItem, TagsTypes } from '../../../utlity/types';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { IoMdClose } from 'react-icons/io';
|
||||
|
||||
import { fetchRecipients, toggleToTemplates, TRANSACTION_TEMPLATE_TOGGLE } from '../../../store/slices/selectedRecipientsSlice';
|
||||
import { fetchDocuments } from '../../../store/slices/documentSlice';
|
||||
import { FaQuestionCircle } from 'react-icons/fa';
|
||||
import typeToIconMap from '../../../helper/iconMap';
|
||||
|
||||
import { IoAdd } from 'react-icons/io5';
|
||||
import Loader from '../../dashboard/Loader';
|
||||
// import { TRANSACTION_TEMPLATE_TOGGLE } from "../../../store/slices/selectedRecipientsSlice";
|
||||
import { handleGroupBorderPosition } from '../../../utlity/tagGroupConUtils';
|
||||
import { hideLoader, showLoader } from '../../../store/slices/loaderSlice';
|
||||
import { IsSendInterface } from './ProcessStepTwo';
|
||||
import { hideLoader } from '../../../store/slices/loaderSlice';
|
||||
import DroppedItemsTagsCon from './DroppedItemsTagsCon';
|
||||
|
||||
export interface DroppedItemsObj {
|
||||
|
|
@ -73,6 +67,44 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
const [droppedItems, setDroppedItems] = useState<DroppedItemsObj>({});
|
||||
|
||||
|
||||
interface HotKeysObj {
|
||||
isActive: boolean;
|
||||
key: string | null;
|
||||
tagId?: string | null;
|
||||
hotKey?: string | null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// const hotKeysObjInitial: HotKeysObj = {
|
||||
// "CtrlA": {
|
||||
// enabled: false,
|
||||
// key: null
|
||||
// },
|
||||
// "Delete": {
|
||||
// enabled: false,
|
||||
// key: null
|
||||
// },
|
||||
// "CtrlC": {
|
||||
// enabled: false,
|
||||
// key: null,
|
||||
// tagId: null
|
||||
// }
|
||||
// }
|
||||
|
||||
const hotKeysObjInitial: HotKeysObj = {
|
||||
isActive: false,
|
||||
key: null,
|
||||
tagId: null,
|
||||
hotKey: null
|
||||
}
|
||||
|
||||
|
||||
|
||||
const [hotKeysObj, setHotKeysObj] = useState<HotKeysObj>(hotKeysObjInitial);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
|
||||
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId }));
|
||||
|
|
@ -97,105 +129,6 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
}
|
||||
}
|
||||
|
||||
// let updatedTags = { ...recTags }
|
||||
// let tagsData = []
|
||||
|
||||
// for (const dropPageIds of Object.keys(updatedTags)) {
|
||||
|
||||
// for (const dropTag of updatedTags[dropPageIds]) {
|
||||
// let mask = null
|
||||
|
||||
// // console.log(dropTag, "line 132")
|
||||
|
||||
// // if (dropTag.subType?.toLowerCase() === "password") {
|
||||
// // console.log(dropTag)
|
||||
// mask = {
|
||||
// "type": dropTag.maskType ? `${dropTag.maskType}`.toUpperCase() : null,
|
||||
// "character": dropTag.maskCharacter ? `${dropTag.maskCharacter}`.toUpperCase() : null
|
||||
// }
|
||||
// // }
|
||||
|
||||
// // console.log(dropTag, "line 204")
|
||||
|
||||
// const isDeleted = "isDeleted" in dropTag ? dropTag.isDeleted : false
|
||||
|
||||
// const updatedTagData = {
|
||||
// "id": "id" in dropTag ? dropTag.id : null,
|
||||
// "label": dropTag.label,
|
||||
// "dimensions": dropTag.dimensions,
|
||||
// "type": dropTag.type.toUpperCase(),
|
||||
// // "subType": (dropTag.subType ? dropTag.subType.toUpperCase() : null),
|
||||
// "minLength": "minLength" in dropTag ? dropTag.minLength : 0,
|
||||
// "maxLength": "maxLength" in dropTag ? dropTag.maxLength : 0,
|
||||
// "error": ("error" in dropTag && dropTag.error) ? `${dropTag.error}`.toUpperCase() : "error",
|
||||
// "regex": "regex" in dropTag ? dropTag.regex : []
|
||||
// // }
|
||||
// ,
|
||||
// "documentId": dropTag.documentId,
|
||||
// "options": ("options" in dropTag) ? dropTag.options : [],
|
||||
// "pageIndex": dropTag.pageIndex,
|
||||
// "recipientId": dropTag.recipientId,
|
||||
// "styles": "styles" in dropTag ? dropTag.styles : {
|
||||
// "font": "",
|
||||
// "italic": false,
|
||||
// "bold": false,
|
||||
// "underline": false,
|
||||
// "color": "black",
|
||||
// "textSize": 0
|
||||
// },
|
||||
// "required": (dropTag.type.toUpperCase() !== "SIGNATURE" && dropTag.type.toUpperCase() !== "INITIALS") ? dropTag.required : true,
|
||||
// // "required": "required" in dropTag ? dropTag.required : ,
|
||||
// "update": "update" in dropTag ? dropTag.update : false,
|
||||
// "readOnly": false,
|
||||
// }
|
||||
|
||||
// // if ("format" in dropTag) {
|
||||
// // updatedTagData.format = `${dropTag.subType}`.toUpperCase();
|
||||
// // updatedTagData.dateFormat = dropTag.format;
|
||||
// // updatedTagData.currentTimeStamp = dropTag.currentTimeStamp
|
||||
// // }
|
||||
|
||||
// if("format" in dropTag && dropTag.format) {
|
||||
// updatedTagData.subType = dropTag.format.toLowerCase();
|
||||
// updatedTagData.format = dropTag.dateFormat;
|
||||
// }
|
||||
|
||||
// if (`${dropTag.type}`.toLowerCase() === "number") {
|
||||
// updatedTagData.decimalPlace = dropTag.decimalPlace
|
||||
// updatedTagData.isCurrency = dropTag.isCurrency
|
||||
// }
|
||||
|
||||
// if (dropTag.type === "TEXT") {
|
||||
// // updatedTagData.multiLine = dropTag.subType === "paragraph"
|
||||
|
||||
// if(dropTag.multiLine) {
|
||||
// updatedTagData.subtype = TEXT.PARAGRAPH
|
||||
// } else {
|
||||
// updatedTagData.subtype = TEXT.SINGLE_LINE
|
||||
// }
|
||||
|
||||
// if ("maskType" in dropTag) {
|
||||
// updatedTagData.maskCharacter = mask.character
|
||||
// updatedTagData.maskType = mask.type
|
||||
// }
|
||||
// }
|
||||
|
||||
// // if ("required" in updatedTagData && !updatedTagData.required) delete updatedTagData.required;
|
||||
|
||||
// if (updatedTagData.subType === 'SINGLE SELECT') updatedTagData.subType = "SINGLE_SELECT"
|
||||
// if (updatedTagData.subType === 'MULTI SELECT') updatedTagData.subType = "MULTI_SELECT"
|
||||
|
||||
// if (updatedTagData.options && !updatedTagData.options.length) delete updatedTagData.options;
|
||||
|
||||
// if (!updatedTagData.id) delete updatedTagData.id;
|
||||
|
||||
// if (!isDeleted) {
|
||||
// // sendTags.mod.push(updatedTagData);
|
||||
// tagsData.push(updatedTagData)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
setDroppedItems(recTags)
|
||||
// Handle your response here
|
||||
} catch (err) {
|
||||
|
|
@ -293,104 +226,6 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
if (Object.keys(droppedItems).length === 0) return;
|
||||
if (!save && isSend === null) return;
|
||||
|
||||
// !save && dispatch(showLoader("Loading ..."))
|
||||
|
||||
// let updatedTags = { ...droppedItems }
|
||||
|
||||
// const sendTags = {
|
||||
// "mod": [],
|
||||
// "remove": []
|
||||
// }
|
||||
|
||||
// let tagsData = []
|
||||
|
||||
// const modified = []
|
||||
// const remove = []
|
||||
|
||||
// console.log(updatedTags, "updatedTags");
|
||||
// for (const dropPageIds of Object.keys(updatedTags)) {
|
||||
// for (const dropTag of updatedTags[dropPageIds]) {
|
||||
// let mask = null
|
||||
|
||||
// // console.log(dropTag, "line 132")
|
||||
|
||||
// // if (dropTag.subType?.toLowerCase() === "password") {
|
||||
// // console.log(dropTag)
|
||||
// mask = {
|
||||
// "type": dropTag.maskType ? `${dropTag.maskType}`.toUpperCase() : null,
|
||||
// "character": dropTag.maskCharacter ? `${dropTag.maskCharacter}`.toUpperCase() : null
|
||||
// }
|
||||
// // }
|
||||
|
||||
// // console.log(dropTag, "line 204")
|
||||
|
||||
// const isDeleted = "isDeleted" in dropTag ? dropTag.isDeleted : false
|
||||
|
||||
// const updatedTagData = {
|
||||
// "id": "id" in dropTag ? dropTag.id : null,
|
||||
// "label": dropTag.label,
|
||||
// "dimensions": dropTag.dimensions,
|
||||
// "type": dropTag.type.toUpperCase(),
|
||||
// // "subType": (dropTag.subType ? dropTag.subType.toUpperCase() : null),
|
||||
// "minLength": "minLength" in dropTag ? dropTag.minLength : 0,
|
||||
// "maxLength": "maxLength" in dropTag ? dropTag.maxLength : 0,
|
||||
// "error": ("error" in dropTag && dropTag.error) ? `${dropTag.error}`.toUpperCase() : "error",
|
||||
// "regex": "regex" in dropTag ? dropTag.regex : []
|
||||
// // }
|
||||
// ,
|
||||
// "documentId": dropTag.documentId,
|
||||
// "options": ("options" in dropTag) ? dropTag.options : [],
|
||||
// "pageIndex": dropTag.pageIndex,
|
||||
// "recipientId": dropTag.recipientId,
|
||||
// "styles": "styles" in dropTag ? dropTag.styles : {
|
||||
// "font": "",
|
||||
// "italic": false,
|
||||
// "bold": false,
|
||||
// "underline": false,
|
||||
// "color": "black",
|
||||
// "textSize": 0
|
||||
// },
|
||||
// "required": (dropTag.type.toUpperCase() !== "SIGNATURE" && dropTag.type.toUpperCase() !== "INITIALS") ? dropTag.required : true,
|
||||
// // "required": "required" in dropTag ? dropTag.required : ,
|
||||
// "update": "update" in dropTag ? dropTag.update : false,
|
||||
// "readOnly": false,
|
||||
// }
|
||||
|
||||
// if ("format" in dropTag) {
|
||||
// updatedTagData.format = `${dropTag.subType}`.toUpperCase();
|
||||
// updatedTagData.dateFormat = dropTag.format;
|
||||
// updatedTagData.currentTimeStamp = dropTag.currentTimeStamp
|
||||
// }
|
||||
|
||||
// if (`${dropTag.type}`.toLowerCase() === "number") {
|
||||
// updatedTagData.decimalPlace = dropTag.decimalPlace
|
||||
// updatedTagData.isCurrency = dropTag.isCurrency
|
||||
// }
|
||||
|
||||
// if (updatedTagData.type === "TEXT") {
|
||||
// updatedTagData.multiLine = dropTag.subType === "paragraph"
|
||||
// if (dropTag.subType === "password") {
|
||||
// updatedTagData.maskCharacter = mask.character
|
||||
// updatedTagData.maskType = mask.type
|
||||
// }
|
||||
// }
|
||||
|
||||
// // if ("required" in updatedTagData && !updatedTagData.required) delete updatedTagData.required;
|
||||
|
||||
// if (updatedTagData.subType === 'SINGLE SELECT') updatedTagData.subType = "SINGLE_SELECT"
|
||||
// if (updatedTagData.subType === 'MULTI SELECT') updatedTagData.subType = "MULTI_SELECT"
|
||||
|
||||
// if (updatedTagData.options && !updatedTagData.options.length) delete updatedTagData.options;
|
||||
|
||||
// if (!updatedTagData.id) delete updatedTagData.id;
|
||||
|
||||
// if (!isDeleted) {
|
||||
// // sendTags.mod.push(updatedTagData);
|
||||
// tagsData.push(updatedTagData)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
let updatedTags: any = [];
|
||||
|
||||
for (const dropPagesId of Object.keys(droppedItems)) {
|
||||
|
|
@ -415,17 +250,6 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
}, [isSend])
|
||||
// Save Tags - END
|
||||
|
||||
// handleTransactionSaving - START
|
||||
|
||||
// useEffect(() => {
|
||||
// const interval = setInterval(async () => {
|
||||
// setTransactionSaving(true)
|
||||
// }, 8000)
|
||||
// return () => clearInterval(interval);
|
||||
// }, [droppedItems])
|
||||
|
||||
// handleTransactionSaving - END
|
||||
|
||||
useEffect(() => {
|
||||
if (transactionSaving) {
|
||||
setTimeout(() => {
|
||||
|
|
@ -494,12 +318,6 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
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") {
|
||||
|
|
@ -519,301 +337,104 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
prepData],
|
||||
}
|
||||
|
||||
console.log("data311", dataToSet)
|
||||
setDroppedItems(dataToSet);
|
||||
setDroppedItemsCounter((prev) => prev + 1);
|
||||
|
||||
setTimeout(() => {
|
||||
const tagIndex = key in droppedItems ? droppedItems[key].length : 0;
|
||||
console.log(tagIndex, "line 307", key);
|
||||
|
||||
setSelectedTag({ key, tagIndex })
|
||||
}, 0)
|
||||
};
|
||||
// HANDLE DROP - END
|
||||
|
||||
|
||||
|
||||
// HANDLE EXPAND TAG - START
|
||||
const handleExpandTag = (event: React.MouseEvent<HTMLDivElement>, key: string, index: number) => {
|
||||
console.log("HANDLE EXPAND TAG - START")
|
||||
event.preventDefault(); // Prevent text selection issues
|
||||
|
||||
const expandingElemIcon = event.currentTarget;
|
||||
const targetElement = expandingElemIcon.nextElementSibling?.parentElement;
|
||||
const targetContainer = targetElement?.parentElement;
|
||||
|
||||
if (!targetContainer || !targetElement) return;
|
||||
|
||||
const elementRect = targetElement.getBoundingClientRect();
|
||||
|
||||
const startX = event.clientX;
|
||||
const startY = event.clientY;
|
||||
|
||||
const startWidth = elementRect.width;
|
||||
const startHeight = elementRect.height;
|
||||
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
|
||||
let newWidth = startWidth + (event.clientX - startX);
|
||||
let newHeight = startHeight + (event.clientY - startY);
|
||||
|
||||
if (newHeight > 200 || newWidth > 400) {
|
||||
if (newHeight > 200) {
|
||||
newHeight = 200
|
||||
}
|
||||
|
||||
if (newWidth > 400) {
|
||||
newWidth = 400
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the new width & height
|
||||
setDroppedItems({
|
||||
...droppedItems,
|
||||
[key]: Array.isArray(droppedItems[key]) // Ensure it's an array
|
||||
? droppedItems[key].map((item, i) =>
|
||||
i === index ? { ...item, dimensions: { ...item.dimensions, width: newWidth, height: newHeight }, update: true } : item
|
||||
)
|
||||
: [], // Provide a fallback in case it's undefined or not an array
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
document.removeEventListener("pointermove", handleMouseMove);
|
||||
document.removeEventListener("pointerup", handleMouseUp);
|
||||
};
|
||||
|
||||
document.addEventListener("pointermove", handleMouseMove);
|
||||
document.addEventListener("pointerup", handleMouseUp);
|
||||
};
|
||||
// HANDLE EXPAND TAG - END
|
||||
|
||||
|
||||
// Helper function to remove group border elements from DOM
|
||||
const removeGroupBorders = (groupId: string) => {
|
||||
console.log(`Removing borders for group: ${groupId}`);
|
||||
|
||||
const borderPositions = ['top', 'right', 'bottom', 'left'];
|
||||
|
||||
borderPositions.forEach(position => {
|
||||
const borderElement = document.querySelector(`[border-group='${groupId}'][border-pos='${position}']`);
|
||||
if (borderElement && borderElement.parentNode) {
|
||||
borderElement.parentNode.removeChild(borderElement);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// const handleAddRadioClick = (key:string) => {
|
||||
// console.log("Handle Radio Clicled", key)
|
||||
// console.log(droppedItems, "line 525")
|
||||
// }
|
||||
|
||||
const handleIGroupBorderPosition = (groupId: string) => {
|
||||
console.log("handleIGroupBorderPosition for group:", groupId);
|
||||
|
||||
const groupElements: NodeListOf<HTMLElement> = document.querySelectorAll(`div[group="${groupId}"]`);
|
||||
|
||||
if (groupElements.length === 0) {
|
||||
console.log("No group elements found for:", groupId);
|
||||
return;
|
||||
}
|
||||
|
||||
let targetContainer = groupElements[0].parentElement?.parentElement;
|
||||
|
||||
if (!targetContainer) {
|
||||
console.log("No target container found");
|
||||
return;
|
||||
}
|
||||
|
||||
const containerRect = targetContainer.getBoundingClientRect();
|
||||
|
||||
// Use consistent offset values
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
// Ensure DOM is fully updated before positioning
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
handleGroupBorderPosition(groupElements, containerRect, offsetX, offsetY);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Enhanced handleGroupBorderPosition with better positioning logic
|
||||
const handleGroupBorderPosition = (groupElements: NodeListOf<HTMLElement>, containerRect: DOMRect, offsetX: number, offsetY: number) => {
|
||||
if (!groupElements || groupElements.length === 0) return;
|
||||
|
||||
const groupId = groupElements[0].getAttribute('group');
|
||||
if (!groupId) return;
|
||||
|
||||
// Calculate the bounding box of all group elements
|
||||
let minLeft = Infinity, minTop = Infinity, maxRight = -Infinity, maxBottom = -Infinity;
|
||||
|
||||
groupElements.forEach(element => {
|
||||
const parentElement = element.parentElement;
|
||||
if (!parentElement) return;
|
||||
|
||||
const rect = parentElement.getBoundingClientRect();
|
||||
const relativeLeft = rect.left - containerRect.left;
|
||||
const relativeTop = rect.top - containerRect.top;
|
||||
const relativeRight = relativeLeft + rect.width;
|
||||
const relativeBottom = relativeTop + rect.height;
|
||||
|
||||
minLeft = Math.min(minLeft, relativeLeft);
|
||||
minTop = Math.min(minTop, relativeTop);
|
||||
maxRight = Math.max(maxRight, relativeRight);
|
||||
maxBottom = Math.max(maxBottom, relativeBottom);
|
||||
});
|
||||
|
||||
// Add some padding around the group
|
||||
const padding = 10;
|
||||
minLeft -= padding;
|
||||
minTop -= padding;
|
||||
maxRight += padding;
|
||||
maxBottom += padding;
|
||||
|
||||
const width = maxRight - minLeft;
|
||||
const height = maxBottom - minTop;
|
||||
|
||||
// Update or create border elements
|
||||
const borderPositions = ['top', 'right', 'bottom', 'left'];
|
||||
|
||||
borderPositions.forEach(position => {
|
||||
let borderElement = document.querySelector(`[border-group='${groupId}'][border-pos='${position}']`) as HTMLElement;
|
||||
|
||||
if (!borderElement) {
|
||||
// Create border element if it doesn't exist
|
||||
borderElement = document.createElement('div');
|
||||
borderElement.className = `group-border ${position === 'bottom' ? 'bottom-border' : ''}`;
|
||||
borderElement.setAttribute('border-group', groupId);
|
||||
borderElement.setAttribute('border-pos', position);
|
||||
|
||||
// Add the + icon for bottom border
|
||||
if (position === 'bottom') {
|
||||
const addIcon = document.createElement('div');
|
||||
addIcon.innerHTML = '<IoAdd />'; // You might need to adjust this based on your icon system
|
||||
addIcon.onclick = () => {
|
||||
// Find the original item to pass to handleAddGroupItemClicked
|
||||
const originalItem = droppedItems[key]?.find(item => 'group' in item && item.group === groupId);
|
||||
if (originalItem) {
|
||||
handleAddGroupItemClicked(key, originalItem);
|
||||
}
|
||||
};
|
||||
borderElement.appendChild(addIcon);
|
||||
}
|
||||
|
||||
// Append to container
|
||||
groupElements[0].parentElement?.parentElement?.appendChild(borderElement);
|
||||
}
|
||||
|
||||
// Position the border element
|
||||
borderElement.style.position = 'absolute';
|
||||
borderElement.style.pointerEvents = position === 'bottom' ? 'auto' : 'none';
|
||||
|
||||
switch (position) {
|
||||
case 'top':
|
||||
borderElement.style.left = `${minLeft}px`;
|
||||
borderElement.style.top = `${minTop}px`;
|
||||
borderElement.style.width = `${width}px`;
|
||||
borderElement.style.height = '2px';
|
||||
break;
|
||||
case 'right':
|
||||
borderElement.style.left = `${maxRight - 2}px`;
|
||||
borderElement.style.top = `${minTop}px`;
|
||||
borderElement.style.width = '2px';
|
||||
borderElement.style.height = `${height}px`;
|
||||
break;
|
||||
case 'bottom':
|
||||
borderElement.style.left = `${minLeft}px`;
|
||||
borderElement.style.top = `${maxBottom - 2}px`;
|
||||
borderElement.style.width = `${width}px`;
|
||||
borderElement.style.height = '2px';
|
||||
break;
|
||||
case 'left':
|
||||
borderElement.style.left = `${minLeft}px`;
|
||||
borderElement.style.top = `${minTop}px`;
|
||||
borderElement.style.width = '2px';
|
||||
borderElement.style.height = `${height}px`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddGroupItemClicked = (key: string, item: any) => {
|
||||
console.log("handleAddGroupItemClicked", item);
|
||||
|
||||
const groupId = item.group;
|
||||
|
||||
// Find all existing items in this group to determine the bottom-most position
|
||||
const existingGroupItems = droppedItems[key]?.filter(existingItem =>
|
||||
'group' in existingItem && existingItem.group === groupId
|
||||
) || [];
|
||||
|
||||
const existingGroupItem = droppedItems[key]?.filter(existingItem =>
|
||||
'group' in existingItem && existingItem.group === groupId
|
||||
) || [];
|
||||
|
||||
existingGroupItem[0].options
|
||||
|
||||
// Find the bottom-most item in the group
|
||||
let bottomMostItem = item;
|
||||
if (existingGroupItems.length > 0) {
|
||||
bottomMostItem = existingGroupItems.reduce((lowest, current) => {
|
||||
const currentBottom = current.dimensions.top + current.dimensions.height;
|
||||
const lowestBottom = lowest.dimensions.top + lowest.dimensions.height;
|
||||
return currentBottom > lowestBottom ? current : lowest;
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate new position: place below the bottom-most item
|
||||
const spacing = 10; // Adjust spacing as needed
|
||||
const newTop = bottomMostItem.dimensions.top + bottomMostItem.dimensions.height + spacing;
|
||||
|
||||
// Use the same left position as the parent (original) item
|
||||
const newItem = {
|
||||
...item,
|
||||
dimensions: {
|
||||
...item.dimensions,
|
||||
left: item.dimensions.left, // Keep same horizontal position as parent
|
||||
top: newTop // Position below the bottom-most item
|
||||
},
|
||||
isGroupExist: true
|
||||
};
|
||||
|
||||
// Update the dropped items
|
||||
setDroppedItems({
|
||||
...droppedItems,
|
||||
[key]: [...droppedItems[key], newItem],
|
||||
});
|
||||
|
||||
// Update group borders after adding the new item
|
||||
// Use setTimeout to ensure state update is processed
|
||||
setTimeout(() => {
|
||||
handleIGroupBorderPosition(groupId);
|
||||
}, 50); // Slightly longer timeout to ensure DOM updates
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize group borders for all existing groups after component updates
|
||||
const timeoutId = setTimeout(() => {
|
||||
const allGroupElements = document.querySelectorAll('[group]');
|
||||
const groupIds = new Set<string>();
|
||||
if (!hotKeysObj.isActive) return
|
||||
|
||||
allGroupElements.forEach((element) => {
|
||||
const groupId = element.getAttribute('group');
|
||||
if (groupId) {
|
||||
groupIds.add(groupId);
|
||||
const docCon = document.getElementById("doc-con");
|
||||
|
||||
switch (hotKeysObj.hotKey) {
|
||||
case "Ctrl+c":
|
||||
// Handle Ctrl+C
|
||||
break;
|
||||
case "Ctrl+v":
|
||||
// Handle Ctrl+V
|
||||
break;
|
||||
case "Ctrl+x":
|
||||
// Handle Ctrl+V
|
||||
break;
|
||||
case "Ctrl+z":
|
||||
// Handle Ctrl+V
|
||||
break;
|
||||
case "Ctrl+y":
|
||||
// Handle Ctrl+V
|
||||
break;
|
||||
case "Ctrl+a":
|
||||
docCon?.querySelectorAll("[data-tag-id]").forEach(tag => {
|
||||
tag.classList.add("border-2", "border-slate-800")
|
||||
tag.setAttribute("all-select-group", "true")
|
||||
|
||||
docCon.addEventListener("click", () => {
|
||||
console.log("focus in", tag)
|
||||
tag.classList.remove("border-2", "border-slate-800")
|
||||
tag.removeAttribute("all-select-group")
|
||||
})
|
||||
// docCon.addEventListener("focusout", () => {
|
||||
// console.log("focus out", tag)
|
||||
// tag.classList.remove("border-2", "border-slate-800")
|
||||
// tag.removeAttribute("all-select-group")
|
||||
// })
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
docCon?.querySelectorAll("[all-select-group]").forEach((tag) => {
|
||||
console.log(tag, "TAGID")
|
||||
})
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, [hotKeysObj])
|
||||
|
||||
const handleDocumentFocus = (key: string) => {
|
||||
const id = key.replace("_", "");
|
||||
const targetCon = document.getElementById(id);
|
||||
|
||||
targetCon?.addEventListener("keydown", (event) => {
|
||||
event.preventDefault();
|
||||
const ctrl = event.ctrlKey;
|
||||
const alt = event.altKey;
|
||||
const metaKey = event.metaKey;
|
||||
const shift = event.shiftKey;
|
||||
const pressedKey = event.key.toLowerCase();
|
||||
|
||||
let hotKey = pressedKey
|
||||
|
||||
|
||||
if (ctrl) {
|
||||
hotKey = "Ctrl+" + pressedKey;
|
||||
} else if (alt) {
|
||||
hotKey = "Alt" + pressedKey;
|
||||
} else if (metaKey) {
|
||||
hotKey = "Meta+" + pressedKey;
|
||||
} else if (shift) {
|
||||
hotKey = "Shift+" + pressedKey;
|
||||
}
|
||||
|
||||
setHotKeysObj({
|
||||
isActive: true,
|
||||
key: pressedKey,
|
||||
tagId: null,
|
||||
hotKey: hotKey
|
||||
});
|
||||
|
||||
groupIds.forEach((groupId) => {
|
||||
handleIGroupBorderPosition(groupId);
|
||||
});
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timeoutId);
|
||||
}, [droppedItems]); // Re-run when droppedItems changes
|
||||
|
||||
// return () => targetCon?.removeEventListener("keydown");
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -824,7 +445,8 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
selectedDocuments.length > 0 ? selectedDocuments.map((doc, indxDoc) => {
|
||||
return (
|
||||
<div key={indxDoc} className='flex flex-col'>
|
||||
<div className='py-2 text-sm'>
|
||||
<div
|
||||
className='py-2 text-sm'>
|
||||
<p className='text-center'>{doc.name}</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -834,8 +456,9 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
const key = `${doc.id}_${page.index}`;
|
||||
return (
|
||||
<div
|
||||
tabIndex={-1}
|
||||
onFocus={() => handleDocumentFocus(key)}
|
||||
key={indx}
|
||||
|
||||
id={`${doc.id}${indx}`}
|
||||
onDrop={(e) => handleDrop(e, doc.id, indxDoc, page.index)}
|
||||
onDragOver={handleDragOver}
|
||||
|
|
@ -844,11 +467,14 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ transactionSaving
|
|||
|
||||
<DroppedItemsTagsCon
|
||||
droppedItems={droppedItems}
|
||||
key={key}
|
||||
pageIdkey={key}
|
||||
selectedTag={selectedTag}
|
||||
selectedRecipients={selectedRecipients}
|
||||
setSelectedTag={setSelectedTag}
|
||||
setDroppedItems={setDroppedItems}
|
||||
accountId={accountId}
|
||||
transaction
|
||||
transactionId={transactionId}
|
||||
transactionTemplateToggle={transactionTemplateToggle}
|
||||
/>
|
||||
|
||||
<img
|
||||
|
|
|
|||
|
|
@ -1,25 +1,47 @@
|
|||
// Functions - START
|
||||
// handleTagClick
|
||||
// -- handleTagClick
|
||||
// -- handleRemoveTag
|
||||
// -- handleTagMouseDown
|
||||
// -- handleExpandTag
|
||||
// -- removeGroupBorders
|
||||
// -- handleIGroupBorderPosition
|
||||
// -- handleGroupBorderPosition
|
||||
// -- handleAddGroupItemClicked
|
||||
|
||||
|
||||
import React from 'react'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { DroppedItemsObj } from './DocumentContainer';
|
||||
import typeToIconMap from '../../../helper/iconMap';
|
||||
import { IoMdClose } from 'react-icons/io';
|
||||
import { IoAdd } from 'react-icons/io5';
|
||||
import { DroppedItem } from '../../../utlity/types';
|
||||
import { FaQuestionCircle } from 'react-icons/fa';
|
||||
import api from '../../../config/api';
|
||||
import { Recipient } from '../../../store/slices/selectedRecipientsSlice';
|
||||
|
||||
interface DroppedItemsTagsConProps {
|
||||
droppedItems: DroppedItemsObj;
|
||||
key: string;
|
||||
selectedTag: DroppedItem
|
||||
setSelectedTag: React.Dispatch<React.SetStateAction<DroppedItem>>;
|
||||
pageIdkey: string;
|
||||
selectedTag: { key: string; index: number } | null;
|
||||
selectedRecipients: Recipient[];
|
||||
setSelectedTag: React.Dispatch<React.SetStateAction<{ key: string; index: number } | null>>;
|
||||
setDroppedItems: React.Dispatch<React.SetStateAction<DroppedItemsObj>>;
|
||||
accountId: string;
|
||||
transactionId: string;
|
||||
transactionTemplateToggle: string;
|
||||
}
|
||||
|
||||
const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems, key, selectedTag, setSelectedTag }) => {
|
||||
const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({
|
||||
droppedItems,
|
||||
pageIdkey,
|
||||
selectedTag,
|
||||
selectedRecipients,
|
||||
setSelectedTag,
|
||||
setDroppedItems,
|
||||
accountId,
|
||||
transactionId,
|
||||
transactionTemplateToggle
|
||||
}) => {
|
||||
|
||||
const positionRef = useRef<{ left: number; top: number }>({ left: 0, top: 0 });
|
||||
|
||||
const handleTagClick = (key: string, index: number) => {
|
||||
setSelectedTag({ key, index })
|
||||
|
|
@ -127,10 +149,13 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
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;
|
||||
|
||||
positionRef.current = { left: event.clientX - containerRect.left - offsetX, top: event.clientY - containerRect.top - offsetY };
|
||||
|
||||
const conScrollWidth = targetContainer?.scrollWidth;
|
||||
const conScrollHeight = targetContainer?.scrollHeight;
|
||||
|
||||
|
|
@ -147,7 +172,7 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
handleGroupBorderPosition(groupElements, containerRect, offsetX, offsetY);
|
||||
}
|
||||
|
||||
let timeOut = null
|
||||
// let timeOut = null
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
// Get new X and Y positions relative to the container
|
||||
let left = event.clientX - containerRect.left - offsetX;
|
||||
|
|
@ -157,15 +182,23 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
left = Math.max(0, Math.min(left, conScrollWidth - elementRect.width));
|
||||
top = Math.max(0, Math.min(top, conScrollHeight - elementRect.height));
|
||||
|
||||
// Save in ref (fast, no re-render)
|
||||
positionRef.current = { left, top };
|
||||
|
||||
// Update DOM directly
|
||||
targetElement!.style.top = `${top}px`;
|
||||
targetElement!.style.left = `${left}px`;
|
||||
|
||||
// Apply the movement to the element first
|
||||
setDroppedItems(prevState => ({
|
||||
...prevState,
|
||||
[key]: Array.isArray(prevState[key])
|
||||
? prevState[key].map((item, i) =>
|
||||
i === index ? { ...item, dimensions: { ...item.dimensions, left, top }, update: true } : item
|
||||
)
|
||||
: [],
|
||||
}));
|
||||
// setDroppedItems(prevState => ({
|
||||
// ...prevState,
|
||||
// [key]: Array.isArray(prevState[key])
|
||||
// ? prevState[key].map((item, i) =>
|
||||
// i === index ? { ...item, dimensions: { ...item.dimensions, left, top }, update: true } : item
|
||||
// )
|
||||
// : [],
|
||||
// }));
|
||||
|
||||
// Update group border position during drag if it's a group element
|
||||
if (groupElements != null && groupElements.length) {
|
||||
// Use a small timeout to ensure DOM is updated before recalculating borders
|
||||
|
|
@ -198,6 +231,17 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
});
|
||||
}
|
||||
|
||||
const { left, top } = positionRef.current;
|
||||
setDroppedItems(prevState => ({
|
||||
...prevState,
|
||||
[key]: Array.isArray(prevState[key])
|
||||
? prevState[key].map((item, i) =>
|
||||
i === index ? { ...item, dimensions: { ...item.dimensions, left, top }, update: true } : item
|
||||
)
|
||||
: [],
|
||||
}));
|
||||
|
||||
|
||||
document.removeEventListener("pointermove", handleMouseMove);
|
||||
document.removeEventListener("pointerup", handleMouseUp);
|
||||
};
|
||||
|
|
@ -208,10 +252,279 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
};
|
||||
// HANDLE TAG MOUSE DOWN - END
|
||||
|
||||
// HANDLE EXPAND TAG - START
|
||||
const handleExpandTag = (event: React.MouseEvent<HTMLDivElement>, key: string, index: number) => {
|
||||
event.preventDefault(); // Prevent text selection issues
|
||||
|
||||
const expandingElemIcon = event.currentTarget;
|
||||
const targetElement = expandingElemIcon.nextElementSibling?.parentElement;
|
||||
const targetContainer = targetElement?.parentElement;
|
||||
|
||||
if (!targetContainer || !targetElement) return;
|
||||
|
||||
const elementRect = targetElement.getBoundingClientRect();
|
||||
|
||||
const startX = event.clientX;
|
||||
const startY = event.clientY;
|
||||
|
||||
const startWidth = elementRect.width;
|
||||
const startHeight = elementRect.height;
|
||||
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
|
||||
let newWidth = startWidth + (event.clientX - startX);
|
||||
let newHeight = startHeight + (event.clientY - startY);
|
||||
|
||||
if (newHeight > 200 || newWidth > 400) {
|
||||
if (newHeight > 200) {
|
||||
newHeight = 200
|
||||
}
|
||||
|
||||
if (newWidth > 400) {
|
||||
newWidth = 400
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the new width & height
|
||||
setDroppedItems({
|
||||
...droppedItems,
|
||||
[key]: Array.isArray(droppedItems[key]) // Ensure it's an array
|
||||
? droppedItems[key].map((item, i) =>
|
||||
i === index ? { ...item, dimensions: { ...item.dimensions, width: newWidth, height: newHeight }, update: true } : item
|
||||
)
|
||||
: [], // Provide a fallback in case it's undefined or not an array
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
document.removeEventListener("pointermove", handleMouseMove);
|
||||
document.removeEventListener("pointerup", handleMouseUp);
|
||||
};
|
||||
|
||||
document.addEventListener("pointermove", handleMouseMove);
|
||||
document.addEventListener("pointerup", handleMouseUp);
|
||||
};
|
||||
// HANDLE EXPAND TAG - END
|
||||
|
||||
const removeGroupBorders = (groupId: string) => {
|
||||
console.log(`Removing borders for group: ${groupId}`);
|
||||
|
||||
const borderPositions = ['top', 'right', 'bottom', 'left'];
|
||||
|
||||
borderPositions.forEach(position => {
|
||||
const borderElement = document.querySelector(`[border-group='${groupId}'][border-pos='${position}']`);
|
||||
if (borderElement && borderElement.parentNode) {
|
||||
borderElement.parentNode.removeChild(borderElement);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleIGroupBorderPosition = (groupId: string) => {
|
||||
const groupElements: NodeListOf<HTMLElement> = document.querySelectorAll(`div[group="${groupId}"]`);
|
||||
|
||||
if (groupElements.length === 0) {
|
||||
console.log("No group elements found for:", groupId);
|
||||
return;
|
||||
}
|
||||
|
||||
let targetContainer = groupElements[0].parentElement?.parentElement;
|
||||
|
||||
if (!targetContainer) {
|
||||
console.log("No target container found");
|
||||
return;
|
||||
}
|
||||
|
||||
const containerRect = targetContainer.getBoundingClientRect();
|
||||
|
||||
// Use consistent offset values
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
// Ensure DOM is fully updated before positioning
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
handleGroupBorderPosition(groupElements, containerRect, offsetX, offsetY);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleGroupBorderPosition = (groupElements: NodeListOf<HTMLElement>, containerRect: DOMRect, offsetX: number, offsetY: number) => {
|
||||
if (!groupElements || groupElements.length === 0) return;
|
||||
|
||||
const groupId = groupElements[0].getAttribute('group');
|
||||
if (!groupId) return;
|
||||
|
||||
// Calculate the bounding box of all group elements
|
||||
let minLeft = Infinity, minTop = Infinity, maxRight = -Infinity, maxBottom = -Infinity;
|
||||
|
||||
groupElements.forEach(element => {
|
||||
const parentElement = element.parentElement;
|
||||
if (!parentElement) return;
|
||||
|
||||
const rect = parentElement.getBoundingClientRect();
|
||||
const relativeLeft = rect.left - containerRect.left;
|
||||
const relativeTop = rect.top - containerRect.top;
|
||||
const relativeRight = relativeLeft + rect.width;
|
||||
const relativeBottom = relativeTop + rect.height;
|
||||
|
||||
minLeft = Math.min(minLeft, relativeLeft);
|
||||
minTop = Math.min(minTop, relativeTop);
|
||||
maxRight = Math.max(maxRight, relativeRight);
|
||||
maxBottom = Math.max(maxBottom, relativeBottom);
|
||||
});
|
||||
|
||||
// Add some padding around the group
|
||||
const padding = 10;
|
||||
minLeft -= padding;
|
||||
minTop -= padding;
|
||||
maxRight += padding;
|
||||
maxBottom += padding;
|
||||
|
||||
const width = maxRight - minLeft;
|
||||
const height = maxBottom - minTop;
|
||||
|
||||
// Update or create border elements
|
||||
const borderPositions = ['top', 'right', 'bottom', 'left'];
|
||||
|
||||
borderPositions.forEach(position => {
|
||||
let borderElement = document.querySelector(`[border-group='${groupId}'][border-pos='${position}']`) as HTMLElement;
|
||||
|
||||
if (!borderElement) {
|
||||
// Create border element if it doesn't exist
|
||||
borderElement = document.createElement('div');
|
||||
borderElement.className = `group-border ${position === 'bottom' ? 'bottom-border' : ''}`;
|
||||
borderElement.setAttribute('border-group', groupId);
|
||||
borderElement.setAttribute('border-pos', position);
|
||||
|
||||
// Add the + icon for bottom border
|
||||
if (position === 'bottom') {
|
||||
const addIcon = document.createElement('div');
|
||||
addIcon.innerHTML = '<IoAdd />'; // You might need to adjust this based on your icon system
|
||||
addIcon.onclick = () => {
|
||||
// Find the original item to pass to handleAddGroupItemClicked
|
||||
const originalItem = droppedItems[key]?.find(item => 'group' in item && item.group === groupId);
|
||||
if (originalItem) {
|
||||
handleAddGroupItemClicked(key, originalItem);
|
||||
}
|
||||
};
|
||||
borderElement.appendChild(addIcon);
|
||||
}
|
||||
|
||||
// Append to container
|
||||
groupElements[0].parentElement?.parentElement?.appendChild(borderElement);
|
||||
}
|
||||
|
||||
// Position the border element
|
||||
borderElement.style.position = 'absolute';
|
||||
borderElement.style.pointerEvents = position === 'bottom' ? 'auto' : 'none';
|
||||
|
||||
switch (position) {
|
||||
case 'top':
|
||||
borderElement.style.left = `${minLeft}px`;
|
||||
borderElement.style.top = `${minTop}px`;
|
||||
borderElement.style.width = `${width}px`;
|
||||
borderElement.style.height = '2px';
|
||||
break;
|
||||
case 'right':
|
||||
borderElement.style.left = `${maxRight - 2}px`;
|
||||
borderElement.style.top = `${minTop}px`;
|
||||
borderElement.style.width = '2px';
|
||||
borderElement.style.height = `${height}px`;
|
||||
break;
|
||||
case 'bottom':
|
||||
borderElement.style.left = `${minLeft}px`;
|
||||
borderElement.style.top = `${maxBottom - 2}px`;
|
||||
borderElement.style.width = `${width}px`;
|
||||
borderElement.style.height = '2px';
|
||||
break;
|
||||
case 'left':
|
||||
borderElement.style.left = `${minLeft}px`;
|
||||
borderElement.style.top = `${minTop}px`;
|
||||
borderElement.style.width = '2px';
|
||||
borderElement.style.height = `${height}px`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddGroupItemClicked = (key: string, item: any) => {
|
||||
const groupId = item.group;
|
||||
|
||||
// Find all existing items in this group to determine the bottom-most position
|
||||
const existingGroupItems = droppedItems[key]?.filter(existingItem =>
|
||||
'group' in existingItem && existingItem.group === groupId
|
||||
) || [];
|
||||
|
||||
const existingGroupItem = droppedItems[key]?.filter(existingItem =>
|
||||
'group' in existingItem && existingItem.group === groupId
|
||||
) || [];
|
||||
|
||||
existingGroupItem[0].options
|
||||
|
||||
// Find the bottom-most item in the group
|
||||
let bottomMostItem = item;
|
||||
if (existingGroupItems.length > 0) {
|
||||
bottomMostItem = existingGroupItems.reduce((lowest, current) => {
|
||||
const currentBottom = current.dimensions.top + current.dimensions.height;
|
||||
const lowestBottom = lowest.dimensions.top + lowest.dimensions.height;
|
||||
return currentBottom > lowestBottom ? current : lowest;
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate new position: place below the bottom-most item
|
||||
const spacing = 10; // Adjust spacing as needed
|
||||
const newTop = bottomMostItem.dimensions.top + bottomMostItem.dimensions.height + spacing;
|
||||
|
||||
// Use the same left position as the parent (original) item
|
||||
const newItem = {
|
||||
...item,
|
||||
dimensions: {
|
||||
...item.dimensions,
|
||||
left: item.dimensions.left, // Keep same horizontal position as parent
|
||||
top: newTop // Position below the bottom-most item
|
||||
},
|
||||
isGroupExist: true
|
||||
};
|
||||
|
||||
// Update the dropped items
|
||||
setDroppedItems({
|
||||
...droppedItems,
|
||||
[key]: [...droppedItems[key], newItem],
|
||||
});
|
||||
|
||||
// Update group borders after adding the new item
|
||||
// Use setTimeout to ensure state update is processed
|
||||
setTimeout(() => {
|
||||
handleIGroupBorderPosition(groupId);
|
||||
}, 50); // Slightly longer timeout to ensure DOM updates
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize group borders for all existing groups after component updates
|
||||
const timeoutId = setTimeout(() => {
|
||||
const allGroupElements = document.querySelectorAll('[group]');
|
||||
const groupIds = new Set<string>();
|
||||
|
||||
allGroupElements.forEach((element) => {
|
||||
const groupId = element.getAttribute('group');
|
||||
if (groupId) {
|
||||
groupIds.add(groupId);
|
||||
}
|
||||
});
|
||||
|
||||
groupIds.forEach((groupId) => {
|
||||
handleIGroupBorderPosition(groupId);
|
||||
});
|
||||
}, 0);
|
||||
|
||||
return () => clearTimeout(timeoutId);
|
||||
}, [droppedItems]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* DROPPED ITEMS - Render only the dropped items for this specific docId and page - STARTS */}
|
||||
{droppedItems[key]?.map((item, index) => {
|
||||
{droppedItems[pageIdkey]?.map((item, index) => {
|
||||
if (item.isDeleted) return;
|
||||
|
||||
const type = item.type.toUpperCase();
|
||||
|
|
@ -222,8 +535,10 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
<div
|
||||
// key={index}
|
||||
draggable="false"
|
||||
data-tag-id={index}
|
||||
data-tag-selected={index === selectedTag?.index}
|
||||
className="absolute rounded dropped-item"
|
||||
onClick={() => handleTagClick(key, index)}
|
||||
onClick={() => handleTagClick(pageIdkey, index)}
|
||||
style={{
|
||||
left: `${item.dimensions.left}px`,
|
||||
top: `${item.dimensions.top}px`,
|
||||
|
|
@ -234,7 +549,7 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
|
||||
|
||||
{/* If Selected Tag Recipient Info- START */}
|
||||
{selectedTag?.key && selectedTag.key === key && selectedTag.index === index &&
|
||||
{selectedTag?.key && selectedTag.key === pageIdkey && 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'
|
||||
|
|
@ -246,18 +561,16 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
<p className='capitalize text-ellipsis whitespace-nowrap'>{item.label}</p>
|
||||
<IoMdClose onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemoveTag(key, index)
|
||||
handleRemoveTag(pageIdkey, index)
|
||||
}} className='cursor-pointer' />
|
||||
</div>
|
||||
</div>}
|
||||
{/* If Selected Tag Recipient Info- END */}
|
||||
|
||||
|
||||
|
||||
|
||||
{/* Expand Circle - STARTS */}
|
||||
{item.type !== "radio" && item.type !== "checkbox" && <div
|
||||
onPointerDown={(e) => handleExpandTag(e, key, index)}
|
||||
onPointerDown={(e) => handleExpandTag(e, pageIdkey, 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 */}
|
||||
|
|
@ -266,7 +579,7 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
{
|
||||
<div
|
||||
{...("group" in item && item.group ? { "group": item.group } : {})}
|
||||
onPointerDown={(e) => handleTagMouseDown(e, key, index)}
|
||||
onPointerDown={(e) => handleTagMouseDown(e, pageIdkey, index)}
|
||||
className='p-2 rounded-sm h-full shadow opacity-40 cursor-grab w-full'
|
||||
style={{ background: selectedRecipient[0]?.color }}
|
||||
>
|
||||
|
|
@ -290,7 +603,7 @@ const DroppedItemsTagsCon: React.FC<DroppedItemsTagsConProps> = ({ droppedItems,
|
|||
<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)}>
|
||||
onClick={() => handleAddGroupItemClicked(pageIdkey, item)}>
|
||||
<IoAdd />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx
|
|||
const priorityOrder = ['SIGNATURE', 'INITIALS', 'STAMP'];
|
||||
|
||||
const data = res.data.filter((obj, indx) => {
|
||||
if (obj.type === "STAMP" || obj.type === "RADIO" || obj.type === "CHECKBOX" || obj.type === "ATTACHMENT") return false
|
||||
// if (obj.type === "STAMP" || obj.type === "RADIO" || obj.type === "CHECKBOX" || obj.type === "ATTACHMENT") return false
|
||||
return true
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -128,10 +128,10 @@ const NavTwo: React.FC<NavTwoProps> = ({ transactionSaving, isFields, setIsField
|
|||
setTimeout(() => {
|
||||
if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS) {
|
||||
if (isSignSend) {
|
||||
// window.open(`./../../../sign/${selfUserSign.recipientId}`, "_self");
|
||||
window.open(`./../../../sign/${selfUserSign.recipientId}`, "_self");
|
||||
}
|
||||
else {
|
||||
// navigate(`/document-completion-screen/${accountId}/${transactionId}`, { replace: true })
|
||||
navigate(`/document-completion-screen/${accountId}/${transactionId}`, { replace: true })
|
||||
}
|
||||
} else {
|
||||
navigate(`/templates`);
|
||||
|
|
|
|||
|
|
@ -119,11 +119,6 @@ const RightSideBar: React.FC<DroppedItemProps> = ({ droppedItems, selectedTag, s
|
|||
};
|
||||
});
|
||||
} else {
|
||||
// setDroppedItems((prev) => {
|
||||
// const updated = [...prev];
|
||||
// updated[selTagIndx] = { ...updated[selTagIndx], [changeTo]: changeWith, update: true }
|
||||
// return updated;
|
||||
// })
|
||||
setDroppedItems((prev) => {
|
||||
return (prev.map((item, idx) => {
|
||||
if (idx === selTagIndx) {
|
||||
|
|
@ -297,18 +292,20 @@ const RightSideBar: React.FC<DroppedItemProps> = ({ droppedItems, selectedTag, s
|
|||
<RecipientsAttrCon selectedRecipientId={selectedTag.recipientId} handlePropertyChange={handlePropertyChange} />
|
||||
<DirectionalControls {...DirectionalControlsProps} selectedType={selectedTag.dimensions} />
|
||||
|
||||
{selectedTag.label &&
|
||||
<LabelAttr label={selectedTag.label} handlePropertyChange={handlePropertyChange} />}
|
||||
|
||||
<ToolTipAttr tooltip={selectedTag.tooltip ?? ""} handlePropertyChange={handlePropertyChange} />
|
||||
|
||||
{
|
||||
(selectedTag.type !== TagsTypes.SIGNATURE && selectedTag.type !== TagsTypes.INITIALS) &&
|
||||
<RequiredAttr required={selectedTag.required ? selectedTag.required : false} handlePropertyChange={handlePropertyChange} />
|
||||
}
|
||||
|
||||
{selectedTag.type.toLowerCase() === TagsTypes.TEMPORAL &&
|
||||
<CurrTimeStampAttr type={selectedTag.type} handlePropertyChange={handlePropertyChange} />}
|
||||
{
|
||||
selectedTag.type.toLowerCase() === TagsTypes.TEMPORAL &&
|
||||
<CurrTimeStampAttr type={selectedTag.type} handlePropertyChange={handlePropertyChange} />
|
||||
}
|
||||
|
||||
{selectedTag.label &&
|
||||
<LabelAttr label={selectedTag.label} handlePropertyChange={handlePropertyChange} />}
|
||||
|
||||
<ToolTipAttr tooltip={selectedTag.tooltip ?? ""} handlePropertyChange={handlePropertyChange} />
|
||||
|
||||
{
|
||||
selectedType && Object.keys(selectedType).length > 0 &&
|
||||
|
|
@ -361,7 +358,7 @@ const RightSideBar: React.FC<DroppedItemProps> = ({ droppedItems, selectedTag, s
|
|||
{
|
||||
selectedTag?.type.toLowerCase() === TagsTypes.NUMBER &&
|
||||
<div>
|
||||
<label htmlFor="" className="">Decimal Places</label>
|
||||
<label htmlFor="" className="font-medium">Decimal Places</label>
|
||||
<input
|
||||
type="number"
|
||||
onChange={(e) => handleDecimalPlace(e)}
|
||||
|
|
@ -392,7 +389,7 @@ const RightSideBar: React.FC<DroppedItemProps> = ({ droppedItems, selectedTag, s
|
|||
onClick={() => setStyleOpen(!styleOpen)}
|
||||
>
|
||||
<label
|
||||
className="block mb-2">Styles</label>
|
||||
className="block mb-2 font-medium">Styles</label>
|
||||
<IoIosArrowDown className={`${styleOpen ? "rotate-[-90deg]" : ""} transition-all`} />
|
||||
</div>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ const CommonAttrDropDown: React.FC<CommonAttrDropDownInt> = ({ selectedType, sel
|
|||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<label htmlFor="" className="">Type</label>
|
||||
<label htmlFor="" className="font-medium">Type</label>
|
||||
<div
|
||||
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.TYPE ? null : DROPDOWNTOGGLE.TYPE)}
|
||||
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ const CurrTimeStampAttr: React.FC<CurrTimeStampAttrInt> = ({ type, handlePropert
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-left items-center gap-1.5 mt-0.5">
|
||||
<div className="flex justify-between items-center border-1 p-1.5 rounded-sm border-slate-200">
|
||||
<label
|
||||
className={`text-xs ${isCurrentTimeStamp ? "text-slate-600" : "text-slate-400"} transitions-all duration-150`}
|
||||
className="text-slate-600 transitions-all duration-150 font-medium"
|
||||
htmlFor="use_current_timestamp"
|
||||
>
|
||||
Use Current Timestamp
|
||||
|
|
|
|||
|
|
@ -73,24 +73,27 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
|
|||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (disabled) return;
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowUp':
|
||||
case 'ArrowDown':
|
||||
case 'ArrowLeft':
|
||||
case 'ArrowRight':
|
||||
event.preventDefault();
|
||||
handleMove(event.key.replace('Arrow', '').toLowerCase() as any);
|
||||
break;
|
||||
}
|
||||
};
|
||||
// Move ON Key Down - START
|
||||
// useEffect(() => {
|
||||
// const handleKeyDown = (event: KeyboardEvent) => {
|
||||
// if (disabled) return;
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [disabled, stepSize]);
|
||||
// switch (event.key) {
|
||||
// case 'ArrowUp':
|
||||
// case 'ArrowDown':
|
||||
// case 'ArrowLeft':
|
||||
// case 'ArrowRight':
|
||||
// event.preventDefault();
|
||||
// handleMove(event.key.replace('Arrow', '').toLowerCase() as any);
|
||||
// break;
|
||||
// }
|
||||
// };
|
||||
|
||||
// window.addEventListener('keydown', handleKeyDown);
|
||||
// return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
// }, [disabled, stepSize]);
|
||||
// Move ON Key Down - END
|
||||
|
||||
const buttonClass = `
|
||||
w-8 h-8 flex items-center justify-center rounded-full border shadow-sm text-[12px]
|
||||
|
|
@ -124,7 +127,7 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
|
|||
<input
|
||||
type="number"
|
||||
value={leftValue}
|
||||
onChange={(e) => {e.preventDefault; handlePositionInputChange('left', e.target.value)}}
|
||||
onChange={(e) => { e.preventDefault; handlePositionInputChange('left', e.target.value) }}
|
||||
onBlur={() => handlePositionInputBlur('left')}
|
||||
onKeyPress={(e) => handleKeyPress(e, 'left')}
|
||||
disabled={disabled}
|
||||
|
|
@ -134,7 +137,7 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
|
|||
<input
|
||||
type="number"
|
||||
value={topValue}
|
||||
onChange={(e) => {e.preventDefault; handlePositionInputChange('top', e.target.value)}}
|
||||
onChange={(e) => { e.preventDefault; handlePositionInputChange('top', e.target.value) }}
|
||||
onBlur={() => handlePositionInputBlur('top')}
|
||||
onKeyPress={(e) => handleKeyPress(e, 'top')}
|
||||
disabled={disabled}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const LabelAttr: React.FC<LabelAttrInt> = ({ label, handlePropertyChange }) => {
|
|||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<label>Label</label>
|
||||
<label className='font-medium'>Label</label>
|
||||
<input
|
||||
value={label}
|
||||
onChange={(e) => handlePropertyChange('label', e.target.value)}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ const MaxMinLenAttr: React.FC<MaxMinLenAttrIntr> = ({ maxLength, minLength, hand
|
|||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<label htmlFor="maxLength">Max Length</label>
|
||||
<div className="flex flex-col">
|
||||
<label className="font-medium" htmlFor="maxLength">Max Length</label>
|
||||
<input
|
||||
id="maxLength"
|
||||
value={maxLength}
|
||||
|
|
@ -50,8 +50,8 @@ const MaxMinLenAttr: React.FC<MaxMinLenAttrIntr> = ({ maxLength, minLength, hand
|
|||
onChange={handleMaxChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<label htmlFor="minLength">Min Length</label>
|
||||
<div className="flex flex-col">
|
||||
<label className="font-medium" htmlFor="minLength">Min Length</label>
|
||||
<input
|
||||
id="minLength"
|
||||
value={minLength}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ interface RequiredAttrInt {
|
|||
|
||||
const RequiredAttr : React.FC<RequiredAttrInt> = ({required, handlePropertyChange}) => {
|
||||
return (
|
||||
<div className="flex justify-between items-center">
|
||||
<label htmlFor="required" className="text-xs text-slate-600 transitions-all duration-150">Required</label>
|
||||
<div className="flex justify-between items-center border-1 p-1.5 rounded-sm border-slate-200">
|
||||
<label htmlFor="required" className="text-slate-600 transitions-all duration-150 font-medium">Required</label>
|
||||
<input
|
||||
id="required"
|
||||
checked={required ? required : false}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ const SelectTagAttr: React.FC<SelectTagAttrInt> = ({ options, selTagKey, selTagI
|
|||
return (
|
||||
<>
|
||||
<div>
|
||||
<label htmlFor="" className="">Add Options</label>
|
||||
<label htmlFor="" className="font-medium">Add Options</label>
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => setSelectedOption({ label: e.target.value, value: e.target.value })}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ const TemporalDateAttr: React.FC<TemporalDateAttrInt> = ({ dateFormat, format, s
|
|||
return (
|
||||
<div>
|
||||
<div className="flex justify-between">
|
||||
<label htmlFor="" className="">Formats</label>
|
||||
<label htmlFor="" className="font-medium">Formats</label>
|
||||
{(dateFormat === TEMPORAL.DATE_TIME || dateFormat === TEMPORAL.TIME) &&
|
||||
<div className="flex justify-center items-center gap-1.5">
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const ToolTipAttr: React.FC<ToolTipAttrInt> = ({ tooltip, handlePropertyChange }
|
|||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<label>ToolTip</label>
|
||||
<label className='font-medium'>ToolTip</label>
|
||||
<input
|
||||
value={tooltip}
|
||||
onChange={(e) => handlePropertyChange('tooltip', e.target.value)}
|
||||
|
|
|
|||
Loading…
Reference in New Issue