From 4a5ede2891f7c353c03fe606d5feb91f209d41bb Mon Sep 17 00:00:00 2001 From: =bhagwanSingh <=bhagwan.r@hicglobalsolutions.com> Date: Tue, 29 Jul 2025 16:38:32 +0530 Subject: [PATCH 1/6] Added Tour --- package-lock.json | 145 ++++++ package.json | 1 + src/App.tsx | 119 ++--- src/components/CommonNav.tsx | 11 +- src/components/client/DocumentPages.tsx | 2 +- src/components/client/SignDocument.tsx | 53 ++- src/components/dashboard/SendForSign.tsx | 4 +- src/components/dashboard/SideBar.tsx | 4 +- src/components/home/StartNow.tsx | 1 + .../process/processStepOne/ProcessStepOne.tsx | 20 +- .../processStepOne/RecipientAddCard.tsx | 1 + .../process/processStepOne/RecipientCards.tsx | 18 +- .../processStepOne/SelectedDocuments.tsx | 4 +- .../processStepTwo/DocumentContainer.tsx | 444 +++++++----------- .../process/processStepTwo/LeftSideBar.tsx | 7 +- .../process/processStepTwo/NavTwo.tsx | 1 + .../rightSideBar/DirectionalControls.tsx | 179 +++---- .../rightSideBar/RightSideBar.tsx | 66 +-- .../rightSideBar/SelectTagAttr.tsx | 55 +-- .../rightSideBar/TemporalDateAttr.tsx | 10 +- src/utlity/JoyRideTour.tsx | 244 ++++++++++ 21 files changed, 853 insertions(+), 536 deletions(-) create mode 100644 src/utlity/JoyRideTour.tsx diff --git a/package-lock.json b/package-lock.json index 8a15b3b..3c842d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "react-draggable": "^4.4.6", "react-icons": "^5.5.0", "react-id-generator": "^3.0.2", + "react-joyride": "^2.9.3", "react-redux": "^9.2.0", "react-router-dom": "^7.2.0", "react-sortablejs": "^6.1.4", @@ -921,6 +922,12 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@gilbarbara/deep-equal": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@gilbarbara/deep-equal/-/deep-equal-0.3.1.tgz", + "integrity": "sha512-I7xWjLs2YSVMc5gGx1Z3ZG1lgFpITPndpi8Ku55GeEIKpACCPQNS/OTqQbxgTCfq0Ncvcc+CrFov96itVh6Qvw==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -2658,6 +2665,12 @@ } } }, + "node_modules/deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2665,6 +2678,15 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3438,6 +3460,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-lite": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-1.2.1.tgz", + "integrity": "sha512-pgF+L5bxC+10hLBgf6R2P4ZZUBOQIIacbdo8YvuCP8/JvsWxG7aZ9p10DYuLtifFci4l3VITphhMlMV4Y+urPw==", + "license": "MIT" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4163,6 +4191,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -4323,12 +4362,84 @@ "react": ">= 16.8.0" } }, + "node_modules/react-innertext": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/react-innertext/-/react-innertext-1.1.5.tgz", + "integrity": "sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": ">=0.0.0 <=99", + "react": ">=0.0.0 <=99" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/react-joyride": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/react-joyride/-/react-joyride-2.9.3.tgz", + "integrity": "sha512-1+Mg34XK5zaqJ63eeBhqdbk7dlGCFp36FXwsEvgpjqrtyywX2C6h9vr3jgxP0bGHCw8Ilsp/nRDzNVq6HJ3rNw==", + "license": "MIT", + "dependencies": { + "@gilbarbara/deep-equal": "^0.3.1", + "deep-diff": "^1.0.2", + "deepmerge": "^4.3.1", + "is-lite": "^1.2.1", + "react-floater": "^0.7.9", + "react-innertext": "^1.1.5", + "react-is": "^16.13.1", + "scroll": "^3.0.1", + "scrollparent": "^2.1.0", + "tree-changes": "^0.11.2", + "type-fest": "^4.27.0" + }, + "peerDependencies": { + "react": "15 - 18", + "react-dom": "15 - 18" + } + }, + "node_modules/react-joyride/node_modules/react-floater": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/react-floater/-/react-floater-0.7.9.tgz", + "integrity": "sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg==", + "license": "MIT", + "dependencies": { + "deepmerge": "^4.3.1", + "is-lite": "^0.8.2", + "popper.js": "^1.16.0", + "prop-types": "^15.8.1", + "tree-changes": "^0.9.1" + }, + "peerDependencies": { + "react": "15 - 18", + "react-dom": "15 - 18" + } + }, + "node_modules/react-joyride/node_modules/react-floater/node_modules/@gilbarbara/deep-equal": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@gilbarbara/deep-equal/-/deep-equal-0.1.2.tgz", + "integrity": "sha512-jk+qzItoEb0D0xSSmrKDDzf9sheQj/BAPxlgNxgmOaA3mxpUa6ndJLYGZKsJnIVEQSD8zcTbyILz7I0HcnBCRA==", + "license": "MIT" + }, + "node_modules/react-joyride/node_modules/react-floater/node_modules/is-lite": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-0.8.2.tgz", + "integrity": "sha512-JZfH47qTsslwaAsqbMI3Q6HNNjUuq6Cmzzww50TdP5Esb6e1y2sK2UAaZZuzfAzpoI2AkxoPQapZdlDuP6Vlsw==", + "license": "MIT" + }, + "node_modules/react-joyride/node_modules/react-floater/node_modules/tree-changes": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.9.3.tgz", + "integrity": "sha512-vvvS+O6kEeGRzMglTKbc19ltLWNtmNt1cpBoSYLj/iEcPVvpJasemKOlxBrmZaCtDJoF+4bwv3m01UKYi8mukQ==", + "license": "MIT", + "dependencies": { + "@gilbarbara/deep-equal": "^0.1.1", + "is-lite": "^0.8.2" + } + }, "node_modules/react-redux": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", @@ -4623,6 +4734,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/scroll": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scroll/-/scroll-3.0.1.tgz", + "integrity": "sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg==", + "license": "MIT" + }, + "node_modules/scrollparent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.1.0.tgz", + "integrity": "sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA==", + "license": "ISC" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -4890,6 +5013,16 @@ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", "license": "MIT" }, + "node_modules/tree-changes": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.11.3.tgz", + "integrity": "sha512-r14mvDZ6tqz8PRQmlFKjhUVngu4VZ9d92ON3tp0EGpFBE6PAHOq8Bx8m8ahbNoGE3uI/npjYcJiqVydyOiYXag==", + "license": "MIT", + "dependencies": { + "@gilbarbara/deep-equal": "^0.3.1", + "is-lite": "^1.2.1" + } + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -4934,6 +5067,18 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", diff --git a/package.json b/package.json index 5343a7b..020c2a9 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "react-draggable": "^4.4.6", "react-icons": "^5.5.0", "react-id-generator": "^3.0.2", + "react-joyride": "^2.9.3", "react-redux": "^9.2.0", "react-router-dom": "^7.2.0", "react-sortablejs": "^6.1.4", diff --git a/src/App.tsx b/src/App.tsx index 5270316..f0e6439 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { BrowserRouter, Route, Routes } from "react-router-dom" +import { BrowserRouter, Route, Routes, useLocation } from "react-router-dom" import Dashboard from "./components/dashboard/Dashboard" import Home from "./components/home/Home" import Login from "./components/login/Login"; @@ -20,81 +20,90 @@ import Account from "./components/accounts/Account"; import TransactionView from "./components/transactions/TransactionView"; import Templates from "./components/templates/Templates"; import DocumentCompletionScreen from "./components/process/CompletionScreen/DocumentCompletionScreen"; +import JoyrideController from "./utlity/JoyRideTour"; const App = () => { + return ( - - {/* */} - + <> + - + {/* */} + - - - - }> - } /> - {/* } /> */} - {/* }> */} + + + + + + }> + } /> + {/* } /> */} + {/* }> */} } /> } /> } /> } /> {/* } /> */} } /> - {/* */} + {/* */} - } /> - + } /> + - - - - } /> + + + + } /> - - - - } /> + + + + } /> - - - - } /> + + + + } /> - - - - } /> + + + + } /> - - - - } /> + + + + } /> - - - - } /> + + + + } /> - {/* Links work wothout Login */} - } /> - } /> - } /> - } /> + {/* Links work wothout Login */} + } /> + } /> + } /> + } /> - {/* Links work wothout Login */} - + {/* Links work wothout Login */} + + + + + {/* */} + + + - {/* */} - ) } diff --git a/src/components/CommonNav.tsx b/src/components/CommonNav.tsx index f128de9..38732d7 100644 --- a/src/components/CommonNav.tsx +++ b/src/components/CommonNav.tsx @@ -152,7 +152,7 @@ const CommonNav: React.FC = () => { if (item) { const userData = { id: item?.id, - name : item?.firstName + " " + item?.lastName , + name: item?.firstName + " " + item?.lastName, email: item?.email, language: "", account: { @@ -162,15 +162,15 @@ const CommonNav: React.FC = () => { }, }; - console.log("userData",userData) + console.log("userData", userData) - setUser(userData); + setUser(userData); sessionStorage.setItem('userDetails', JSON.stringify(userData)); sessionStorage.setItem('activeAccountId', JSON.stringify(userData.account.id)); - + // Dispatch event for initial load dispatchSessionStorageChange('activeAccountId', userData.account.id); - + console.log("Data is saved in sessionStorage"); } @@ -295,6 +295,7 @@ const CommonNav: React.FC = () => {
diff --git a/src/components/process/processStepOne/RecipientAddCard.tsx b/src/components/process/processStepOne/RecipientAddCard.tsx index 8711c50..3157d3c 100644 --- a/src/components/process/processStepOne/RecipientAddCard.tsx +++ b/src/components/process/processStepOne/RecipientAddCard.tsx @@ -159,6 +159,7 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase ,
{transactionTemplateToggle === 'templates' && ( diff --git a/src/components/process/processStepOne/RecipientCards.tsx b/src/components/process/processStepOne/RecipientCards.tsx index 3492139..cecb18d 100644 --- a/src/components/process/processStepOne/RecipientCards.tsx +++ b/src/components/process/processStepOne/RecipientCards.tsx @@ -59,15 +59,15 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg const handleRemoveRecipient = (recipient) => { if (!accountId || !transactionId) return; -<<<<<<< HEAD +// <<<<<<< HEAD // dispatch(removeSelectedRecipient(recipient)) - dispatch(removeRecipientAsync([{ - recipientId: recipient.id, - email: recipient.email, - accountId: accountId, - transactionId: transactionId, - }])) -======= + // dispatch(removeRecipientAsync([{ + // recipientId: recipient.id, + // email: recipient.email, + // accountId: accountId, + // transactionId: transactionId, + // }])) +// ======= if (recipient.uuid) { dispatch(removeSelectedRecipient(recipient)) } else { @@ -78,7 +78,7 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg transactionId: transactionId, })) } ->>>>>>> origin/main +// >>>>>>> origin/main if (recipients.length === 2) { let leftRecipient = recipients.filter((obj) => { if ("id" in obj && "id" in recipient) { diff --git a/src/components/process/processStepOne/SelectedDocuments.tsx b/src/components/process/processStepOne/SelectedDocuments.tsx index fc92937..9aa6829 100644 --- a/src/components/process/processStepOne/SelectedDocuments.tsx +++ b/src/components/process/processStepOne/SelectedDocuments.tsx @@ -87,7 +87,9 @@ const SelectedDocuments = ({transactionTemplateToggle}) => { return ( <> {/* Upload Card First */} -
+
{/* Uploaded documents */} = ({ isSend }) => { // const selectedDocuments = useSelector((state: RootState) => state.selectedDocuments.selectedDocuments) const selectedDocuments = useSelector((state: RootState) => state.documents.documents) - console.log("selectedDocuments",selectedDocuments) + console.log("selectedDocuments", selectedDocuments) const [droppedItems, setDroppedItems] = useState({}); console.log("droppedItems", droppedItems) @@ -190,7 +191,7 @@ const DocumentContainer: React.FC = ({ isSend }) => { useEffect(() => { if (isSend === null) return; - // dispatch(showLoader("Creating Transaction")) + dispatch(showLoader("Loading ...")) let updatedTags = { ...droppedItems } @@ -209,7 +210,6 @@ const DocumentContainer: React.FC = ({ isSend }) => { for (const dropTag of updatedTags[dropPageIds]) { let mask = null - // console.log(dropTag, "line 132") // if (dropTag.subType?.toLowerCase() === "password") { @@ -248,8 +248,8 @@ const DocumentContainer: React.FC = ({ isSend }) => { "color": "black", "textSize": 0 }, - // "required": (dropTag.type.toUpperCase() !== "SIGNATURE" && dropTag.type.toUpperCase() !== "INITIALS") ? dropTag.required : true, - "required": "required" in dropTag ? dropTag.required : true, + "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, } @@ -292,13 +292,17 @@ const DocumentContainer: React.FC = ({ isSend }) => { // for(const recipient of selectedRecipients) { // const recrecipient // } + + tagsData = groupByRecipientId(tagsData); + sendTagsToRecipients(tagsData, accountId, transactionId); (async () => { 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") + dispatch(hideLoader()) })() }, [isSend]) // Save Tags - END @@ -331,6 +335,19 @@ const DocumentContainer: React.FC = ({ isSend }) => { const key = `${docId}_${pageIndex}`; // const IconComponent = typeToIconMap[field.type] || ; + // Handling Initia Width and height of Some tags - START + if (dragElemData.label === TagsTypes.STAMP) { + dragElemData.width = 160 + dragElemData.height = 160 + } else if (dragElemData.label === TagsTypes.SIGNATURE) { + dragElemData.width = 200 + dragElemData.height = 75 + } else if (dragElemData.label === TagsTypes.INITIALS) { + dragElemData.width = 85 + dragElemData.height = 75 + } + // Handling Initia Width and height of Some tags - END + let prepData = { properties: data.properties, icon: typeToIconMap[field.label.toUpperCase()] || , @@ -355,6 +372,7 @@ const DocumentContainer: React.FC = ({ isSend }) => { pageIndex: pageIndex, recipientId: dragElemData.recipientId, recipientIndx: dragElemData.recipientIndx, + required: (dragElemData.label !== TagsTypes.SIGNATURE && dragElemData.label !== TagsTypes.INITIALS) ? false : true, update: true, isDeleted: false } @@ -726,104 +744,104 @@ const DocumentContainer: React.FC = ({ isSend }) => { }; // Enhanced handleGroupBorderPosition with better positioning logic -const handleGroupBorderPosition = (groupElements: NodeListOf, 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 = ''; // 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); + const handleGroupBorderPosition = (groupElements: NodeListOf, 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 = ''; // 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); } - - // 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; - } - }); -}; + + // 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); @@ -835,6 +853,12 @@ const handleGroupBorderPosition = (groupElements: NodeListOf, conta '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) { @@ -875,131 +899,27 @@ const handleGroupBorderPosition = (groupElements: NodeListOf, conta useEffect(() => { - // Initialize group borders for all existing groups after component updates - const timeoutId = setTimeout(() => { - const allGroupElements = document.querySelectorAll('[group]'); - const groupIds = new Set(); - - allGroupElements.forEach((element) => { - const groupId = element.getAttribute('group'); - if (groupId) { - groupIds.add(groupId); - } - }); - - groupIds.forEach((groupId) => { - handleIGroupBorderPosition(groupId); - }); - }, 100); - - return () => clearTimeout(timeoutId); -}, [droppedItems]); // Re-run when droppedItems changes + // Initialize group borders for all existing groups after component updates + const timeoutId = setTimeout(() => { + const allGroupElements = document.querySelectorAll('[group]'); + const groupIds = new Set(); + + allGroupElements.forEach((element) => { + const groupId = element.getAttribute('group'); + if (groupId) { + groupIds.add(groupId); + } + }); + + groupIds.forEach((groupId) => { + handleIGroupBorderPosition(groupId); + }); + }, 100); + + return () => clearTimeout(timeoutId); + }, [droppedItems]); // Re-run when droppedItems changes - - // const handleAddRadio = (e: React.MouseEvent, key: string, index: number) => { - // // const dataToSet: DroppedItemsObj = { - // // ...droppedItems, - // // [key]: [...(droppedItems[key] || []), - // // { - // // ...prepData, - // // radioGroups: dragElemData.label === "radio" ? [{ ...prepData }] : [] - // // }], - // // } - - // // const lastRadioElemRect = e.currentTarget?.parentElement.previousSibling.getBoundingClientRect(); - // // console.log(lastRadioElemRect, "lastRadioElemRect") - - // const setNewData = droppedItems; - - // if (Array.isArray(setNewData[key][index].radioGroups) && setNewData[key][index].radioGroups?.length > 0) { - // setNewData[key][index].radioGroups?.push(setNewData[key][index].radioGroups[0]) - // } - - // setDroppedItems(setNewData); - // }; - - - - // const handleRadioTagMouseDown = (event: React.MouseEvent, key: string, index: number, radioIndex: number) => { - - // event.preventDefault(); - - // let targetContainer = event?.currentTarget?.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 handleMouseMove = (event: PointerEvent) => { - // // Get new X and Y positions relative to the container - // // let x = offsetX; - // // let y = offsetY; - - // let x = event.clientX - elementRect.left; - // let y = event.clientY - elementRect.top; - - // const newData = droppedItems; - - // 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.top = y; - - // let topMin = Number.POSITIVE_INFINITY; - // let topMax = Number.NEGATIVE_INFINITY; - // let leftMin = Number.POSITIVE_INFINITY; - // let leftMax = Number.NEGATIVE_INFINITY; - - // for (const radio of newData[key][index].radioGroups) { - // if (radio.dimensions.left < leftMin) { - // leftMin = radio.dimensions.left; - // } - // if (radio.dimensions.left > leftMax) { - // leftMax = radio.dimensions.left; - // } - // if (radio.dimensions.top < topMin) { - // topMin = radio.dimensions.top; - // } - // if (radio.dimensions.top > topMax) { - // topMax = radio.dimensions.top; - // } - // } - - // newData[key][index].radioPosition = { - // topMin: topMin, - // topMax: topMax, - // leftMin: leftMin, - // leftMax: leftMax, - // width: leftMax - leftMin, - // height: topMax - topMin - // } - - // newData[key][index].dimensions.left = x; - // newData[key][index].dimensions.top = y; - // } - - // setDroppedItems({ ...newData }); - // }; - - // const handleMouseUp = () => { - // document.removeEventListener("pointermove", handleMouseMove); - // document.removeEventListener("pointerup", handleMouseUp); - // }; - - // // Add event listeners - // document.addEventListener("pointermove", handleMouseMove); - // document.addEventListener("pointerup", handleMouseUp); - // } - - - // NEW DIRECTIONAL MOVEMENT HANDLER - START - const handleDirectionalMove = (direction: 'up' | 'down' | 'left' | 'right', stepSize: number = 5) => { if (!selectedTag) return; @@ -1043,38 +963,38 @@ const handleGroupBorderPosition = (groupElements: NodeListOf, conta }; // Add this new handler function to your parent component -const handleDirectPositionChange = (newLeft: number, newTop: number) => { - console.log("handleDirectPositionChange",newLeft,newTop) - if (!selectedTag) return; + const handleDirectPositionChange = (newLeft: number, newTop: number) => { + console.log("handleDirectPositionChange", newLeft, newTop) + if (!selectedTag) return; - const { key, index } = selectedTag; - const currentItem = droppedItems[key]?.[index]; + const { key, index } = selectedTag; + const currentItem = droppedItems[key]?.[index]; - if (!currentItem) return; + if (!currentItem) return; - // Ensure values are not negative - const clampedLeft = Math.max(0, newLeft); - const clampedTop = Math.max(0, newTop); + // Ensure values are not negative + const clampedLeft = Math.max(0, newLeft); + const clampedTop = Math.max(0, newTop); - setDroppedItems({ - ...droppedItems, - [key]: Array.isArray(droppedItems[key]) - ? droppedItems[key].map((item, i) => - i === index - ? { - ...item, - dimensions: { - ...item.dimensions, - left: clampedLeft, - top: clampedTop - }, - update: true - } - : item - ) - : [], - }); -}; + setDroppedItems({ + ...droppedItems, + [key]: Array.isArray(droppedItems[key]) + ? droppedItems[key].map((item, i) => + i === index + ? { + ...item, + dimensions: { + ...item.dimensions, + left: clampedLeft, + top: clampedTop + }, + update: true + } + : item + ) + : [], + }); + }; return ( <> @@ -1128,7 +1048,7 @@ const handleDirectPositionChange = (newLeft: number, newTop: number) => { {/* If Selected Tag Recipient Info- START */} {selectedTag?.key && selectedTag.key === key && selectedTag.index === index && -
+

{ {/* Expand Circle - STARTS */} - {item.type !== "radio" &&

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'>
} @@ -1178,8 +1098,6 @@ const handleDirectPositionChange = (newLeft: number, newTop: number) => { { "group" in item && item.group && "isGroupExist" in item && !item.isGroupExist && <> - -
@@ -1208,11 +1126,11 @@ const handleDirectPositionChange = (newLeft: number, newTop: number) => { - {/* Side details of documents Pages and document Name - START */} -

- page {indx + 1} of {doc.pages && doc.pages.length} -

- {/*

+ {/* Side details of documents Pages and document Name - START */} +

+ page {indx + 1} of {doc.pages && doc.pages.length} +

+ {/*

Document {indxDoc + 1} {doc.name}

*/} {/* Side details of documents Pages and document Name - END */} diff --git a/src/components/process/processStepTwo/LeftSideBar.tsx b/src/components/process/processStepTwo/LeftSideBar.tsx index a687121..bcd5417 100644 --- a/src/components/process/processStepTwo/LeftSideBar.tsx +++ b/src/components/process/processStepTwo/LeftSideBar.tsx @@ -65,7 +65,7 @@ const LeftSideBar: React.FC = ({ isFields, selectedRecipientIn <> {/* Left Side Bar - START */} { - selectedRecipients.length &&
+ selectedRecipients.length > 0 &&
{isFields && <> {/* Fields List and Recipeint - Start */} {/* Side Bar showing Recipients */} @@ -74,6 +74,7 @@ const LeftSideBar: React.FC = ({ isFields, selectedRecipientIn onBlur={() => setDropDownToggle(false)}> {/* Selected Recipient */}
setDropDownToggle(!dropDownToggle)} className='flex items-center justify-between gap-2 w-full p-2 text-xs rounded-sm border-1 border-slate-200 cursor-pointer'>
@@ -110,7 +111,9 @@ const LeftSideBar: React.FC = ({ isFields, selectedRecipientIn {/* Side Bar showing Recipients - ENDS*/} {/* Drag Drop Tags Start */} -
+
diff --git a/src/components/process/processStepTwo/NavTwo.tsx b/src/components/process/processStepTwo/NavTwo.tsx index 533d067..1602604 100644 --- a/src/components/process/processStepTwo/NavTwo.tsx +++ b/src/components/process/processStepTwo/NavTwo.tsx @@ -262,6 +262,7 @@ const NavTwo: React.FC = ({ isFields, setIsFields, isSend, setIsSen {/* Send */}
handleSend()} className='flex items-center gap-2 cursor-pointer text-xs px-4 py-2 ml-3 rounded-sm bg-[var(--primary)]'>

Send

diff --git a/src/components/process/processStepTwo/rightSideBar/DirectionalControls.tsx b/src/components/process/processStepTwo/rightSideBar/DirectionalControls.tsx index 493e4b8..fe79bb8 100644 --- a/src/components/process/processStepTwo/rightSideBar/DirectionalControls.tsx +++ b/src/components/process/processStepTwo/rightSideBar/DirectionalControls.tsx @@ -44,11 +44,8 @@ const DirectionalControls: React.FC = ({ }; const handlePositionInputChange = (type: 'left' | 'top', value: string) => { - if (type === 'left') { - setLeftValue(value); - } else { - setTopValue(value); - } + if (type === 'left') setLeftValue(value); + else setTopValue(value); }; const handlePositionInputBlur = (type: 'left' | 'top') => { @@ -57,11 +54,8 @@ const DirectionalControls: React.FC = ({ const numericValue = parseFloat(type === 'left' ? leftValue : topValue); if (isNaN(numericValue)) { const { top = 0, left = 0 } = selectedType || {}; - if (type === 'left') { - setLeftValue(Math.round(left).toString()); - } else { - setTopValue(Math.round(top).toString()); - } + setLeftValue(Math.round(left).toString()); + setTopValue(Math.round(top).toString()); return; } @@ -73,9 +67,7 @@ const DirectionalControls: React.FC = ({ }; const handleKeyPress = (e: React.KeyboardEvent, type: 'left' | 'top') => { - if (e.key === 'Enter') { - handlePositionInputBlur(type); - } + if (e.key === 'Enter') handlePositionInputBlur(type); }; useEffect(() => { @@ -84,20 +76,11 @@ const DirectionalControls: React.FC = ({ switch (event.key) { case 'ArrowUp': - event.preventDefault(); - handleMove('up'); - break; case 'ArrowDown': - event.preventDefault(); - handleMove('down'); - break; case 'ArrowLeft': - event.preventDefault(); - handleMove('left'); - break; case 'ArrowRight': event.preventDefault(); - handleMove('right'); + handleMove(event.key.replace('Arrow', '').toLowerCase() as any); break; } }; @@ -107,115 +90,67 @@ const DirectionalControls: React.FC = ({ }, [disabled, stepSize]); const buttonClass = ` - p-1 rounded-sm transition-all duration-200 border shadow-sm text-[10px] - ${disabled - ? 'bg-gray-100 text-gray-400 cursor-not-allowed' - : 'bg-white text-gray-600 hover:bg-blue-100 active:bg-blue-200 cursor-pointer'} - flex items-center justify-center w-6 h-6 `; - - const inputClass = ` - w-12 h-6 text-[10px] text-center border rounded px-1 bg-white + w-8 h-8 flex items-center justify-center rounded-full border shadow-sm text-[12px] ${disabled - ? 'bg-gray-100 text-gray-400 cursor-not-allowed border-gray-300' - : 'text-gray-600 border-gray-300 focus:border-blue-400 focus:outline-none'} + ? 'bg-gray-100 text-gray-400 cursor-not-allowed' + : 'bg-white text-gray-700 hover:bg-blue-100 active:bg-blue-200 cursor-pointer'} `; - const { top = 0, left = 0, width = 0, height = 0 } = selectedType || {}; + const inputClass = ` + w-14 text-center text-[12px] rounded border px-1 py-0.5 bg-white + ${disabled + ? 'bg-gray-100 text-gray-400 cursor-not-allowed' + : 'border-gray-300 text-gray-700 focus:outline-none focus:ring focus:border-blue-400'} + `; return ( -
- {/* Top Button */} -
-
- + + {/* Middle: Left / Inputs / Right */} +
+ + + {/* Input fields */} +
+ handlePositionInputChange('left', e.target.value)} + onBlur={() => handlePositionInputBlur('left')} + onKeyPress={(e) => handleKeyPress(e, 'left')} disabled={disabled} - className={buttonClass} - title="Move up" - type="button" - > - - - Top + className={inputClass} + placeholder="Left" + /> + handlePositionInputChange('top', e.target.value)} + onBlur={() => handlePositionInputBlur('top')} + onKeyPress={(e) => handleKeyPress(e, 'top')} + disabled={disabled} + className={inputClass} + placeholder="Top" + />
+ +
- {/* Middle Row: Left - Center (Inputs) - Right */} -
- {/* Left Button */} -
- - Left -
- - {/* Center Panel */} -
- {/* Floating dimensions tooltip */} -
- handlePositionInputChange('left', e.target.value)} - onBlur={() => handlePositionInputBlur('left')} - onKeyPress={(e) => handleKeyPress(e, 'left')} - disabled={disabled} - className="w-[40px] h-[16px] text-[10px] text-center border-none focus:outline-none text-black font-mono" - /> - Γ— - handlePositionInputChange('top', e.target.value)} - onBlur={() => handlePositionInputBlur('top')} - onKeyPress={(e) => handleKeyPress(e, 'top')} - disabled={disabled} - className="w-[40px] h-[16px] text-[10px] text-center border-none focus:outline-none text-black font-mono" - /> -
-
- - - {/* Right Button */} -
- - Right -
-
- - {/* Bottom Button */} -
-
- - Bottom -
-
+ {/* Bottom */} +
); - }; -export default DirectionalControls; \ No newline at end of file +export default DirectionalControls; diff --git a/src/components/process/processStepTwo/rightSideBar/RightSideBar.tsx b/src/components/process/processStepTwo/rightSideBar/RightSideBar.tsx index ec08e9c..227accc 100644 --- a/src/components/process/processStepTwo/rightSideBar/RightSideBar.tsx +++ b/src/components/process/processStepTwo/rightSideBar/RightSideBar.tsx @@ -122,28 +122,26 @@ const RightSideBar: React.FC = ({ selectedTag, setDroppedItems console.log("changeTo", changeTo, "changeWith", changeWith) if (changeTo === '' || changeWith === '') return - if (changeWith === "paragraph") { - return - } + // if (changeTo === "subType" && (changeWith === TEMPORAL.DATE || changeWith === TEMPORAL.DATE_TIME || changeWith === TEMPORAL.TIME)) { + // // let change: string = changeWith; + // // if (change === "DATE TIME") { + // // change = "DATE_TIME" + // // } + // setDroppedItems((prev) => { + // console.log("Temporal30", prev); + // return { + // ...prev, + // [selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array + // ? prev[selTagKey].map((item, i) => + // i === selTagIndx ? { ...item, [changeTo]: changeWith || "", format: "", update: true } : item + // ) + // : [], // Fallback in case it's undefined or not an array + // }; + // }); - if (changeTo === "subType" && (changeWith === TEMPORAL.DATE || changeWith === TEMPORAL.DATE_TIME || changeWith === TEMPORAL.TIME)) { - // let change: string = changeWith; - // if (change === "DATE TIME") { - // change = "DATE_TIME" - // } - setDroppedItems((prev) => { - console.log("Temporal30", prev); - return { - ...prev, - [selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array - ? prev[selTagKey].map((item, i) => - i === selTagIndx ? { ...item, [changeTo]: changeWith || "", format: "", update: true } : item - ) - : [], // Fallback in case it's undefined or not an array - }; - }); - - } else if (changeTo === "subType" && typeof changeWith === "string" && changeWith.toLowerCase() === "password") { + // } else + + if (changeTo === "subType" && typeof changeWith === "string" && changeWith.toLowerCase() === "password") { console.log("Second check") console.log("Line 161") setDroppedItems((prev) => ( @@ -174,13 +172,26 @@ const RightSideBar: React.FC = ({ selectedTag, setDroppedItems }// Provide a fallback in case it's undefined or not an array )); - } else if (changeTo === "format" && selectedTag.subType === TEMPORAL.DATE_TIME) { + } + + + + else if (changeTo === "format" && selectedTag.subType === TEMPORAL.DATE_TIME) { console.log("Fourth Check") let val = timeFormats[0].format; - if (!is24Hrs) { + console.log(is24Hrs, "is24Hrs Line 176") + if (is24Hrs === null) { + val = timeFormats[0].format + } else if(!is24Hrs) { val = timeFormats[1].format + } else { + val = timeFormats[0].format } - console.log("val", val) + // console.log("val", val, is24Hrs) + + // if(is24Hrs === null) { + // changeWith = changeWith + " " + val; + // } setDroppedItems((prev) => { const updatedArray = Array.isArray(prev[selTagKey]) @@ -199,9 +210,9 @@ const RightSideBar: React.FC = ({ selectedTag, setDroppedItems [selTagKey]: updatedArray, }; }); - - - } else { + } + + else { setDroppedItems((prev) => { const updatedItems = Array.isArray(prev[selTagKey]) @@ -284,6 +295,7 @@ const RightSideBar: React.FC = ({ selectedTag, setDroppedItems const tagHeight = selectedTag?.dimensions?.height - 18; if ( + selectedTag.type === TagsTypes.TEXT && selectedTag.subType !== TEXT.PASSWORD && selectedTag.subType !== TEXT.PARAGRAPH && tagHeight > fontSize * 2 diff --git a/src/components/process/processStepTwo/rightSideBar/SelectTagAttr.tsx b/src/components/process/processStepTwo/rightSideBar/SelectTagAttr.tsx index 0ec0d4b..721dd3e 100644 --- a/src/components/process/processStepTwo/rightSideBar/SelectTagAttr.tsx +++ b/src/components/process/processStepTwo/rightSideBar/SelectTagAttr.tsx @@ -15,31 +15,31 @@ const SelectTagAttr: React.FC = ({ options, selTagKey, selTagI const [selectedOption, setSelectedOption] = useState() const handleAddSelectOption = () => { - if (selectedOption && selectedOption.length) { - setDroppedItems((prev) => { - console.log("Previous droppedItems:", prev); + if (selectedOption && selectedOption.length) { + setDroppedItems((prev) => { + console.log("Previous droppedItems:", prev); - const newState = { - ...prev, - [selTagKey]: Array.isArray(prev[selTagKey]) - ? prev[selTagKey].map((item, i) => { - if (i === selTagIndx) { - return { - ...item, - options: item.options ? [...item.options, selectedOption] : [selectedOption], - update: true, - }; - } - return item; - }) - : [], - }; + const newState = { + ...prev, + [selTagKey]: Array.isArray(prev[selTagKey]) + ? prev[selTagKey].map((item, i) => { + if (i === selTagIndx) { + return { + ...item, + options: item.options ? [...item.options, selectedOption] : [selectedOption], + update: true, + }; + } + return item; + }) + : [], + }; - console.log("New droppedItems state:", newState); - return newState; - }); - } -}; + console.log("New droppedItems state:", newState); + return newState; + }); + } + }; const handleSelectOptionDel = (indx: number) => { @@ -65,14 +65,11 @@ const SelectTagAttr: React.FC = ({ options, selTagKey, selTagI setSelectedOption(e.target.value)} - value={selectedOption} + // value={selectedOption} onKeyUp={(e) => { if (e.code === "Enter") { - // if (selectedOption) { - // setSelectedOptions((prev) => [...prev, selectedOption]); - // setSelectedOption(""); - // } - handleAddSelectOption() + e.currentTarget.value = ""; + handleAddSelectOption(); } }} className="bg-slate-100 w-full outline-none p-2 rounded" /> diff --git a/src/components/process/processStepTwo/rightSideBar/TemporalDateAttr.tsx b/src/components/process/processStepTwo/rightSideBar/TemporalDateAttr.tsx index 0d07995..f8977df 100644 --- a/src/components/process/processStepTwo/rightSideBar/TemporalDateAttr.tsx +++ b/src/components/process/processStepTwo/rightSideBar/TemporalDateAttr.tsx @@ -23,10 +23,11 @@ interface TemporalDateAttrInt { const TemporalDateAttr: React.FC = ({ subType, format, dropDownToggle, setDropDownToggle, handlePropertyChange }) => { - + const [is24Hrs, setIs24Hrs] = useState(true); const handleIs24HrsClick = (checked: boolean) => { + console.log(is24Hrs, checked, "line 30") if (subType === TEMPORAL.TIME) { if (!checked) { handlePropertyChange("format", timeFormats[1].format, is24Hrs) @@ -34,6 +35,9 @@ const TemporalDateAttr: React.FC = ({ subType, format, drop handlePropertyChange("format", timeFormats[0].format, is24Hrs) } } + else if (subType === TEMPORAL.DATE_TIME) { + handlePropertyChange("format", (format.split(" ").slice(0, -1).join(" ")), !is24Hrs) + } setIs24Hrs(checked) } @@ -86,11 +90,11 @@ const TemporalDateAttr: React.FC = ({ subType, format, drop val = val + " " + timeFormats[1].format; } } - console.log('line 89' , val ) + console.log('line 89', val) return (
handlePropertyChange("format", valObj["format"])} + onClick={() => handlePropertyChange("format", valObj["format"], is24Hrs)} className="px-2 py-1 hover:bg-slate-200 cursor-pointer" > {val} diff --git a/src/utlity/JoyRideTour.tsx b/src/utlity/JoyRideTour.tsx new file mode 100644 index 0000000..b582928 --- /dev/null +++ b/src/utlity/JoyRideTour.tsx @@ -0,0 +1,244 @@ +import { useLocation } from "react-router-dom"; +import { useEffect, useState } from "react"; +import Joyride, { CallBackProps, STATUS, Step } from "react-joyride"; + +const JoyrideController = () => { + const location = useLocation(); + const [runTour, setRunTour] = useState(false); + const [steps, setSteps] = useState([]); + const [stepIndex, setStepIndex] = useState(0); + + useEffect(() => { + let timeout: NodeJS.Timeout; + + const tryStartTour = () => { + let currentSteps: Step[] = []; + + if (location.pathname === "/") { + currentSteps = [ + { + target: "body", // This makes the welcome step show in center of screen + content: "πŸ‘‹ Welcome to the SME! Let's take a quick tour.", + placement: "center", + disableBeacon: true, + }, + { + target: "#user-details-avatar", + content: "User Details", + placement: "left", + disableBeacon: true, + + }, + { + target: "#send-for-sign-self-sign-btn", + content: "Send document for signature, or for Self Sign", + placement: "left", + disableBeacon: true, + + }, + { + target: "#nav-link-dash", + content: ( +
+

Easy Navigation to see transaction and templates.

+

+ Templates: you can save all recipient documents and tags and + use them multiple times on one click. +

+
+ ), + placement: "left", + disableBeacon: true, + + }, + { + target: "#start-now-upload-con", + content: ( +
+

Let's Start Some Action

+

+ Click On Start Now To upload your first document for signature +

+
+ ), + placement: "top", + disableBeacon: true, + + }, + ]; + } else if (location.pathname.includes("/process-step-one")) { + currentSteps = [ + { + target: "body", // This makes the welcome step show in center of screen + content: ( +
+

πŸ‘‹ Welcome To process step one

+

+ Here we have to add core two ingredients Document, Recipient to start cooking +

+
+ ), + placement: "center", + disableBeacon: true, + }, + { + target: "#upload-doc-step-one", + content: "Add Documents", + placement: "right", + disableBeacon: true, + + }, + { + target: "#add-recipient-step-one", + content: "Add recipient for sign", + placement: "right", + disableBeacon: true, + + }, + { + target: "#add-tags-btn-step-one", + content: "Click On Add Tags", + placement: "right", + disableBeacon: true, + + }, + ]; + } else if (location.pathname.includes("/process-step-two")) { + currentSteps = [ + { + target: "body", // This makes the welcome step show in center of screen + content: ( +
+

πŸ‘‹ This is Final Step

+
+

Here we can add tags in documents and assign them to recipients

+
+ ), + placement: "center", + disableBeacon: true, + }, + { + target: "#switch-recipients-left", + content: "Switch Recipients", + placement: "right", + disableBeacon: true, + }, + { + target: "#tags-con-dash-left", + content: "All Tags, Drag and drop on the document", + placement: "right", + disableBeacon: true, + }, + { + target: "#send-sign-dash-btn", + content:
+

When setisfied with all the change, Click on Send

+
, + placement: "right", + disableBeacon: true, + }, + ]; + } else if (location.pathname.includes("/sign/")) { + currentSteps = [ + { + target: "body", // This makes the welcome step show in center of screen + content: ( +
+

πŸ‘‹ Welcome to SME, Let's Start the tour

+
+ ), + placement: "center", + disableBeacon: true, + }, + { + target: "#tags-list-client-side", + content:
+

Drag and drop tags onto the document to fill or sign.

+
, + placement: "right", + disableBeacon: true, + }, + { + target: "#sign-client-side-btn", + content:
+

Check your document carefully When you're satisfied Click on Sign button

+
, + placement: "right", + disableBeacon: true, + }, + ]; + } + + const allTargetsExist = currentSteps.every((step) => + step.target === "body" ? true : document.querySelector(step.target) + ); + + if (allTargetsExist) { + setSteps(currentSteps); + setRunTour(true); + setStepIndex(0); + } else { + // Try again after slight delay (in case DOM not ready yet) + timeout = setTimeout(tryStartTour, 300); + } + }; + + setRunTour(false); + setSteps([]); + setStepIndex(0); + timeout = setTimeout(tryStartTour, 300); + + return () => clearTimeout(timeout); + }, [location]); + + // Optional: handle callback (e.g. restart, stop, next) + const handleJoyrideCallback = (data: CallBackProps) => { + const { status, type } = data; + const finished = [STATUS.FINISHED, STATUS.SKIPPED].includes(status); + if (finished) { + setRunTour(false); + } + }; + + return ( + + + ); +}; + +export default JoyrideController; -- 2.40.1 From 6de3205493d8878efe362712aebc4c5aab925c5b Mon Sep 17 00:00:00 2001 From: =bhagwanSingh <=bhagwan.r@hicglobalsolutions.com> Date: Tue, 29 Jul 2025 19:57:49 +0530 Subject: [PATCH 2/6] Added Updates transaction code update and ps1 code update29-07 --- src/App.tsx | 2 +- src/components/accounts/Account.tsx | 4 - .../accounts/TransactionDataTable.tsx | 10 +- .../process/processStepOne/ProcessStepOne.tsx | 33 ++--- .../transactions/TransactionView.tsx | 116 +++++++++++------- src/utlity/JoyRideTour.tsx | 2 +- 6 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 91e1ca5..045023e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -49,8 +49,8 @@ const App = () => { {/* } /> */} } /> {/* */} + } /> - {/* */} } /> diff --git a/src/components/accounts/Account.tsx b/src/components/accounts/Account.tsx index 3612665..8a6c996 100644 --- a/src/components/accounts/Account.tsx +++ b/src/components/accounts/Account.tsx @@ -213,10 +213,6 @@ const Account = () => { const navigate = useNavigate(); - const handleTransactionClick = (id: number) => { - navigate(`/accounts/${activeAccountId}/transactions/${id}`); - }; - const handleInvite = async (data: { i_accountName: number; email: string; role: string }) => { setInviteLoading(true); try { diff --git a/src/components/accounts/TransactionDataTable.tsx b/src/components/accounts/TransactionDataTable.tsx index 908909c..c5178fd 100644 --- a/src/components/accounts/TransactionDataTable.tsx +++ b/src/components/accounts/TransactionDataTable.tsx @@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react' import { PiDotsThreeOutlineVerticalFill } from 'react-icons/pi'; import api from '../../config/api'; import { Transaction } from '../transactions/Transactions'; +import { useNavigate } from 'react-router-dom'; +import { FaCheck } from 'react-icons/fa'; @@ -16,10 +18,12 @@ const TransactionDataTable = () => { JSON.parse(sessionStorage.getItem('activeAccountId') || 'null') ); + const navigate = useNavigate(); + const fetchTransactions = async () => { console.log("fetchTransactions") try { - const response = await api(`/api/accounts/${activeAccountId}/transactions`); + const response = await api.get(`/api/accounts/${activeAccountId}/transactions?sortBy=lastModifiedAt desc`); setTransactions(response.data || []); } catch (error) { console.error("Error fetching transactions:", error); @@ -28,6 +32,10 @@ const TransactionDataTable = () => { const [transactions, setTransactions] = useState([]); + const handleTransactionClick = (id: number) => { + navigate(`/accounts/${activeAccountId}/transactions/${id}`); + }; + useEffect(() => { if (activeAccountId) { fetchTransactions(); diff --git a/src/components/process/processStepOne/ProcessStepOne.tsx b/src/components/process/processStepOne/ProcessStepOne.tsx index 3150468..bdd1270 100644 --- a/src/components/process/processStepOne/ProcessStepOne.tsx +++ b/src/components/process/processStepOne/ProcessStepOne.tsx @@ -65,7 +65,7 @@ const ProcessStepOne = () => { console.log("selectedRecipients", selectedRecipients) useEffect(() => { -// <<<<<<< HEAD + // <<<<<<< HEAD // Fetching Transaction Details - START (async () => { try { @@ -75,18 +75,19 @@ const ProcessStepOne = () => { console.log("Error - transactions details") } })() - // Fetching Transaction Details - END + // Fetching Transaction Details - END -// ======= - // (async () => { - // const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) - // console.log(res.data); - // })() -// >>>>>>> origin/main - (async () => { - const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) - console.log(res.data); - })() + // ======= + // (async () => { + // const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) + // console.log(res.data); + // })() + // >>>>>>> origin/main + + // (async () => { + // const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`) + // console.log(res.data); + // })() selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId })); selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId })); @@ -315,9 +316,9 @@ const ProcessStepOne = () => {

Add Recipient and Message

-
+
diff --git a/src/components/transactions/TransactionView.tsx b/src/components/transactions/TransactionView.tsx index 5ec0c86..b97dc0c 100644 --- a/src/components/transactions/TransactionView.tsx +++ b/src/components/transactions/TransactionView.tsx @@ -1,5 +1,5 @@ import { AiFillSignature } from 'react-icons/ai'; -import { Link, useParams } from 'react-router-dom'; +import { Link, useNavigate, useParams } from 'react-router-dom'; import { LuGitGraph } from 'react-icons/lu'; import AccountNav from '../accounts/AccountNav'; import { useEffect, useState } from 'react'; @@ -7,6 +7,8 @@ import api from '../../config/api'; import SigningOrderDiagram from '../../SigningOrderDiagram '; import { IoCloseOutline } from 'react-icons/io5'; import { MdEditDocument } from "react-icons/md"; +import { useSelector } from 'react-redux'; +import { RootState } from '../../store/store'; // Sample recipient data β€” you can replace this with actual API data later const recipients = [ @@ -30,8 +32,8 @@ const recipients = [ const TransactionView = () => { const { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>(); - console.log("account" , accountId , transactionId) - + + const navigate = useNavigate(); if (!accountId || !transactionId) { window.location.href = "/"; @@ -40,6 +42,8 @@ const TransactionView = () => { const [transactionDetails, setTransactionDetails] = useState(null); const [signingOrderModal, setSigningOrderModal] = useState({ open: false }); + const user = useSelector((state: RootState) => state.user) + console.log(transactionDetails, "line 37"); const fetchData = async () => { @@ -56,6 +60,11 @@ const TransactionView = () => { fetchData() }, [accountId, transactionId]) + + const handleNavigateToSign = (id: number) => { + window.open(`./../../../../sign/${id}`) + } + return ( <> {transactionDetails && @@ -64,17 +73,17 @@ const TransactionView = () => {
{/* Header */}

- Complete with Forms Made Easy: { transactionDetails?.transaction?.subject ?? "Untitled"} + Complete with Forms Made Easy: {transactionDetails?.transaction?.subject ?? "Untitled"}

{/* new Date(transactionDetails?.transaction?.lastModifiedAt * 1000) */} -

From Shanu.R

+

From {transactionDetails?.transaction.createdBy.firstName + " " + transactionDetails?.transaction.createdBy.lastName}

Last Change on {new Date(transactionDetails?.transaction?.lastModifiedAt * 1000).toISOString()}

Created at {new Date(transactionDetails?.transaction?.createdAt * 1000).toISOString()}

-

Draft

+

{transactionDetails?.transaction.status}

{/* Buttons */}
@@ -97,51 +106,66 @@ const TransactionView = () => {
{/* Recipients Section */} - {transactionDetails.recipients.length > 0 && -
-
-

Signers

-

setSigningOrderModal({ ...signingOrderModal, open: true })}> - - Signing Graph -

-
+ {transactionDetails.recipients.length > 0 && +
+
+

Signers

+

setSigningOrderModal({ ...signingOrderModal, open: true })}> + + Signing Graph +

+
- {/* Recipients List */} - {transactionDetails.recipients.map((recipient, index) => ( -
-
-
-

{recipient.id}

-
-

{recipient.name}

-

{recipient.email}

- {recipient.hostEmail !== null &&

Host: {recipient.hostEmail}

} + {/* Recipients List */} + {transactionDetails.recipients.map((recipient, index) => ( +
+
+
+ {/*

{index+1}

*/} +
+

{recipient.name}

+

{recipient.email}

+ {recipient.hostEmail !== null && recipient.hostEmail !== "" &&

Host: {recipient.hostEmail}

} +
-
- +
-
-
- ))} -
+ ))} +
} -
-

Message

-

{ transactionDetails?.transaction?.message ?? "No Message Found...!"}

-
+ {transactionDetails?.transaction?.subject !== "" && +
+

Subject

+

{`${transactionDetails?.transaction?.subject ? transactionDetails?.transaction?.subject : "Not Found"} `}

+
} + + {transactionDetails?.transaction?.message !== "" && +
+

Message

+

{`${transactionDetails?.transaction?.message ? transactionDetails?.transaction?.message : "Not Found"} `}

+
}
@@ -152,10 +176,10 @@ const TransactionView = () => {

- 1 of 10 - -

- + 1 of 10 + +

+
@@ -165,7 +189,7 @@ const TransactionView = () => {
- {signingOrderModal.open && + {signingOrderModal.open &&
diff --git a/src/utlity/JoyRideTour.tsx b/src/utlity/JoyRideTour.tsx index b582928..b564cc6 100644 --- a/src/utlity/JoyRideTour.tsx +++ b/src/utlity/JoyRideTour.tsx @@ -144,7 +144,7 @@ const JoyrideController = () => { target: "body", // This makes the welcome step show in center of screen content: (
-

πŸ‘‹ Welcome to SME, Let's Start the tour

+

πŸ‘‹ Hi there! Welcome to SME. Let’s start signing.

), placement: "center", -- 2.40.1 From 1a4ea46c5b8df8da79ba594fa8b0d07c979735ff Mon Sep 17 00:00:00 2001 From: =bhagwanSingh <=bhagwan.r@hicglobalsolutions.com> Date: Wed, 30 Jul 2025 13:59:55 +0530 Subject: [PATCH 3/6] a --- .../process/processStepOne/ProcessStepOne.tsx | 4 +- src/components/templates/Templates.tsx | 2 +- src/index.css | 59 +++++++++++++------ 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/components/process/processStepOne/ProcessStepOne.tsx b/src/components/process/processStepOne/ProcessStepOne.tsx index bdd1270..4c1b9ea 100644 --- a/src/components/process/processStepOne/ProcessStepOne.tsx +++ b/src/components/process/processStepOne/ProcessStepOne.tsx @@ -69,7 +69,7 @@ const ProcessStepOne = () => { // Fetching Transaction Details - START (async () => { try { - const res = await api.get(`/api/accounts/${accountId}/transactions/${transactionId}`); + const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`); setTransactionDetails(res.data) } catch (e) { console.log("Error - transactions details") @@ -323,7 +323,7 @@ const ProcessStepOne = () => { onClick={() => handleNextClick(false)} className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition" > - {signType === SignTypeEnum.selfSign ? "Add Tags" : "Add Tags"} + {signType === SignTypeEnum.selfSign ? "Sign" : "Next"}
diff --git a/src/components/templates/Templates.tsx b/src/components/templates/Templates.tsx index 47c22c6..a75a6e6 100644 --- a/src/components/templates/Templates.tsx +++ b/src/components/templates/Templates.tsx @@ -30,7 +30,7 @@ const Templates = () => { console.log("handleAddTemplate called"); try { const res = await api.post(`/api/accounts/${activeAccountId}/templates`); - navigate(`/process-step-one/${activeAccountId}/template/${res.data}`) + navigate(`/process-step-one/${activeAccountId}/template/${res.data.id}`) } catch (error) { console.log(error) } diff --git a/src/index.css b/src/index.css index c140aab..e4f589e 100644 --- a/src/index.css +++ b/src/index.css @@ -113,14 +113,14 @@ canvas { left: 50%; transform: translateX(-50%); z-index: 50; - background-color: var(--primary); + background-color: var(--primary); color: var(--primaryLight); padding: 2px 8px; border-radius: 5px; } .bottom-border>div:hover { - background-color: var(--primaryLight2) ; + background-color: var(--primaryLight2); opacity: 0.9; transition: all 0.3s ease-in-out; cursor: pointer; @@ -129,8 +129,8 @@ canvas { /* Group Border - END */ - /* Loader CSS */ - /* From Uiverse.io by Juanes200122 */ +/* Loader CSS */ +/* From Uiverse.io by Juanes200122 */ .pl { width: 6em; height: 6em; @@ -158,10 +158,12 @@ canvas { animation-name: ringD; stroke: #41644A; } - - /* Animations */ + +/* Animations */ @keyframes ringA { - from, 4% { + + from, + 4% { stroke-dasharray: 0 660; stroke-width: 20; stroke-dashoffset: -330; @@ -179,7 +181,8 @@ canvas { stroke-dashoffset: -595; } - 40%, 54% { + 40%, + 54% { stroke-dasharray: 0 660; stroke-width: 20; stroke-dashoffset: -660; @@ -197,7 +200,8 @@ canvas { stroke-dashoffset: -925; } - 90%, to { + 90%, + to { stroke-dasharray: 0 660; stroke-width: 20; stroke-dashoffset: -990; @@ -205,7 +209,9 @@ canvas { } @keyframes ringB { - from, 12% { + + from, + 12% { stroke-dasharray: 0 220; stroke-width: 20; stroke-dashoffset: -110; @@ -223,7 +229,8 @@ canvas { stroke-dashoffset: -195; } - 48%, 62% { + 48%, + 62% { stroke-dasharray: 0 220; stroke-width: 20; stroke-dashoffset: -220; @@ -241,7 +248,8 @@ canvas { stroke-dashoffset: -305; } - 98%, to { + 98%, + to { stroke-dasharray: 0 220; stroke-width: 20; stroke-dashoffset: -330; @@ -267,7 +275,8 @@ canvas { stroke-dashoffset: -175; } - 36%, 58% { + 36%, + 58% { stroke-dasharray: 0 440; stroke-width: 20; stroke-dashoffset: -220; @@ -285,7 +294,8 @@ canvas { stroke-dashoffset: -395; } - 94%, to { + 94%, + to { stroke-dasharray: 0 440; stroke-width: 20; stroke-dashoffset: -440; @@ -293,7 +303,9 @@ canvas { } @keyframes ringD { - from, 8% { + + from, + 8% { stroke-dasharray: 0 440; stroke-width: 20; stroke-dashoffset: 0; @@ -311,7 +323,8 @@ canvas { stroke-dashoffset: -175; } - 44%, 50% { + 44%, + 50% { stroke-dasharray: 0 440; stroke-width: 20; stroke-dashoffset: -220; @@ -329,14 +342,16 @@ canvas { stroke-dashoffset: -395; } - 86%, to { + 86%, + to { stroke-dasharray: 0 440; stroke-width: 20; stroke-dashoffset: -440; } } + .bottom-border>div:hover { - background-color: var(--primaryLight2) ; + background-color: var(--primaryLight2); opacity: 0.9; transition: all 0.3s ease-in-out; cursor: pointer; @@ -344,3 +359,11 @@ canvas { /* Group Border - END */ + + +/* JoyRide - START */ +.__floater__body > div > button:last-child { + display: none !important; +} + +/* JoyRide - END */ \ No newline at end of file -- 2.40.1 From 7cbd74fc1497518ba54b026d10a1f789838d21a5 Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Wed, 30 Jul 2025 14:15:44 +0530 Subject: [PATCH 4/6] loaderUI --- src/components/contacts/Contacts.tsx | 152 +++++++++++++------------ src/components/dashboard/Loader.tsx | 1 - src/components/templates/Templates.tsx | 22 ++-- src/helper/LoaderUi.tsx | 31 ++--- 4 files changed, 106 insertions(+), 100 deletions(-) diff --git a/src/components/contacts/Contacts.tsx b/src/components/contacts/Contacts.tsx index 0942e70..e164dfd 100644 --- a/src/components/contacts/Contacts.tsx +++ b/src/components/contacts/Contacts.tsx @@ -83,11 +83,11 @@ const Contacts = () => { const handleContactSubmit = async (data: ContactData, type: "") => { try { - let res ; + let res; setCreateAndInviteLoader(true); if (type === 'Edit') { - res = await api.put(`/api/accounts/${activeAccountId}/contacts`, [data]) - }else{ + res = await api.put(`/api/accounts/${activeAccountId}/contacts`, [data]) + } else { res = await api.post(`/api/accounts/${activeAccountId}/contacts`, [data]); } if (res.status === 200) { @@ -115,82 +115,84 @@ const Contacts = () => { return ( <> -
-
setShowModal((prev) => !prev)} - className="flex items-center gap-2 bg-[var(--primary)] px-3 py-1.5 rounded-sm hover:opacity-90 "> - - +
+
+
setShowModal((prev) => !prev)} + className="flex items-center gap-2 bg-[var(--primary)] px-3 py-1.5 rounded-sm hover:opacity-90 "> + + +
-
-
- - - - - - - - - - - {loading ? ( +
+
First NameLast NameEmailActions
+ - + + + + - ) : contacts.length === 0 ? ( - - - - ) : ( - contacts.map((contact) => ( - - - - - + + + {loading ? ( + + - )) - )} - -
Loading...First NameLast NameEmailActions
No contacts found.
{contact.firstName}{contact.lastName}{contact.email} -
- - - {openMenuId === contact.id && ( -
- - -
- )} -
-
Loading...
- {showModal && - - } + ) : contacts.length === 0 ? ( + + No contacts found. + + ) : ( + contacts.map((contact) => ( + + {contact.firstName} + {contact.lastName} + {contact.email} + +
+ + + {openMenuId === contact.id && ( +
+ + +
+ )} +
+ + + )) + )} + + + {showModal && + + } +
); diff --git a/src/components/dashboard/Loader.tsx b/src/components/dashboard/Loader.tsx index 3f1093e..8e094ca 100644 --- a/src/components/dashboard/Loader.tsx +++ b/src/components/dashboard/Loader.tsx @@ -1,4 +1,3 @@ -import React from 'react' import { LuSignature } from "react-icons/lu"; import { useSelector } from 'react-redux'; import { RootState } from '../../store/store'; diff --git a/src/components/templates/Templates.tsx b/src/components/templates/Templates.tsx index 47c22c6..9a4391d 100644 --- a/src/components/templates/Templates.tsx +++ b/src/components/templates/Templates.tsx @@ -136,7 +136,15 @@ const Templates = () => { - {templates.length > 0 ? ( + {loading ? ( + + + + + + + + ) : templates.length > 0 ? ( {templates.map((item, index) => { return ( @@ -200,18 +208,12 @@ const Templates = () => { ) : ( - -
- {/* Pulsing background div */} -
- - {/* Loader stays on top, no animation */} - -
+ + No templates found. - + )}
diff --git a/src/helper/LoaderUi.tsx b/src/helper/LoaderUi.tsx index c118cb4..0113300 100644 --- a/src/helper/LoaderUi.tsx +++ b/src/helper/LoaderUi.tsx @@ -1,19 +1,22 @@ +import { LuSignature } from "react-icons/lu"; interface StyleProps { - classStyle : string + classStyle?: string; } -const LoaderUi = ({ classStyle }:StyleProps) => { - return ( -
- - - - - - -
- ) -} +const LoaderUi = ({ classStyle = '' }: StyleProps) => { + return ( +
+ {/* Overlay */} +
-export default LoaderUi \ No newline at end of file + {/* Loader box */} +
+ +

Loading...!

+
+
+ ); +}; + +export default LoaderUi; -- 2.40.1 From 21290040cb38127ad161df960f14a6b4fe08b311 Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Wed, 30 Jul 2025 15:32:44 +0530 Subject: [PATCH 5/6] loaderUI --- src/components/contacts/Contacts.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/contacts/Contacts.tsx b/src/components/contacts/Contacts.tsx index e164dfd..b4cce43 100644 --- a/src/components/contacts/Contacts.tsx +++ b/src/components/contacts/Contacts.tsx @@ -4,6 +4,7 @@ import api from '../../config/api'; import ContactFormModal, { ContactData } from './ContactsFormModal'; import { Bounce, toast } from 'react-toastify'; import { IoMdAdd } from 'react-icons/io'; +import LoaderUi from '../../helper/LoaderUi'; type ContactSchema = [{ id: number, @@ -25,6 +26,7 @@ const Contacts = () => { console.log("editJsonData", editJsonData) const fetchContacts = async () => { + setLoading(true) try { const res = await api.get(`/api/accounts/${activeAccountId}/contacts`); setContacts(res.data.content || []); @@ -140,7 +142,7 @@ const Contacts = () => { {loading ? ( - Loading... + ) : contacts.length === 0 ? ( -- 2.40.1 From 0cf16a05f013a3eb8716dd27d07e754fb56a285c Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Wed, 30 Jul 2025 16:27:12 +0530 Subject: [PATCH 6/6] merge code --- src/components/accounts/Account.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/accounts/Account.tsx b/src/components/accounts/Account.tsx index 8a6c996..90c091b 100644 --- a/src/components/accounts/Account.tsx +++ b/src/components/accounts/Account.tsx @@ -245,6 +245,7 @@ const Account = () => { return ( <> + -- 2.40.1