Compare commits
	
		
			No commits in common. "500006c1ef35228544c600a99e00fe176e7153cb" and "bab312b9ee6527f03d5dc1ecd2685b380fceab87" have entirely different histories.
		
	
	
		
			500006c1ef
			...
			bab312b9ee
		
	
		
							
								
								
									
										166
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										166
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -27,7 +27,6 @@
 | 
				
			|||||||
        "react-apexcharts": "^1.7.0",
 | 
					        "react-apexcharts": "^1.7.0",
 | 
				
			||||||
        "react-dom": "^18.2.0",
 | 
					        "react-dom": "^18.2.0",
 | 
				
			||||||
        "react-hook-form": "^7.54.2",
 | 
					        "react-hook-form": "^7.54.2",
 | 
				
			||||||
        "react-quill": "^2.0.0",
 | 
					 | 
				
			||||||
        "react-redux": "^9.2.0",
 | 
					        "react-redux": "^9.2.0",
 | 
				
			||||||
        "react-router-dom": "^6.20.1",
 | 
					        "react-router-dom": "^6.20.1",
 | 
				
			||||||
        "react-toastify": "^11.0.2",
 | 
					        "react-toastify": "^11.0.2",
 | 
				
			||||||
@ -1495,15 +1494,6 @@
 | 
				
			|||||||
      "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
 | 
					      "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
 | 
				
			||||||
      "devOptional": true
 | 
					      "devOptional": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@types/quill": {
 | 
					 | 
				
			||||||
      "version": "1.3.10",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "parchment": "^1.1.2"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/@types/react": {
 | 
					    "node_modules/@types/react": {
 | 
				
			||||||
      "version": "18.3.16",
 | 
					      "version": "18.3.16",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz",
 | 
				
			||||||
@ -2110,6 +2100,7 @@
 | 
				
			|||||||
      "version": "1.0.8",
 | 
					      "version": "1.0.8",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
 | 
				
			||||||
      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
 | 
					      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "call-bind-apply-helpers": "^1.0.0",
 | 
					        "call-bind-apply-helpers": "^1.0.0",
 | 
				
			||||||
        "es-define-property": "^1.0.0",
 | 
					        "es-define-property": "^1.0.0",
 | 
				
			||||||
@ -2127,6 +2118,7 @@
 | 
				
			|||||||
      "version": "1.0.1",
 | 
					      "version": "1.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
 | 
					      "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "es-errors": "^1.3.0",
 | 
					        "es-errors": "^1.3.0",
 | 
				
			||||||
        "function-bind": "^1.1.2"
 | 
					        "function-bind": "^1.1.2"
 | 
				
			||||||
@ -2139,6 +2131,7 @@
 | 
				
			|||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==",
 | 
					      "integrity": "sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "call-bind": "^1.0.8",
 | 
					        "call-bind": "^1.0.8",
 | 
				
			||||||
        "get-intrinsic": "^1.2.5"
 | 
					        "get-intrinsic": "^1.2.5"
 | 
				
			||||||
@ -2217,15 +2210,6 @@
 | 
				
			|||||||
        "node": ">=6.0"
 | 
					        "node": ">=6.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/clone": {
 | 
					 | 
				
			||||||
      "version": "2.1.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					 | 
				
			||||||
      "engines": {
 | 
					 | 
				
			||||||
        "node": ">=0.8"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/clsx": {
 | 
					    "node_modules/clsx": {
 | 
				
			||||||
      "version": "2.1.1",
 | 
					      "version": "2.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
 | 
				
			||||||
@ -2389,26 +2373,6 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/deep-equal": {
 | 
					 | 
				
			||||||
      "version": "1.1.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "is-arguments": "^1.1.1",
 | 
					 | 
				
			||||||
        "is-date-object": "^1.0.5",
 | 
					 | 
				
			||||||
        "is-regex": "^1.1.4",
 | 
					 | 
				
			||||||
        "object-is": "^1.1.5",
 | 
					 | 
				
			||||||
        "object-keys": "^1.1.1",
 | 
					 | 
				
			||||||
        "regexp.prototype.flags": "^1.5.1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "engines": {
 | 
					 | 
				
			||||||
        "node": ">= 0.4"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "funding": {
 | 
					 | 
				
			||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/deep-is": {
 | 
					    "node_modules/deep-is": {
 | 
				
			||||||
      "version": "0.1.4",
 | 
					      "version": "0.1.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
 | 
				
			||||||
@ -2419,6 +2383,7 @@
 | 
				
			|||||||
      "version": "1.1.4",
 | 
					      "version": "1.1.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
 | 
				
			||||||
      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
 | 
					      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "es-define-property": "^1.0.0",
 | 
					        "es-define-property": "^1.0.0",
 | 
				
			||||||
        "es-errors": "^1.3.0",
 | 
					        "es-errors": "^1.3.0",
 | 
				
			||||||
@ -2435,6 +2400,7 @@
 | 
				
			|||||||
      "version": "1.2.1",
 | 
					      "version": "1.2.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
 | 
					      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "define-data-property": "^1.0.1",
 | 
					        "define-data-property": "^1.0.1",
 | 
				
			||||||
        "has-property-descriptors": "^1.0.0",
 | 
					        "has-property-descriptors": "^1.0.0",
 | 
				
			||||||
@ -2516,6 +2482,7 @@
 | 
				
			|||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==",
 | 
					      "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "call-bind-apply-helpers": "^1.0.0",
 | 
					        "call-bind-apply-helpers": "^1.0.0",
 | 
				
			||||||
        "es-errors": "^1.3.0",
 | 
					        "es-errors": "^1.3.0",
 | 
				
			||||||
@ -2608,6 +2575,7 @@
 | 
				
			|||||||
      "version": "1.0.1",
 | 
					      "version": "1.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
 | 
					      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">= 0.4"
 | 
					        "node": ">= 0.4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -2616,6 +2584,7 @@
 | 
				
			|||||||
      "version": "1.3.0",
 | 
					      "version": "1.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
 | 
					      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">= 0.4"
 | 
					        "node": ">= 0.4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -2980,12 +2949,6 @@
 | 
				
			|||||||
        "node": ">=0.10.0"
 | 
					        "node": ">=0.10.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/eventemitter3": {
 | 
					 | 
				
			||||||
      "version": "2.0.3",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==",
 | 
					 | 
				
			||||||
      "license": "MIT"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/events": {
 | 
					    "node_modules/events": {
 | 
				
			||||||
      "version": "3.3.0",
 | 
					      "version": "3.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
 | 
				
			||||||
@ -2996,23 +2959,11 @@
 | 
				
			|||||||
        "node": ">=0.8.x"
 | 
					        "node": ">=0.8.x"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/extend": {
 | 
					 | 
				
			||||||
      "version": "3.0.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
 | 
					 | 
				
			||||||
      "license": "MIT"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/fast-deep-equal": {
 | 
					    "node_modules/fast-deep-equal": {
 | 
				
			||||||
      "version": "3.1.3",
 | 
					      "version": "3.1.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 | 
				
			||||||
      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
 | 
					      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/fast-diff": {
 | 
					 | 
				
			||||||
      "version": "1.1.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==",
 | 
					 | 
				
			||||||
      "license": "Apache-2.0"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/fast-json-stable-stringify": {
 | 
					    "node_modules/fast-json-stable-stringify": {
 | 
				
			||||||
      "version": "2.1.0",
 | 
					      "version": "2.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
 | 
				
			||||||
@ -3172,6 +3123,7 @@
 | 
				
			|||||||
      "version": "1.1.2",
 | 
					      "version": "1.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
 | 
					      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "funding": {
 | 
					      "funding": {
 | 
				
			||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -3198,6 +3150,7 @@
 | 
				
			|||||||
      "version": "1.2.3",
 | 
					      "version": "1.2.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
 | 
				
			||||||
      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
 | 
					      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "funding": {
 | 
					      "funding": {
 | 
				
			||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -3214,6 +3167,7 @@
 | 
				
			|||||||
      "version": "1.2.5",
 | 
					      "version": "1.2.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.5.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.5.tgz",
 | 
				
			||||||
      "integrity": "sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==",
 | 
					      "integrity": "sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "call-bind-apply-helpers": "^1.0.0",
 | 
					        "call-bind-apply-helpers": "^1.0.0",
 | 
				
			||||||
        "dunder-proto": "^1.0.0",
 | 
					        "dunder-proto": "^1.0.0",
 | 
				
			||||||
@ -3323,6 +3277,7 @@
 | 
				
			|||||||
      "version": "1.2.0",
 | 
					      "version": "1.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
 | 
					      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">= 0.4"
 | 
					        "node": ">= 0.4"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -3364,6 +3319,7 @@
 | 
				
			|||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
 | 
					      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "es-define-property": "^1.0.0"
 | 
					        "es-define-property": "^1.0.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -3390,6 +3346,7 @@
 | 
				
			|||||||
      "version": "1.1.0",
 | 
					      "version": "1.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
 | 
					      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">= 0.4"
 | 
					        "node": ">= 0.4"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -3401,6 +3358,7 @@
 | 
				
			|||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
 | 
					      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "has-symbols": "^1.0.3"
 | 
					        "has-symbols": "^1.0.3"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -3415,6 +3373,7 @@
 | 
				
			|||||||
      "version": "2.0.2",
 | 
					      "version": "2.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
 | 
					      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "function-bind": "^1.1.2"
 | 
					        "function-bind": "^1.1.2"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -3501,22 +3460,6 @@
 | 
				
			|||||||
        "node": ">= 0.4"
 | 
					        "node": ">= 0.4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/is-arguments": {
 | 
					 | 
				
			||||||
      "version": "1.2.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==",
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "call-bound": "^1.0.2",
 | 
					 | 
				
			||||||
        "has-tostringtag": "^1.0.2"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "engines": {
 | 
					 | 
				
			||||||
        "node": ">= 0.4"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "funding": {
 | 
					 | 
				
			||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/is-array-buffer": {
 | 
					    "node_modules/is-array-buffer": {
 | 
				
			||||||
      "version": "3.0.4",
 | 
					      "version": "3.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
 | 
				
			||||||
@ -3625,6 +3568,7 @@
 | 
				
			|||||||
      "version": "1.0.5",
 | 
					      "version": "1.0.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
 | 
				
			||||||
      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
 | 
					      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "has-tostringtag": "^1.0.0"
 | 
					        "has-tostringtag": "^1.0.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -3739,6 +3683,7 @@
 | 
				
			|||||||
      "version": "1.2.0",
 | 
					      "version": "1.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==",
 | 
					      "integrity": "sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "call-bind": "^1.0.7",
 | 
					        "call-bind": "^1.0.7",
 | 
				
			||||||
        "gopd": "^1.1.0",
 | 
					        "gopd": "^1.1.0",
 | 
				
			||||||
@ -4081,12 +4026,6 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
					        "url": "https://github.com/sponsors/sindresorhus"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/lodash": {
 | 
					 | 
				
			||||||
      "version": "4.17.21",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
 | 
					 | 
				
			||||||
      "license": "MIT"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/lodash.merge": {
 | 
					    "node_modules/lodash.merge": {
 | 
				
			||||||
      "version": "4.6.2",
 | 
					      "version": "4.6.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
 | 
				
			||||||
@ -4227,26 +4166,11 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/object-is": {
 | 
					 | 
				
			||||||
      "version": "1.1.6",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "call-bind": "^1.0.7",
 | 
					 | 
				
			||||||
        "define-properties": "^1.2.1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "engines": {
 | 
					 | 
				
			||||||
        "node": ">= 0.4"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "funding": {
 | 
					 | 
				
			||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/object-keys": {
 | 
					    "node_modules/object-keys": {
 | 
				
			||||||
      "version": "1.1.1",
 | 
					      "version": "1.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
 | 
					      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">= 0.4"
 | 
					        "node": ">= 0.4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -4388,12 +4312,6 @@
 | 
				
			|||||||
      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
 | 
					      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
 | 
				
			||||||
      "license": "(MIT AND Zlib)"
 | 
					      "license": "(MIT AND Zlib)"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/parchment": {
 | 
					 | 
				
			||||||
      "version": "1.1.4",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==",
 | 
					 | 
				
			||||||
      "license": "BSD-3-Clause"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/parent-module": {
 | 
					    "node_modules/parent-module": {
 | 
				
			||||||
      "version": "1.0.1",
 | 
					      "version": "1.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
 | 
				
			||||||
@ -4550,34 +4468,6 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/quill": {
 | 
					 | 
				
			||||||
      "version": "1.3.7",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
 | 
					 | 
				
			||||||
      "license": "BSD-3-Clause",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "clone": "^2.1.1",
 | 
					 | 
				
			||||||
        "deep-equal": "^1.0.1",
 | 
					 | 
				
			||||||
        "eventemitter3": "^2.0.3",
 | 
					 | 
				
			||||||
        "extend": "^3.0.2",
 | 
					 | 
				
			||||||
        "parchment": "^1.1.4",
 | 
					 | 
				
			||||||
        "quill-delta": "^3.6.2"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/quill-delta": {
 | 
					 | 
				
			||||||
      "version": "3.6.3",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "deep-equal": "^1.0.1",
 | 
					 | 
				
			||||||
        "extend": "^3.0.2",
 | 
					 | 
				
			||||||
        "fast-diff": "1.1.2"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "engines": {
 | 
					 | 
				
			||||||
        "node": ">=0.10"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/randombytes": {
 | 
					    "node_modules/randombytes": {
 | 
				
			||||||
      "version": "2.1.0",
 | 
					      "version": "2.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
 | 
				
			||||||
@ -4645,21 +4535,6 @@
 | 
				
			|||||||
      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
 | 
					      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/react-quill": {
 | 
					 | 
				
			||||||
      "version": "2.0.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "@types/quill": "^1.3.10",
 | 
					 | 
				
			||||||
        "lodash": "^4.17.4",
 | 
					 | 
				
			||||||
        "quill": "^1.3.7"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "peerDependencies": {
 | 
					 | 
				
			||||||
        "react": "^16 || ^17 || ^18",
 | 
					 | 
				
			||||||
        "react-dom": "^16 || ^17 || ^18"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/react-redux": {
 | 
					    "node_modules/react-redux": {
 | 
				
			||||||
      "version": "9.2.0",
 | 
					      "version": "9.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
 | 
				
			||||||
@ -4776,6 +4651,7 @@
 | 
				
			|||||||
      "version": "1.5.3",
 | 
					      "version": "1.5.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
 | 
				
			||||||
      "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
 | 
					      "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "call-bind": "^1.0.7",
 | 
					        "call-bind": "^1.0.7",
 | 
				
			||||||
        "define-properties": "^1.2.1",
 | 
					        "define-properties": "^1.2.1",
 | 
				
			||||||
@ -5070,6 +4946,7 @@
 | 
				
			|||||||
      "version": "1.2.2",
 | 
					      "version": "1.2.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
 | 
					      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "define-data-property": "^1.1.4",
 | 
					        "define-data-property": "^1.1.4",
 | 
				
			||||||
        "es-errors": "^1.3.0",
 | 
					        "es-errors": "^1.3.0",
 | 
				
			||||||
@ -5086,6 +4963,7 @@
 | 
				
			|||||||
      "version": "2.0.2",
 | 
					      "version": "2.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
 | 
					      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "define-data-property": "^1.1.4",
 | 
					        "define-data-property": "^1.1.4",
 | 
				
			||||||
        "es-errors": "^1.3.0",
 | 
					        "es-errors": "^1.3.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
    "react-apexcharts": "^1.7.0",
 | 
					    "react-apexcharts": "^1.7.0",
 | 
				
			||||||
    "react-dom": "^18.2.0",
 | 
					    "react-dom": "^18.2.0",
 | 
				
			||||||
    "react-hook-form": "^7.54.2",
 | 
					    "react-hook-form": "^7.54.2",
 | 
				
			||||||
    "react-quill": "^2.0.0",
 | 
					 | 
				
			||||||
    "react-redux": "^9.2.0",
 | 
					    "react-redux": "^9.2.0",
 | 
				
			||||||
    "react-router-dom": "^6.20.1",
 | 
					    "react-router-dom": "^6.20.1",
 | 
				
			||||||
    "react-toastify": "^11.0.2",
 | 
					    "react-toastify": "^11.0.2",
 | 
				
			||||||
 | 
				
			|||||||
@ -190,12 +190,6 @@
 | 
				
			|||||||
  padding-left: 50px;
 | 
					  padding-left: 50px;
 | 
				
			||||||
} */
 | 
					} */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.small-text {
 | 
					.small-text{
 | 
				
			||||||
  font-size: 12px;
 | 
					  font-size: 12px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
.layout-wrapper:not(.layout-horizontal)
 | 
					 | 
				
			||||||
  .layout-navbar
 | 
					 | 
				
			||||||
  .dropdown-menu[data-bs-popper] {
 | 
					 | 
				
			||||||
  inset-block-start: 100%;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								public/assets/vendor/css/core.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								public/assets/vendor/css/core.css
									
									
									
									
										vendored
									
									
								
							@ -5069,9 +5069,6 @@ fieldset:disabled .btn {
 | 
				
			|||||||
.card-group > .card {
 | 
					.card-group > .card {
 | 
				
			||||||
  margin-bottom: var(--bs-card-group-margin);
 | 
					  margin-bottom: var(--bs-card-group-margin);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.card-minHeight{
 | 
					 | 
				
			||||||
  min-height: 430px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@media (min-width: 576px) {
 | 
					@media (min-width: 576px) {
 | 
				
			||||||
  .card-group {
 | 
					  .card-group {
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
@ -16892,8 +16889,7 @@ li:not(:first-child) .dropdown-item,
 | 
				
			|||||||
  box-shadow: var(--bs-box-shadow-xs);
 | 
					  box-shadow: var(--bs-box-shadow-xs);
 | 
				
			||||||
  filter: none;
 | 
					  filter: none;
 | 
				
			||||||
  opacity: 1;
 | 
					  opacity: 1;
 | 
				
			||||||
  transform: translate(6px, -9px);
 | 
					  transform: translate(23px, -25px);
 | 
				
			||||||
  z-index: 1056;
 | 
					 | 
				
			||||||
  border-radius: 0.25rem;
 | 
					  border-radius: 0.25rem;
 | 
				
			||||||
  transition: all 0.23s ease 0.1s;
 | 
					  transition: all 0.23s ease 0.1s;
 | 
				
			||||||
  /* For hover effect of close btn */
 | 
					  /* For hover effect of close btn */
 | 
				
			||||||
@ -16903,18 +16899,18 @@ li:not(:first-child) .dropdown-item,
 | 
				
			|||||||
    transition: none;
 | 
					    transition: none;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/* .modal .btn-close:hover,
 | 
					.modal .btn-close:hover,
 | 
				
			||||||
.modal .btn-close:focus,
 | 
					.modal .btn-close:focus,
 | 
				
			||||||
.modal .btn-close:active {
 | 
					.modal .btn-close:active {
 | 
				
			||||||
  opacity: 1;
 | 
					  opacity: 1;
 | 
				
			||||||
  outline: 0;
 | 
					  outline: 0;
 | 
				
			||||||
  transform: translate(20px, -20px);
 | 
					  transform: translate(20px, -20px);
 | 
				
			||||||
} */
 | 
					}
 | 
				
			||||||
/* :dir(rtl) .modal .btn-close:hover,
 | 
					:dir(rtl) .modal .btn-close:hover,
 | 
				
			||||||
:dir(rtl) .modal .btn-close:focus,
 | 
					:dir(rtl) .modal .btn-close:focus,
 | 
				
			||||||
:dir(rtl) .modal .btn-close:active {
 | 
					:dir(rtl) .modal .btn-close:active {
 | 
				
			||||||
  transform: translate(26px, -20px);
 | 
					  transform: translate(26px, -20px);
 | 
				
			||||||
} */
 | 
					}
 | 
				
			||||||
.modal .btn-close::before {
 | 
					.modal .btn-close::before {
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  background-color: var(--bs-secondary-color);
 | 
					  background-color: var(--bs-secondary-color);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
import { DireProvider } from "./Context/DireContext";
 | 
					 | 
				
			||||||
import AppRoutes from "./router/AppRoutes";
 | 
					import AppRoutes from "./router/AppRoutes";
 | 
				
			||||||
import { ToastContainer } from "react-toastify";
 | 
					import { ToastContainer } from "react-toastify";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -6,13 +5,8 @@ import { ToastContainer } from "react-toastify";
 | 
				
			|||||||
const App = () => {
 | 
					const App = () => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="app">
 | 
					    <div className="app">
 | 
				
			||||||
      <DireProvider>
 | 
					 | 
				
			||||||
      <AppRoutes />
 | 
					      <AppRoutes />
 | 
				
			||||||
      </DireProvider>
 | 
					    <ToastContainer></ToastContainer>
 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      <ToastContainer>
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    </ToastContainer>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
				
			|||||||
@ -1,21 +0,0 @@
 | 
				
			|||||||
import React, { createContext, useContext, useState } from "react";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const DireContext = createContext(undefined);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const DireProvider = ({ children }) => {
 | 
					 | 
				
			||||||
  const [dirActions, setDirActions] = useState([]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <DireContext.Provider value={{ dirActions, setDirActions }}>
 | 
					 | 
				
			||||||
      {children}
 | 
					 | 
				
			||||||
    </DireContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useDir = () => {
 | 
					 | 
				
			||||||
  const context = useContext(DireContext);
 | 
					 | 
				
			||||||
  if (!context) {
 | 
					 | 
				
			||||||
    throw new Error("useDir must be used within a <DireProvider>");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return context;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -1,15 +0,0 @@
 | 
				
			|||||||
import React, { createContext, useContext, useState } from "react";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const FabContext = createContext();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const FabProvider = ({ children }) => {
 | 
					 | 
				
			||||||
  const [actions, setActions] = useState([]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <FabContext.Provider value={{ actions, setActions }}>
 | 
					 | 
				
			||||||
      {children}
 | 
					 | 
				
			||||||
    </FabContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useFab = () => useContext(FabContext);
 | 
					 | 
				
			||||||
@ -5,7 +5,6 @@ import { convertShortTime } from "../../utils/dateUtils";
 | 
				
			|||||||
import RenderAttendanceStatus from "./RenderAttendanceStatus";
 | 
					import RenderAttendanceStatus from "./RenderAttendanceStatus";
 | 
				
			||||||
import usePagination from "../../hooks/usePagination";
 | 
					import usePagination from "../../hooks/usePagination";
 | 
				
			||||||
import { useNavigate } from "react-router-dom";
 | 
					import { useNavigate } from "react-router-dom";
 | 
				
			||||||
import {ITEMS_PER_PAGE} from "../../utils/constants";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Attendance = ({ attendance, getRole, handleModalData }) => {
 | 
					const Attendance = ({ attendance, getRole, handleModalData }) => {
 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					  const [loading, setLoading] = useState(false);
 | 
				
			||||||
@ -34,7 +33,7 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const { currentPage, totalPages, currentItems, paginate } = usePagination(
 | 
					  const { currentPage, totalPages, currentItems, paginate } = usePagination(
 | 
				
			||||||
    filteredData,
 | 
					    filteredData,
 | 
				
			||||||
    ITEMS_PER_PAGE
 | 
					    20
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,192 +0,0 @@
 | 
				
			|||||||
import React from "react";
 | 
					 | 
				
			||||||
import Avatar from "../common/Avatar";
 | 
					 | 
				
			||||||
import { getBucketNameById } from "./DirectoryUtils";
 | 
					 | 
				
			||||||
import { useBuckets } from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
import { getPhoneIcon } from "./DirectoryUtils";
 | 
					 | 
				
			||||||
import { useDir } from "../../Context/DireContext";
 | 
					 | 
				
			||||||
const CardViewDirectory = ({
 | 
					 | 
				
			||||||
  IsActive,
 | 
					 | 
				
			||||||
  contact,
 | 
					 | 
				
			||||||
  setSelectedContact,
 | 
					 | 
				
			||||||
  setIsOpenModal,
 | 
					 | 
				
			||||||
  setOpen_contact,
 | 
					 | 
				
			||||||
  setIsOpenModalNote,
 | 
					 | 
				
			||||||
  IsDeleted,
 | 
					 | 
				
			||||||
  restore,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const { buckets } = useBuckets();
 | 
					 | 
				
			||||||
  const { dirActions, setDirActions } = useDir();
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div
 | 
					 | 
				
			||||||
      className="card text-start border-1"
 | 
					 | 
				
			||||||
      style={{ background: `${!IsActive ? "#f8f6f6" : ""}` }}
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <div className="card-body  px-1 py-2 pb-0">
 | 
					 | 
				
			||||||
        <div className="d-flex justify-content-between">
 | 
					 | 
				
			||||||
          <div
 | 
					 | 
				
			||||||
            className={`d-flex align-items-center ${
 | 
					 | 
				
			||||||
              IsActive && "cursor-pointer"
 | 
					 | 
				
			||||||
            }`}
 | 
					 | 
				
			||||||
            onClick={() => {
 | 
					 | 
				
			||||||
              if (IsActive) {
 | 
					 | 
				
			||||||
                setIsOpenModalNote(true);
 | 
					 | 
				
			||||||
                setOpen_contact(contact);
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <Avatar
 | 
					 | 
				
			||||||
              size="xs"
 | 
					 | 
				
			||||||
              firstName={
 | 
					 | 
				
			||||||
                (contact?.name || "").trim().split(" ")[0]?.charAt(0) || ""
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              lastName={
 | 
					 | 
				
			||||||
                (contact?.name || "").trim().split(" ")[1]?.charAt(0) || ""
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            />{" "}
 | 
					 | 
				
			||||||
            <span className="text-heading fs-6"> {contact?.name}</span>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div>
 | 
					 | 
				
			||||||
            {IsActive && (
 | 
					 | 
				
			||||||
              <div className="dropdown z-2">
 | 
					 | 
				
			||||||
                <button
 | 
					 | 
				
			||||||
                  type="button"
 | 
					 | 
				
			||||||
                  className="btn btn-xs btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0 m-0"
 | 
					 | 
				
			||||||
                  data-bs-toggle="dropdown"
 | 
					 | 
				
			||||||
                  aria-expanded="false"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  <i
 | 
					 | 
				
			||||||
                    className="bx bx-dots-vertical-rounded text-muted p-0"
 | 
					 | 
				
			||||||
                    data-bs-toggle="tooltip"
 | 
					 | 
				
			||||||
                    data-bs-offset="0,8"
 | 
					 | 
				
			||||||
                    data-bs-placement="top"
 | 
					 | 
				
			||||||
                    data-bs-custom-class="tooltip-dark"
 | 
					 | 
				
			||||||
                    title="More Action"
 | 
					 | 
				
			||||||
                  ></i>
 | 
					 | 
				
			||||||
                </button>
 | 
					 | 
				
			||||||
                <ul className="dropdown-menu dropdown-menu-end w-auto">
 | 
					 | 
				
			||||||
                  <li
 | 
					 | 
				
			||||||
                    onClick={() => {
 | 
					 | 
				
			||||||
                      setSelectedContact(contact);
 | 
					 | 
				
			||||||
                      setIsOpenModal(true);
 | 
					 | 
				
			||||||
                    }}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    <a className="dropdown-item px-2 cursor-pointer py-1">
 | 
					 | 
				
			||||||
                      <i className="bx bx-edit bx-xs text-primary  me-2"></i>
 | 
					 | 
				
			||||||
                      <span className="align-left ">Modify</span>
 | 
					 | 
				
			||||||
                    </a>
 | 
					 | 
				
			||||||
                  </li>
 | 
					 | 
				
			||||||
                  <li>
 | 
					 | 
				
			||||||
                    <a
 | 
					 | 
				
			||||||
                      className="dropdown-item  px-2 cursor-pointer py-1"
 | 
					 | 
				
			||||||
                      onClick={() => IsDeleted(contact?.id)}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      <i className="bx bx-trash text-danger  bx-xs me-2"></i>
 | 
					 | 
				
			||||||
                      <span className="align-left">Delete</span>
 | 
					 | 
				
			||||||
                    </a>
 | 
					 | 
				
			||||||
                  </li>
 | 
					 | 
				
			||||||
                </ul>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
            {!IsActive && (
 | 
					 | 
				
			||||||
              <i
 | 
					 | 
				
			||||||
                className={`bx  ${
 | 
					 | 
				
			||||||
                  dirActions.action && dirActions.id === contact.id
 | 
					 | 
				
			||||||
                    ? "bx-loader-alt bx-spin"
 | 
					 | 
				
			||||||
                    : "bx-recycle"
 | 
					 | 
				
			||||||
                } me-1 text-primary cursor-pointer`}
 | 
					 | 
				
			||||||
                title="Restore"
 | 
					 | 
				
			||||||
                onClick={() => {
 | 
					 | 
				
			||||||
                  setDirActions({ action: false, id: contact.id });
 | 
					 | 
				
			||||||
                  restore(contact.id);
 | 
					 | 
				
			||||||
                }}
 | 
					 | 
				
			||||||
              ></i>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <ul className="list-inline m-0 ps-4 d-flex align-items-start">
 | 
					 | 
				
			||||||
          {/* <li className="list-inline-item me-1 small">
 | 
					 | 
				
			||||||
            <i className="fa-solid fa-briefcase me-2"></i>
 | 
					 | 
				
			||||||
          </li> */}
 | 
					 | 
				
			||||||
          <li className="list-inline-item text-break small ms-5">
 | 
					 | 
				
			||||||
            {contact.organization}
 | 
					 | 
				
			||||||
          </li>
 | 
					 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <div
 | 
					 | 
				
			||||||
        className={`card-footer text-start px-1 py-1 ${
 | 
					 | 
				
			||||||
          IsActive && "cursor-pointer"
 | 
					 | 
				
			||||||
        }`}
 | 
					 | 
				
			||||||
        onClick={() => {
 | 
					 | 
				
			||||||
          if (IsActive) {
 | 
					 | 
				
			||||||
            setIsOpenModalNote(true);
 | 
					 | 
				
			||||||
            setOpen_contact(contact);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <hr className="my-0" />
 | 
					 | 
				
			||||||
        {contact.contactEmails[0] && (
 | 
					 | 
				
			||||||
          <ul className="list-unstyled my-1 d-flex align-items-start   ms-2">
 | 
					 | 
				
			||||||
            <li className="me-2">
 | 
					 | 
				
			||||||
              <i className="bx bx-envelope bx-xs mt-1"></i>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
            <li className="flex-grow-1 text-break small">
 | 
					 | 
				
			||||||
              {contact.contactEmails[0].emailAddress}
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
          </ul>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {contact.contactPhones[0] && (
 | 
					 | 
				
			||||||
          <ul className="list-inline m-0  ms-2">
 | 
					 | 
				
			||||||
            <li className="list-inline-item me-1">
 | 
					 | 
				
			||||||
              <i
 | 
					 | 
				
			||||||
                className={` ${getPhoneIcon(
 | 
					 | 
				
			||||||
                  contact.contactPhones[0].label
 | 
					 | 
				
			||||||
                )} bx-xs`}
 | 
					 | 
				
			||||||
              ></i>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
            <li className="list-inline-item text-small">
 | 
					 | 
				
			||||||
              {contact.contactPhones[0]?.phoneNumber}
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
          </ul>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {contact?.contactCategory?.name ? (
 | 
					 | 
				
			||||||
          <ul className="list-inline m-0   ms-2">
 | 
					 | 
				
			||||||
            <li className="list-inline-item me-2 my-1">
 | 
					 | 
				
			||||||
              <i className="fa-solid fa-tag fs-6 ms-1"></i>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
            <li className="list-inline-item text-small active">
 | 
					 | 
				
			||||||
              {contact?.contactCategory?.name}
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
          </ul>
 | 
					 | 
				
			||||||
        ) : (
 | 
					 | 
				
			||||||
          <ul className="list-inline m-0   ms-2">
 | 
					 | 
				
			||||||
            <li className="list-inline-item me-2 my-1">
 | 
					 | 
				
			||||||
              <i className="fa-solid fa-tag fs-6 ms-1"></i>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
            <li className="list-inline-item text-small active">Other</li>
 | 
					 | 
				
			||||||
          </ul>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <ul className="list-inline m-0   ms-2">
 | 
					 | 
				
			||||||
          {contact?.bucketIds?.map((bucketId) => (
 | 
					 | 
				
			||||||
            <li key={bucketId} className="list-inline-item me-1">
 | 
					 | 
				
			||||||
              <span
 | 
					 | 
				
			||||||
                className="badge bg-label-primary rounded-pill d-flex align-items-center gap-1"
 | 
					 | 
				
			||||||
                style={{ padding: "0.1rem 0.3rem" }}
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <i className="bx bx-pin bx-xs"></i>
 | 
					 | 
				
			||||||
                <span className="small-text">
 | 
					 | 
				
			||||||
                  {getBucketNameById(buckets, bucketId)}
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
              </span>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
          ))}
 | 
					 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default CardViewDirectory;
 | 
					 | 
				
			||||||
@ -1,65 +0,0 @@
 | 
				
			|||||||
import { z } from "zod";
 | 
					 | 
				
			||||||
export const ContactSchema = z
 | 
					 | 
				
			||||||
  .object({
 | 
					 | 
				
			||||||
    name: z.string().min(1, "Name is required"),
 | 
					 | 
				
			||||||
    organization: z.string().min(1, "Organization name is required"),
 | 
					 | 
				
			||||||
    contactCategoryId: z.string().nullable().optional(),
 | 
					 | 
				
			||||||
    address: z.string().optional(),
 | 
					 | 
				
			||||||
    description: z.string().min(1, { message: "Description is required" }),
 | 
					 | 
				
			||||||
    projectIds: z.array(z.string()).nullable().optional(), // min(1, "Project is required")
 | 
					 | 
				
			||||||
    contactEmails: z
 | 
					 | 
				
			||||||
      .array(
 | 
					 | 
				
			||||||
        z.object({
 | 
					 | 
				
			||||||
          label: z.string(),
 | 
					 | 
				
			||||||
           emailAddress: z.string().email("Invalid email").or(z.literal("")),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      .optional()
 | 
					 | 
				
			||||||
      .default([]),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    contactPhones: z
 | 
					 | 
				
			||||||
      .array(
 | 
					 | 
				
			||||||
        z.object({
 | 
					 | 
				
			||||||
          label: z.string(),
 | 
					 | 
				
			||||||
          phoneNumber: z
 | 
					 | 
				
			||||||
            .string()
 | 
					 | 
				
			||||||
            .min(6, "Invalid Number")
 | 
					 | 
				
			||||||
            .max(13, "Invalid Number")
 | 
					 | 
				
			||||||
            .regex(/^[\d\s+()-]+$/, "Invalid phone number format").or(z.literal("")),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      .optional()
 | 
					 | 
				
			||||||
      .default([]),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tags: z
 | 
					 | 
				
			||||||
      .array(
 | 
					 | 
				
			||||||
        z.object({
 | 
					 | 
				
			||||||
          id: z.string().nullable(),
 | 
					 | 
				
			||||||
          name: z.string(),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      .min(1, { message: "At least one tag is required" }),
 | 
					 | 
				
			||||||
bucketIds: z.array(z.string()).nonempty({ message: "At least one label is required" })
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//    .refine((data) => {
 | 
					 | 
				
			||||||
//   const hasValidEmail = (data.contactEmails || []).some(
 | 
					 | 
				
			||||||
//     (e) => e.emailAddress?.trim() !== ""
 | 
					 | 
				
			||||||
//   );
 | 
					 | 
				
			||||||
//   const hasValidPhone = (data.contactPhones || []).some(
 | 
					 | 
				
			||||||
//     (p) => p.phoneNumber?.trim() !== ""
 | 
					 | 
				
			||||||
//   );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//   return hasValidEmail || hasValidPhone;
 | 
					 | 
				
			||||||
// }, {
 | 
					 | 
				
			||||||
//   message: "At least one contact (email or phone) is required",
 | 
					 | 
				
			||||||
//   path: ["contactPhone"],
 | 
					 | 
				
			||||||
// });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Buckets
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const bucketScheam = z.object( {
 | 
					 | 
				
			||||||
  name: z.string().min( 1, {message: "Name is required"} ),
 | 
					 | 
				
			||||||
  description:z.string().min(1,{message:"Description is required"})
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
import {useBuckets} from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getEmailIcon = (type) => {
 | 
					 | 
				
			||||||
  switch (type) {
 | 
					 | 
				
			||||||
    case 'Work': return "bx bx-briefcase me-1 " ;
 | 
					 | 
				
			||||||
    case 'Personal': return "bx bx-user me-1";
 | 
					 | 
				
			||||||
    case 'support': return "bx headphone-mic me-1";
 | 
					 | 
				
			||||||
    case 'billing': return "bx bx-receipt me-1";
 | 
					 | 
				
			||||||
    default: return "bx bx-envelope me-1";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getPhoneIcon = (type) => {
 | 
					 | 
				
			||||||
  switch (type) {
 | 
					 | 
				
			||||||
    case 'Business': return "bx bx-phone me-1 ";
 | 
					 | 
				
			||||||
    case 'Personal': return "bx bx-mobile me-1 ";
 | 
					 | 
				
			||||||
    case 'Office': return "bx bx-phone me-1 ";
 | 
					 | 
				
			||||||
    default: return "bx bx-phone me-1";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getBucketNameById = (buckets, id) => {
 | 
					 | 
				
			||||||
  const bucket = buckets.find(b => b.id === id);
 | 
					 | 
				
			||||||
  return bucket ? bucket.name : 'Unknown';
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -1,158 +0,0 @@
 | 
				
			|||||||
import React, { useState, useEffect } from "react";
 | 
					 | 
				
			||||||
import { useSortableData } from "../../hooks/useSortableData";
 | 
					 | 
				
			||||||
import Avatar from "../common/Avatar";
 | 
					 | 
				
			||||||
const EmployeeList = ({ employees, onChange, bucket }) => {
 | 
					 | 
				
			||||||
  const [employeefiltered, setEmployeeFilter] = useState([]);
 | 
					 | 
				
			||||||
  const [employeeStatusList, setEmployeeStatusList] = useState([]);
 | 
					 | 
				
			||||||
  const [searchTerm, setSearchTerm] = useState("");
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    setEmployeeFilter(employees?.filter((emp) => emp.email != null) || []);
 | 
					 | 
				
			||||||
  }, [employees]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Initialize checked employees based on assignedEmployee prop
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (Array.isArray(bucket?.employeeIds)) {
 | 
					 | 
				
			||||||
      const initialStatus = bucket?.employeeIds?.map((id) => ({
 | 
					 | 
				
			||||||
        employeeId: id,
 | 
					 | 
				
			||||||
        isActive: true,
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      setEmployeeStatusList(initialStatus);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [bucket]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Send updated list to parent
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (onChange) {
 | 
					 | 
				
			||||||
      onChange(employeeStatusList);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [employeeStatusList]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleCheckboxChange = (id) => {
 | 
					 | 
				
			||||||
    setEmployeeStatusList((prev) => {
 | 
					 | 
				
			||||||
      const exists = prev.find((emp) => emp.employeeId === id);
 | 
					 | 
				
			||||||
      if (exists) {
 | 
					 | 
				
			||||||
        return prev.map((emp) =>
 | 
					 | 
				
			||||||
          emp.employeeId === id ? { ...emp, isActive: !emp.isActive } : emp
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        return [...prev, { employeeId: id, isActive: true }];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const isChecked = (id) => {
 | 
					 | 
				
			||||||
    const found = employeeStatusList.find((emp) => emp.employeeId === id);
 | 
					 | 
				
			||||||
    return found?.isActive || false;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Sorting
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    items: sortedEmployees,
 | 
					 | 
				
			||||||
    requestSort,
 | 
					 | 
				
			||||||
    sortConfig,
 | 
					 | 
				
			||||||
  } = useSortableData(employeefiltered, {
 | 
					 | 
				
			||||||
    key: (e) => `${e?.firstName} ${e?.lastName}`,
 | 
					 | 
				
			||||||
    direction: "asc",
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const getSortIcon = () => {
 | 
					 | 
				
			||||||
    if (!sortConfig) return null;
 | 
					 | 
				
			||||||
    return sortConfig.direction === "asc" ? (
 | 
					 | 
				
			||||||
      <i className="bx bx-caret-up text-secondary"></i>
 | 
					 | 
				
			||||||
    ) : (
 | 
					 | 
				
			||||||
      <i className="bx bx-caret-down text-secondary"></i>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const filteredEmployees = sortedEmployees?.filter((employee) => {
 | 
					 | 
				
			||||||
    const fullName =
 | 
					 | 
				
			||||||
      `${employee?.firstName} ${employee?.lastName}`?.toLowerCase();
 | 
					 | 
				
			||||||
    return fullName.includes(searchTerm.toLowerCase());
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <div className="d-flex justify-content-between align-items-center mt-2">
 | 
					 | 
				
			||||||
        <p className="m-0  fw-normal">Add Employee</p>
 | 
					 | 
				
			||||||
        <div className="px-1">
 | 
					 | 
				
			||||||
          <input
 | 
					 | 
				
			||||||
            type="search"
 | 
					 | 
				
			||||||
            className="form-control form-control-sm"
 | 
					 | 
				
			||||||
            placeholder="Search Employee..."
 | 
					 | 
				
			||||||
            value={searchTerm}
 | 
					 | 
				
			||||||
            onChange={(e) => setSearchTerm(e.target.value)}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div className="table-responsive px-1 my-1 px-sm-0">
 | 
					 | 
				
			||||||
        <table className="table align-middle mb-0">
 | 
					 | 
				
			||||||
          <thead className="table-light">
 | 
					 | 
				
			||||||
            <tr>
 | 
					 | 
				
			||||||
              <th
 | 
					 | 
				
			||||||
                onClick={() =>
 | 
					 | 
				
			||||||
                  requestSort((e) => `${e.firstName} ${e.lastName}`)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                className="text-start cursor-pointer"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <span className="ps-2">Name {getSortIcon()}</span>
 | 
					 | 
				
			||||||
              </th>
 | 
					 | 
				
			||||||
              <th className="text-start">Role</th>
 | 
					 | 
				
			||||||
            </tr>
 | 
					 | 
				
			||||||
          </thead>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          <tbody>
 | 
					 | 
				
			||||||
            {employees.length === 0 ? (
 | 
					 | 
				
			||||||
              <tr>
 | 
					 | 
				
			||||||
                <td colSpan={4}>
 | 
					 | 
				
			||||||
                  <div className="d-flex justify-content-center align-items-center py-5">
 | 
					 | 
				
			||||||
                    No Employee Available
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </td>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            ) : filteredEmployees.length === 0 ? (
 | 
					 | 
				
			||||||
              <tr className="my-4">
 | 
					 | 
				
			||||||
                <td colSpan={4}>
 | 
					 | 
				
			||||||
                  <div className="d-flex justify-content-center align-items-center py-5">
 | 
					 | 
				
			||||||
                    No Matching Employee Found.
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </td>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            ) : (
 | 
					 | 
				
			||||||
              filteredEmployees?.map((employee) => (
 | 
					 | 
				
			||||||
                <tr key={employee.id}>
 | 
					 | 
				
			||||||
                  <td>
 | 
					 | 
				
			||||||
                    <div className="d-flex align-items-center text-start">
 | 
					 | 
				
			||||||
                      <input
 | 
					 | 
				
			||||||
                        className="form-check-input me-3 mt-1"
 | 
					 | 
				
			||||||
                        type="checkbox"
 | 
					 | 
				
			||||||
                        checked={isChecked(employee.id)}
 | 
					 | 
				
			||||||
                        onChange={() => handleCheckboxChange(employee?.id)}
 | 
					 | 
				
			||||||
                        disabled={bucket?.createdBy?.id === employee?.id}
 | 
					 | 
				
			||||||
                      />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                      <Avatar
 | 
					 | 
				
			||||||
                        size="xs"
 | 
					 | 
				
			||||||
                        classAvatar="m-0"
 | 
					 | 
				
			||||||
                        firstName={employee.firstName}
 | 
					 | 
				
			||||||
                        lastName={employee.lastName}
 | 
					 | 
				
			||||||
                      />
 | 
					 | 
				
			||||||
                      <span
 | 
					 | 
				
			||||||
                        className="text-truncate mx-0"
 | 
					 | 
				
			||||||
                        style={{ maxWidth: "150px" }}
 | 
					 | 
				
			||||||
                      >{`${employee.firstName} ${employee.lastName}`}</span>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                  </td>
 | 
					 | 
				
			||||||
                  <td className="text-start">
 | 
					 | 
				
			||||||
                    <small className="text-muted">{employee.jobRole}</small>
 | 
					 | 
				
			||||||
                  </td>
 | 
					 | 
				
			||||||
                </tr>
 | 
					 | 
				
			||||||
              ))
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </tbody>
 | 
					 | 
				
			||||||
        </table>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default EmployeeList;
 | 
					 | 
				
			||||||
@ -1,131 +0,0 @@
 | 
				
			|||||||
import React, { useEffect } from "react";
 | 
					 | 
				
			||||||
import Avatar from "../common/Avatar";
 | 
					 | 
				
			||||||
import { getEmailIcon, getPhoneIcon } from "./DirectoryUtils";
 | 
					 | 
				
			||||||
import { useDir } from "../../Context/DireContext";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ListViewDirectory = ({
 | 
					 | 
				
			||||||
  IsActive,
 | 
					 | 
				
			||||||
  contact,
 | 
					 | 
				
			||||||
  setSelectedContact,
 | 
					 | 
				
			||||||
  setIsOpenModal,
 | 
					 | 
				
			||||||
  setOpen_contact,
 | 
					 | 
				
			||||||
  setIsOpenModalNote,
 | 
					 | 
				
			||||||
  IsDeleted,
 | 
					 | 
				
			||||||
  restore,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const { dirActions, setDirActions } = useDir();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <tr className={!IsActive ? "bg-light" : ""}>
 | 
					 | 
				
			||||||
      <td
 | 
					 | 
				
			||||||
        className="text-start cursor-pointer"
 | 
					 | 
				
			||||||
        style={{ width: "18%" }}
 | 
					 | 
				
			||||||
        colSpan={2}
 | 
					 | 
				
			||||||
        onClick={() => {
 | 
					 | 
				
			||||||
          if (IsActive) {
 | 
					 | 
				
			||||||
            setIsOpenModalNote(true);
 | 
					 | 
				
			||||||
            setOpen_contact(contact);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <div className="d-flex align-items-center">
 | 
					 | 
				
			||||||
          <Avatar
 | 
					 | 
				
			||||||
            size="xs"
 | 
					 | 
				
			||||||
            classAvatar="m-0"
 | 
					 | 
				
			||||||
            firstName={
 | 
					 | 
				
			||||||
              (contact?.name || "").trim().split(" ")[0]?.charAt(0) || ""
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            lastName={
 | 
					 | 
				
			||||||
              (contact?.name || "").trim().split(" ")[1]?.charAt(0) || ""
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          <span className="text-truncate mx-0" style={{ maxWidth: "150px" }}>
 | 
					 | 
				
			||||||
            {contact?.name || ""}
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <td className="px-2" style={{ width: "20%" }}>
 | 
					 | 
				
			||||||
        <div className="d-flex flex-column align-items-start text-truncate">
 | 
					 | 
				
			||||||
         {contact.contactEmails.length > 0 ? (contact.contactEmails?.map((email, index) => (
 | 
					 | 
				
			||||||
            <span key={email.id} className="text-truncate">
 | 
					 | 
				
			||||||
              <i
 | 
					 | 
				
			||||||
                className={getEmailIcon(email.label)}
 | 
					 | 
				
			||||||
                style={{ fontSize: "12px" }}
 | 
					 | 
				
			||||||
              ></i>
 | 
					 | 
				
			||||||
              <a
 | 
					 | 
				
			||||||
                href={`mailto:${email.emailAddress}`}
 | 
					 | 
				
			||||||
                className="text-decoration-none ms-1"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                {email.emailAddress}
 | 
					 | 
				
			||||||
              </a>
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
          ))):(<span className="small-text m-0 px-2">NA</span>)}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <td className="px-2" style={{ width: "20%" }}>
 | 
					 | 
				
			||||||
        <div className="d-flex flex-column align-items-start text-truncate">
 | 
					 | 
				
			||||||
           {contact.contactPhones?.length > 0 ? (
 | 
					 | 
				
			||||||
            contact.contactPhones?.map((phone, index) => (
 | 
					 | 
				
			||||||
            <span key={phone.id}>
 | 
					 | 
				
			||||||
              <i
 | 
					 | 
				
			||||||
                className={getPhoneIcon(phone.label)}
 | 
					 | 
				
			||||||
                style={{ fontSize: "12px" }}
 | 
					 | 
				
			||||||
              ></i>
 | 
					 | 
				
			||||||
              <span className="ms-1">{phone.phoneNumber}</span>
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
          ))
 | 
					 | 
				
			||||||
          ):(<span className="text-small m-0 px-2">NA</span>)}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <td
 | 
					 | 
				
			||||||
        colSpan={2}
 | 
					 | 
				
			||||||
        className="text-start text-truncate px-2"
 | 
					 | 
				
			||||||
        style={{ width: "20%", maxWidth: "200px" }}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        {contact.organization}
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <td className="px-2" style={{ width: "10%" }}>
 | 
					 | 
				
			||||||
        <span className="badge badge-outline-secondary">
 | 
					 | 
				
			||||||
          {contact?.contactCategory?.name || "Other"}
 | 
					 | 
				
			||||||
        </span>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <td className="align-middle text-center" style={{ width: "12%" }}>
 | 
					 | 
				
			||||||
        {IsActive && (
 | 
					 | 
				
			||||||
          <>
 | 
					 | 
				
			||||||
            <i
 | 
					 | 
				
			||||||
              className="bx bx-edit bx-sm text-primary cursor-pointer me-2"
 | 
					 | 
				
			||||||
              onClick={() => {
 | 
					 | 
				
			||||||
                setSelectedContact(contact);
 | 
					 | 
				
			||||||
                setIsOpenModal(true);
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
            ></i>
 | 
					 | 
				
			||||||
            <i
 | 
					 | 
				
			||||||
              className="bx bx-trash bx-sm text-danger cursor-pointer"
 | 
					 | 
				
			||||||
              onClick={() => IsDeleted(contact.id)}
 | 
					 | 
				
			||||||
            ></i>
 | 
					 | 
				
			||||||
          </>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
        {!IsActive && (
 | 
					 | 
				
			||||||
          <i
 | 
					 | 
				
			||||||
            className={`bx  ${
 | 
					 | 
				
			||||||
              dirActions.action && dirActions.id === contact.id ?  "bx-loader-alt bx-spin"
 | 
					 | 
				
			||||||
                    : "bx-recycle"
 | 
					 | 
				
			||||||
            } me-1 text-primary cursor-pointer`}
 | 
					 | 
				
			||||||
            title="Restore"
 | 
					 | 
				
			||||||
            onClick={() => {
 | 
					 | 
				
			||||||
              setDirActions({ action: false, id: contact.id });
 | 
					 | 
				
			||||||
              restore(contact.id);
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
          ></i>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
    </tr>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default ListViewDirectory;
 | 
					 | 
				
			||||||
@ -1,429 +0,0 @@
 | 
				
			|||||||
import React, { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import IconButton from "../common/IconButton";
 | 
					 | 
				
			||||||
import { useForm } from "react-hook-form";
 | 
					 | 
				
			||||||
import { zodResolver } from "@hookform/resolvers/zod";
 | 
					 | 
				
			||||||
import { bucketScheam } from "./DirectorySchema";
 | 
					 | 
				
			||||||
import showToast from "../../services/toastService";
 | 
					 | 
				
			||||||
import Directory from "../../pages/Directory/Directory";
 | 
					 | 
				
			||||||
import { DirectoryRepository } from "../../repositories/DirectoryRepository";
 | 
					 | 
				
			||||||
import { cacheData, getCachedData } from "../../slices/apiDataManager";
 | 
					 | 
				
			||||||
import { useBuckets } from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
import EmployeeList from "./EmployeeList";
 | 
					 | 
				
			||||||
import { useAllEmployees, useEmployees } from "../../hooks/useEmployees";
 | 
					 | 
				
			||||||
import { useSortableData } from "../../hooks/useSortableData";
 | 
					 | 
				
			||||||
import ConfirmModal from "../common/ConfirmModal";
 | 
					 | 
				
			||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
					 | 
				
			||||||
import { DIRECTORY_ADMIN, DIRECTORY_MANAGER } from "../../utils/constants";
 | 
					 | 
				
			||||||
import { useProfile } from "../../hooks/useProfile";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ManageBucket = () => {
 | 
					 | 
				
			||||||
  const { profile } = useProfile();
 | 
					 | 
				
			||||||
  const [bucketList, setBucketList] = useState([]);
 | 
					 | 
				
			||||||
  const { employeesList } = useAllEmployees(false);
 | 
					 | 
				
			||||||
  const [selectedEmployee, setSelectEmployee] = useState([]);
 | 
					 | 
				
			||||||
  const { buckets, loading, refetch } = useBuckets();
 | 
					 | 
				
			||||||
  const [action_bucket, setAction_bucket] = useState(false);
 | 
					 | 
				
			||||||
  const [isSubmitting, setSubmitting] = useState(false);
 | 
					 | 
				
			||||||
  const [selected_bucket, select_bucket] = useState(null);
 | 
					 | 
				
			||||||
  const [deleteBucket, setDeleteBucket] = useState(null);
 | 
					 | 
				
			||||||
  const [searchTerm, setSearchTerm] = useState("");
 | 
					 | 
				
			||||||
  const DirManager = useHasUserPermission(DIRECTORY_MANAGER);
 | 
					 | 
				
			||||||
  const DirAdmin = useHasUserPermission(DIRECTORY_ADMIN);
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    items: sortedBuckteList,
 | 
					 | 
				
			||||||
    requestSort,
 | 
					 | 
				
			||||||
    sortConfig,
 | 
					 | 
				
			||||||
  } = useSortableData(bucketList, {
 | 
					 | 
				
			||||||
    key: (e) => `${e.name}`,
 | 
					 | 
				
			||||||
    direction: "asc",
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  const getSortIcon = () => {
 | 
					 | 
				
			||||||
    if (!sortConfig) return null;
 | 
					 | 
				
			||||||
    return sortConfig.direction === "asc" ? (
 | 
					 | 
				
			||||||
      <i className="bx bx-caret-up text-secondary"></i>
 | 
					 | 
				
			||||||
    ) : (
 | 
					 | 
				
			||||||
      <i className="bx bx-caret-down text-secondary"></i>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    register,
 | 
					 | 
				
			||||||
    handleSubmit,
 | 
					 | 
				
			||||||
    reset,
 | 
					 | 
				
			||||||
    formState: { errors },
 | 
					 | 
				
			||||||
  } = useForm({
 | 
					 | 
				
			||||||
    resolver: zodResolver(bucketScheam),
 | 
					 | 
				
			||||||
    defaultValues: {
 | 
					 | 
				
			||||||
      name: "",
 | 
					 | 
				
			||||||
      description: "",
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const onSubmit = async (data) => {
 | 
					 | 
				
			||||||
    setSubmitting(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      const cache_buckets = getCachedData("buckets") || [];
 | 
					 | 
				
			||||||
      let response;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Utility: Compare arrays regardless of order
 | 
					 | 
				
			||||||
      const arraysAreEqual = (a, b) => {
 | 
					 | 
				
			||||||
        if (a.length !== b.length) return false;
 | 
					 | 
				
			||||||
        const setA = new Set(a);
 | 
					 | 
				
			||||||
        const setB = new Set(b);
 | 
					 | 
				
			||||||
        return [...setA].every((id) => setB.has(id));
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // UPDATE existing bucket
 | 
					 | 
				
			||||||
      if (selected_bucket) {
 | 
					 | 
				
			||||||
        const payload = { ...data, id: selected_bucket.id };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 1. Update bucket details
 | 
					 | 
				
			||||||
        response = await DirectoryRepository.UpdateBuckets(
 | 
					 | 
				
			||||||
          selected_bucket.id,
 | 
					 | 
				
			||||||
          payload
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const updatedBuckets = cache_buckets.map((bucket) =>
 | 
					 | 
				
			||||||
          bucket.id === selected_bucket.id ? response?.data : bucket
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cacheData("buckets", updatedBuckets);
 | 
					 | 
				
			||||||
        setBucketList(updatedBuckets);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 2. Update employee assignments if they changed
 | 
					 | 
				
			||||||
        const existingEmployeeIds = selected_bucket?.employeeIds || [];
 | 
					 | 
				
			||||||
        const employeesToUpdate = selectedEmployee.filter((emp) => {
 | 
					 | 
				
			||||||
          const isExisting = existingEmployeeIds.includes(emp.employeeId);
 | 
					 | 
				
			||||||
          return (!isExisting && emp.isActive) || (isExisting && !emp.isActive);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Create a filtered list of active employee IDs to compare
 | 
					 | 
				
			||||||
        const newActiveEmployeeIds = selectedEmployee
 | 
					 | 
				
			||||||
          .filter((emp) => {
 | 
					 | 
				
			||||||
            const isExisting = existingEmployeeIds.includes(emp.employeeId);
 | 
					 | 
				
			||||||
            return (
 | 
					 | 
				
			||||||
              (!isExisting && emp.isActive) || (isExisting && !emp.isActive)
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          })
 | 
					 | 
				
			||||||
          .map((emp) => emp.employeeId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (
 | 
					 | 
				
			||||||
          !arraysAreEqual(newActiveEmployeeIds, existingEmployeeIds) &&
 | 
					 | 
				
			||||||
          employeesToUpdate.length != 0
 | 
					 | 
				
			||||||
        ) {
 | 
					 | 
				
			||||||
          try {
 | 
					 | 
				
			||||||
            response = await DirectoryRepository.AssignedBuckets(
 | 
					 | 
				
			||||||
              selected_bucket.id,
 | 
					 | 
				
			||||||
              employeesToUpdate
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          } catch (assignError) {
 | 
					 | 
				
			||||||
            const assignMessage =
 | 
					 | 
				
			||||||
              assignError?.response?.data?.message ||
 | 
					 | 
				
			||||||
              assignError?.message ||
 | 
					 | 
				
			||||||
              "Error assigning employees.";
 | 
					 | 
				
			||||||
            showToast(assignMessage, "error");
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        const updatedData = cache_buckets?.map((bucket) =>
 | 
					 | 
				
			||||||
          bucket.id === response?.data?.id ? response.data : bucket
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cacheData("buckets", updatedData);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        setBucketList(updatedData);
 | 
					 | 
				
			||||||
        showToast("Bucket Updated Successfully", "success");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // CREATE new bucket
 | 
					 | 
				
			||||||
      else {
 | 
					 | 
				
			||||||
        response = await DirectoryRepository.CreateBuckets(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const updatedBuckets = [...cache_buckets, response?.data];
 | 
					 | 
				
			||||||
        cacheData("buckets", updatedBuckets);
 | 
					 | 
				
			||||||
        setBucketList(updatedBuckets);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        showToast("Bucket Created Successfully", "success");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      handleBack();
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      const message =
 | 
					 | 
				
			||||||
        error?.response?.data?.message ||
 | 
					 | 
				
			||||||
        error?.message ||
 | 
					 | 
				
			||||||
        "Error occurred during API call";
 | 
					 | 
				
			||||||
      showToast(message, "error");
 | 
					 | 
				
			||||||
    } finally {
 | 
					 | 
				
			||||||
      setSubmitting(false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleDeleteContact = async () => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      const resp = await DirectoryRepository.DeleteBucket(deleteBucket);
 | 
					 | 
				
			||||||
      const cache_buckets = getCachedData("buckets") || [];
 | 
					 | 
				
			||||||
      const updatedBuckets = cache_buckets.filter(
 | 
					 | 
				
			||||||
        (bucket) => bucket.id != deleteBucket
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      cacheData("buckets", updatedBuckets);
 | 
					 | 
				
			||||||
      setBucketList(updatedBuckets);
 | 
					 | 
				
			||||||
      showToast("Bucket deleted successfully", "success");
 | 
					 | 
				
			||||||
      setDeleteBucket(null);
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      const message =
 | 
					 | 
				
			||||||
        error?.response?.data?.message ||
 | 
					 | 
				
			||||||
        error?.message ||
 | 
					 | 
				
			||||||
        "Error occurred during API call.";
 | 
					 | 
				
			||||||
      showToast(message, "error");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    reset({
 | 
					 | 
				
			||||||
      name: selected_bucket?.name || "",
 | 
					 | 
				
			||||||
      description: selected_bucket?.description || "",
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }, [selected_bucket]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    setBucketList(buckets);
 | 
					 | 
				
			||||||
  }, [buckets]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleBack = () => {
 | 
					 | 
				
			||||||
    select_bucket(null);
 | 
					 | 
				
			||||||
    setAction_bucket(false);
 | 
					 | 
				
			||||||
    setSubmitting(false);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const sortedBucktesList = sortedBuckteList?.filter((bucket) => {
 | 
					 | 
				
			||||||
    const term = searchTerm?.toLowerCase();
 | 
					 | 
				
			||||||
    const name = bucket.name?.toLowerCase();
 | 
					 | 
				
			||||||
    return name?.includes(term);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      {deleteBucket && (
 | 
					 | 
				
			||||||
        <div
 | 
					 | 
				
			||||||
          className={`modal fade  ${deleteBucket ? "show" : ""}`}
 | 
					 | 
				
			||||||
          tabIndex="-1"
 | 
					 | 
				
			||||||
          role="dialog"
 | 
					 | 
				
			||||||
          style={{
 | 
					 | 
				
			||||||
            display: deleteBucket ? "block" : "none",
 | 
					 | 
				
			||||||
            backgroundColor: deleteBucket ? "rgba(0,0,0,0.5)" : "transparent",
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <ConfirmModal
 | 
					 | 
				
			||||||
            type={"delete"}
 | 
					 | 
				
			||||||
            header={"Delete Bucket"}
 | 
					 | 
				
			||||||
            message={"Are you sure you want delete?"}
 | 
					 | 
				
			||||||
            onSubmit={handleDeleteContact}
 | 
					 | 
				
			||||||
            onClose={() => setDeleteBucket(null)}
 | 
					 | 
				
			||||||
            // loading={IsDeleting}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div className="container m-0 p-0" style={{ minHeight: "200px" }}>
 | 
					 | 
				
			||||||
        <div className="d-flex justify-content-center">
 | 
					 | 
				
			||||||
          <p className="fs-6 fw-semibold m-0">Manage Buckets</p>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="d-flex justify-content-between px-2 px-sm-0 mt-5 mt-3 align-items-center ">
 | 
					 | 
				
			||||||
          {action_bucket ? (
 | 
					 | 
				
			||||||
            <i
 | 
					 | 
				
			||||||
              className={`fa-solid fa-arrow-left fs-5 cursor-pointer`}
 | 
					 | 
				
			||||||
              onClick={handleBack}
 | 
					 | 
				
			||||||
            ></i>
 | 
					 | 
				
			||||||
          ) : (
 | 
					 | 
				
			||||||
            <div className="d-flex align-items-center gap-2">
 | 
					 | 
				
			||||||
              <input
 | 
					 | 
				
			||||||
                type="search"
 | 
					 | 
				
			||||||
                className="form-control form-control-sm"
 | 
					 | 
				
			||||||
                placeholder="Search Bucket ..."
 | 
					 | 
				
			||||||
                value={searchTerm}
 | 
					 | 
				
			||||||
                onChange={(e) => setSearchTerm(e.target.value)}
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
              <i
 | 
					 | 
				
			||||||
                className={`bx bx-refresh cursor-pointer fs-4 ${
 | 
					 | 
				
			||||||
                  loading ? "spin" : ""
 | 
					 | 
				
			||||||
                }`}
 | 
					 | 
				
			||||||
                title="Refresh"
 | 
					 | 
				
			||||||
                onClick={() => refetch()}
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          <button
 | 
					 | 
				
			||||||
            type="button"
 | 
					 | 
				
			||||||
            className={`btn  btn-sm btn-primary ms-auto ${
 | 
					 | 
				
			||||||
              action_bucket ? "d-none" : ""
 | 
					 | 
				
			||||||
            }`}
 | 
					 | 
				
			||||||
            onClick={() => setAction_bucket(true)}
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <i className="bx bx-plus-circle me-2"></i>
 | 
					 | 
				
			||||||
            Add Bucket
 | 
					 | 
				
			||||||
          </button>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div>
 | 
					 | 
				
			||||||
          {!action_bucket ? (
 | 
					 | 
				
			||||||
            <div className="table-responsive text-nowrap pt-1 px-2 px-sm-0 mt-3">
 | 
					 | 
				
			||||||
              <table className="table  px-2">
 | 
					 | 
				
			||||||
                <thead className="p-0">
 | 
					 | 
				
			||||||
                  <tr className="p-0">
 | 
					 | 
				
			||||||
                    <th
 | 
					 | 
				
			||||||
                      colSpan={2}
 | 
					 | 
				
			||||||
                      className="cursor-pointer"
 | 
					 | 
				
			||||||
                      onClick={() => requestSort((e) => `${e.name} `)}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      <div className="d-flex justify-content-start align-items-center gap-1 mx-2">
 | 
					 | 
				
			||||||
                        <span>Name {getSortIcon()}</span>
 | 
					 | 
				
			||||||
                      </div>
 | 
					 | 
				
			||||||
                    </th>
 | 
					 | 
				
			||||||
                    <th className="text-start d-none d-sm-table-cell">
 | 
					 | 
				
			||||||
                      <div className="d-flex align-items-center justify-content-center gap-1">
 | 
					 | 
				
			||||||
                        <span>Description</span>
 | 
					 | 
				
			||||||
                      </div>
 | 
					 | 
				
			||||||
                    </th>
 | 
					 | 
				
			||||||
                    <th>Contacts</th>
 | 
					 | 
				
			||||||
                    <th>
 | 
					 | 
				
			||||||
                      <div className="d-flex align-items-center justify-content-center gap-1">
 | 
					 | 
				
			||||||
                        <span>Action</span>
 | 
					 | 
				
			||||||
                      </div>
 | 
					 | 
				
			||||||
                    </th>
 | 
					 | 
				
			||||||
                  </tr>
 | 
					 | 
				
			||||||
                </thead>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <tbody className="table-border-bottom-0 overflow-auto">
 | 
					 | 
				
			||||||
                  {loading && (
 | 
					 | 
				
			||||||
                    <tr className="mt-10">
 | 
					 | 
				
			||||||
                      <td colSpan={5}>
 | 
					 | 
				
			||||||
                        {" "}
 | 
					 | 
				
			||||||
                        <div className="d-flex justify-content-center align-items-center py-5">
 | 
					 | 
				
			||||||
                          Loading...
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                      </td>
 | 
					 | 
				
			||||||
                    </tr>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                  {!loading && buckets.length == 0 && (
 | 
					 | 
				
			||||||
                    <tr>
 | 
					 | 
				
			||||||
                      <td colSpan={5}>
 | 
					 | 
				
			||||||
                        <div className="d-flex justify-content-center align-items-center py-5">
 | 
					 | 
				
			||||||
                          Bucket Not Available.
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                      </td>
 | 
					 | 
				
			||||||
                    </tr>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                  {!loading && sortedBucktesList.length == 0 && (
 | 
					 | 
				
			||||||
                    <tr>
 | 
					 | 
				
			||||||
                      <td className="text-center py-4 h-25" colSpan={5}>
 | 
					 | 
				
			||||||
                        <div className="d-flex justify-content-center align-items-center py-5">
 | 
					 | 
				
			||||||
                          No Matching Bucket Found.
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                      </td>
 | 
					 | 
				
			||||||
                    </tr>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                  {!loading &&
 | 
					 | 
				
			||||||
                    sortedBucktesList.map((bucket) => (
 | 
					 | 
				
			||||||
                      <tr key={bucket.id}>
 | 
					 | 
				
			||||||
                        <td colSpan={2} className="text-start text-wrap">
 | 
					 | 
				
			||||||
                          <i className="bx bx-right-arrow-alt me-1"></i>{" "}
 | 
					 | 
				
			||||||
                          {bucket.name}
 | 
					 | 
				
			||||||
                        </td>
 | 
					 | 
				
			||||||
                        <td
 | 
					 | 
				
			||||||
                          className="text-start d-none d-sm-table-cell text-truncate"
 | 
					 | 
				
			||||||
                          style={{
 | 
					 | 
				
			||||||
                            maxWidth: "300px",
 | 
					 | 
				
			||||||
                            whiteSpace: "wrap",
 | 
					 | 
				
			||||||
                            overflow: "hidden",
 | 
					 | 
				
			||||||
                            textOverflow: "ellipsis",
 | 
					 | 
				
			||||||
                          }}
 | 
					 | 
				
			||||||
                          title={bucket.description}
 | 
					 | 
				
			||||||
                        >
 | 
					 | 
				
			||||||
                          {bucket.description}
 | 
					 | 
				
			||||||
                        </td>
 | 
					 | 
				
			||||||
                        <td>{bucket.numberOfContacts}</td>
 | 
					 | 
				
			||||||
                        <td className="justify-content-center">
 | 
					 | 
				
			||||||
                          {(DirManager ||
 | 
					 | 
				
			||||||
                            DirAdmin ||
 | 
					 | 
				
			||||||
                            bucket?.createdBy?.id ===
 | 
					 | 
				
			||||||
                              profile?.employeeInfo?.id) && (
 | 
					 | 
				
			||||||
                            <div className="d-flex justify-content-center align-items-center gap-2">
 | 
					 | 
				
			||||||
                              <i
 | 
					 | 
				
			||||||
                                className="bx bx-edit bx-sm text-primary cursor-pointer "
 | 
					 | 
				
			||||||
                                onClick={() => {
 | 
					 | 
				
			||||||
                                  select_bucket(bucket);
 | 
					 | 
				
			||||||
                                  setAction_bucket(true);
 | 
					 | 
				
			||||||
                                }}
 | 
					 | 
				
			||||||
                              ></i>
 | 
					 | 
				
			||||||
                              <i
 | 
					 | 
				
			||||||
                                className="bx bx-trash bx-sm text-danger cursor-pointer"
 | 
					 | 
				
			||||||
                                onClick={() => setDeleteBucket(bucket?.id)}
 | 
					 | 
				
			||||||
                              ></i>
 | 
					 | 
				
			||||||
                            </div>
 | 
					 | 
				
			||||||
                          )}
 | 
					 | 
				
			||||||
                        </td>
 | 
					 | 
				
			||||||
                      </tr>
 | 
					 | 
				
			||||||
                    ))}
 | 
					 | 
				
			||||||
                </tbody>
 | 
					 | 
				
			||||||
              </table>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          ) : (
 | 
					 | 
				
			||||||
            <>
 | 
					 | 
				
			||||||
              <form onSubmit={handleSubmit(onSubmit)} className="px-2 px-sm-0">
 | 
					 | 
				
			||||||
                <div className="">
 | 
					 | 
				
			||||||
                  <label className="form-label">Bucket Name</label>
 | 
					 | 
				
			||||||
                  <input
 | 
					 | 
				
			||||||
                    className="form-control form-control-sm"
 | 
					 | 
				
			||||||
                    {...register("name")}
 | 
					 | 
				
			||||||
                  />
 | 
					 | 
				
			||||||
                  {errors.name && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">{errors.name.message}</small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div className="">
 | 
					 | 
				
			||||||
                  <label className="form-label">Bucket Discription</label>
 | 
					 | 
				
			||||||
                  <textarea
 | 
					 | 
				
			||||||
                    className="form-control form-control-sm"
 | 
					 | 
				
			||||||
                    rows="3"
 | 
					 | 
				
			||||||
                    {...register("description")}
 | 
					 | 
				
			||||||
                  />
 | 
					 | 
				
			||||||
                  {errors.description && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">
 | 
					 | 
				
			||||||
                      {errors.description.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                {selected_bucket && (
 | 
					 | 
				
			||||||
                  <EmployeeList
 | 
					 | 
				
			||||||
                    employees={employeesList}
 | 
					 | 
				
			||||||
                    onChange={(data) => setSelectEmployee(data)}
 | 
					 | 
				
			||||||
                    bucket={selected_bucket}
 | 
					 | 
				
			||||||
                  />
 | 
					 | 
				
			||||||
                )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <div className="mt-2 d-flex justify-content-center gap-3">
 | 
					 | 
				
			||||||
                  <button
 | 
					 | 
				
			||||||
                    onClick={() => handleBack()}
 | 
					 | 
				
			||||||
                    className="btn btn-sm btn-secondary"
 | 
					 | 
				
			||||||
                    disabled={isSubmitting}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    Cancel
 | 
					 | 
				
			||||||
                  </button>
 | 
					 | 
				
			||||||
                  <button
 | 
					 | 
				
			||||||
                    type="submit"
 | 
					 | 
				
			||||||
                    className="btn btn-sm btn-primary"
 | 
					 | 
				
			||||||
                    disabled={isSubmitting}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    {isSubmitting ? "Please wait..." : "Submit"}
 | 
					 | 
				
			||||||
                  </button>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </form>
 | 
					 | 
				
			||||||
            </>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default ManageBucket;
 | 
					 | 
				
			||||||
@ -1,55 +1,40 @@
 | 
				
			|||||||
import React, { useEffect, useState } from "react";
 | 
					import React, { useEffect } from "react";
 | 
				
			||||||
import {
 | 
					import { useForm, useFieldArray, FormProvider } from "react-hook-form";
 | 
				
			||||||
  useForm,
 | 
					 | 
				
			||||||
  useFieldArray,
 | 
					 | 
				
			||||||
  FormProvider,
 | 
					 | 
				
			||||||
  useFormContext,
 | 
					 | 
				
			||||||
} from "react-hook-form";
 | 
					 | 
				
			||||||
import { zodResolver } from "@hookform/resolvers/zod";
 | 
					import { zodResolver } from "@hookform/resolvers/zod";
 | 
				
			||||||
import TagInput from "../common/TagInput";
 | 
					import TagInput from "../common/TagInput";
 | 
				
			||||||
import IconButton from "../common/IconButton";
 | 
					import { z } from "zod";
 | 
				
			||||||
import useMaster, {
 | 
					 | 
				
			||||||
  useContactCategory,
 | 
					 | 
				
			||||||
  useContactTags,
 | 
					 | 
				
			||||||
} from "../../hooks/masterHook/useMaster";
 | 
					 | 
				
			||||||
import { useDispatch, useSelector } from "react-redux";
 | 
					 | 
				
			||||||
import { changeMaster } from "../../slices/localVariablesSlice";
 | 
					 | 
				
			||||||
import { useBuckets, useOrganization } from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
import { useProjects } from "../../hooks/useProjects";
 | 
					 | 
				
			||||||
import SelectMultiple from "../common/SelectMultiple";
 | 
					 | 
				
			||||||
import { ContactSchema } from "./DirectorySchema";
 | 
					 | 
				
			||||||
import InputSuggestions from "../common/InputSuggestion";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ManageDirectory = ({ submitContact, onCLosed }) => {
 | 
					export const directorySchema = z.object({
 | 
				
			||||||
  const selectedMaster = useSelector(
 | 
					  firstName: z.string().min(1, "First Name is required"),
 | 
				
			||||||
    (store) => store.localVariables.selectedMaster
 | 
					  lastName: z.string().min(1, "Last Name is required"),
 | 
				
			||||||
  );
 | 
					  organization: z.string().min(1, "Organization name is required"),
 | 
				
			||||||
  const [categoryData, setCategoryData] = useState([]);
 | 
					  type: z.string().min(1, "Type is required"),
 | 
				
			||||||
 | 
					  address: z.string().optional(),
 | 
				
			||||||
 | 
					  description: z.string().min(1, { message: "Description is required" }),
 | 
				
			||||||
 | 
					  email: z
 | 
				
			||||||
 | 
					    .array(z.string().email("Invalid email"))
 | 
				
			||||||
 | 
					    .nonempty("At least one email required"),
 | 
				
			||||||
 | 
					  phone: z
 | 
				
			||||||
 | 
					    .array(z.string().regex(/^\d{10}$/, "Phone must be 10 digits"))
 | 
				
			||||||
 | 
					    .nonempty("At least one phone number is required"),
 | 
				
			||||||
 | 
					  tags: z.array(z.string()).optional(),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [TagsData, setTagsData] = useState([]);
 | 
					 | 
				
			||||||
  const { data, loading } = useMaster();
 | 
					 | 
				
			||||||
  const { buckets, loading: bucketsLoaging } = useBuckets();
 | 
					 | 
				
			||||||
  const { projects, loading: projectLoading } = useProjects();
 | 
					 | 
				
			||||||
  const { contactCategory, loading: contactCategoryLoading } =
 | 
					 | 
				
			||||||
    useContactCategory();
 | 
					 | 
				
			||||||
  const { organizationList, loading: orgLoading } = useOrganization();
 | 
					 | 
				
			||||||
  const { contactTags, loading: Tagloading } = useContactTags();
 | 
					 | 
				
			||||||
  const [IsSubmitting, setSubmitting] = useState(false);
 | 
					 | 
				
			||||||
  const dispatch = useDispatch();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ManageDirectory = () => {
 | 
				
			||||||
  const methods = useForm({
 | 
					  const methods = useForm({
 | 
				
			||||||
    resolver: zodResolver(ContactSchema),
 | 
					    resolver: zodResolver(directorySchema),
 | 
				
			||||||
    defaultValues: {
 | 
					    defaultValues: {
 | 
				
			||||||
      name: "",
 | 
					      firstName: "",
 | 
				
			||||||
 | 
					      lastName: "",
 | 
				
			||||||
      organization: "",
 | 
					      organization: "",
 | 
				
			||||||
      contactCategoryId: null,
 | 
					      type: "",
 | 
				
			||||||
      address: "",
 | 
					      address: "",
 | 
				
			||||||
      description: "",
 | 
					      description: "",
 | 
				
			||||||
      projectIds: [],
 | 
					      email: [""],
 | 
				
			||||||
      contactEmails: [],
 | 
					      phone: [""],
 | 
				
			||||||
      contactPhones: [],
 | 
					 | 
				
			||||||
      tags: [],
 | 
					      tags: [],
 | 
				
			||||||
      bucketIds: [],
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -59,9 +44,6 @@ const ManageDirectory = ({ submitContact, onCLosed }) => {
 | 
				
			|||||||
    control,
 | 
					    control,
 | 
				
			||||||
    getValues,
 | 
					    getValues,
 | 
				
			||||||
    trigger,
 | 
					    trigger,
 | 
				
			||||||
    setValue,
 | 
					 | 
				
			||||||
    watch,
 | 
					 | 
				
			||||||
    reset,
 | 
					 | 
				
			||||||
    formState: { errors },
 | 
					    formState: { errors },
 | 
				
			||||||
  } = methods;
 | 
					  } = methods;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -69,359 +51,160 @@ const ManageDirectory = ({ submitContact, onCLosed }) => {
 | 
				
			|||||||
    fields: emailFields,
 | 
					    fields: emailFields,
 | 
				
			||||||
    append: appendEmail,
 | 
					    append: appendEmail,
 | 
				
			||||||
    remove: removeEmail,
 | 
					    remove: removeEmail,
 | 
				
			||||||
  } = useFieldArray({ control, name: "contactEmails" });
 | 
					  } = useFieldArray({ control, name: "email" });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
    fields: phoneFields,
 | 
					    fields: phoneFields,
 | 
				
			||||||
    append: appendPhone,
 | 
					    append: appendPhone,
 | 
				
			||||||
    remove: removePhone,
 | 
					    remove: removePhone,
 | 
				
			||||||
  } = useFieldArray({ control, name: "contactPhones" });
 | 
					  } = useFieldArray({ control, name: "phone" });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (emailFields.length === 0) {
 | 
					    if (emailFields.length === 0) appendEmail(""); 
 | 
				
			||||||
      appendEmail({ label: "Work", emailAddress: "" });
 | 
					    if (phoneFields.length === 0) appendPhone(""); 
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (phoneFields.length === 0) {
 | 
					 | 
				
			||||||
      appendPhone({ label: "Office", phoneNumber: "" });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [emailFields.length, phoneFields.length]);
 | 
					  }, [emailFields.length, phoneFields.length]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = (data) => {
 | 
				
			||||||
 | 
					    // console.log("Submitted:\n" + JSON.stringify(data, null, 2));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleAddEmail = async () => {
 | 
					  const handleAddEmail = async () => {
 | 
				
			||||||
    const emails = getValues("contactEmails");
 | 
					    const emails = getValues("email");
 | 
				
			||||||
    const lastIndex = emails.length - 1;
 | 
					    const lastIndex = emails.length - 1;
 | 
				
			||||||
    const valid = await trigger(`contactEmails.${lastIndex}.emailAddress`);
 | 
					    const valid = await trigger(`email.${lastIndex}`);
 | 
				
			||||||
    if (valid) {
 | 
					    if (valid) appendEmail(""); 
 | 
				
			||||||
      appendEmail({ label: "Work", emailAddress: "" });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleAddPhone = async () => {
 | 
					  const handleAddPhone = async () => {
 | 
				
			||||||
    const phones = getValues("contactPhones");
 | 
					    const phones = getValues("phone");
 | 
				
			||||||
    const lastIndex = phones.length - 1;
 | 
					    const lastIndex = phones.length - 1;
 | 
				
			||||||
    const valid = await trigger(`contactPhones.${lastIndex}.phoneNumber`);
 | 
					    const valid = await trigger(`phone.${lastIndex}`);
 | 
				
			||||||
    if (valid) {
 | 
					    if (valid) appendPhone(""); 
 | 
				
			||||||
      appendPhone({ label: "Office", phoneNumber: "" });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const watchBucketIds = watch("bucketIds");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const toggleBucketId = (id) => {
 | 
					 | 
				
			||||||
    const updated = watchBucketIds?.includes(id)
 | 
					 | 
				
			||||||
      ? watchBucketIds.filter((val) => val !== id)
 | 
					 | 
				
			||||||
      : [...watchBucketIds, id];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setValue("bucketIds", updated, { shouldValidate: true });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const handleCheckboxChange = (id) => {
 | 
					 | 
				
			||||||
    const updated = watchBucketIds.includes(id)
 | 
					 | 
				
			||||||
      ? watchBucketIds.filter((i) => i !== id)
 | 
					 | 
				
			||||||
      : [...watchBucketIds, id];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setValue("bucketIds", updated, { shouldValidate: true });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const onSubmit = (data) => {
 | 
					 | 
				
			||||||
    const cleaned = {
 | 
					 | 
				
			||||||
      ...data,
 | 
					 | 
				
			||||||
      contactEmails: (data.contactEmails || []).filter(
 | 
					 | 
				
			||||||
        (e) => e.emailAddress?.trim() !== ""
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
      contactPhones: (data.contactPhones || []).filter(
 | 
					 | 
				
			||||||
        (p) => p.phoneNumber?.trim() !== ""
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setSubmitting(true);
 | 
					 | 
				
			||||||
    submitContact(cleaned, reset, setSubmitting);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const orgValue = watch("organization");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleClosed = () => {
 | 
					 | 
				
			||||||
    onCLosed();
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <FormProvider {...methods}>
 | 
					    <FormProvider {...methods}>
 | 
				
			||||||
      <form className="p-2 p-sm-0" onSubmit={handleSubmit(onSubmit)}>
 | 
					      <form className="p-2 p-sm-0" onSubmit={handleSubmit(onSubmit)}>
 | 
				
			||||||
        <div className="d-flex justify-content-center align-items-center">
 | 
					 | 
				
			||||||
          <h6 className="m-0 fw-18"> Create New Contact</h6>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="row">
 | 
					        <div className="row">
 | 
				
			||||||
          <div className="col-md-6  text-start">
 | 
					          <div className="col-md-6">
 | 
				
			||||||
            <label className="form-label">Name</label>
 | 
					            <label className="form-label">First Name</label>
 | 
				
			||||||
            <input
 | 
					            <input className="form-control form-control-sm" {...register("firstName")} />
 | 
				
			||||||
              className="form-control form-control-sm"
 | 
					            {errors.firstName && <small className="danger-text">{errors.firstName.message}</small>}
 | 
				
			||||||
              {...register("name")}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            {errors.name && (
 | 
					 | 
				
			||||||
              <small className="danger-text">{errors.name.message}</small>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div className="col-md-6  text-start">
 | 
					 | 
				
			||||||
            <label className="form-label">Organization</label>
 | 
					 | 
				
			||||||
            <InputSuggestions
 | 
					 | 
				
			||||||
              organizationList={organizationList}
 | 
					 | 
				
			||||||
              value={getValues("organization") || ""}
 | 
					 | 
				
			||||||
              onChange={(val) => setValue("organization", val)}
 | 
					 | 
				
			||||||
              error={errors.organization?.message}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="row mt-1">
 | 
					 | 
				
			||||||
          <div className="col-md-6">
 | 
					          <div className="col-md-6">
 | 
				
			||||||
            {emailFields.map((field, index) => (
 | 
					            <label className="form-label">Last Name</label>
 | 
				
			||||||
              <div
 | 
					            <input className="form-control form-control-sm" {...register("lastName")} />
 | 
				
			||||||
                key={field.id}
 | 
					            {errors.lastName && <small className="danger-text">{errors.lastName.message}</small>}
 | 
				
			||||||
                className="row d-flex align-items-center mb-1"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <div className="col-5  text-start">
 | 
					 | 
				
			||||||
                  <label className="form-label">Label</label>
 | 
					 | 
				
			||||||
                  <select
 | 
					 | 
				
			||||||
                    className="form-select form-select-sm"
 | 
					 | 
				
			||||||
                    {...register(`contactEmails.${index}.label`)}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    <option value="Work">Work</option>
 | 
					 | 
				
			||||||
                    <option value="Personal">Personal</option>
 | 
					 | 
				
			||||||
                    <option value="Other">Other</option>
 | 
					 | 
				
			||||||
                  </select>
 | 
					 | 
				
			||||||
                  {errors.contactEmails?.[index]?.label && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">
 | 
					 | 
				
			||||||
                      {errors.contactEmails[index].label.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
                <div className="col-7  text-start">
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div className="col-12">
 | 
				
			||||||
 | 
					          <label className="form-label">Organization</label>
 | 
				
			||||||
 | 
					          <input className="form-control form-control-sm" {...register("organization")} />
 | 
				
			||||||
 | 
					          {errors.organization && <small className="danger-text">{errors.organization.message}</small>}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div className="row">
 | 
				
			||||||
 | 
					          <div className="col-md-6">
 | 
				
			||||||
            <label className="form-label">Email</label>
 | 
					            <label className="form-label">Email</label>
 | 
				
			||||||
                  <div className="d-flex align-items-center">
 | 
					            {emailFields.map((field, index) => (<>
 | 
				
			||||||
 | 
					              <div key={field.id} className="d-flex align-items-center mb-1">
 | 
				
			||||||
                <input
 | 
					                <input
 | 
				
			||||||
                  type="email"
 | 
					                  type="email"
 | 
				
			||||||
                  className="form-control form-control-sm"
 | 
					                  className="form-control form-control-sm"
 | 
				
			||||||
                      {...register(`contactEmails.${index}.emailAddress`)}
 | 
					                  {...register(`email.${index}`)}
 | 
				
			||||||
                  placeholder="email@example.com"
 | 
					                  placeholder="email@example.com"
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
                {index === emailFields.length - 1 ? (
 | 
					                {index === emailFields.length - 1 ? (
 | 
				
			||||||
                      // <button
 | 
					                  <button
 | 
				
			||||||
                      //   type="button"
 | 
					                    type="button"
 | 
				
			||||||
                      //   className="btn btn-xs btn-primary ms-1"
 | 
					                    className="btn btn-xs btn-primary ms-1"
 | 
				
			||||||
                      //   onClick={handleAddEmail}
 | 
					 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					 | 
				
			||||||
                      // >
 | 
					 | 
				
			||||||
                      <i
 | 
					 | 
				
			||||||
                        className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary"
 | 
					 | 
				
			||||||
                    onClick={handleAddEmail}
 | 
					                    onClick={handleAddEmail}
 | 
				
			||||||
                      />
 | 
					                  >
 | 
				
			||||||
 | 
					                    <i className="bx bx-plus bx-xs" />
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                      // <button
 | 
					                  <button
 | 
				
			||||||
                      //   type="button"
 | 
					                    type="button"
 | 
				
			||||||
                      //   className="btn btn-xs btn-danger ms-1 p-0"
 | 
					                    className="btn btn-xs btn-danger ms-1"
 | 
				
			||||||
                      //   onClick={() => removeEmail(index)}
 | 
					 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					 | 
				
			||||||
                      // >
 | 
					 | 
				
			||||||
                      <i
 | 
					 | 
				
			||||||
                        className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-primary"
 | 
					 | 
				
			||||||
                    onClick={() => removeEmail(index)} 
 | 
					                    onClick={() => removeEmail(index)} 
 | 
				
			||||||
                      />
 | 
					                  >
 | 
				
			||||||
 | 
					                    <i className="bx bx-x bx-xs" />
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
                  {errors.contactEmails?.[index]?.emailAddress && (
 | 
					              {errors.email?.[index] && (
 | 
				
			||||||
                    <small className="danger-text">
 | 
					        <small className="danger-text ms-2">
 | 
				
			||||||
                      {errors.contactEmails[index].emailAddress.message}
 | 
					          {errors.email[index]?.message}
 | 
				
			||||||
        </small>
 | 
					        </small>
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
                </div>
 | 
					              </>
 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            ))}
 | 
					            ))}
 | 
				
			||||||
 | 
					                  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div className="col-md-6">
 | 
					          <div className="col-md-6">
 | 
				
			||||||
            {phoneFields.map((field, index) => (
 | 
					 | 
				
			||||||
              <div
 | 
					 | 
				
			||||||
                key={field.id}
 | 
					 | 
				
			||||||
                className="row d-flex align-items-center mb-2"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <div className="col-5  text-start">
 | 
					 | 
				
			||||||
                  <label className="form-label">Label</label>
 | 
					 | 
				
			||||||
                  <select
 | 
					 | 
				
			||||||
                    className="form-select form-select-sm"
 | 
					 | 
				
			||||||
                    {...register(`contactPhones.${index}.label`)}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    <option value="Office">Office</option>
 | 
					 | 
				
			||||||
                    <option value="Personal">Personal</option>
 | 
					 | 
				
			||||||
                    <option value="Business">Business</option>
 | 
					 | 
				
			||||||
                  </select>
 | 
					 | 
				
			||||||
                  {errors.phone?.[index]?.label && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">
 | 
					 | 
				
			||||||
                      {errors.ContactPhones[index].label.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div className="col-7  text-start">
 | 
					 | 
				
			||||||
            <label className="form-label">Phone</label>
 | 
					            <label className="form-label">Phone</label>
 | 
				
			||||||
                  <div className="d-flex align-items-center">
 | 
					            {phoneFields.map((field, index) => (<>
 | 
				
			||||||
 | 
					              <div key={field.id} className="d-flex align-items-center mb-1">
 | 
				
			||||||
                <input
 | 
					                <input
 | 
				
			||||||
                  type="text"
 | 
					                  type="text"
 | 
				
			||||||
                  className="form-control form-control-sm"
 | 
					                  className="form-control form-control-sm"
 | 
				
			||||||
                      {...register(`contactPhones.${index}.phoneNumber`)}
 | 
					                  {...register(`phone.${index}`)}
 | 
				
			||||||
                  placeholder="9876543210"
 | 
					                  placeholder="9876543210"
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
                {index === phoneFields.length - 1 ? (
 | 
					                {index === phoneFields.length - 1 ? (
 | 
				
			||||||
                      // <button
 | 
					                  <button
 | 
				
			||||||
                      //   type="button"
 | 
					                    type="button"
 | 
				
			||||||
                      //   className="btn btn-xs btn-primary ms-1"
 | 
					                    className="btn btn-xs btn-primary ms-1"
 | 
				
			||||||
                      //   onClick={handleAddPhone}
 | 
					 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					 | 
				
			||||||
                      // >
 | 
					 | 
				
			||||||
                      <i
 | 
					 | 
				
			||||||
                        className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary"
 | 
					 | 
				
			||||||
                    onClick={handleAddPhone}
 | 
					                    onClick={handleAddPhone}
 | 
				
			||||||
                      />
 | 
					                  >
 | 
				
			||||||
 | 
					                    <i className="bx bx-plus bx-xs" />
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                      // <button
 | 
					                  <button
 | 
				
			||||||
                      //   type="button"
 | 
					                    type="button"
 | 
				
			||||||
                      //   className="btn btn-xs btn-danger ms-1"
 | 
					                    className="btn btn-xs btn-danger ms-1"
 | 
				
			||||||
                      //   onClick={() => removePhone(index)}
 | 
					                    onClick={() => removePhone(index)} // Remove the phone field
 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					                  >
 | 
				
			||||||
                      // >
 | 
					                    <i className="bx bx-x bx-xs" />
 | 
				
			||||||
                      <i
 | 
					                  </button>
 | 
				
			||||||
                        className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-danager"
 | 
					 | 
				
			||||||
                        onClick={() => removePhone(index)}
 | 
					 | 
				
			||||||
                      />
 | 
					 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
                  {errors.contactPhones?.[index]?.phoneNumber && (
 | 
					              {errors.phone?.[ index ] && <small className="danger-text ms-2">{errors.phone[ index ]?.message}</small>}
 | 
				
			||||||
                    <small className="danger-text">
 | 
					              </>
 | 
				
			||||||
                      {errors.contactPhones[index].phoneNumber.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            ))}
 | 
					            ))}
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          {errors.contactPhone?.message && (
 | 
					 | 
				
			||||||
            <div className="danger-text">{errors.contactPhone.message}</div>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className="row my-1">
 | 
					        <div className="row my-1">
 | 
				
			||||||
          <div className="col-md-6  text-start">
 | 
					          <div className="col-md-6">
 | 
				
			||||||
            <label className="form-label">Category</label>
 | 
					            <label className="form-label">Type</label>
 | 
				
			||||||
            <select
 | 
					            <input className="form-control form-control-sm" {...register("type")} />
 | 
				
			||||||
              className="form-select form-select-sm"
 | 
					            {errors.type && <small className="danger-text">{errors.type.message}</small>}
 | 
				
			||||||
              {...register("contactCategoryId")}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              {contactCategoryLoading && !contactCategory ? (
 | 
					 | 
				
			||||||
                <option disabled value="">
 | 
					 | 
				
			||||||
                  Loading...
 | 
					 | 
				
			||||||
                </option>
 | 
					 | 
				
			||||||
              ) : (
 | 
					 | 
				
			||||||
                <>
 | 
					 | 
				
			||||||
                  <option disabled value="">
 | 
					 | 
				
			||||||
                    Select Category
 | 
					 | 
				
			||||||
                  </option>
 | 
					 | 
				
			||||||
                  {contactCategory?.map((cate) => (
 | 
					 | 
				
			||||||
                    <option key={cate.id} value={cate.id}>
 | 
					 | 
				
			||||||
                      {cate.name}
 | 
					 | 
				
			||||||
                    </option>
 | 
					 | 
				
			||||||
                  ))}
 | 
					 | 
				
			||||||
                </>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </select>
 | 
					 | 
				
			||||||
            {errors.contactCategoryId && (
 | 
					 | 
				
			||||||
              <small className="danger-text">
 | 
					 | 
				
			||||||
                {errors.contactCategoryId.message}
 | 
					 | 
				
			||||||
              </small>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          <div className="col-12 col-md-6 text-start">
 | 
					          <div className="col-md-6">
 | 
				
			||||||
            <SelectMultiple
 | 
					            <TagInput name="tags" label="Tags" />
 | 
				
			||||||
              name="projectIds"
 | 
					 | 
				
			||||||
              label="Select Projects"
 | 
					 | 
				
			||||||
              options={projects}
 | 
					 | 
				
			||||||
              labelKey="name"
 | 
					 | 
				
			||||||
              valueKey="id"
 | 
					 | 
				
			||||||
              IsLoading={projectLoading}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            {errors.projectIds && (
 | 
					 | 
				
			||||||
              <small className="danger-text">{errors.projectIds.message}</small>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className="col-12 text-start">
 | 
					        <div className="col-12">
 | 
				
			||||||
          <TagInput name="tags" label="Tags" options={contactTags} />
 | 
					 | 
				
			||||||
          {errors.tags && (
 | 
					 | 
				
			||||||
            <small className="danger-text">{errors.tags.message}</small>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="row">
 | 
					 | 
				
			||||||
          <div className="col-md-12 mt-1 text-start">
 | 
					 | 
				
			||||||
            <label className="form-label ">Select Bucket</label>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <ul className="d-flex flex-wrap px-1 list-unstyled  mb-0">
 | 
					 | 
				
			||||||
              {bucketsLoaging && <p>Loading...</p>}
 | 
					 | 
				
			||||||
              {buckets?.map((item) => (
 | 
					 | 
				
			||||||
                <li
 | 
					 | 
				
			||||||
                  key={item.id}
 | 
					 | 
				
			||||||
                  className="list-inline-item flex-shrink-0 me-6 mb-2"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  <div className="form-check ">
 | 
					 | 
				
			||||||
                    <input
 | 
					 | 
				
			||||||
                      type="checkbox"
 | 
					 | 
				
			||||||
                      className="form-check-input"
 | 
					 | 
				
			||||||
                      id={`item-${item.id}`}
 | 
					 | 
				
			||||||
                      checked={watchBucketIds.includes(item.id)}
 | 
					 | 
				
			||||||
                      onChange={() => handleCheckboxChange(item.id)}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <label
 | 
					 | 
				
			||||||
                      className="form-check-label"
 | 
					 | 
				
			||||||
                      htmlFor={`item-${item.id}`}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      {item.name}
 | 
					 | 
				
			||||||
                    </label>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </li>
 | 
					 | 
				
			||||||
              ))}
 | 
					 | 
				
			||||||
              {errors.bucketIds && (
 | 
					 | 
				
			||||||
                <small className="danger-text mt-0">
 | 
					 | 
				
			||||||
                  {errors.bucketIds.message}
 | 
					 | 
				
			||||||
                </small>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </ul>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-start">
 | 
					 | 
				
			||||||
          <label className="form-label">Address</label>
 | 
					          <label className="form-label">Address</label>
 | 
				
			||||||
          <textarea
 | 
					          <textarea className="form-control form-control-sm" rows="2" {...register("address")} />
 | 
				
			||||||
            className="form-control form-control-sm"
 | 
					 | 
				
			||||||
            rows="2"
 | 
					 | 
				
			||||||
            {...register("address")}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className="col-12 text-start">
 | 
					        <div className="col-12">
 | 
				
			||||||
          <label className="form-label">Description</label>
 | 
					          <label className="form-label">Description</label>
 | 
				
			||||||
          <textarea
 | 
					          <textarea className="form-control form-control-sm" rows="2" {...register("description")} />
 | 
				
			||||||
            className="form-control form-control-sm"
 | 
					          {errors.description && <small className="danger-text">{errors.description.message}</small>}
 | 
				
			||||||
            rows="2"
 | 
					 | 
				
			||||||
            {...register("description")}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          {errors.description && (
 | 
					 | 
				
			||||||
            <small className="danger-text">{errors.description.message}</small>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className="d-flex justify-content-center gap-1 py-2">
 | 
					        <div className="d-flex justify-content-evenly py-2">
 | 
				
			||||||
          <button className="btn btn-sm btn-primary" type="submit">
 | 
					          <button className="btn btn-sm btn-primary" type="submit">Submit</button>
 | 
				
			||||||
            {IsSubmitting ? "Please Wait..." : "Submit"}
 | 
					          <button className="btn btn-sm btn-secondary" type="button">Cancel</button>
 | 
				
			||||||
          </button>
 | 
					 | 
				
			||||||
          <button
 | 
					 | 
				
			||||||
            className="btn btn-sm btn-secondary"
 | 
					 | 
				
			||||||
            type="button"
 | 
					 | 
				
			||||||
            onClick={handleClosed}
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            Cancel
 | 
					 | 
				
			||||||
          </button>
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </form>
 | 
					      </form>
 | 
				
			||||||
    </FormProvider>
 | 
					    </FormProvider>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,220 +0,0 @@
 | 
				
			|||||||
import React, { useState } from "react";
 | 
					 | 
				
			||||||
import ReactQuill from "react-quill";
 | 
					 | 
				
			||||||
import moment from "moment";
 | 
					 | 
				
			||||||
import Avatar from "../common/Avatar";
 | 
					 | 
				
			||||||
import { DirectoryRepository } from "../../repositories/DirectoryRepository";
 | 
					 | 
				
			||||||
import showToast from "../../services/toastService";
 | 
					 | 
				
			||||||
import { cacheData, getCachedData } from "../../slices/apiDataManager";
 | 
					 | 
				
			||||||
import "../common/TextEditor/Editor.css";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const NoteCardDirectory = ({
 | 
					 | 
				
			||||||
  refetchProfile,
 | 
					 | 
				
			||||||
  refetchNotes,
 | 
					 | 
				
			||||||
  noteItem,
 | 
					 | 
				
			||||||
  contactId,
 | 
					 | 
				
			||||||
  setProfileContact,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const [editing, setEditing] = useState(false);
 | 
					 | 
				
			||||||
  const [editorValue, setEditorValue] = useState(noteItem.note);
 | 
					 | 
				
			||||||
  const [isLoading, setIsLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [isDeleting, setIsDeleting] = useState(false);
 | 
					 | 
				
			||||||
  const [isActivProcess, setActiveProcessing] = useState(false);
 | 
					 | 
				
			||||||
  const handleUpdateNote = async () => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      setIsLoading(true);
 | 
					 | 
				
			||||||
      const payload = {
 | 
					 | 
				
			||||||
        id: noteItem.id,
 | 
					 | 
				
			||||||
        note: editorValue,
 | 
					 | 
				
			||||||
        contactId: contactId,
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const response = await DirectoryRepository.UpdateNote(
 | 
					 | 
				
			||||||
        noteItem.id,
 | 
					 | 
				
			||||||
        payload
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      setProfileContact((prev) => ({
 | 
					 | 
				
			||||||
        ...prev,
 | 
					 | 
				
			||||||
        notes: prev.notes.map((note) =>
 | 
					 | 
				
			||||||
          note.id === noteItem.id ? response?.data : note
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const cached_contactProfile = getCachedData("Contact Profile");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (
 | 
					 | 
				
			||||||
        cached_contactProfile &&
 | 
					 | 
				
			||||||
        cached_contactProfile.contactId === contactId
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        const updatedProfile = {
 | 
					 | 
				
			||||||
          ...cached_contactProfile,
 | 
					 | 
				
			||||||
          data: {
 | 
					 | 
				
			||||||
            ...cached_contactProfile?.data,
 | 
					 | 
				
			||||||
            notes: cached_contactProfile?.data?.notes.map((note) =>
 | 
					 | 
				
			||||||
              note.id === noteItem.id ? response?.data : note
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        cacheData("Contact Profile", updatedProfile);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      setEditing(false);
 | 
					 | 
				
			||||||
      setIsLoading(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      showToast("Note Updated successfully", "success");
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      setIsLoading(false);
 | 
					 | 
				
			||||||
      const msg =
 | 
					 | 
				
			||||||
        error.reponse.data.message ||
 | 
					 | 
				
			||||||
        error.message ||
 | 
					 | 
				
			||||||
        "Error occured during API calling.";
 | 
					 | 
				
			||||||
      showToast("Failed to update note", "error");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleDeleteNote = async (activeStatue) => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      activeStatue ? setActiveProcessing(true) : setIsDeleting(true);
 | 
					 | 
				
			||||||
      const resp = await DirectoryRepository.DeleteNote(
 | 
					 | 
				
			||||||
        noteItem.id,
 | 
					 | 
				
			||||||
        activeStatue
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      setProfileContact((prev) => ({
 | 
					 | 
				
			||||||
        ...prev,
 | 
					 | 
				
			||||||
        notes: prev.notes.filter((note) => note.id !== noteItem.id),
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const cachedContactProfile = getCachedData("Contact Profile");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (
 | 
					 | 
				
			||||||
        cachedContactProfile &&
 | 
					 | 
				
			||||||
        cachedContactProfile.contactId === contactId
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        const updatedCache = {
 | 
					 | 
				
			||||||
          ...cachedContactProfile,
 | 
					 | 
				
			||||||
          data: {
 | 
					 | 
				
			||||||
            ...cachedContactProfile?.data,
 | 
					 | 
				
			||||||
            notes: (cachedContactProfile?.data?.notes || []).filter(
 | 
					 | 
				
			||||||
              (note) => note.id !== noteItem.id
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cacheData("Contact Profile", updatedCache);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      setIsDeleting(false);
 | 
					 | 
				
			||||||
      setActiveProcessing(false);
 | 
					 | 
				
			||||||
      refetchNotes(contactId, false);
 | 
					 | 
				
			||||||
      refetchProfile(contactId);
 | 
					 | 
				
			||||||
      showToast(
 | 
					 | 
				
			||||||
        `Note ${activeStatue ? "Restored" : "Deleted"} Successfully`,
 | 
					 | 
				
			||||||
        "success"
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      setIsDeleting(false);
 | 
					 | 
				
			||||||
      const msg =
 | 
					 | 
				
			||||||
        error.response?.data?.message ||
 | 
					 | 
				
			||||||
        error.message ||
 | 
					 | 
				
			||||||
        "Error occured during API calling";
 | 
					 | 
				
			||||||
      showToast(msg, "error");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div
 | 
					 | 
				
			||||||
      className="card p-1 shadow-sm border-1 mb-5 conntactNote rounded"
 | 
					 | 
				
			||||||
      style={{
 | 
					 | 
				
			||||||
        width: "100%",
 | 
					 | 
				
			||||||
        minWidth: "300px",
 | 
					 | 
				
			||||||
        borderRadius: "0px",
 | 
					 | 
				
			||||||
        background: `${noteItem.isActive ? "" : "#f8f6f6"}`,
 | 
					 | 
				
			||||||
      }}
 | 
					 | 
				
			||||||
      key={noteItem.id}
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <div className="d-flex justify-content-between align-items-center mb-1">
 | 
					 | 
				
			||||||
        <div className="d-flex align-items-center">
 | 
					 | 
				
			||||||
          <Avatar
 | 
					 | 
				
			||||||
            size="xs"
 | 
					 | 
				
			||||||
            firstName={noteItem.createdBy.firstName}
 | 
					 | 
				
			||||||
            lastName={noteItem.createdBy.lastName}
 | 
					 | 
				
			||||||
            className="m-0"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          <div className="d-flex flex-column ms-2">
 | 
					 | 
				
			||||||
            <span className="fw-semibold small">
 | 
					 | 
				
			||||||
              {noteItem.createdBy.firstName} {noteItem.createdBy.lastName}
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
            <span className="text-muted" style={{ fontSize: "10px" }}>
 | 
					 | 
				
			||||||
              {moment
 | 
					 | 
				
			||||||
                .utc(noteItem.createdAt)
 | 
					 | 
				
			||||||
                .add(5, "hours")
 | 
					 | 
				
			||||||
                .add(30, "minutes")
 | 
					 | 
				
			||||||
                .format("MMMM DD, YYYY [at] hh:mm A")}
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div>
 | 
					 | 
				
			||||||
          {noteItem.isActive ? (
 | 
					 | 
				
			||||||
            <>
 | 
					 | 
				
			||||||
              <i
 | 
					 | 
				
			||||||
                className="bx bxs-edit bx-sm me-1 text-primary cursor-pointer"
 | 
					 | 
				
			||||||
                onClick={() => setEditing(true)}
 | 
					 | 
				
			||||||
              ></i>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              {!isDeleting ? (
 | 
					 | 
				
			||||||
                <i
 | 
					 | 
				
			||||||
                  className="bx bx-trash bx-sm me-1 text-secondary cursor-pointer"
 | 
					 | 
				
			||||||
                  onClick={() => handleDeleteNote(!noteItem.isActive)}
 | 
					 | 
				
			||||||
                ></i>
 | 
					 | 
				
			||||||
              ) : (
 | 
					 | 
				
			||||||
                <div
 | 
					 | 
				
			||||||
                  className="spinner-border spinner-border-sm text-secondary"
 | 
					 | 
				
			||||||
                  role="status"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  <span className="visually-hidden">Loading...</span>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </>
 | 
					 | 
				
			||||||
          ) : isActivProcess ? (
 | 
					 | 
				
			||||||
            <i className="bx  bx-loader-alt bx-spin text-primary"></i>
 | 
					 | 
				
			||||||
          ) : (
 | 
					 | 
				
			||||||
            <i
 | 
					 | 
				
			||||||
              className="bx bx-recycle  me-1 text-primary cursor-pointer"
 | 
					 | 
				
			||||||
              onClick={() => handleDeleteNote(!noteItem.isActive)}
 | 
					 | 
				
			||||||
              title="Restore"
 | 
					 | 
				
			||||||
            ></i>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <hr className="mt-0" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {editing ? (
 | 
					 | 
				
			||||||
        <>
 | 
					 | 
				
			||||||
          <ReactQuill
 | 
					 | 
				
			||||||
            value={editorValue}
 | 
					 | 
				
			||||||
            onChange={setEditorValue}
 | 
					 | 
				
			||||||
            theme="snow"
 | 
					 | 
				
			||||||
            className="compact-editor"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          <div className="d-flex justify-content-end gap-2">
 | 
					 | 
				
			||||||
            <span
 | 
					 | 
				
			||||||
              className="text-secondary cursor-pointer"
 | 
					 | 
				
			||||||
              aria-disabled={isLoading}
 | 
					 | 
				
			||||||
              onClick={() => setEditing(false)}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              Cancel
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
            <span
 | 
					 | 
				
			||||||
              className="text-primary cursor-pointer"
 | 
					 | 
				
			||||||
              aria-disabled={isLoading}
 | 
					 | 
				
			||||||
              onClick={handleUpdateNote}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              {isLoading ? "Please Wait..." : "Submit"}
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </>
 | 
					 | 
				
			||||||
      ) : (
 | 
					 | 
				
			||||||
        <div dangerouslySetInnerHTML={{ __html: noteItem.note }} />
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default NoteCardDirectory;
 | 
					 | 
				
			||||||
@ -1,188 +0,0 @@
 | 
				
			|||||||
import React, { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import Editor from "../common/TextEditor/Editor";
 | 
					 | 
				
			||||||
import Avatar from "../common/Avatar";
 | 
					 | 
				
			||||||
import { useForm } from "react-hook-form";
 | 
					 | 
				
			||||||
import { z } from "zod";
 | 
					 | 
				
			||||||
import { zodResolver } from "@hookform/resolvers/zod";
 | 
					 | 
				
			||||||
import { showText } from "pdf-lib";
 | 
					 | 
				
			||||||
import { DirectoryRepository } from "../../repositories/DirectoryRepository";
 | 
					 | 
				
			||||||
import moment from "moment";
 | 
					 | 
				
			||||||
import { cacheData, getCachedData } from "../../slices/apiDataManager";
 | 
					 | 
				
			||||||
import NoteCardDirectory from "./NoteCardDirectory";
 | 
					 | 
				
			||||||
import showToast from "../../services/toastService";
 | 
					 | 
				
			||||||
import { useContactNotes } from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const schema = z.object({
 | 
					 | 
				
			||||||
  note: z.string().min(1, { message: "Note is required" }),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const NotesDirectory = ({
 | 
					 | 
				
			||||||
  refetchProfile,
 | 
					 | 
				
			||||||
  isLoading,
 | 
					 | 
				
			||||||
  contactProfile,
 | 
					 | 
				
			||||||
  setProfileContact,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const [IsActive, setIsActive] = useState(true);
 | 
					 | 
				
			||||||
  const { contactNotes, refetch } = useContactNotes(contactProfile?.id, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const [NotesData, setNotesData] = useState();
 | 
					 | 
				
			||||||
  const [IsSubmitting, setIsSubmitting] = useState(false);
 | 
					 | 
				
			||||||
  const [addNote, setAddNote] = useState(true);
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    register,
 | 
					 | 
				
			||||||
    handleSubmit,
 | 
					 | 
				
			||||||
    setValue,
 | 
					 | 
				
			||||||
    watch,
 | 
					 | 
				
			||||||
    formState: { errors },
 | 
					 | 
				
			||||||
  } = useForm({
 | 
					 | 
				
			||||||
    resolver: zodResolver(schema),
 | 
					 | 
				
			||||||
    defaultValues: {
 | 
					 | 
				
			||||||
      note: "",
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const noteValue = watch("note");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleEditorChange = (value) => {
 | 
					 | 
				
			||||||
    setValue("note", value, { shouldValidate: true });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const onSubmit = async (data) => {
 | 
					 | 
				
			||||||
    const newNote = { ...data, contactId: contactProfile?.id };
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      setIsSubmitting(true);
 | 
					 | 
				
			||||||
      const response = await DirectoryRepository.CreateNote(newNote);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const createdNote = response.data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setProfileContact((prev) => ({
 | 
					 | 
				
			||||||
        ...prev,
 | 
					 | 
				
			||||||
        notes: [...(prev.notes || []), createdNote],
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const cached_contactProfile = getCachedData("Contact Profile");
 | 
					 | 
				
			||||||
      if (
 | 
					 | 
				
			||||||
        cached_contactProfile &&
 | 
					 | 
				
			||||||
        cached_contactProfile.contactId === contactProfile?.id
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        const updatedProfile = {
 | 
					 | 
				
			||||||
          ...cached_contactProfile.data,
 | 
					 | 
				
			||||||
          notes: [...(cached_contactProfile.notes || []), createdNote],
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        cacheData("Contact Profile", updatedProfile);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setValue("note", "");
 | 
					 | 
				
			||||||
      setIsSubmitting(false);
 | 
					 | 
				
			||||||
      showToast("Note added successfully!", "success");
 | 
					 | 
				
			||||||
      setAddNote(true);
 | 
					 | 
				
			||||||
      setIsActive(true);
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      setIsSubmitting(false);
 | 
					 | 
				
			||||||
      const msg =
 | 
					 | 
				
			||||||
        error.response.data.message ||
 | 
					 | 
				
			||||||
        error.message ||
 | 
					 | 
				
			||||||
        "Error occured during API calling";
 | 
					 | 
				
			||||||
      showToast(msg, "error");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const onCancel = () => {
 | 
					 | 
				
			||||||
    setValue("note", "");
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const handleSwitch = () => {
 | 
					 | 
				
			||||||
    setIsActive(!IsActive);
 | 
					 | 
				
			||||||
    if (IsActive) {
 | 
					 | 
				
			||||||
      refetch(contactProfile?.id, false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="text-start">
 | 
					 | 
				
			||||||
      <div className="d-flex align-items-center justify-content-between">
 | 
					 | 
				
			||||||
        <p className="fw-semibold m-0">Notes :</p>
 | 
					 | 
				
			||||||
        <div className="m-0 d-flex aligin-items-center">
 | 
					 | 
				
			||||||
          <label className="switch switch-primary">
 | 
					 | 
				
			||||||
            <input
 | 
					 | 
				
			||||||
              type="checkbox"
 | 
					 | 
				
			||||||
              className="switch-input"
 | 
					 | 
				
			||||||
              onChange={() => handleSwitch(!IsActive)}
 | 
					 | 
				
			||||||
              value={IsActive}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <span className="switch-toggle-slider">
 | 
					 | 
				
			||||||
              <span className="switch-on">
 | 
					 | 
				
			||||||
                {/* <i class="icon-base bx bx-check"></i> */}
 | 
					 | 
				
			||||||
              </span>
 | 
					 | 
				
			||||||
              <span className="switch-off">
 | 
					 | 
				
			||||||
                {/* <i class="icon-base bx bx-x"></i> */}
 | 
					 | 
				
			||||||
              </span>
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
            <span className="switch-label ">Show Including Inactive Notes</span>
 | 
					 | 
				
			||||||
          </label>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {addNote && (
 | 
					 | 
				
			||||||
        <form onSubmit={handleSubmit(onSubmit)}>
 | 
					 | 
				
			||||||
          <Editor
 | 
					 | 
				
			||||||
            value={noteValue}
 | 
					 | 
				
			||||||
            loading={IsSubmitting}
 | 
					 | 
				
			||||||
            onChange={handleEditorChange}
 | 
					 | 
				
			||||||
            onCancel={onCancel}
 | 
					 | 
				
			||||||
            onSubmit={handleSubmit(onSubmit)}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          {errors.notes && (
 | 
					 | 
				
			||||||
            <p className="text-danger small mt-1">{errors.note.message}</p>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </form>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
      <div className="d-flex justify-content-end px-2">
 | 
					 | 
				
			||||||
        <span
 | 
					 | 
				
			||||||
          className={`btn btn-sm   ${addNote ? "btn-danger" : "btn-primary"}`}
 | 
					 | 
				
			||||||
          onClick={() => setAddNote(!addNote)}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          {addNote ? "Hide Editor" : "Add Note"}
 | 
					 | 
				
			||||||
        </span>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <div className=" justify-content-start  px-1 mt-1">
 | 
					 | 
				
			||||||
        {isLoading && (
 | 
					 | 
				
			||||||
          <div className="text-center">
 | 
					 | 
				
			||||||
            {" "}
 | 
					 | 
				
			||||||
            <p>Loading...</p>{" "}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
        {!isLoading &&
 | 
					 | 
				
			||||||
          [...(IsActive ? contactProfile?.notes || [] : contactNotes || [])]
 | 
					 | 
				
			||||||
            .reverse()
 | 
					 | 
				
			||||||
            .map((noteItem) => (
 | 
					 | 
				
			||||||
              <NoteCardDirectory
 | 
					 | 
				
			||||||
                refetchProfile={refetchProfile}
 | 
					 | 
				
			||||||
                refetchNotes={refetch}
 | 
					 | 
				
			||||||
                refetchContact={refetch}
 | 
					 | 
				
			||||||
                noteItem={noteItem}
 | 
					 | 
				
			||||||
                contactId={contactProfile?.id}
 | 
					 | 
				
			||||||
                setProfileContact={setProfileContact}
 | 
					 | 
				
			||||||
                key={noteItem.id}
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            ))}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {IsActive && (
 | 
					 | 
				
			||||||
          <div>
 | 
					 | 
				
			||||||
            {!isLoading && contactProfile?.notes.length == 0 && !addNote && (
 | 
					 | 
				
			||||||
              <div className="text-center mt-5">No Notes Found</div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
        {!IsActive && (
 | 
					 | 
				
			||||||
          <div>
 | 
					 | 
				
			||||||
            {!isLoading && contactNotes.length == 0 && !addNote && (
 | 
					 | 
				
			||||||
              <div className="text-center  mt-5">No Notes Found</div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default NotesDirectory;
 | 
					 | 
				
			||||||
@ -1,234 +0,0 @@
 | 
				
			|||||||
import React, { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import { useContactProfile } from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
import Avatar from "../common/Avatar";
 | 
					 | 
				
			||||||
import moment from "moment";
 | 
					 | 
				
			||||||
import NotesDirectory from "./NotesDirectory";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ProfileContactDirectory = ({ contact, setOpen_contact, closeModal }) => {
 | 
					 | 
				
			||||||
  const { contactProfile, loading, refetch } = useContactProfile(contact?.id);
 | 
					 | 
				
			||||||
  const [copiedIndex, setCopiedIndex] = useState(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const [profileContact, setProfileContact] = useState();
 | 
					 | 
				
			||||||
  const [expanded, setExpanded] = useState(false);
 | 
					 | 
				
			||||||
  const description = contactProfile?.description || "";
 | 
					 | 
				
			||||||
  const limit = 500;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const toggleReadMore = () => setExpanded(!expanded);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const isLong = description.length > limit;
 | 
					 | 
				
			||||||
  const displayText = expanded
 | 
					 | 
				
			||||||
    ? description
 | 
					 | 
				
			||||||
    : description.slice(0, limit) + (isLong ? "..." : "");
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    setProfileContact(contactProfile);
 | 
					 | 
				
			||||||
  }, [contactProfile]);
 | 
					 | 
				
			||||||
  const handleCopy = (email, index) => {
 | 
					 | 
				
			||||||
    navigator.clipboard.writeText(email);
 | 
					 | 
				
			||||||
    setCopiedIndex(index);
 | 
					 | 
				
			||||||
    setTimeout(() => setCopiedIndex(null), 2000); // Reset after 2 seconds
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="p-1">
 | 
					 | 
				
			||||||
      <div className="text-center m-0 p-0">
 | 
					 | 
				
			||||||
        <p className="fw-semibold fs-6 m-0">Contact Profile</p>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <div>
 | 
					 | 
				
			||||||
        <div className="d-flex align-items-center mb-2">
 | 
					 | 
				
			||||||
          <Avatar
 | 
					 | 
				
			||||||
            size="sm"
 | 
					 | 
				
			||||||
            classAvatar="m-0"
 | 
					 | 
				
			||||||
            firstName={
 | 
					 | 
				
			||||||
              (contact?.name || "").trim().split(" ")[0]?.charAt(0) || ""
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            lastName={
 | 
					 | 
				
			||||||
              (contact?.name || "").trim().split(" ")[1]?.charAt(0) || ""
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          <div className="d-flex flex-column text-start ms-1">
 | 
					 | 
				
			||||||
            <span className="m-0 fw-semibold">{contact?.name}</span>
 | 
					 | 
				
			||||||
            <small className="text-secondary small-text">
 | 
					 | 
				
			||||||
              {contactProfile?.tags?.map((tag) => tag.name).join(" | ")}
 | 
					 | 
				
			||||||
            </small>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="row">
 | 
					 | 
				
			||||||
          <div className="col-12 col-md-6 d-flex flex-column text-start">
 | 
					 | 
				
			||||||
            {contactProfile?.contactEmails?.length > 0 && (
 | 
					 | 
				
			||||||
              <div className="d-flex mb-2">
 | 
					 | 
				
			||||||
                <div style={{ width: "100px", minWidth: "100px" }}>
 | 
					 | 
				
			||||||
                  <p className="m-0">Email:</p>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div style={{ flex: 1 }}>
 | 
					 | 
				
			||||||
                  <ul className="list-unstyled mb-0">
 | 
					 | 
				
			||||||
                    {contactProfile.contactEmails.map((email, idx) => (
 | 
					 | 
				
			||||||
                      <li className="d-flex align-items-center mb-1" key={idx}>
 | 
					 | 
				
			||||||
                        <i className="bx bx-envelope bx-xs me-1 mt-1"></i>
 | 
					 | 
				
			||||||
                        <span className="me-1 flex-grow text-break overflow-wrap">
 | 
					 | 
				
			||||||
                          {email.emailAddress}
 | 
					 | 
				
			||||||
                        </span>
 | 
					 | 
				
			||||||
                        <i
 | 
					 | 
				
			||||||
                          className={`bx bx-copy-alt cursor-pointer bx-xs text-start ${
 | 
					 | 
				
			||||||
                            copiedIndex === idx
 | 
					 | 
				
			||||||
                              ? "text-secondary"
 | 
					 | 
				
			||||||
                              : "text-primary"
 | 
					 | 
				
			||||||
                          }`}
 | 
					 | 
				
			||||||
                          title={copiedIndex === idx ? "Copied!" : "Copy Email"}
 | 
					 | 
				
			||||||
                          style={{ flexShrink: 0 }}
 | 
					 | 
				
			||||||
                          onClick={() => handleCopy(email.emailAddress, idx)}
 | 
					 | 
				
			||||||
                        ></i>
 | 
					 | 
				
			||||||
                      </li>
 | 
					 | 
				
			||||||
                    ))}
 | 
					 | 
				
			||||||
                  </ul>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            {contactProfile?.contactPhones?.length > 0 && (
 | 
					 | 
				
			||||||
              <div className="d-flex mb-2">
 | 
					 | 
				
			||||||
                <div style={{ width: "100px", minWidth: "100px" }}>
 | 
					 | 
				
			||||||
                  <p className="m-0">Phone : </p>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div>
 | 
					 | 
				
			||||||
                  <ul className="list-inline mb-0">
 | 
					 | 
				
			||||||
                    {contactProfile?.contactPhones.map((phone, idx) => (
 | 
					 | 
				
			||||||
                      <li className="list-inline-item me-3" key={idx}>
 | 
					 | 
				
			||||||
                        <i className="bx bx-phone bx-xs me-1"></i>
 | 
					 | 
				
			||||||
                        {phone.phoneNumber}
 | 
					 | 
				
			||||||
                      </li>
 | 
					 | 
				
			||||||
                    ))}
 | 
					 | 
				
			||||||
                  </ul>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            {contactProfile?.createdAt && (
 | 
					 | 
				
			||||||
              <div className="d-flex  mb-2">
 | 
					 | 
				
			||||||
                <div style={{ width: "100px", minWidth: "100px" }}>
 | 
					 | 
				
			||||||
                  <p className="m-0">Created : </p>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div className="d-flex align-items-center">
 | 
					 | 
				
			||||||
                  <li className="list-inline-item">
 | 
					 | 
				
			||||||
                    <i className="bx bx-calendar-week bx-xs me-1"></i>
 | 
					 | 
				
			||||||
                    {moment(contactProfile.createdAt).format("MMMM, DD YYYY")}
 | 
					 | 
				
			||||||
                  </li>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
            {contactProfile?.address && (
 | 
					 | 
				
			||||||
              <div className="d-flex mb-2">
 | 
					 | 
				
			||||||
                <div style={{ width: "100px", minWidth: "100px" }}>
 | 
					 | 
				
			||||||
                  <p className="m-0">Location:</p>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div className="d-flex align-items-center">
 | 
					 | 
				
			||||||
                  <i className="bx bx-map bx-xs me-1 "></i>
 | 
					 | 
				
			||||||
                  <span className="text-break small">
 | 
					 | 
				
			||||||
                    {contactProfile.address}
 | 
					 | 
				
			||||||
                  </span>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          <div className="col-12 col-md-6 d-flex flex-column text-start">
 | 
					 | 
				
			||||||
            {contactProfile?.organization && (
 | 
					 | 
				
			||||||
              <div className="d-flex mb-2">
 | 
					 | 
				
			||||||
                <div style={{ width: "100px", minWidth: "100px" }}>
 | 
					 | 
				
			||||||
                  <p className="m-0">Orgnization : </p>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div className="d-flex align-items-center">
 | 
					 | 
				
			||||||
                  <i className="fa-solid fa-briefcase me-2"></i>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                  <span style={{ wordBreak: "break-word" }}>
 | 
					 | 
				
			||||||
                    {contactProfile.organization}
 | 
					 | 
				
			||||||
                  </span>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
            {contactProfile?.contactCategory && (
 | 
					 | 
				
			||||||
              <div className="d-flex mb-2">
 | 
					 | 
				
			||||||
                <div style={{ width: "100px", minWidth: "100px" }}>
 | 
					 | 
				
			||||||
                  <p className="m-0">Category : </p>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div>
 | 
					 | 
				
			||||||
                  <ul className="list-inline mb-0">
 | 
					 | 
				
			||||||
                    <li className="list-inline-item">
 | 
					 | 
				
			||||||
                      <i className="bx bx-user bx-xs me-1"></i>
 | 
					 | 
				
			||||||
                      {contactProfile.contactCategory.name}
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                  </ul>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            {contactProfile?.buckets?.length > 0 && (
 | 
					 | 
				
			||||||
              <div className="d-flex ">
 | 
					 | 
				
			||||||
                {contactProfile?.contactEmails?.length > 0 && (
 | 
					 | 
				
			||||||
                  <div className="d-flex mb-2 align-items-center">
 | 
					 | 
				
			||||||
                    <div style={{ width: "100px", minWidth: "100px" }}>
 | 
					 | 
				
			||||||
                      <p className="m-0">Buckets : </p>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div>
 | 
					 | 
				
			||||||
                      <ul className="list-inline mb-0">
 | 
					 | 
				
			||||||
                        {contactProfile.buckets.map((bucket) => (
 | 
					 | 
				
			||||||
                          <li className="list-inline-item me-2" key={bucket.id}>
 | 
					 | 
				
			||||||
                            <span className="badge bg-label-primary my-1">
 | 
					 | 
				
			||||||
                              {bucket.name}
 | 
					 | 
				
			||||||
                            </span>
 | 
					 | 
				
			||||||
                          </li>
 | 
					 | 
				
			||||||
                        ))}
 | 
					 | 
				
			||||||
                      </ul>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                )}
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        {contactProfile?.projects?.length > 0 && (
 | 
					 | 
				
			||||||
          <div className="d-flex mb-2 align-items-start">
 | 
					 | 
				
			||||||
            <div style={{ minWidth: "100px" }}>
 | 
					 | 
				
			||||||
              <p className="m-0 text-start">Projects :</p>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div className="text-start">
 | 
					 | 
				
			||||||
              <ul className="list-inline mb-0">
 | 
					 | 
				
			||||||
                {contactProfile.projects.map((project, index) => (
 | 
					 | 
				
			||||||
                  <li className="list-inline-item me-2" key={project.id}>
 | 
					 | 
				
			||||||
                    {project.name}
 | 
					 | 
				
			||||||
                    {index < contactProfile.projects.length - 1 && ","}
 | 
					 | 
				
			||||||
                  </li>
 | 
					 | 
				
			||||||
                ))}
 | 
					 | 
				
			||||||
              </ul>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="d-flex mb-2 align-items-start">
 | 
					 | 
				
			||||||
          <div style={{ minWidth: "100px" }}>
 | 
					 | 
				
			||||||
            <p className="m-0 text-start">Description :</p>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div className="text-start">
 | 
					 | 
				
			||||||
            {displayText}
 | 
					 | 
				
			||||||
            {isLong && (
 | 
					 | 
				
			||||||
              <span
 | 
					 | 
				
			||||||
                onClick={toggleReadMore}
 | 
					 | 
				
			||||||
                className="text-primary mx-1 cursor-pointer"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                {expanded ? "Read less" : "Read more"}
 | 
					 | 
				
			||||||
              </span>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <hr className="my-1" />
 | 
					 | 
				
			||||||
        <NotesDirectory
 | 
					 | 
				
			||||||
          refetchProfile={refetch}
 | 
					 | 
				
			||||||
          isLoading={loading}
 | 
					 | 
				
			||||||
          contactProfile={profileContact}
 | 
					 | 
				
			||||||
          setProfileContact={setProfileContact}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default ProfileContactDirectory;
 | 
					 | 
				
			||||||
@ -1,465 +0,0 @@
 | 
				
			|||||||
import React, { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  useForm,
 | 
					 | 
				
			||||||
  useFieldArray,
 | 
					 | 
				
			||||||
  FormProvider,
 | 
					 | 
				
			||||||
  useFormContext,
 | 
					 | 
				
			||||||
} from "react-hook-form";
 | 
					 | 
				
			||||||
import { zodResolver } from "@hookform/resolvers/zod";
 | 
					 | 
				
			||||||
import TagInput from "../common/TagInput";
 | 
					 | 
				
			||||||
import IconButton from "../common/IconButton";
 | 
					 | 
				
			||||||
import useMaster, {
 | 
					 | 
				
			||||||
  useContactCategory,
 | 
					 | 
				
			||||||
  useContactTags,
 | 
					 | 
				
			||||||
} from "../../hooks/masterHook/useMaster";
 | 
					 | 
				
			||||||
import { useDispatch, useSelector } from "react-redux";
 | 
					 | 
				
			||||||
import { changeMaster } from "../../slices/localVariablesSlice";
 | 
					 | 
				
			||||||
import { useBuckets, useOrganization } from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
import { useProjects } from "../../hooks/useProjects";
 | 
					 | 
				
			||||||
import SelectMultiple from "../common/SelectMultiple";
 | 
					 | 
				
			||||||
import { ContactSchema } from "./DirectorySchema";
 | 
					 | 
				
			||||||
import InputSuggestions from "../common/InputSuggestion";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const UpdateContact = ({ submitContact, existingContact, onCLosed }) => {
 | 
					 | 
				
			||||||
  const selectedMaster = useSelector(
 | 
					 | 
				
			||||||
    (store) => store.localVariables.selectedMaster
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  const [categoryData, setCategoryData] = useState([]);
 | 
					 | 
				
			||||||
  const [TagsData, setTagsData] = useState([]);
 | 
					 | 
				
			||||||
  const { data, loading } = useMaster();
 | 
					 | 
				
			||||||
  const { buckets, loading: bucketsLoaging } = useBuckets();
 | 
					 | 
				
			||||||
  const { projects, loading: projectLoading } = useProjects();
 | 
					 | 
				
			||||||
  const { contactCategory, loading: contactCategoryLoading } =
 | 
					 | 
				
			||||||
    useContactCategory();
 | 
					 | 
				
			||||||
  const { contactTags, loading: Tagloading } = useContactTags();
 | 
					 | 
				
			||||||
  const [ IsSubmitting, setSubmitting ] = useState( false );
 | 
					 | 
				
			||||||
  const [isInitialized, setIsInitialized] = useState(false);
 | 
					 | 
				
			||||||
  const dispatch = useDispatch();
 | 
					 | 
				
			||||||
  const {organizationList} = useOrganization()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const methods = useForm({
 | 
					 | 
				
			||||||
    resolver: zodResolver(ContactSchema),
 | 
					 | 
				
			||||||
    defaultValues: {
 | 
					 | 
				
			||||||
      name: "",
 | 
					 | 
				
			||||||
      organization: "",
 | 
					 | 
				
			||||||
      contactCategoryId: null,
 | 
					 | 
				
			||||||
      address: "",
 | 
					 | 
				
			||||||
      description: "",
 | 
					 | 
				
			||||||
      projectIds: [],
 | 
					 | 
				
			||||||
      contactEmails: [],
 | 
					 | 
				
			||||||
      contactPhones: [],
 | 
					 | 
				
			||||||
      tags: [],
 | 
					 | 
				
			||||||
      bucketIds: [],
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    register,
 | 
					 | 
				
			||||||
    handleSubmit,
 | 
					 | 
				
			||||||
    control,
 | 
					 | 
				
			||||||
    getValues,
 | 
					 | 
				
			||||||
    trigger,
 | 
					 | 
				
			||||||
    setValue,
 | 
					 | 
				
			||||||
    watch,
 | 
					 | 
				
			||||||
    reset,
 | 
					 | 
				
			||||||
    formState: { errors },
 | 
					 | 
				
			||||||
  } = methods;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    fields: emailFields,
 | 
					 | 
				
			||||||
    append: appendEmail,
 | 
					 | 
				
			||||||
    remove: removeEmail,
 | 
					 | 
				
			||||||
  } = useFieldArray({ control, name: "contactEmails" });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    fields: phoneFields,
 | 
					 | 
				
			||||||
    append: appendPhone,
 | 
					 | 
				
			||||||
    remove: removePhone,
 | 
					 | 
				
			||||||
  } = useFieldArray({ control, name: "contactPhones" });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleAddEmail = async () => {
 | 
					 | 
				
			||||||
    const emails = getValues("contactEmails");
 | 
					 | 
				
			||||||
    const lastIndex = emails.length - 1;
 | 
					 | 
				
			||||||
    const valid = await trigger(`contactEmails.${lastIndex}.emailAddress`);
 | 
					 | 
				
			||||||
    if (valid) {
 | 
					 | 
				
			||||||
      appendEmail({ label: "Work", emailAddress: "" });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleAddPhone = async () => {
 | 
					 | 
				
			||||||
    const phones = getValues("contactPhones");
 | 
					 | 
				
			||||||
    const lastIndex = phones.length - 1;
 | 
					 | 
				
			||||||
    const valid = await trigger(`contactPhones.${lastIndex}.phoneNumber`);
 | 
					 | 
				
			||||||
    if (valid) {
 | 
					 | 
				
			||||||
      appendPhone({ label: "Office", phoneNumber: "" });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const watchBucketIds = watch("bucketIds");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const toggleBucketId = (id) => {
 | 
					 | 
				
			||||||
    const updated = watchBucketIds?.includes(id)
 | 
					 | 
				
			||||||
      ? watchBucketIds.filter((val) => val !== id)
 | 
					 | 
				
			||||||
      : [...watchBucketIds, id];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setValue("bucketIds", updated, { shouldValidate: true });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const handleCheckboxChange = (id) => {
 | 
					 | 
				
			||||||
    const updated = watchBucketIds.includes(id)
 | 
					 | 
				
			||||||
      ? watchBucketIds.filter((i) => i !== id)
 | 
					 | 
				
			||||||
      : [...watchBucketIds, id];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setValue("bucketIds", updated, { shouldValidate: true });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const onSubmit = async (data) => {
 | 
					 | 
				
			||||||
const cleaned = {
 | 
					 | 
				
			||||||
  ...data,
 | 
					 | 
				
			||||||
  contactEmails: (data.contactEmails || [])
 | 
					 | 
				
			||||||
    .filter((e) => e.emailAddress?.trim() !== "")
 | 
					 | 
				
			||||||
    .map((email, index) => {
 | 
					 | 
				
			||||||
      const existingEmail = existingContact.contactEmails?.[index];
 | 
					 | 
				
			||||||
      return existingEmail
 | 
					 | 
				
			||||||
        ? { ...email, id: existingEmail.id } 
 | 
					 | 
				
			||||||
        : email;
 | 
					 | 
				
			||||||
    }),
 | 
					 | 
				
			||||||
  contactPhones: (data.contactPhones || [])
 | 
					 | 
				
			||||||
    .filter((p) => p.phoneNumber?.trim() !== "")
 | 
					 | 
				
			||||||
    .map((phone, index) => {
 | 
					 | 
				
			||||||
      const existingPhone = existingContact.contactPhones?.[index];
 | 
					 | 
				
			||||||
      return existingPhone
 | 
					 | 
				
			||||||
        ? { ...phone, id: existingPhone.id }
 | 
					 | 
				
			||||||
        : phone;
 | 
					 | 
				
			||||||
    }),
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
setSubmitting(true);
 | 
					 | 
				
			||||||
await submitContact({ ...cleaned, id: existingContact.id });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setSubmitting(false);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 const orgValue = watch("organization")
 | 
					 | 
				
			||||||
  const handleClosed = () => {
 | 
					 | 
				
			||||||
    onCLosed();
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const isValidContact =
 | 
					 | 
				
			||||||
      existingContact &&
 | 
					 | 
				
			||||||
      typeof existingContact === "object" &&
 | 
					 | 
				
			||||||
      !Array.isArray(existingContact);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!isInitialized &&isValidContact && TagsData) {
 | 
					 | 
				
			||||||
      reset({
 | 
					 | 
				
			||||||
        name: existingContact.name || "",
 | 
					 | 
				
			||||||
        organization: existingContact.organization || "",
 | 
					 | 
				
			||||||
        contactEmails: existingContact.contactEmails || [],
 | 
					 | 
				
			||||||
        contactPhones: existingContact.contactPhones || [],
 | 
					 | 
				
			||||||
        contactCategoryId: existingContact.contactCategory?.id || null,
 | 
					 | 
				
			||||||
        address: existingContact.address || "",
 | 
					 | 
				
			||||||
        description: existingContact.description || "",
 | 
					 | 
				
			||||||
        projectIds: existingContact.projectIds || null,
 | 
					 | 
				
			||||||
        tags: existingContact.tags || [],
 | 
					 | 
				
			||||||
        bucketIds: existingContact.bucketIds || [],
 | 
					 | 
				
			||||||
      } );
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      if (!existingContact.contactPhones || existingContact.contactPhones.length === 0) {
 | 
					 | 
				
			||||||
      appendPhone({ label: "Office", phoneNumber: "" });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!existingContact.contactEmails || existingContact.contactEmails.length === 0) {
 | 
					 | 
				
			||||||
      appendEmail({ label: "Work", emailAddress: "" });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      setIsInitialized(true)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // return()=> reset()
 | 
					 | 
				
			||||||
  }, [ existingContact, buckets, projects ] );
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <FormProvider {...methods}>
 | 
					 | 
				
			||||||
      <form className="p-2 p-sm-0" onSubmit={handleSubmit(onSubmit)}>
 | 
					 | 
				
			||||||
        <div className="d-flex justify-content-center align-items-center">
 | 
					 | 
				
			||||||
          <h6 className="m-0 fw-18"> Update Contact</h6>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="row">
 | 
					 | 
				
			||||||
          <div className="col-md-6  text-start">
 | 
					 | 
				
			||||||
            <label className="form-label">Name</label>
 | 
					 | 
				
			||||||
            <input
 | 
					 | 
				
			||||||
              className="form-control form-control-sm"
 | 
					 | 
				
			||||||
              {...register("name")}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            {errors.name && (
 | 
					 | 
				
			||||||
              <small className="danger-text">{errors.name.message}</small>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         
 | 
					 | 
				
			||||||
          <div className="col-md-6  text-start">
 | 
					 | 
				
			||||||
            <label className="form-label">Organization</label>
 | 
					 | 
				
			||||||
            <InputSuggestions
 | 
					 | 
				
			||||||
          organizationList={organizationList}
 | 
					 | 
				
			||||||
          value={getValues("organization") || ""}
 | 
					 | 
				
			||||||
          onChange={(val) => setValue("organization", val)}
 | 
					 | 
				
			||||||
          error={errors.organization?.message}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
            {errors.organization && (
 | 
					 | 
				
			||||||
              <small className="danger-text">
 | 
					 | 
				
			||||||
                {errors.organization.message}
 | 
					 | 
				
			||||||
              </small>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="row mt-1">
 | 
					 | 
				
			||||||
          <div className="col-md-6">
 | 
					 | 
				
			||||||
            {emailFields.map((field, index) => (
 | 
					 | 
				
			||||||
              <div
 | 
					 | 
				
			||||||
                key={field.id}
 | 
					 | 
				
			||||||
                className="row d-flex align-items-center mb-1"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <div className="col-5  text-start">
 | 
					 | 
				
			||||||
                  <label className="form-label">Label</label>
 | 
					 | 
				
			||||||
                  <select
 | 
					 | 
				
			||||||
                    className="form-select form-select-sm"
 | 
					 | 
				
			||||||
                    {...register(`contactEmails.${index}.label`)}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    <option value="Work">Work</option>
 | 
					 | 
				
			||||||
                    <option value="Personal">Personal</option>
 | 
					 | 
				
			||||||
                    <option value="Other">Other</option>
 | 
					 | 
				
			||||||
                  </select>
 | 
					 | 
				
			||||||
                  {errors.contactEmails?.[index]?.label && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">
 | 
					 | 
				
			||||||
                      {errors.contactEmails[index].label.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div className="col-7  text-start">
 | 
					 | 
				
			||||||
                  <label className="form-label">Email</label>
 | 
					 | 
				
			||||||
                  <div className="d-flex align-items-center">
 | 
					 | 
				
			||||||
                    <input
 | 
					 | 
				
			||||||
                      type="email"
 | 
					 | 
				
			||||||
                      className="form-control form-control-sm"
 | 
					 | 
				
			||||||
                      {...register(`contactEmails.${index}.emailAddress`)}
 | 
					 | 
				
			||||||
                      placeholder="email@example.com"
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    {index === emailFields.length - 1 ? (
 | 
					 | 
				
			||||||
                      // <button
 | 
					 | 
				
			||||||
                      //   type="button"
 | 
					 | 
				
			||||||
                      //   className="btn btn-xs btn-primary ms-1"
 | 
					 | 
				
			||||||
                        
 | 
					 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					 | 
				
			||||||
                      // >
 | 
					 | 
				
			||||||
                        <i className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary" onClick={handleAddEmail}/>
 | 
					 | 
				
			||||||
                 
 | 
					 | 
				
			||||||
                    ) : (
 | 
					 | 
				
			||||||
                      // <button
 | 
					 | 
				
			||||||
                      //   type="button"
 | 
					 | 
				
			||||||
                      //   className="btn btn-xs btn-danger ms-1 p-0"
 | 
					 | 
				
			||||||
                      //   onClick={() => removeEmail(index)}
 | 
					 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					 | 
				
			||||||
                      // >
 | 
					 | 
				
			||||||
                        <i className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-danger" onClick={() => removeEmail(index)}/>
 | 
					 | 
				
			||||||
              
 | 
					 | 
				
			||||||
                    )}
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                  {errors.contactEmails?.[index]?.emailAddress && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">
 | 
					 | 
				
			||||||
                      {errors.contactEmails[index].emailAddress.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            ))}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div className="col-md-6">
 | 
					 | 
				
			||||||
            {phoneFields.map((field, index) => (
 | 
					 | 
				
			||||||
              <div
 | 
					 | 
				
			||||||
                key={field.id}
 | 
					 | 
				
			||||||
                className="row d-flex align-items-center mb-2"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <div className="col-5  text-start">
 | 
					 | 
				
			||||||
                  <label className="form-label">Label</label>
 | 
					 | 
				
			||||||
                  <select
 | 
					 | 
				
			||||||
                    className="form-select form-select-sm"
 | 
					 | 
				
			||||||
                    {...register(`contactPhones.${index}.label`)}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    <option value="Office">Office</option>
 | 
					 | 
				
			||||||
                    <option value="Personal">Personal</option>
 | 
					 | 
				
			||||||
                    <option value="Business">Business</option>
 | 
					 | 
				
			||||||
                  </select>
 | 
					 | 
				
			||||||
                  {errors.phone?.[index]?.label && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">
 | 
					 | 
				
			||||||
                      {errors.ContactPhones[index].label.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div className="col-7  text-start">
 | 
					 | 
				
			||||||
                  <label className="form-label">Phone</label>
 | 
					 | 
				
			||||||
                  <div className="d-flex align-items-center">
 | 
					 | 
				
			||||||
                    <input
 | 
					 | 
				
			||||||
                      type="text"
 | 
					 | 
				
			||||||
                      className="form-control form-control-sm"
 | 
					 | 
				
			||||||
                      {...register(`contactPhones.${index}.phoneNumber`)}
 | 
					 | 
				
			||||||
                      placeholder="9876543210"
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    {index === phoneFields.length - 1 ? (
 | 
					 | 
				
			||||||
                      // <button
 | 
					 | 
				
			||||||
                      //   type="button"
 | 
					 | 
				
			||||||
                      //   className="btn btn-xs btn-primary ms-1"
 | 
					 | 
				
			||||||
                      //   onClick={handleAddPhone}
 | 
					 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					 | 
				
			||||||
                      // >
 | 
					 | 
				
			||||||
                        <i className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary" onClick={handleAddPhone} />
 | 
					 | 
				
			||||||
                    ) : (
 | 
					 | 
				
			||||||
                      // <button
 | 
					 | 
				
			||||||
                      //   type="button"
 | 
					 | 
				
			||||||
                      //   className="btn btn-xs btn-danger ms-1"
 | 
					 | 
				
			||||||
                      //   onClick={() => removePhone(index)}
 | 
					 | 
				
			||||||
                      //   style={{ width: "24px", height: "24px" }}
 | 
					 | 
				
			||||||
                      // >
 | 
					 | 
				
			||||||
                        <i className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-danger" onClick={() => removePhone(index)} />
 | 
					 | 
				
			||||||
                    )}
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                  {errors.contactPhones?.[index]?.phoneNumber && (
 | 
					 | 
				
			||||||
                    <small className="danger-text">
 | 
					 | 
				
			||||||
                      {errors.contactPhones[index].phoneNumber.message}
 | 
					 | 
				
			||||||
                    </small>
 | 
					 | 
				
			||||||
                  )}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            ))}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          {errors.contactPhone?.message && (
 | 
					 | 
				
			||||||
            <div className="danger-text">{errors.contactPhone.message}</div>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="row my-1">
 | 
					 | 
				
			||||||
          <div className="col-md-6  text-start">
 | 
					 | 
				
			||||||
            <label className="form-label">Category</label>
 | 
					 | 
				
			||||||
            <select
 | 
					 | 
				
			||||||
              className="form-select form-select-sm"
 | 
					 | 
				
			||||||
              {...register("contactCategoryId")}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              {contactCategoryLoading && !contactCategory ? (
 | 
					 | 
				
			||||||
                <option disabled value="">
 | 
					 | 
				
			||||||
                  Loading...
 | 
					 | 
				
			||||||
                </option>
 | 
					 | 
				
			||||||
              ) : (
 | 
					 | 
				
			||||||
                <>
 | 
					 | 
				
			||||||
                  <option disabled  value="">
 | 
					 | 
				
			||||||
                    Select Category
 | 
					 | 
				
			||||||
                  </option>
 | 
					 | 
				
			||||||
                  {contactCategory?.map((cate) => (
 | 
					 | 
				
			||||||
                    <option key={cate.id} value={cate.id}>
 | 
					 | 
				
			||||||
                      {cate.name}
 | 
					 | 
				
			||||||
                    </option>
 | 
					 | 
				
			||||||
                  ))}
 | 
					 | 
				
			||||||
                </>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </select>
 | 
					 | 
				
			||||||
            {errors.contactCategoryId && (
 | 
					 | 
				
			||||||
              <small className="danger-text">
 | 
					 | 
				
			||||||
                {errors.contactCategoryId.message}
 | 
					 | 
				
			||||||
              </small>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div className="col-12 col-md-6 text-start">
 | 
					 | 
				
			||||||
            <SelectMultiple
 | 
					 | 
				
			||||||
              name="projectIds"
 | 
					 | 
				
			||||||
              label="Select Projects"
 | 
					 | 
				
			||||||
              options={projects}
 | 
					 | 
				
			||||||
              labelKey="name"
 | 
					 | 
				
			||||||
              valueKey="id"
 | 
					 | 
				
			||||||
              IsLoading={projectLoading}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            {errors.projectIds && (
 | 
					 | 
				
			||||||
              <small className="danger-text">{errors.projectIds.message}</small>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-start">
 | 
					 | 
				
			||||||
          <TagInput name="tags" label="Tags" options={contactTags} />
 | 
					 | 
				
			||||||
          {errors.tags && (
 | 
					 | 
				
			||||||
            <small className="danger-text">{errors.tags.message}</small>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="row">
 | 
					 | 
				
			||||||
         <div className="col-md-12 mt-1 text-start">
 | 
					 | 
				
			||||||
            <label className="form-label ">Select Label</label>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <ul className="d-flex flex-wrap px-1 list-unstyled  mb-0">
 | 
					 | 
				
			||||||
              {bucketsLoaging && <p>Loading...</p>}
 | 
					 | 
				
			||||||
              {buckets?.map((item) => (
 | 
					 | 
				
			||||||
                <li
 | 
					 | 
				
			||||||
                  key={item.id}
 | 
					 | 
				
			||||||
                  className="list-inline-item flex-shrink-0 me-6 mb-2"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  <div className="form-check ">
 | 
					 | 
				
			||||||
                    <input
 | 
					 | 
				
			||||||
                      type="checkbox"
 | 
					 | 
				
			||||||
                      className="form-check-input"
 | 
					 | 
				
			||||||
                      id={`item-${item.id}`}
 | 
					 | 
				
			||||||
                      checked={watchBucketIds.includes(item.id)}
 | 
					 | 
				
			||||||
                      onChange={() => handleCheckboxChange(item.id)}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <label
 | 
					 | 
				
			||||||
                      className="form-check-label"
 | 
					 | 
				
			||||||
                      htmlFor={`item-${item.id}`}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      {item.name}
 | 
					 | 
				
			||||||
                    </label>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </li>
 | 
					 | 
				
			||||||
              ))}
 | 
					 | 
				
			||||||
              {errors.bucketIds && (
 | 
					 | 
				
			||||||
                <small className="danger-text mt-0">
 | 
					 | 
				
			||||||
                  {errors.bucketIds.message}
 | 
					 | 
				
			||||||
                </small>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </ul>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-start">
 | 
					 | 
				
			||||||
          <label className="form-label">Address</label>
 | 
					 | 
				
			||||||
          <textarea
 | 
					 | 
				
			||||||
            className="form-control form-control-sm"
 | 
					 | 
				
			||||||
            rows="2"
 | 
					 | 
				
			||||||
            {...register("address")}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-start">
 | 
					 | 
				
			||||||
          <label className="form-label">Description</label>
 | 
					 | 
				
			||||||
          <textarea
 | 
					 | 
				
			||||||
            className="form-control form-control-sm"
 | 
					 | 
				
			||||||
            rows="2"
 | 
					 | 
				
			||||||
            {...register("description")}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          {errors.description && (
 | 
					 | 
				
			||||||
            <small className="danger-text">{errors.description.message}</small>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="d-flex justify-content-center gap-1 py-2">
 | 
					 | 
				
			||||||
          <button className="btn btn-sm btn-primary" type="submit" disabled={IsSubmitting}>
 | 
					 | 
				
			||||||
            {IsSubmitting ? "Please Wait..." : "Update"}
 | 
					 | 
				
			||||||
          </button>
 | 
					 | 
				
			||||||
          <button
 | 
					 | 
				
			||||||
            className="btn btn-sm btn-secondary"
 | 
					 | 
				
			||||||
            type="button"
 | 
					 | 
				
			||||||
            onClick={handleClosed}
 | 
					 | 
				
			||||||
            disabled={IsSubmitting}
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            Cancel
 | 
					 | 
				
			||||||
          </button>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </form>
 | 
					 | 
				
			||||||
    </FormProvider>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default UpdateContact;
 | 
					 | 
				
			||||||
@ -637,7 +637,6 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
 | 
				
			|||||||
                      aria-label="manage employee"
 | 
					                      aria-label="manage employee"
 | 
				
			||||||
                      type="reset"
 | 
					                      type="reset"
 | 
				
			||||||
                      className="btn btn-sm btn-primary ms-2"
 | 
					                      className="btn btn-sm btn-primary ms-2"
 | 
				
			||||||
                      disabled={isloading}
 | 
					 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                      Clear
 | 
					                      Clear
 | 
				
			||||||
                    </button>
 | 
					                    </button>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ const Footer = () => {
 | 
				
			|||||||
      <>
 | 
					      <>
 | 
				
			||||||
                  <footer className="content-footer footer bg-footer-theme">
 | 
					                  <footer className="content-footer footer bg-footer-theme">
 | 
				
			||||||
                   <div className="container-xxl d-flex flex-wrap justify-content-between py-2 flex-md-row flex-column">
 | 
					                   <div className="container-xxl d-flex flex-wrap justify-content-between py-2 flex-md-row flex-column">
 | 
				
			||||||
                  <div className="mb-2 mb-md-0 small-text" style={{width: "100%", textAlign: "right"}}>
 | 
					                  <div className="mb-2 mb-md-0" style={{width: "100%", textAlign: "right"}}>
 | 
				
			||||||
                  © {new Date().getFullYear()}
 | 
					                  © {new Date().getFullYear()}
 | 
				
			||||||
                  , by <a href="https://marcosolutions.co.in/" target="_blank" className="font-weight-light footer-link">MARCO AIoT Technologies Pvt. Ltd.</a>
 | 
					                  , by <a href="https://marcosolutions.co.in/" target="_blank" className="font-weight-light footer-link">MARCO AIoT Technologies Pvt. Ltd.</a>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -602,7 +602,7 @@ const Header = () => {
 | 
				
			|||||||
                  <span className="align-middle">My Profile</span>
 | 
					                  <span className="align-middle">My Profile</span>
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
              </li>
 | 
					              </li>
 | 
				
			||||||
              <li onClick={handleProfilePage}>
 | 
					              <li>
 | 
				
			||||||
                <a
 | 
					                <a
 | 
				
			||||||
                  aria-label="go to setting "
 | 
					                  aria-label="go to setting "
 | 
				
			||||||
                  className="dropdown-item cusor-pointer"
 | 
					                  className="dropdown-item cusor-pointer"
 | 
				
			||||||
@ -611,7 +611,7 @@ const Header = () => {
 | 
				
			|||||||
                  <span className="align-middle">Settings</span>
 | 
					                  <span className="align-middle">Settings</span>
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
              </li>
 | 
					              </li>
 | 
				
			||||||
              {/* <li>
 | 
					              <li>
 | 
				
			||||||
                <a
 | 
					                <a
 | 
				
			||||||
                  aria-label="go to billing "
 | 
					                  aria-label="go to billing "
 | 
				
			||||||
                  className="dropdown-item cusor-pointer"
 | 
					                  className="dropdown-item cusor-pointer"
 | 
				
			||||||
@ -626,10 +626,8 @@ const Header = () => {
 | 
				
			|||||||
                    </span>
 | 
					                    </span>
 | 
				
			||||||
                  </span>
 | 
					                  </span>
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
              </li> */}
 | 
					              </li>
 | 
				
			||||||
              <li onClick={openChangePassword}>
 | 
					              <li onClick={openChangePassword}> {/* Use the function from the context */}
 | 
				
			||||||
                {" "}
 | 
					 | 
				
			||||||
                {/* Use the function from the context */}
 | 
					 | 
				
			||||||
                <a
 | 
					                <a
 | 
				
			||||||
                  aria-label="go to profile"
 | 
					                  aria-label="go to profile"
 | 
				
			||||||
                  className="dropdown-item cusor-pointer"
 | 
					                  className="dropdown-item cusor-pointer"
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,6 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
 | 
				
			|||||||
    .object({
 | 
					    .object({
 | 
				
			||||||
      ...(project?.id ? { id: z.string().optional() } : {}),
 | 
					      ...(project?.id ? { id: z.string().optional() } : {}),
 | 
				
			||||||
      name: z.string().min(1, { message: "Project Name is required" }),
 | 
					      name: z.string().min(1, { message: "Project Name is required" }),
 | 
				
			||||||
      shortName: z.string().optional(),
 | 
					 | 
				
			||||||
      contactPerson: z
 | 
					      contactPerson: z
 | 
				
			||||||
        .string()
 | 
					        .string()
 | 
				
			||||||
        .min( 1, {message: "Contact Person Name is required"} )
 | 
					        .min( 1, {message: "Contact Person Name is required"} )
 | 
				
			||||||
@ -73,7 +72,6 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
 | 
				
			|||||||
    defaultValues: {
 | 
					    defaultValues: {
 | 
				
			||||||
      id: project?.id || "",
 | 
					      id: project?.id || "",
 | 
				
			||||||
      name: project?.name || "",
 | 
					      name: project?.name || "",
 | 
				
			||||||
      shortName: project?.shortName || "",
 | 
					 | 
				
			||||||
      contactPerson: project?.contactPerson || "",
 | 
					      contactPerson: project?.contactPerson || "",
 | 
				
			||||||
      projectAddress: project?.projectAddress || "",
 | 
					      projectAddress: project?.projectAddress || "",
 | 
				
			||||||
      startDate: formatDate(project?.startDate) || currentDate,
 | 
					      startDate: formatDate(project?.startDate) || currentDate,
 | 
				
			||||||
@ -90,7 +88,6 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
 | 
				
			|||||||
        ? {
 | 
					        ? {
 | 
				
			||||||
            id: project?.id || "",
 | 
					            id: project?.id || "",
 | 
				
			||||||
            name: project?.name || "",
 | 
					            name: project?.name || "",
 | 
				
			||||||
            shortName: project?.shortName || "",
 | 
					 | 
				
			||||||
            contactPerson: project?.contactPerson || "",
 | 
					            contactPerson: project?.contactPerson || "",
 | 
				
			||||||
            projectAddress: project?.projectAddress || "",
 | 
					            projectAddress: project?.projectAddress || "",
 | 
				
			||||||
            startDate: formatDate(project?.startDate) || "",
 | 
					            startDate: formatDate(project?.startDate) || "",
 | 
				
			||||||
@ -111,7 +108,6 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
 | 
				
			|||||||
    reset({
 | 
					    reset({
 | 
				
			||||||
      id: project?.id || "",
 | 
					      id: project?.id || "",
 | 
				
			||||||
      name: project?.name || "",
 | 
					      name: project?.name || "",
 | 
				
			||||||
      shortName: project?.shortName || "",
 | 
					 | 
				
			||||||
      contactPerson: project?.contactPerson || "",
 | 
					      contactPerson: project?.contactPerson || "",
 | 
				
			||||||
      projectAddress: project?.projectAddress || "",
 | 
					      projectAddress: project?.projectAddress || "",
 | 
				
			||||||
      startDate: formatDate(project?.startDate) || currentDate,
 | 
					      startDate: formatDate(project?.startDate) || currentDate,
 | 
				
			||||||
@ -161,27 +157,6 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
 | 
				
			|||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
              <label className="form-label" htmlFor="shortName">
 | 
					 | 
				
			||||||
                Short Name
 | 
					 | 
				
			||||||
              </label>
 | 
					 | 
				
			||||||
              <input
 | 
					 | 
				
			||||||
                type="text"
 | 
					 | 
				
			||||||
                id="shortName"
 | 
					 | 
				
			||||||
                name="shortName"
 | 
					 | 
				
			||||||
                className="form-control"
 | 
					 | 
				
			||||||
                placeholder="Short Name"
 | 
					 | 
				
			||||||
                {...register("shortName")}
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
              {errors.shortName && (
 | 
					 | 
				
			||||||
                <div
 | 
					 | 
				
			||||||
                  className="danger-text text-start"
 | 
					 | 
				
			||||||
                  style={{ fontSize: "12px" }}
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  {errors.shortName.message}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div className="col-12 col-md-12">
 | 
					            <div className="col-12 col-md-12">
 | 
				
			||||||
              <label className="form-label" htmlFor="contactPerson">
 | 
					              <label className="form-label" htmlFor="contactPerson">
 | 
				
			||||||
                Contact Person
 | 
					                Contact Person
 | 
				
			||||||
 | 
				
			|||||||
@ -1,17 +1,19 @@
 | 
				
			|||||||
import React, { useState, useEffect } from "react";
 | 
					import React, { useState,useEffect } from "react";
 | 
				
			||||||
import ManageProjectInfo from "./ManageProjectInfo";
 | 
					import ManageProjectInfo from "./ManageProjectInfo";
 | 
				
			||||||
import showToast from "../../services/toastService";
 | 
					import showToast from "../../services/toastService";
 | 
				
			||||||
import ProjectRepository from "../../repositories/ProjectRepository";
 | 
					import ProjectRepository from "../../repositories/ProjectRepository";
 | 
				
			||||||
import { cacheData, getCachedData } from "../../slices/apiDataManager";
 | 
					import { cacheData,getCachedData } from "../../slices/apiDataManager";
 | 
				
			||||||
import { hasUserPermission } from "../../utils/authUtils";
 | 
					import {hasUserPermission} from "../../utils/authUtils";
 | 
				
			||||||
import moment from "moment";
 | 
					import moment from "moment";
 | 
				
			||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
					import {useHasUserPermission} from "../../hooks/useHasUserPermission";
 | 
				
			||||||
import { MANAGE_PROJECT } from "../../utils/constants";
 | 
					import {MANAGE_PROJECT} from "../../utils/constants";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectBanner = ({ project_data }) => {
 | 
					
 | 
				
			||||||
 | 
					const ProjectBanner = ( {project_data} ) =>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  const [showModal, setShowModal] = useState(false);
 | 
					  const [showModal, setShowModal] = useState(false);
 | 
				
			||||||
  const manageProject = useHasUserPermission(MANAGE_PROJECT);
 | 
					  const manageProject =  useHasUserPermission(MANAGE_PROJECT)
 | 
				
			||||||
  const [CurrentProject, setCurrentProject] = useState(project_data);
 | 
					  const [ CurrentProject, setCurrentProject ] = useState( project_data )
 | 
				
			||||||
  if (project_data == null) {
 | 
					  if (project_data == null) {
 | 
				
			||||||
    return <span>incomplete project information</span>;
 | 
					    return <span>incomplete project information</span>;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -19,39 +21,42 @@ const ProjectBanner = ({ project_data }) => {
 | 
				
			|||||||
  const handleShow = () => setShowModal(true);
 | 
					  const handleShow = () => setShowModal(true);
 | 
				
			||||||
  const handleClose = () => setShowModal(false);
 | 
					  const handleClose = () => setShowModal(false);
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
  const handleFormSubmit = (updatedProject, setLoading) => {
 | 
					  const handleFormSubmit = ( updatedProject,setLoading ) =>
 | 
				
			||||||
    if (CurrentProject?.id) {
 | 
					  {
 | 
				
			||||||
      ProjectRepository.updateProject(CurrentProject.id, updatedProject)
 | 
					   
 | 
				
			||||||
        .then((response) => {
 | 
					         if ( CurrentProject?.id )
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                 ProjectRepository.updateProject(CurrentProject.id,updatedProject).then( ( response ) =>
 | 
				
			||||||
 | 
					                 { 
 | 
				
			||||||
                   const updatedProjectData = {
 | 
					                   const updatedProjectData = {
 | 
				
			||||||
                     ...CurrentProject, 
 | 
					                     ...CurrentProject, 
 | 
				
			||||||
                     ...response.data, 
 | 
					                     ...response.data, 
 | 
				
			||||||
                     building: CurrentProject.building, 
 | 
					                     building: CurrentProject.building, 
 | 
				
			||||||
                   };
 | 
					                   };
 | 
				
			||||||
          setCurrentProject(updatedProject);
 | 
					                   setCurrentProject( updatedProject )
 | 
				
			||||||
                   
 | 
					                   
 | 
				
			||||||
          cacheData(`projectinfo-${CurrentProject.id}`, updatedProjectData);
 | 
					                   cacheData( `projectinfo-${ CurrentProject.id }`, updatedProjectData );
 | 
				
			||||||
                   const projects_list = getCachedData("projectslist");
 | 
					                   const projects_list = getCachedData("projectslist");
 | 
				
			||||||
          if (projects_list) {
 | 
					                   if ( projects_list )
 | 
				
			||||||
            const updatedProjectsList = projects_list.map((project) =>
 | 
					                   {
 | 
				
			||||||
              project.id === CurrentProject.id
 | 
					                    const updatedProjectsList = projects_list.map(project => 
 | 
				
			||||||
                ? {
 | 
					                      project.id === CurrentProject.id ? {
 | 
				
			||||||
                        ...project,       
 | 
					                        ...project,       
 | 
				
			||||||
                         ...response.data,
 | 
					                         ...response.data,
 | 
				
			||||||
                        //  tenant:project.tenant
 | 
					                        //  tenant:project.tenant
 | 
				
			||||||
                  }
 | 
					                      } : project
 | 
				
			||||||
                : project
 | 
					 | 
				
			||||||
                     );
 | 
					                     );
 | 
				
			||||||
                     
 | 
					                     
 | 
				
			||||||
            cacheData("projectslist", updatedProjectsList);
 | 
					                     cacheData("projectslist",updatedProjectsList)
 | 
				
			||||||
                   }
 | 
					                   }
 | 
				
			||||||
                   
 | 
					                   
 | 
				
			||||||
          showToast("Project updated successfully.", "success");
 | 
					                     showToast( "Project updated successfully.", "success" );
 | 
				
			||||||
          setLoading(false);
 | 
					                     setLoading(false)
 | 
				
			||||||
          setShowModal(false);
 | 
					                     setShowModal(false)
 | 
				
			||||||
                   })
 | 
					                   })
 | 
				
			||||||
                   .catch((error) => {
 | 
					                   .catch((error) => {
 | 
				
			||||||
          showToast(error.message, "error");
 | 
					                     showToast( error.message, "error" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                   });       
 | 
					                   });       
 | 
				
			||||||
          }    
 | 
					          }    
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -59,10 +64,10 @@ const ProjectBanner = ({ project_data }) => {
 | 
				
			|||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        className={`modal fade ${showModal ? "show" : ""}`}
 | 
					        className={`modal fade ${showModal ? 'show' : ''}`}
 | 
				
			||||||
        tabIndex="-1"
 | 
					        tabIndex="-1"
 | 
				
			||||||
        role="dialog"
 | 
					        role="dialog"
 | 
				
			||||||
        style={{ display: showModal ? "block" : "none" }}
 | 
					        style={{ display: showModal ? 'block' : 'none' }}
 | 
				
			||||||
        aria-hidden={!showModal}
 | 
					        aria-hidden={!showModal}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
         <ManageProjectInfo
 | 
					         <ManageProjectInfo
 | 
				
			||||||
@ -84,19 +89,13 @@ const ProjectBanner = ({ project_data }) => {
 | 
				
			|||||||
                style={{ width: "40px", height: "40px" }}
 | 
					                style={{ width: "40px", height: "40px" }}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
              <h5 className="mb-0">
 | 
					              <h5 className="mb-0">
 | 
				
			||||||
                {CurrentProject.name
 | 
					                {CurrentProject.name ? CurrentProject.name : "N/A"}
 | 
				
			||||||
                  ? CurrentProject.shortName
 | 
					 | 
				
			||||||
                    ? `${CurrentProject.name} (${CurrentProject.shortName})`
 | 
					 | 
				
			||||||
                    : CurrentProject.name
 | 
					 | 
				
			||||||
                  : "N/A"}
 | 
					 | 
				
			||||||
              </h5>
 | 
					              </h5>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            {manageProject && (
 | 
					            {manageProject && (
 | 
				
			||||||
              <button
 | 
					              <button
 | 
				
			||||||
                  type="button"
 | 
					                  type="button"
 | 
				
			||||||
                className={`btn btn-sm btn-primary ${
 | 
					                  className={`btn btn-sm btn-primary ${!manageProject && 'd-none'}`}
 | 
				
			||||||
                  !manageProject && "d-none"
 | 
					 | 
				
			||||||
                }`}
 | 
					 | 
				
			||||||
                  data-bs-toggle="modal"
 | 
					                  data-bs-toggle="modal"
 | 
				
			||||||
                  data-bs-target="#edit-project-modal"
 | 
					                  data-bs-target="#edit-project-modal"
 | 
				
			||||||
                  onClick={handleShow}
 | 
					                  onClick={handleShow}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ import {
 | 
				
			|||||||
  getProjectStatusName,
 | 
					  getProjectStatusName,
 | 
				
			||||||
} from "../../utils/projectStatus";
 | 
					} from "../../utils/projectStatus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectCard = ({ projectData, recall }) => {
 | 
					const ProjectCard = ({ projectData }) => {
 | 
				
			||||||
  const [projectInfo, setProjectInfo] = useState(projectData);
 | 
					  const [projectInfo, setProjectInfo] = useState(projectData);
 | 
				
			||||||
  const [projectDetails, setProjectDetails] = useState(null);
 | 
					  const [projectDetails, setProjectDetails] = useState(null);
 | 
				
			||||||
  const [showModal, setShowModal] = useState(false);
 | 
					  const [showModal, setShowModal] = useState(false);
 | 
				
			||||||
@ -78,7 +78,7 @@ const ProjectCard = ({ projectData, recall }) => {
 | 
				
			|||||||
            );
 | 
					            );
 | 
				
			||||||
            cacheData("projectslist", updatedProjectsList);
 | 
					            cacheData("projectslist", updatedProjectsList);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          recall(getCachedData("projectslist"));
 | 
					
 | 
				
			||||||
          showToast("Project updated successfully.", "success");
 | 
					          showToast("Project updated successfully.", "success");
 | 
				
			||||||
          setShowModal(false);
 | 
					          setShowModal(false);
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
@ -88,6 +88,7 @@ const ProjectCard = ({ projectData, recall }) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      {showModal && projectDetails && (
 | 
					      {showModal && projectDetails && (
 | 
				
			||||||
@ -118,16 +119,17 @@ const ProjectCard = ({ projectData, recall }) => {
 | 
				
			|||||||
                  ></i>
 | 
					                  ></i>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className="me-2">
 | 
					                <div className="me-2">
 | 
				
			||||||
                  <h5
 | 
					                  <h5 className="mb-0">
 | 
				
			||||||
                    className="mb-0 stretched-link text-heading text-start"
 | 
					                    <a
 | 
				
			||||||
 | 
					                      className="stretched-link text-heading"
 | 
				
			||||||
                      onClick={handleViewProject}
 | 
					                      onClick={handleViewProject}
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                    {projectInfo.shortName
 | 
					                      {projectInfo.name}
 | 
				
			||||||
                      ? projectInfo.shortName
 | 
					                    </a>
 | 
				
			||||||
                      : projectInfo.name}
 | 
					 | 
				
			||||||
                  </h5>
 | 
					                  </h5>
 | 
				
			||||||
                  <div className="client-info text-body">
 | 
					                  <div className="client-info text-body">
 | 
				
			||||||
                    <span>{projectInfo.shortName ? projectInfo.name : ""}</span>
 | 
					                    <span className="fw-medium">Client: </span>
 | 
				
			||||||
 | 
					                    <span>{projectInfo.contactPerson}</span>
 | 
				
			||||||
                  </div>
 | 
					                  </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
@ -139,14 +141,9 @@ const ProjectCard = ({ projectData, recall }) => {
 | 
				
			|||||||
                    data-bs-toggle="dropdown"
 | 
					                    data-bs-toggle="dropdown"
 | 
				
			||||||
                    aria-expanded="false"
 | 
					                    aria-expanded="false"
 | 
				
			||||||
                  >
 | 
					                  >
 | 
				
			||||||
                    {modifyProjectLoading ? (
 | 
					                    {modifyProjectLoading? <div class="spinner-border spinner-border-sm text-secondary" role="status">
 | 
				
			||||||
                      <div
 | 
					                      <span class="visually-hidden">Loading...</span>
 | 
				
			||||||
                        className="spinner-border spinner-border-sm text-secondary"
 | 
					                    </div> :
 | 
				
			||||||
                        role="status"
 | 
					 | 
				
			||||||
                      >
 | 
					 | 
				
			||||||
                        <span className="visually-hidden">Loading...</span>
 | 
					 | 
				
			||||||
                      </div>
 | 
					 | 
				
			||||||
                    ) : (
 | 
					 | 
				
			||||||
                      <i
 | 
					                      <i
 | 
				
			||||||
                        className="bx bx-dots-vertical-rounded bx-sm text-muted"
 | 
					                        className="bx bx-dots-vertical-rounded bx-sm text-muted"
 | 
				
			||||||
                        data-bs-toggle="tooltip"
 | 
					                        data-bs-toggle="tooltip"
 | 
				
			||||||
@ -154,8 +151,7 @@ const ProjectCard = ({ projectData, recall }) => {
 | 
				
			|||||||
                        data-bs-placement="top"
 | 
					                        data-bs-placement="top"
 | 
				
			||||||
                        data-bs-custom-class="tooltip-dark"
 | 
					                        data-bs-custom-class="tooltip-dark"
 | 
				
			||||||
                        title="More Action"
 | 
					                        title="More Action"
 | 
				
			||||||
                      ></i>
 | 
					                      ></i>}
 | 
				
			||||||
                    )}
 | 
					 | 
				
			||||||
                  </button>
 | 
					                  </button>
 | 
				
			||||||
                  <ul className="dropdown-menu dropdown-menu-end">
 | 
					                  <ul className="dropdown-menu dropdown-menu-end">
 | 
				
			||||||
                    <li>
 | 
					                    <li>
 | 
				
			||||||
@ -195,12 +191,6 @@ const ProjectCard = ({ projectData, recall }) => {
 | 
				
			|||||||
          <div className="card-body pb-1">
 | 
					          <div className="card-body pb-1">
 | 
				
			||||||
            <div className="d-flex align-items-center flex-wrap">
 | 
					            <div className="d-flex align-items-center flex-wrap">
 | 
				
			||||||
              <div className="text-start mb-4">
 | 
					              <div className="text-start mb-4">
 | 
				
			||||||
                <p className="mb-1">
 | 
					 | 
				
			||||||
                  <span className="text-heading fw-medium">
 | 
					 | 
				
			||||||
                    Contact Person:{" "}
 | 
					 | 
				
			||||||
                  </span>
 | 
					 | 
				
			||||||
                  {projectInfo.contactPerson ? projectInfo.contactPerson : "NA"}
 | 
					 | 
				
			||||||
                </p>
 | 
					 | 
				
			||||||
                <p className="mb-1">
 | 
					                <p className="mb-1">
 | 
				
			||||||
                  <span className="text-heading fw-medium">Start Date: </span>
 | 
					                  <span className="text-heading fw-medium">Start Date: </span>
 | 
				
			||||||
                  {projectInfo.startDate
 | 
					                  {projectInfo.startDate
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,10 @@
 | 
				
			|||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import { hasUserPermission } from "../../utils/authUtils";
 | 
					import { hasUserPermission } from "../../utils/authUtils";
 | 
				
			||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
					import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
				
			||||||
import { DIRECTORY_ADMIN, DIRECTORY_MANAGER, DIRECTORY_USER, VIEW_PROJECT_INFRA } from "../../utils/constants";
 | 
					import { VIEW_PROJECT_INFRA } from "../../utils/constants";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectNav = ({ onPillClick, activePill }) => {
 | 
					const ProjectNav = ({ onPillClick, activePill }) => {
 | 
				
			||||||
  const HasViewInfraStructure = useHasUserPermission( VIEW_PROJECT_INFRA );
 | 
					  const HasViewInfraStructure = useHasUserPermission(VIEW_PROJECT_INFRA);
 | 
				
			||||||
  const DirAdmin = useHasUserPermission(DIRECTORY_ADMIN);
 | 
					 | 
				
			||||||
  const DireManager = useHasUserPermission(DIRECTORY_MANAGER)
 | 
					 | 
				
			||||||
  const DirUser = useHasUserPermission(DIRECTORY_USER)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="nav-align-top">
 | 
					    <div className="nav-align-top">
 | 
				
			||||||
@ -76,7 +73,6 @@ const ProjectNav = ({ onPillClick, activePill }) => {
 | 
				
			|||||||
            <i className="bx bxs-file-image bx-sm me-1_5"></i> <span className="d-none d-md-inline">Image Gallary</span>
 | 
					            <i className="bx bxs-file-image bx-sm me-1_5"></i> <span className="d-none d-md-inline">Image Gallary</span>
 | 
				
			||||||
          </a>
 | 
					          </a>
 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
        {(DirAdmin || DireManager || DirUser) && (
 | 
					 | 
				
			||||||
        <li className="nav-item">
 | 
					        <li className="nav-item">
 | 
				
			||||||
          <a
 | 
					          <a
 | 
				
			||||||
            className={`nav-link ${activePill === "directory" ? "active" : ""}`}
 | 
					            className={`nav-link ${activePill === "directory" ? "active" : ""}`}
 | 
				
			||||||
@ -89,8 +85,6 @@ const ProjectNav = ({ onPillClick, activePill }) => {
 | 
				
			|||||||
           <i className='bx bxs-contact bx-sm me-1_5'></i> <span className="d-none d-md-inline">Directory</span>
 | 
					           <i className='bx bxs-contact bx-sm me-1_5'></i> <span className="d-none d-md-inline">Directory</span>
 | 
				
			||||||
          </a>
 | 
					          </a>
 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      </ul>
 | 
					      </ul>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ function hashString(str) {
 | 
				
			|||||||
  return hash;
 | 
					  return hash;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Avatar = ({ firstName, lastName, size = "sm", classAvatar }) => {
 | 
					const Avatar = ({ firstName, lastName, size = "sm" }) => {
 | 
				
			||||||
  // Combine firstName and lastName to create a unique string for hashing
 | 
					  // Combine firstName and lastName to create a unique string for hashing
 | 
				
			||||||
  const fullName = `${firstName} ${lastName}`;
 | 
					  const fullName = `${firstName} ${lastName}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,7 +51,7 @@ const Avatar = ({ firstName, lastName, size = "sm", classAvatar }) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="avatar-wrapper p-1">
 | 
					    <div className="avatar-wrapper p-1">
 | 
				
			||||||
     <div className={`avatar avatar-${size} me-2 ${classAvatar}`}>
 | 
					      <div className={`avatar avatar-${size} me-2`}>
 | 
				
			||||||
        <span className={`avatar-initial rounded-circle ${bgClass}`}>
 | 
					        <span className={`avatar-initial rounded-circle ${bgClass}`}>
 | 
				
			||||||
          {generateAvatarText(firstName, lastName)}
 | 
					          {generateAvatarText(firstName, lastName)}
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,32 +3,30 @@ import { useNavigate } from "react-router-dom";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const Breadcrumb = ({ data }) => {
 | 
					const Breadcrumb = ({ data }) => {
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <nav aria-label="breadcrumb">
 | 
					    <nav aria-label="breadcrumb">
 | 
				
			||||||
      <ol className="breadcrumb breadcrumb-custom-icon">
 | 
					      <ol className="breadcrumb breadcrumb-custom-icon">
 | 
				
			||||||
        {data.map((item, index) => (
 | 
					        {data.map((item, index) =>
 | 
				
			||||||
          item.link ? (
 | 
					          item.link ? (
 | 
				
			||||||
            <li className="breadcrumb-item cursor-pointer" key={index}>
 | 
					            <li className="breadcrumb-item cursor-pointer" key={index}>
 | 
				
			||||||
              <a
 | 
					              <a
 | 
				
			||||||
                role="button"
 | 
					                aria-label="breadcrumb link link-underline-primary "
 | 
				
			||||||
                tabIndex={0}
 | 
					 | 
				
			||||||
                aria-label="breadcrumb link"
 | 
					 | 
				
			||||||
                onClick={() => navigate(item.link)}
 | 
					                onClick={() => navigate(item.link)}
 | 
				
			||||||
                onKeyDown={(e) => {
 | 
					 | 
				
			||||||
                  if (e.key === 'Enter') navigate(item.link);
 | 
					 | 
				
			||||||
                }}
 | 
					 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                {item.label}
 | 
					                {item.label}
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
              <i className="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
 | 
					              <i className="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
          ) : (
 | 
					          ) : (
 | 
				
			||||||
            <li className="breadcrumb-item active" key={index}>
 | 
					            <li
 | 
				
			||||||
 | 
					              className="breadcrumb-item active "
 | 
				
			||||||
 | 
					              key={new Date().getMilliseconds()}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {" "}
 | 
				
			||||||
              {item.label}
 | 
					              {item.label}
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        ))}
 | 
					        )}
 | 
				
			||||||
      </ol>
 | 
					      </ol>
 | 
				
			||||||
    </nav>
 | 
					    </nav>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
				
			|||||||
@ -1,98 +1,90 @@
 | 
				
			|||||||
import React, { useState, useEffect } from "react";
 | 
					import React, { useState, useEffect } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FilterIcon = ({
 | 
					const FilterIcon = ({ taskListData, onApplyFilters, currentSelectedBuilding, currentSelectedFloors, currentSelectedActivities }) => {
 | 
				
			||||||
  taskListData,
 | 
					  // State for filters, now managed within FilterIcon
 | 
				
			||||||
  onApplyFilters,
 | 
					  const [selectedBuilding, setSelectedBuilding] = useState(currentSelectedBuilding);
 | 
				
			||||||
  currentSelectedBuilding,
 | 
					  const [selectedFloors, setSelectedFloors] = useState(currentSelectedFloors);
 | 
				
			||||||
  currentSelectedFloors,
 | 
					  const [selectedActivities, setSelectedActivities] = useState(currentSelectedActivities);
 | 
				
			||||||
  currentSelectedActivities,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const [selectedBuilding, setSelectedBuilding] = useState(currentSelectedBuilding || "");
 | 
					 | 
				
			||||||
  const [selectedFloors, setSelectedFloors] = useState(currentSelectedFloors || []);
 | 
					 | 
				
			||||||
  const [selectedActivities, setSelectedActivities] = useState(currentSelectedActivities || []);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Update internal state when props change (e.g., project selection in DailyTask clears filters)
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    setSelectedBuilding(currentSelectedBuilding || "");
 | 
					    setSelectedBuilding(currentSelectedBuilding);
 | 
				
			||||||
    setSelectedFloors(currentSelectedFloors || []);
 | 
					    setSelectedFloors(currentSelectedFloors);
 | 
				
			||||||
    setSelectedActivities(currentSelectedActivities || []);
 | 
					    setSelectedActivities(currentSelectedActivities);
 | 
				
			||||||
  }, [currentSelectedBuilding, currentSelectedFloors, currentSelectedActivities]);
 | 
					  }, [currentSelectedBuilding, currentSelectedFloors, currentSelectedActivities]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getUniqueFilterValues = (key, overrideBuilding, overrideFloors) => {
 | 
					  // Helper to get unique values for filters based on current selections
 | 
				
			||||||
 | 
					  const getUniqueFilterValues = (key) => {
 | 
				
			||||||
    if (!taskListData) return [];
 | 
					    if (!taskListData) return [];
 | 
				
			||||||
 | 
					    let relevantTasks = taskListData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let filteredTasks = [...taskListData];
 | 
					    // Filter tasks based on selected building for floors and activities
 | 
				
			||||||
 | 
					    if (selectedBuilding) {
 | 
				
			||||||
    if (overrideBuilding) {
 | 
					      relevantTasks = relevantTasks.filter(task =>
 | 
				
			||||||
      filteredTasks = filteredTasks.filter(
 | 
					        task?.workItem?.workArea?.floor?.building?.name === selectedBuilding
 | 
				
			||||||
        (task) =>
 | 
					 | 
				
			||||||
          task?.workItem?.workArea?.floor?.building?.name === overrideBuilding
 | 
					 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (overrideFloors?.length > 0) {
 | 
					    // Filter tasks based on selected floors for activities
 | 
				
			||||||
      filteredTasks = filteredTasks.filter((task) =>
 | 
					    if (selectedFloors.length > 0) {
 | 
				
			||||||
        overrideFloors.includes(task?.workItem?.workArea?.floor?.floorName)
 | 
					      relevantTasks = relevantTasks.filter(task =>
 | 
				
			||||||
 | 
					        selectedFloors.includes(task?.workItem?.workArea?.floor?.floorName)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const values = filteredTasks.map((task) => {
 | 
					    const values = relevantTasks.map(task => {
 | 
				
			||||||
      if (key === "building") return task?.workItem?.workArea?.floor?.building?.name;
 | 
					      if (key === 'building') return task?.workItem?.workArea?.floor?.building?.name;
 | 
				
			||||||
      if (key === "floor") return task?.workItem?.workArea?.floor?.floorName;
 | 
					      if (key === 'floor') return task?.workItem?.workArea?.floor?.floorName;
 | 
				
			||||||
      if (key === "activity") return task?.workItem?.activityMaster?.activityName;
 | 
					      if (key === 'activity') return task?.workItem?.activityMaster?.activityName;
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    });
 | 
					    }).filter(Boolean); // Remove null or undefined values
 | 
				
			||||||
 | 
					    return [...new Set(values)].sort(); // Sort for consistent order
 | 
				
			||||||
    return [...new Set(values.filter(Boolean))].sort();
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const uniqueBuildings = getUniqueFilterValues("building");
 | 
					  const uniqueBuildings = getUniqueFilterValues('building');
 | 
				
			||||||
  const uniqueFloors = getUniqueFilterValues("floor", selectedBuilding);
 | 
					  const uniqueFloors = getUniqueFilterValues('floor');
 | 
				
			||||||
  const uniqueActivities = getUniqueFilterValues("activity", selectedBuilding, selectedFloors);
 | 
					  const uniqueActivities = getUniqueFilterValues('activity');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Handle filter selection with dependency logic
 | 
				
			||||||
  const handleFilterChange = (filterType, value) => {
 | 
					  const handleFilterChange = (filterType, value) => {
 | 
				
			||||||
    let updatedBuilding = selectedBuilding;
 | 
					    let newSelectedBuilding = selectedBuilding;
 | 
				
			||||||
    let updatedFloors = [...selectedFloors];
 | 
					    let newSelectedFloors = [...selectedFloors];
 | 
				
			||||||
    let updatedActivities = [...selectedActivities];
 | 
					    let newSelectedActivities = [...selectedActivities];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (filterType === "building") {
 | 
					    if (filterType === 'building') {
 | 
				
			||||||
      updatedBuilding = value;
 | 
					      if (selectedBuilding !== value) {
 | 
				
			||||||
      updatedFloors = [];
 | 
					        newSelectedFloors = [];
 | 
				
			||||||
      updatedActivities = [];
 | 
					        newSelectedActivities = [];
 | 
				
			||||||
    } else if (filterType === "floor") {
 | 
					      }
 | 
				
			||||||
      if (updatedFloors.includes(value)) {
 | 
					      newSelectedBuilding = value;
 | 
				
			||||||
        updatedFloors = updatedFloors.filter((floor) => floor !== value);
 | 
					    } else if (filterType === 'floor') {
 | 
				
			||||||
      } else {
 | 
					      newSelectedFloors = selectedFloors.includes(value) ? selectedFloors.filter(item => item !== value) : [...selectedFloors, value];
 | 
				
			||||||
        updatedFloors.push(value);
 | 
					      if (!newSelectedFloors.includes(value) && selectedFloors.includes(value)) {
 | 
				
			||||||
 | 
					        newSelectedActivities = [];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else if (filterType === 'activity') {
 | 
				
			||||||
 | 
					      newSelectedActivities = selectedActivities.includes(value) ? selectedActivities.filter(item => item !== value) : [...selectedActivities, value];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const validActivities = getUniqueFilterValues("activity", updatedBuilding, updatedFloors);
 | 
					    setSelectedBuilding(newSelectedBuilding);
 | 
				
			||||||
      updatedActivities = updatedActivities.filter((act) => validActivities.includes(act));
 | 
					    setSelectedFloors(newSelectedFloors);
 | 
				
			||||||
    } else if (filterType === "activity") {
 | 
					    setSelectedActivities(newSelectedActivities);
 | 
				
			||||||
      if (updatedActivities.includes(value)) {
 | 
					 | 
				
			||||||
        updatedActivities = updatedActivities.filter((act) => act !== value);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        updatedActivities.push(value);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setSelectedBuilding(updatedBuilding);
 | 
					 | 
				
			||||||
    setSelectedFloors(updatedFloors);
 | 
					 | 
				
			||||||
    setSelectedActivities(updatedActivities);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Communicate the updated filter states back to the parent
 | 
				
			||||||
    onApplyFilters({
 | 
					    onApplyFilters({
 | 
				
			||||||
      selectedBuilding: updatedBuilding,
 | 
					      selectedBuilding: newSelectedBuilding,
 | 
				
			||||||
      selectedFloors: updatedFloors,
 | 
					      selectedFloors: newSelectedFloors,
 | 
				
			||||||
      selectedActivities: updatedActivities,
 | 
					      selectedActivities: newSelectedActivities,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const clearAllFilters = () => {
 | 
					  const clearAllFilters = () => {
 | 
				
			||||||
    setSelectedBuilding("");
 | 
					    setSelectedBuilding('');
 | 
				
			||||||
    setSelectedFloors([]);
 | 
					    setSelectedFloors([]);
 | 
				
			||||||
    setSelectedActivities([]);
 | 
					    setSelectedActivities([]);
 | 
				
			||||||
 | 
					    // Communicate cleared filters back to the parent
 | 
				
			||||||
    onApplyFilters({
 | 
					    onApplyFilters({
 | 
				
			||||||
      selectedBuilding: "",
 | 
					      selectedBuilding: '',
 | 
				
			||||||
      selectedFloors: [],
 | 
					      selectedFloors: [],
 | 
				
			||||||
      selectedActivities: [],
 | 
					      selectedActivities: [],
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@ -106,19 +98,20 @@ const FilterIcon = ({
 | 
				
			|||||||
        data-bs-toggle="dropdown"
 | 
					        data-bs-toggle="dropdown"
 | 
				
			||||||
        aria-expanded="false"
 | 
					        aria-expanded="false"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <i
 | 
					        <i className="fa-solid fa-filter bx-sm "></i>
 | 
				
			||||||
          className="fa-solid fa-filter bx-sm"
 | 
					 | 
				
			||||||
          style={{ color: selectedBuilding || selectedFloors.length > 0 || selectedActivities.length > 0 ? "#7161EF" : "gray" }}
 | 
					 | 
				
			||||||
        ></i>
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
      <ul
 | 
					      <ul
 | 
				
			||||||
        className="dropdown-menu p-2"
 | 
					        className="dropdown-menu p-2"
 | 
				
			||||||
        aria-labelledby="filterDropdown"
 | 
					        aria-labelledby="filterDropdown"
 | 
				
			||||||
        style={{ minWidth: "360px", fontSize: "13px" }}
 | 
					        style={{
 | 
				
			||||||
 | 
					          minWidth: "360px",
 | 
				
			||||||
 | 
					          fontSize: "13px",
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        // Prevent dropdown from closing when clicking inside it
 | 
				
			||||||
        onClick={(e) => e.stopPropagation()}
 | 
					        onClick={(e) => e.stopPropagation()}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {/* Building */}
 | 
					        {/* Building Filter - Now a Dropdown */}
 | 
				
			||||||
        <li>
 | 
					        <li>
 | 
				
			||||||
          <div className="fw-bold text-dark mb-1">Building</div>
 | 
					          <div className="fw-bold text-dark mb-1">Building</div>
 | 
				
			||||||
          <div className="row">
 | 
					          <div className="row">
 | 
				
			||||||
@ -129,26 +122,33 @@ const FilterIcon = ({
 | 
				
			|||||||
                onChange={(e) => handleFilterChange("building", e.target.value)}
 | 
					                onChange={(e) => handleFilterChange("building", e.target.value)}
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                <option value="">Select Building</option>
 | 
					                <option value="">Select Building</option>
 | 
				
			||||||
                {uniqueBuildings.map((building, idx) => (
 | 
					                {uniqueBuildings.length > 0 ? (
 | 
				
			||||||
                  <option key={idx} value={building}>
 | 
					                  uniqueBuildings.map((building, idx) => (
 | 
				
			||||||
 | 
					                    <option key={`building-option-${idx}`} value={building}>
 | 
				
			||||||
                      {building}
 | 
					                      {building}
 | 
				
			||||||
                    </option>
 | 
					                    </option>
 | 
				
			||||||
                ))}
 | 
					                  ))
 | 
				
			||||||
 | 
					                ) : (
 | 
				
			||||||
 | 
					                  <option value="" disabled>No buildings available</option>
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
              </select>
 | 
					              </select>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {/* Floor */}
 | 
					        {/* Floor Filter - Visible only if a building is selected */}
 | 
				
			||||||
        {selectedBuilding && (
 | 
					        {selectedBuilding && (
 | 
				
			||||||
          <>
 | 
					          <>
 | 
				
			||||||
            <li><hr className="my-1" /></li>
 | 
					 | 
				
			||||||
            <li>
 | 
					            <li>
 | 
				
			||||||
              <div className="fw-bold text-dark mb-1">Floors</div>
 | 
					              <hr className="my-1" />
 | 
				
			||||||
 | 
					            </li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <li>
 | 
				
			||||||
 | 
					              <div className="fw-bold text-dark mb-1">Floor</div>
 | 
				
			||||||
              <div className="row">
 | 
					              <div className="row">
 | 
				
			||||||
                {uniqueFloors.length > 0 ? (
 | 
					                {uniqueFloors.length > 0 ? (
 | 
				
			||||||
                  uniqueFloors.map((floor, idx) => (
 | 
					                  uniqueFloors.map((floor, idx) => (
 | 
				
			||||||
                    <div className="col-6" key={idx}>
 | 
					                    <div className="col-6" key={`floor-${idx}`}>
 | 
				
			||||||
                      <div className="form-check mb-1">
 | 
					                      <div className="form-check mb-1">
 | 
				
			||||||
                        <input
 | 
					                        <input
 | 
				
			||||||
                          className="form-check-input"
 | 
					                          className="form-check-input"
 | 
				
			||||||
@ -157,30 +157,36 @@ const FilterIcon = ({
 | 
				
			|||||||
                          checked={selectedFloors.includes(floor)}
 | 
					                          checked={selectedFloors.includes(floor)}
 | 
				
			||||||
                          onChange={() => handleFilterChange("floor", floor)}
 | 
					                          onChange={() => handleFilterChange("floor", floor)}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                        <label className="form-check-label" htmlFor={`floor-${floor}`}>
 | 
					                        <label
 | 
				
			||||||
 | 
					                          className="form-check-label"
 | 
				
			||||||
 | 
					                          htmlFor={`floor-${floor}`}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
                          {floor}
 | 
					                          {floor}
 | 
				
			||||||
                        </label>
 | 
					                        </label>
 | 
				
			||||||
                      </div>
 | 
					                      </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                  ))
 | 
					                  ))
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                  <div className="col-12 text-muted">No floors found.</div>
 | 
					                  <div className="col-12 text-muted">No floors for selected building.</div>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
          </>
 | 
					          </>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {/* Activity */}
 | 
					        {/* Activity Filter - Visible only if a floor is selected */}
 | 
				
			||||||
        {selectedFloors.length > 0 && (
 | 
					        {selectedFloors.length > 0 && (
 | 
				
			||||||
          <>
 | 
					          <>
 | 
				
			||||||
            <li><hr className="my-1" /></li>
 | 
					 | 
				
			||||||
            <li>
 | 
					            <li>
 | 
				
			||||||
              <div className="fw-bold text-dark mb-1">Activities</div>
 | 
					              <hr className="my-1" />
 | 
				
			||||||
 | 
					            </li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <li>
 | 
				
			||||||
 | 
					              <div className="fw-bold text-dark mb-1">Activity</div>
 | 
				
			||||||
              <div className="row">
 | 
					              <div className="row">
 | 
				
			||||||
                {uniqueActivities.length > 0 ? (
 | 
					                {uniqueActivities.length > 0 ? (
 | 
				
			||||||
                  uniqueActivities.map((activity, idx) => (
 | 
					                  uniqueActivities.map((activity, idx) => (
 | 
				
			||||||
                    <div className="col-6" key={idx}>
 | 
					                    <div className="col-6" key={`activity-${idx}`}>
 | 
				
			||||||
                      <div className="form-check mb-1">
 | 
					                      <div className="form-check mb-1">
 | 
				
			||||||
                        <input
 | 
					                        <input
 | 
				
			||||||
                          className="form-check-input"
 | 
					                          className="form-check-input"
 | 
				
			||||||
@ -189,60 +195,43 @@ const FilterIcon = ({
 | 
				
			|||||||
                          checked={selectedActivities.includes(activity)}
 | 
					                          checked={selectedActivities.includes(activity)}
 | 
				
			||||||
                          onChange={() => handleFilterChange("activity", activity)}
 | 
					                          onChange={() => handleFilterChange("activity", activity)}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                        <label className="form-check-label" htmlFor={`activity-${activity}`}>
 | 
					                        <label
 | 
				
			||||||
 | 
					                          className="form-check-label"
 | 
				
			||||||
 | 
					                          htmlFor={`activity-${activity}`}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
                          {activity}
 | 
					                          {activity}
 | 
				
			||||||
                        </label>
 | 
					                        </label>
 | 
				
			||||||
                      </div>
 | 
					                      </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                  ))
 | 
					                  ))
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                  <div className="col-12 text-muted">No activities found.</div>
 | 
					                  <div className="col-12 text-muted">No activities for selected floor(s).</div>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
          </>
 | 
					          </>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {/* Action Buttons */}
 | 
					        {/* Clear Filters */}
 | 
				
			||||||
        <li><hr className="my-1" /></li>
 | 
					        {(selectedBuilding ||
 | 
				
			||||||
        {(selectedBuilding || selectedFloors.length > 0 || selectedActivities.length > 0) && (
 | 
					          selectedFloors.length > 0 ||
 | 
				
			||||||
          <li className="d-flex justify-content-end gap-2 px-2">
 | 
					          selectedActivities.length > 0) && (
 | 
				
			||||||
 | 
					            <>
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
 | 
					                <hr className="my-1" />
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
                <button
 | 
					                <button
 | 
				
			||||||
                  type="button"
 | 
					                  type="button"
 | 
				
			||||||
              className="btn btn-sm"
 | 
					                  className="dropdown-item text-danger px-2 py-1"
 | 
				
			||||||
              style={{
 | 
					                  style={{ fontSize: "13px" }}
 | 
				
			||||||
                backgroundColor: "#7161EF",
 | 
					 | 
				
			||||||
                color: "white",
 | 
					 | 
				
			||||||
                fontSize: "13px",
 | 
					 | 
				
			||||||
                padding: "4px 16px",
 | 
					 | 
				
			||||||
                borderRadius: "8px",
 | 
					 | 
				
			||||||
                boxShadow: "0 1px 4px rgba(0,0,0,0.1)"
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
                  onClick={clearAllFilters}
 | 
					                  onClick={clearAllFilters}
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
              Clear
 | 
					                  Clear All Filters
 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
            <button
 | 
					 | 
				
			||||||
              type="button"
 | 
					 | 
				
			||||||
              className="btn btn-sm"
 | 
					 | 
				
			||||||
              style={{
 | 
					 | 
				
			||||||
                backgroundColor: "#7161EF",
 | 
					 | 
				
			||||||
                color: "white",
 | 
					 | 
				
			||||||
                fontSize: "13px",
 | 
					 | 
				
			||||||
                padding: "4px 16px",
 | 
					 | 
				
			||||||
                borderRadius: "8px",
 | 
					 | 
				
			||||||
                boxShadow: "0 1px 4px rgba(0,0,0,0.1)"
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
              onClick={() => {
 | 
					 | 
				
			||||||
                document.getElementById("filterDropdown").click();
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              Apply
 | 
					 | 
				
			||||||
                </button>
 | 
					                </button>
 | 
				
			||||||
              </li>
 | 
					              </li>
 | 
				
			||||||
 | 
					            </>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      </ul>
 | 
					      </ul>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
				
			|||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
.fab-container {
 | 
					 | 
				
			||||||
  position: fixed;
 | 
					 | 
				
			||||||
  bottom: 35px;
 | 
					 | 
				
			||||||
  right: 30px;
 | 
					 | 
				
			||||||
  z-index: 1050;
 | 
					 | 
				
			||||||
  display: flex;
 | 
					 | 
				
			||||||
  flex-direction: column;
 | 
					 | 
				
			||||||
  align-items: end;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.fab-main {
 | 
					 | 
				
			||||||
  /* width: 45px;
 | 
					 | 
				
			||||||
  height: 45px;
 | 
					 | 
				
			||||||
  border-radius: 100%;
 | 
					 | 
				
			||||||
  background-color: #0d6efd;
 | 
					 | 
				
			||||||
  color: white;
 | 
					 | 
				
			||||||
  border: none; */
 | 
					 | 
				
			||||||
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
 | 
					 | 
				
			||||||
  /* font-size: 24px; */
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  pointer-events: auto;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.fab-option {
 | 
					 | 
				
			||||||
  pointer-events: auto;
 | 
					 | 
				
			||||||
  margin-bottom: 10px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@media (max-width: 768px) {
 | 
					 | 
				
			||||||
  .fab-container {
 | 
					 | 
				
			||||||
    right: 20px;
 | 
					 | 
				
			||||||
    left: 50%;
 | 
					 | 
				
			||||||
    bottom: 20px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,33 +0,0 @@
 | 
				
			|||||||
import React, { useState } from "react";
 | 
					 | 
				
			||||||
import {useFab} from "../../Context/FabContext";
 | 
					 | 
				
			||||||
import './FloatingMenu.css'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const FloatingMenu = () => {
 | 
					 | 
				
			||||||
  const { actions } = useFab(); 
 | 
					 | 
				
			||||||
  const [open, setOpen] = useState(false);
 | 
					 | 
				
			||||||
  if (actions.length === 0) return null; 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="fab-container">
 | 
					 | 
				
			||||||
     {open &&
 | 
					 | 
				
			||||||
  actions.map((action, index) => (
 | 
					 | 
				
			||||||
    <button
 | 
					 | 
				
			||||||
      key={index}
 | 
					 | 
				
			||||||
      className={`badge bg-${action.color} rounded-pill mb-2 d-inline-flex align-items-center gap-2 px-3 py-1 cursor-pointer fab-option`}
 | 
					 | 
				
			||||||
      onClick={action.onClick}
 | 
					 | 
				
			||||||
      title={action.label}
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <i className={action.icon}></i>
 | 
					 | 
				
			||||||
      <span>{action.label}</span> 
 | 
					 | 
				
			||||||
    </button>
 | 
					 | 
				
			||||||
))}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          <button type="button" className="btn btn-lg btn-icon rounded-pill me-2 btn-primary fab-main " onClick={() => setOpen(!open)}>
 | 
					 | 
				
			||||||
        <span className={`bx ${open ? "bx-x" : "bx-plus"}`}></span>
 | 
					 | 
				
			||||||
      </button>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default FloatingMenu;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -8,45 +8,32 @@ const GlobalModel = ({
 | 
				
			|||||||
  dialogClass = '',  // For additional custom classes on modal dialog
 | 
					  dialogClass = '',  // For additional custom classes on modal dialog
 | 
				
			||||||
  role = 'dialog',   // Accessibility role for the modal
 | 
					  role = 'dialog',   // Accessibility role for the modal
 | 
				
			||||||
  size = '',         // Dynamically set the size (sm, lg, xl)
 | 
					  size = '',         // Dynamically set the size (sm, lg, xl)
 | 
				
			||||||
  dataAttributes = {}, // Additional dynamic data-bs-* attributes
 | 
					  dataAttributes = {} // Additional dynamic data-bs-* attributes
 | 
				
			||||||
  IsCloseBtn=true
 | 
					 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
  const modalRef = useRef(null);  // Reference to the modal element
 | 
					  const modalRef = useRef(null);  // Reference to the modal element
 | 
				
			||||||
 | 
					
 | 
				
			||||||
useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    const modalElement = modalRef.current;
 | 
					    const modalElement = modalRef.current;
 | 
				
			||||||
  const modalInstance = new window.bootstrap.Modal(modalElement, {
 | 
					    const modalInstance = new window.bootstrap.Modal(modalElement);
 | 
				
			||||||
    backdrop: false,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Show modal if isOpen is true
 | 
				
			||||||
    if (isOpen) {
 | 
					    if (isOpen) {
 | 
				
			||||||
      modalInstance.show();
 | 
					      modalInstance.show();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      modalInstance.hide();
 | 
					      modalInstance.hide();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Handle modal hide event to invoke the closeModal function
 | 
				
			||||||
    const handleHideModal = () => {
 | 
					    const handleHideModal = () => {
 | 
				
			||||||
    closeModal();
 | 
					      closeModal();  // Close the modal via React state
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // ✅ FIX: Remove any lingering body classes/styles
 | 
					 | 
				
			||||||
    document.body.classList.remove('modal-open');
 | 
					 | 
				
			||||||
    document.body.style.overflow = '';
 | 
					 | 
				
			||||||
    document.body.style.paddingRight = '';
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    modalElement.addEventListener('hidden.bs.modal', handleHideModal);
 | 
					    modalElement.addEventListener('hidden.bs.modal', handleHideModal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return () => {
 | 
					    return () => {
 | 
				
			||||||
      modalElement.removeEventListener('hidden.bs.modal', handleHideModal);
 | 
					      modalElement.removeEventListener('hidden.bs.modal', handleHideModal);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Also clean up just in case component unmounts
 | 
					 | 
				
			||||||
    document.body.classList.remove('modal-open');
 | 
					 | 
				
			||||||
    document.body.style.overflow = '';
 | 
					 | 
				
			||||||
    document.body.style.paddingRight = '';
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}, [isOpen, closeModal]);
 | 
					  }, [isOpen, closeModal]);
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Dynamically set the modal size classes (modal-sm, modal-lg, modal-xl)
 | 
					  // Dynamically set the modal size classes (modal-sm, modal-lg, modal-xl)
 | 
				
			||||||
  const modalSizeClass = size ? `modal-${size}` : '';  // Default is empty if no size is specified
 | 
					  const modalSizeClass = size ? `modal-${size}` : '';  // Default is empty if no size is specified
 | 
				
			||||||
@ -54,20 +41,7 @@ useEffect(() => {
 | 
				
			|||||||
  // Dynamically generate data-bs attributes
 | 
					  // Dynamically generate data-bs attributes
 | 
				
			||||||
  const dataAttributesProps = Object.keys(dataAttributes).map(key => ({
 | 
					  const dataAttributesProps = Object.keys(dataAttributes).map(key => ({
 | 
				
			||||||
    [key]: dataAttributes[key],
 | 
					    [key]: dataAttributes[key],
 | 
				
			||||||
  } ) );
 | 
					  }));
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   // The gray background
 | 
					 | 
				
			||||||
    const backdropStyle = {
 | 
					 | 
				
			||||||
      position: 'fixed',
 | 
					 | 
				
			||||||
      top: 0,
 | 
					 | 
				
			||||||
      bottom: 0,
 | 
					 | 
				
			||||||
      left: 0,
 | 
					 | 
				
			||||||
      right: 0,
 | 
					 | 
				
			||||||
      backgroundColor: 'rgba(0,0,0,0.3)',
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
@ -78,19 +52,18 @@ useEffect(() => {
 | 
				
			|||||||
      aria-hidden="true"
 | 
					      aria-hidden="true"
 | 
				
			||||||
      ref={modalRef}  // Assign the ref to the modal element
 | 
					      ref={modalRef}  // Assign the ref to the modal element
 | 
				
			||||||
      {...dataAttributesProps}
 | 
					      {...dataAttributesProps}
 | 
				
			||||||
      style={backdropStyle}
 | 
					 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div className={`modal-dialog ${dialogClass} ${modalSizeClass } mx-sm-auto mx-1`} role={role} >
 | 
					      <div className={`modal-dialog ${dialogClass} ${modalSizeClass } mx-sm-auto mx-1`} role={role}>
 | 
				
			||||||
        <div className="modal-content">
 | 
					        <div className="modal-content">
 | 
				
			||||||
          <div className="modal-header p-0">
 | 
					          <div className="modal-header p-0">
 | 
				
			||||||
            {/* Close button inside the modal header */}
 | 
					            {/* Close button inside the modal header */}
 | 
				
			||||||
           {IsCloseBtn && <button
 | 
					            <button
 | 
				
			||||||
              type="button"
 | 
					              type="button"
 | 
				
			||||||
              className="btn-close"
 | 
					              className="btn-close"
 | 
				
			||||||
              data-bs-dismiss="modal"
 | 
					              data-bs-dismiss="modal"
 | 
				
			||||||
              aria-label="Close"
 | 
					              aria-label="Close"
 | 
				
			||||||
              onClick={closeModal}  // Trigger the React closeModal function
 | 
					              onClick={closeModal}  // Trigger the React closeModal function
 | 
				
			||||||
            ></button>}
 | 
					            ></button>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          <div className="modal-body  p-sm-4 p-0">
 | 
					          <div className="modal-body  p-sm-4 p-0">
 | 
				
			||||||
            {children}  {/* Render children here, which can be the ReportTask component */}
 | 
					            {children}  {/* Render children here, which can be the ReportTask component */}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,79 +0,0 @@
 | 
				
			|||||||
import React, { useState } from "react";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const InputSuggestions = ({
 | 
					 | 
				
			||||||
  organizationList = [],
 | 
					 | 
				
			||||||
  value,
 | 
					 | 
				
			||||||
  onChange,
 | 
					 | 
				
			||||||
  error,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const [filteredList, setFilteredList] = useState([]);
 | 
					 | 
				
			||||||
  const [showSuggestions, setShowSuggestions] = useState(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleInputChange = (e) => {
 | 
					 | 
				
			||||||
    const val = e.target.value;
 | 
					 | 
				
			||||||
    onChange(val);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const matches = organizationList.filter((org) =>
 | 
					 | 
				
			||||||
      org.toLowerCase().includes(val.toLowerCase())
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    setFilteredList(matches);
 | 
					 | 
				
			||||||
    setShowSuggestions(true);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleSelectSuggestion = (val) => {
 | 
					 | 
				
			||||||
    onChange(val);
 | 
					 | 
				
			||||||
    setShowSuggestions(false);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="position-relative">
 | 
					 | 
				
			||||||
      <input
 | 
					 | 
				
			||||||
        className="form-control form-control-sm"
 | 
					 | 
				
			||||||
        value={value}
 | 
					 | 
				
			||||||
        onChange={handleInputChange}
 | 
					 | 
				
			||||||
        onBlur={() => setTimeout(() => setShowSuggestions(false), 150)}
 | 
					 | 
				
			||||||
        onFocus={() => {
 | 
					 | 
				
			||||||
          if (value) setShowSuggestions(true);
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      {showSuggestions && filteredList.length > 0 && (
 | 
					 | 
				
			||||||
        <ul
 | 
					 | 
				
			||||||
          className="list-group shadow-sm position-absolute w-100 bg-white border  zindex-tooltip"
 | 
					 | 
				
			||||||
          style={{
 | 
					 | 
				
			||||||
            maxHeight: "180px",
 | 
					 | 
				
			||||||
            overflowY: "auto",
 | 
					 | 
				
			||||||
            marginTop: "2px",
 | 
					 | 
				
			||||||
            zIndex: 1000,
 | 
					 | 
				
			||||||
            borderRadius:"0px"
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          {filteredList.map((org) => (
 | 
					 | 
				
			||||||
            <li
 | 
					 | 
				
			||||||
              key={org}
 | 
					 | 
				
			||||||
              className="list-group-item list-group-item-action border-none "
 | 
					 | 
				
			||||||
              style={{
 | 
					 | 
				
			||||||
                cursor: "pointer",
 | 
					 | 
				
			||||||
                padding: "5px 12px",
 | 
					 | 
				
			||||||
                fontSize: "14px",
 | 
					 | 
				
			||||||
                transition: "background-color 0.2s",
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
              onMouseDown={() => handleSelectSuggestion(org)}
 | 
					 | 
				
			||||||
              onMouseEnter={(e) =>
 | 
					 | 
				
			||||||
                (e.currentTarget.style.backgroundColor = "#f8f9fa")
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              onMouseLeave={(e) =>
 | 
					 | 
				
			||||||
                (e.currentTarget.style.backgroundColor = "transparent")
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              {org}
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
          ))}
 | 
					 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {error && <small className="danger-text">{error}</small>}
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default InputSuggestions;
 | 
					 | 
				
			||||||
@ -1,158 +0,0 @@
 | 
				
			|||||||
/* Container for the multi-select dropdown */
 | 
					 | 
				
			||||||
.multi-select-dropdown-container {
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Header of the dropdown */
 | 
					 | 
				
			||||||
.multi-select-dropdown-header {
 | 
					 | 
				
			||||||
  display: flex;
 | 
					 | 
				
			||||||
  justify-content: space-between;
 | 
					 | 
				
			||||||
  align-items: center;
 | 
					 | 
				
			||||||
  padding: 5px;
 | 
					 | 
				
			||||||
  border: 1px solid #ddd;
 | 
					 | 
				
			||||||
  border-radius: 5px;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  transition: all 0.3s ease;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-header .placeholder-style {
 | 
					 | 
				
			||||||
  color: #6c757d;
 | 
					 | 
				
			||||||
  font-size: 14px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-header .placeholder-style-selected {
 | 
					 | 
				
			||||||
  /* color: #0d6efd; */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  font-size: 12px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Arrow icon */
 | 
					 | 
				
			||||||
.multi-select-dropdown-arrow {
 | 
					 | 
				
			||||||
  width: 14px;
 | 
					 | 
				
			||||||
  height: 14px;
 | 
					 | 
				
			||||||
  margin-left: 10px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Dropdown options */
 | 
					 | 
				
			||||||
.multi-select-dropdown-options {
 | 
					 | 
				
			||||||
  position: absolute;
 | 
					 | 
				
			||||||
  top: 100%;
 | 
					 | 
				
			||||||
  left: 0;
 | 
					 | 
				
			||||||
  right: 0;
 | 
					 | 
				
			||||||
  z-index: 10;
 | 
					 | 
				
			||||||
  border: 1px solid #ddd;
 | 
					 | 
				
			||||||
  border-radius: 3px;
 | 
					 | 
				
			||||||
  background-color: white;
 | 
					 | 
				
			||||||
  max-height: 250px;
 | 
					 | 
				
			||||||
  overflow-y: auto;
 | 
					 | 
				
			||||||
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
 | 
					 | 
				
			||||||
  margin-top: 5px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Search input */
 | 
					 | 
				
			||||||
.multi-select-dropdown-search {
 | 
					 | 
				
			||||||
  padding: 4px;
 | 
					 | 
				
			||||||
  border-bottom: 1px solid #f1f3f5;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-search-input {
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
  padding: 4px;
 | 
					 | 
				
			||||||
  border: none;
 | 
					 | 
				
			||||||
  outline: none;
 | 
					 | 
				
			||||||
  background-color: #f8f9fa;
 | 
					 | 
				
			||||||
  border-radius: 6px;
 | 
					 | 
				
			||||||
  font-size: 14px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Select All checkbox */
 | 
					 | 
				
			||||||
.multi-select-dropdown-select-all {
 | 
					 | 
				
			||||||
  display: flex;
 | 
					 | 
				
			||||||
  align-items: center;
 | 
					 | 
				
			||||||
  padding: 4px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-select-all .custom-checkbox {
 | 
					 | 
				
			||||||
  margin-right: 8px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-select-all-label {
 | 
					 | 
				
			||||||
  font-size: 14px;
 | 
					 | 
				
			||||||
  color: #333;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Options in dropdown */
 | 
					 | 
				
			||||||
.multi-select-dropdown-option {
 | 
					 | 
				
			||||||
  display: flex;
 | 
					 | 
				
			||||||
  align-items: center;
 | 
					 | 
				
			||||||
  padding: 4px;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  transition: background-color 0.3s ease;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-option:hover {
 | 
					 | 
				
			||||||
  background-color: #f1f3f5;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-option.selected {
 | 
					 | 
				
			||||||
  background-color: #dbe7ff;
 | 
					 | 
				
			||||||
  color: #0d6efd;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.multi-select-dropdown-option input[type="checkbox"] {
 | 
					 | 
				
			||||||
  margin-right: 10px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Custom checkbox */
 | 
					 | 
				
			||||||
.custom-checkbox {
 | 
					 | 
				
			||||||
  width: 18px;
 | 
					 | 
				
			||||||
  height: 18px;
 | 
					 | 
				
			||||||
  border-radius: 4px;
 | 
					 | 
				
			||||||
  border: 1px solid #ddd;
 | 
					 | 
				
			||||||
  background-color: white;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
  margin-right: 10px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.custom-checkbox:checked {
 | 
					 | 
				
			||||||
  background-color: #696cff;
 | 
					 | 
				
			||||||
  border-color: #696cff;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.custom-checkbox:checked::after {
 | 
					 | 
				
			||||||
  content: '';
 | 
					 | 
				
			||||||
  position: absolute;
 | 
					 | 
				
			||||||
  top: 2px;
 | 
					 | 
				
			||||||
  left: 2px;
 | 
					 | 
				
			||||||
  width: 10px;
 | 
					 | 
				
			||||||
  height: 10px;
 | 
					 | 
				
			||||||
  border-radius: 2px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.multi-select-dropdown-Not-found{
 | 
					 | 
				
			||||||
 text-align: center;
 | 
					 | 
				
			||||||
 padding: 1px 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.multi-select-dropdown-Not-found:hover {
 | 
					 | 
				
			||||||
  background: #e2dfdf;
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Responsive styles */
 | 
					 | 
				
			||||||
@media (max-width: 767px) {
 | 
					 | 
				
			||||||
  .multi-select-dropdown-container {
 | 
					 | 
				
			||||||
    width: 100%;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .multi-select-dropdown-header {
 | 
					 | 
				
			||||||
    font-size: 12px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .multi-select-dropdown-options {
 | 
					 | 
				
			||||||
    width: 100%;
 | 
					 | 
				
			||||||
    max-height: 200px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,131 +0,0 @@
 | 
				
			|||||||
import React, { useState, useEffect, useRef } from "react";
 | 
					 | 
				
			||||||
import { useFormContext } from "react-hook-form";
 | 
					 | 
				
			||||||
import "./MultiSelectDropdown.css";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const SelectMultiple = ({
 | 
					 | 
				
			||||||
  name,
 | 
					 | 
				
			||||||
  options = [],
 | 
					 | 
				
			||||||
  label = "Select options",
 | 
					 | 
				
			||||||
  labelKey = "name",
 | 
					 | 
				
			||||||
  valueKey = "id",
 | 
					 | 
				
			||||||
  placeholder = "Please select...",
 | 
					 | 
				
			||||||
  IsLoading = false,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const { setValue, watch } = useFormContext();
 | 
					 | 
				
			||||||
  const selectedValues = watch(name) || [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const [isOpen, setIsOpen] = useState(false);
 | 
					 | 
				
			||||||
  const [searchText, setSearchText] = useState("");
 | 
					 | 
				
			||||||
  const dropdownRef = useRef(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const handleClickOutside = (e) => {
 | 
					 | 
				
			||||||
      if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
 | 
					 | 
				
			||||||
        setIsOpen(false);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    document.addEventListener("mousedown", handleClickOutside);
 | 
					 | 
				
			||||||
    return () => document.removeEventListener("mousedown", handleClickOutside);
 | 
					 | 
				
			||||||
  }, []);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleCheckboxChange = (value) => {
 | 
					 | 
				
			||||||
    const updated = selectedValues.includes(value)
 | 
					 | 
				
			||||||
      ? selectedValues.filter((v) => v !== value)
 | 
					 | 
				
			||||||
      : [...selectedValues, value];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setValue(name, updated, { shouldValidate: true });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const filteredOptions = options.filter((item) =>
 | 
					 | 
				
			||||||
    item[labelKey]?.toLowerCase().includes(searchText.toLowerCase())
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div ref={dropdownRef} className="multi-select-dropdown-container">
 | 
					 | 
				
			||||||
      <label className="form-label mb-1">{label}</label>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div
 | 
					 | 
				
			||||||
        className="multi-select-dropdown-header"
 | 
					 | 
				
			||||||
        onClick={() => setIsOpen((prev) => !prev)}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <span
 | 
					 | 
				
			||||||
          className={
 | 
					 | 
				
			||||||
            selectedValues.length > 0
 | 
					 | 
				
			||||||
              ? "placeholder-style-selected"
 | 
					 | 
				
			||||||
              : "placeholder-style"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <div className="selected-badges-container">
 | 
					 | 
				
			||||||
            {selectedValues.length > 0 ? (
 | 
					 | 
				
			||||||
              selectedValues.map((val) => {
 | 
					 | 
				
			||||||
                const found = options.find((opt) => opt[valueKey] === val);
 | 
					 | 
				
			||||||
                return (
 | 
					 | 
				
			||||||
                  <span
 | 
					 | 
				
			||||||
                    key={val}
 | 
					 | 
				
			||||||
                    className="badge badge-selected-item mx-1 mb-1"
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    {found ? found[labelKey] : ""}
 | 
					 | 
				
			||||||
                  </span>
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
              })
 | 
					 | 
				
			||||||
            ) : (
 | 
					 | 
				
			||||||
              <span className="placeholder-text">{placeholder}</span>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </span>
 | 
					 | 
				
			||||||
        <i className="bx bx-chevron-down"></i>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {isOpen && (
 | 
					 | 
				
			||||||
        <div className="multi-select-dropdown-options">
 | 
					 | 
				
			||||||
          <div className="multi-select-dropdown-search">
 | 
					 | 
				
			||||||
            <input
 | 
					 | 
				
			||||||
              type="text"
 | 
					 | 
				
			||||||
              placeholder="Search..."
 | 
					 | 
				
			||||||
              value={searchText}
 | 
					 | 
				
			||||||
              onChange={(e) => setSearchText(e.target.value)}
 | 
					 | 
				
			||||||
              className="multi-select-dropdown-search-input"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          {filteredOptions.map((item) => {
 | 
					 | 
				
			||||||
            const labelVal = item[labelKey];
 | 
					 | 
				
			||||||
            const valueVal = item[valueKey];
 | 
					 | 
				
			||||||
            const isChecked = selectedValues.includes(valueVal);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return (
 | 
					 | 
				
			||||||
              <div
 | 
					 | 
				
			||||||
                key={valueVal}
 | 
					 | 
				
			||||||
                className={`multi-select-dropdown-option ${
 | 
					 | 
				
			||||||
                  isChecked ? "selected" : ""
 | 
					 | 
				
			||||||
                }`}
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <input
 | 
					 | 
				
			||||||
                  type="checkbox"
 | 
					 | 
				
			||||||
                  className="custom-checkbox form-check-input"
 | 
					 | 
				
			||||||
                  checked={isChecked}
 | 
					 | 
				
			||||||
                  onChange={() => handleCheckboxChange(valueVal)}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <label className="text-secondary">{labelVal}</label>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          })}
 | 
					 | 
				
			||||||
          {!IsLoading && filteredOptions.length === 0 && (
 | 
					 | 
				
			||||||
            <div className="multi-select-dropdown-Not-found">
 | 
					 | 
				
			||||||
              <label className="text-muted">
 | 
					 | 
				
			||||||
                Not Found {`'${searchText}'`}
 | 
					 | 
				
			||||||
              </label>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
          {IsLoading && filteredOptions.length === 0 && (
 | 
					 | 
				
			||||||
            <div className="multi-select-dropdown-Not-found">
 | 
					 | 
				
			||||||
              <label className="text-muted">Loading...</label>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default SelectMultiple;
 | 
					 | 
				
			||||||
@ -1,106 +1,32 @@
 | 
				
			|||||||
import { useFormContext, useWatch } from "react-hook-form";
 | 
					import React, { useState, useEffect } from "react";
 | 
				
			||||||
import React, { useEffect, useState } from "react";
 | 
					import { useFormContext } from "react-hook-form";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TagInput = ({
 | 
					const TagInput = ({
 | 
				
			||||||
  label = "Tags",
 | 
					  label = "Tags",
 | 
				
			||||||
  name = "tags",
 | 
					  name = "tags",
 | 
				
			||||||
  placeholder = "Start typing to add... like employee, manager",
 | 
					  placeholder = "Enter ... ",
 | 
				
			||||||
  color = "#e9ecef",
 | 
					  color = "#e9ecef",
 | 
				
			||||||
  options = [],
 | 
					 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
  const [tags, setTags] = useState([]);
 | 
					  const [tags, setTags] = useState([]);
 | 
				
			||||||
  const [input, setInput] = useState("");
 | 
					  const [input, setInput] = useState("");
 | 
				
			||||||
  const [suggestions, setSuggestions] = useState([]);
 | 
					  const { setValue } = useFormContext();
 | 
				
			||||||
  const { setValue, trigger, control } = useFormContext();
 | 
					 | 
				
			||||||
  const watchedTags = useWatch({ control, name });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
useEffect(() => {
 | 
					 | 
				
			||||||
  if (
 | 
					 | 
				
			||||||
    Array.isArray(watchedTags) &&
 | 
					 | 
				
			||||||
    JSON.stringify(tags) !== JSON.stringify(watchedTags)
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    setTags(watchedTags);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}, [JSON.stringify(watchedTags)]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (input.trim() === "") {
 | 
					    setValue(name, tags); // sync to form when tags change
 | 
				
			||||||
      setSuggestions([]);
 | 
					  }, [tags, name, setValue]);
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      const filtered = options?.filter(
 | 
					 | 
				
			||||||
        (opt) =>
 | 
					 | 
				
			||||||
          opt?.name?.toLowerCase()?.includes(input.toLowerCase()) &&
 | 
					 | 
				
			||||||
          !tags?.some((tag) => tag.name === opt.name)
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      setSuggestions(filtered);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [input, options, tags]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const addTag = async (tagObj) => {
 | 
					  const addTag = (e) => {
 | 
				
			||||||
    if (!tags.some((tag) => tag.name === tagObj.name)) {
 | 
					    e.preventDefault();
 | 
				
			||||||
      const cleanedTag = {
 | 
					    const trimmed = input.trim();
 | 
				
			||||||
        id: tagObj.id ?? null,
 | 
					    if (trimmed !== "" && !tags.includes(trimmed)) {
 | 
				
			||||||
        name: tagObj.name,
 | 
					      setTags([...tags, trimmed]);
 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      const newTags = [...tags, cleanedTag];
 | 
					 | 
				
			||||||
      setTags(newTags);
 | 
					 | 
				
			||||||
      setValue(name, newTags, { shouldValidate: true });
 | 
					 | 
				
			||||||
      await trigger(name);
 | 
					 | 
				
			||||||
      setInput("");
 | 
					      setInput("");
 | 
				
			||||||
      setSuggestions([]);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const removeTag = (indexToRemove) => {
 | 
					  const removeTag = (removeIndex) => {
 | 
				
			||||||
    const newTags = tags.filter((_, i) => i !== indexToRemove);
 | 
					    const updated = tags.filter((_, i) => i !== removeIndex);
 | 
				
			||||||
    setTags(newTags);
 | 
					    setTags(updated);
 | 
				
			||||||
    setValue(name, newTags, { shouldValidate: true });
 | 
					 | 
				
			||||||
    trigger(name);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleInputKeyDown = (e) => {
 | 
					 | 
				
			||||||
    if ((e.key === "Enter" || e.key === " ")&& input.trim() !== "") {
 | 
					 | 
				
			||||||
      e.preventDefault();
 | 
					 | 
				
			||||||
      const existing = options.find(
 | 
					 | 
				
			||||||
        (opt) => opt.name.toLowerCase() === input.trim().toLowerCase()
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      const newTag = existing
 | 
					 | 
				
			||||||
        ? existing
 | 
					 | 
				
			||||||
        : {
 | 
					 | 
				
			||||||
            id: null,
 | 
					 | 
				
			||||||
            name: input.trim(),
 | 
					 | 
				
			||||||
            description: input.trim(),
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
      addTag(newTag);
 | 
					 | 
				
			||||||
    } else if (e.key === "Backspace" && input === "") {
 | 
					 | 
				
			||||||
      setTags((prev) => prev.slice(0, -1));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const handleInputKey = (e) => {
 | 
					 | 
				
			||||||
  const key = e.key?.toLowerCase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if ((key === "enter" || key === " " || e.code === "Space") && input.trim() !== "") {
 | 
					 | 
				
			||||||
    e.preventDefault();
 | 
					 | 
				
			||||||
    const existing = options.find(
 | 
					 | 
				
			||||||
      (opt) => opt.name.toLowerCase() === input.trim().toLowerCase()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    const newTag = existing
 | 
					 | 
				
			||||||
      ? existing
 | 
					 | 
				
			||||||
      : {
 | 
					 | 
				
			||||||
          id: null,
 | 
					 | 
				
			||||||
          name: input.trim(),
 | 
					 | 
				
			||||||
          description: input.trim(),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    addTag(newTag);
 | 
					 | 
				
			||||||
  } else if ((key === "backspace" || e.code === "Backspace") && input === "") {
 | 
					 | 
				
			||||||
    setTags((prev) => prev.slice(0, -1));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleSuggestionClick = (suggestion) => {
 | 
					 | 
				
			||||||
    addTag(suggestion);
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const backgroundColor = color || "#f8f9fa";
 | 
					  const backgroundColor = color || "#f8f9fa";
 | 
				
			||||||
@ -108,77 +34,35 @@ useEffect(() => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <label htmlFor={name} className="form-label">
 | 
					      <label htmlFor={name} className="form-label">{label}</label>
 | 
				
			||||||
        {label}
 | 
					      <div className="form-control form-control-sm d-flex justify-content-start flex-wrap gap-1" style={{ minHeight: "12px" }}>
 | 
				
			||||||
      </label>
 | 
					        {tags.map((tag, i) => (
 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div
 | 
					 | 
				
			||||||
        className="form-control form-control-sm p-1"
 | 
					 | 
				
			||||||
        style={{ minHeight: "38px", position: "relative" }}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <div className="d-flex flex-wrap align-items-center gap-1">
 | 
					 | 
				
			||||||
          {tags.map((tag, index) => (
 | 
					 | 
				
			||||||
          <span
 | 
					          <span
 | 
				
			||||||
              key={index}
 | 
					            key={i}
 | 
				
			||||||
            className="d-flex align-items-center"
 | 
					            className="d-flex align-items-center"
 | 
				
			||||||
            style={{
 | 
					            style={{
 | 
				
			||||||
              color: iconColor,
 | 
					              color: iconColor,
 | 
				
			||||||
              backgroundColor,
 | 
					              backgroundColor,
 | 
				
			||||||
                padding: "2px 6px",
 | 
					              padding: "2px 3px",
 | 
				
			||||||
                borderRadius: "2px",
 | 
					              borderRadius: "2px"
 | 
				
			||||||
                fontSize: "0.85rem",
 | 
					 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
              {tag.name}
 | 
					            {tag}
 | 
				
			||||||
              <i
 | 
					            <i className="bx bx-x bx-xs ms-1" onClick={() => removeTag(i)}></i>
 | 
				
			||||||
                className="bx bx-x bx-xs ms-1"
 | 
					 | 
				
			||||||
                onClick={() => removeTag(index)}
 | 
					 | 
				
			||||||
                style={{ cursor: "pointer" }}
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
        ))}
 | 
					        ))}
 | 
				
			||||||
 | 
					 | 
				
			||||||
        <input
 | 
					        <input
 | 
				
			||||||
          type="text"
 | 
					          type="text"
 | 
				
			||||||
 | 
					          className="border-0 flex-grow-1"
 | 
				
			||||||
          value={input}
 | 
					          value={input}
 | 
				
			||||||
          onChange={(e) => setInput(e.target.value)}
 | 
					          onChange={(e) => setInput(e.target.value)}
 | 
				
			||||||
            onKeyDown={handleInputKeyDown}
 | 
					          onKeyDown={(e) => (e.key === "Enter" ? addTag(e) : null)}
 | 
				
			||||||
              onKeyUp={handleInputKey}
 | 
					 | 
				
			||||||
          placeholder={placeholder}
 | 
					          placeholder={placeholder}
 | 
				
			||||||
            style={{
 | 
					          style={{ outline: "none", minWidth: "120px" }}
 | 
				
			||||||
              border: "none",
 | 
					 | 
				
			||||||
              outline: "none",
 | 
					 | 
				
			||||||
              flex: 1,
 | 
					 | 
				
			||||||
              minWidth: "120px",
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					 | 
				
			||||||
        {suggestions.length > 0 && (
 | 
					 | 
				
			||||||
          <ul
 | 
					 | 
				
			||||||
            className="list-group position-absolute mt-1 bg-white w-50 shadow-sm "
 | 
					 | 
				
			||||||
            style={{
 | 
					 | 
				
			||||||
              zIndex: 1000,
 | 
					 | 
				
			||||||
              maxHeight: "150px",
 | 
					 | 
				
			||||||
              overflowY: "auto",
 | 
					 | 
				
			||||||
              boxShadow:"0px 4px 10px rgba(0, 0, 0, 0.2)",borderRadius:"3px",border:"1px solid #ddd"
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            {suggestions.map((sugg, i) => (
 | 
					 | 
				
			||||||
              <li
 | 
					 | 
				
			||||||
                key={i}
 | 
					 | 
				
			||||||
                className="dropdown-item p-1 hoverBox"
 | 
					 | 
				
			||||||
                onClick={() => handleSuggestionClick(sugg)}
 | 
					 | 
				
			||||||
                style={{cursor: "pointer", fontSize: "0.875rem"}}
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                {sugg.name}
 | 
					 | 
				
			||||||
              </li>
 | 
					 | 
				
			||||||
            ))}
 | 
					 | 
				
			||||||
          </ul>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default TagInput;
 | 
					export default TagInput;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,132 +0,0 @@
 | 
				
			|||||||
.editor-wrapper {
 | 
					 | 
				
			||||||
  max-width: 100%;
 | 
					 | 
				
			||||||
  margin: 1px auto;
 | 
					 | 
				
			||||||
  background: #fff;
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  overflow: hidden;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-container {
 | 
					 | 
				
			||||||
  border: 1px solid #ccc;
 | 
					 | 
				
			||||||
  border-bottom: none;
 | 
					 | 
				
			||||||
  min-height: 80px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.custom-toolbar {
 | 
					 | 
				
			||||||
  /* text-align: left; */
 | 
					 | 
				
			||||||
  background-color: transparent;
 | 
					 | 
				
			||||||
  border: 1px solid #ccc;
 | 
					 | 
				
			||||||
  border-top: none;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/* Target the dropdown in the toolbar */
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker.ql-header {
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Open the dropdown upwards */
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker.ql-header .ql-picker-options {
 | 
					 | 
				
			||||||
  bottom: 100%; /* Move it above the picker */
 | 
					 | 
				
			||||||
  top: auto;    /* Cancel default dropdown positioning */
 | 
					 | 
				
			||||||
  margin-bottom: 5px; /* Optional spacing */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker.ql-header {
 | 
					 | 
				
			||||||
  font-family: Arial, sans-serif;
 | 
					 | 
				
			||||||
  font-size: 10px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker-label {
 | 
					 | 
				
			||||||
  background-color: #eee;
 | 
					 | 
				
			||||||
  /* padding: 6px 10px; */
 | 
					 | 
				
			||||||
  border-radius: 4px;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  color: #333;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker-options {
 | 
					 | 
				
			||||||
  background-color: white;
 | 
					 | 
				
			||||||
  border: 1px solid #ccc;
 | 
					 | 
				
			||||||
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
 | 
					 | 
				
			||||||
  border-radius: 4px;
 | 
					 | 
				
			||||||
  overflow: hidden;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker-options span {
 | 
					 | 
				
			||||||
  padding: 2px 1px;
 | 
					 | 
				
			||||||
  display: block;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker-options span:hover {
 | 
					 | 
				
			||||||
  background-color: #f0f0f0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker-item{
 | 
					 | 
				
			||||||
  padding: 0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.ql-snow.ql-toolbar button, .ql-snow .ql-toolbar button {
 | 
					 | 
				
			||||||
    background: none;
 | 
					 | 
				
			||||||
    border: none;
 | 
					 | 
				
			||||||
    cursor: pointer;
 | 
					 | 
				
			||||||
    display: inline-block;
 | 
					 | 
				
			||||||
    float: left;
 | 
					 | 
				
			||||||
   font-size: 15px;
 | 
					 | 
				
			||||||
    padding: 2px 2px;
 | 
					 | 
				
			||||||
    width: 28px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.ql-toolbar.ql-snow{
 | 
					 | 
				
			||||||
  padding: 4px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@media (max-width: 768px) {
 | 
					 | 
				
			||||||
.ql-toolbar.ql-snow .ql-formats {
 | 
					 | 
				
			||||||
    margin-right: 1px;
 | 
					 | 
				
			||||||
    align-items: center;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-snow.ql-toolbar button,
 | 
					 | 
				
			||||||
.ql-snow .ql-toolbar button {
 | 
					 | 
				
			||||||
  background: none;
 | 
					 | 
				
			||||||
  border: none;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  height: 18px;
 | 
					 | 
				
			||||||
  padding: 2px 2px;
 | 
					 | 
				
			||||||
  width: 22px;
 | 
					 | 
				
			||||||
  font-size: 14px;
 | 
					 | 
				
			||||||
  /* REMOVE THIS to fix side-alignment */
 | 
					 | 
				
			||||||
  /* float: left; */
 | 
					 | 
				
			||||||
  vertical-align: middle;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ql-snow .ql-picker-label {
 | 
					 | 
				
			||||||
  font-size: 10px;          /* Smaller text */
 | 
					 | 
				
			||||||
  padding: 0 6px;           /* Horizontal padding */
 | 
					 | 
				
			||||||
  height: 20px;             /* Height of the label */
 | 
					 | 
				
			||||||
  line-height: 20px;        /* Match height to vertically center single-line text */
 | 
					 | 
				
			||||||
  background-color: #eee;
 | 
					 | 
				
			||||||
  border-radius: 0px;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  color: #333;
 | 
					 | 
				
			||||||
  text-align: center;
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  display: flex;            /* Enable flexbox */
 | 
					 | 
				
			||||||
  align-items: center;      /* Vertical centering */
 | 
					 | 
				
			||||||
  justify-content: center;  /* Horizontal centering */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Remove custom upward-opening styles */
 | 
					 | 
				
			||||||
.ql-toolbar .ql-picker.ql-header .ql-picker-options {
 | 
					 | 
				
			||||||
  top: 100%;        /* Position it below the label */
 | 
					 | 
				
			||||||
  bottom: auto;     /* Cancel the upward positioning */
 | 
					 | 
				
			||||||
  margin-top: 5px;  /* Optional spacing */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.ql-editor {
 | 
					 | 
				
			||||||
      padding: 4px 15px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,96 +0,0 @@
 | 
				
			|||||||
import React, { useRef } from "react";
 | 
					 | 
				
			||||||
import ReactQuill from "react-quill";
 | 
					 | 
				
			||||||
import "quill/dist/quill.snow.css";
 | 
					 | 
				
			||||||
import "./Editor.css";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const Editor = ({
 | 
					 | 
				
			||||||
  value,
 | 
					 | 
				
			||||||
  loading,
 | 
					 | 
				
			||||||
  onChange,
 | 
					 | 
				
			||||||
  onCancel,
 | 
					 | 
				
			||||||
  onSubmit,
 | 
					 | 
				
			||||||
  placeholder = "Start writing...",
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const modules = {
 | 
					 | 
				
			||||||
    toolbar: {
 | 
					 | 
				
			||||||
      container: "#custom-toolbar",
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const formats = [
 | 
					 | 
				
			||||||
    "header",
 | 
					 | 
				
			||||||
    "bold",
 | 
					 | 
				
			||||||
    "italic",
 | 
					 | 
				
			||||||
    "underline",
 | 
					 | 
				
			||||||
    "strike",
 | 
					 | 
				
			||||||
    "list",
 | 
					 | 
				
			||||||
    "bullet",
 | 
					 | 
				
			||||||
    "blockquote",
 | 
					 | 
				
			||||||
    "code-block",
 | 
					 | 
				
			||||||
    "link",
 | 
					 | 
				
			||||||
    "align",
 | 
					 | 
				
			||||||
    "image",
 | 
					 | 
				
			||||||
  ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="editor-wrapper m-5">
 | 
					 | 
				
			||||||
      <div id="custom-toolbar" className="ql-toolbar ql-snow custom-toolbar">
 | 
					 | 
				
			||||||
        <div className="d-flex justify-content-between align-items-center w-100">
 | 
					 | 
				
			||||||
          {/* Left: Quill Format Buttons */}
 | 
					 | 
				
			||||||
          <span className="d-flex">
 | 
					 | 
				
			||||||
            <span className="ql-formats">
 | 
					 | 
				
			||||||
              <select className="ql-header" defaultValue="">
 | 
					 | 
				
			||||||
                <option value="1" />
 | 
					 | 
				
			||||||
                <option value="2" />
 | 
					 | 
				
			||||||
                <option value="" />
 | 
					 | 
				
			||||||
              </select>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              <button className="ql-bold" />
 | 
					 | 
				
			||||||
              <button className="ql-italic" />
 | 
					 | 
				
			||||||
              <button className="ql-underline" />
 | 
					 | 
				
			||||||
              <button className="ql-strike" />
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <span className="ql-formats">
 | 
					 | 
				
			||||||
              <button className="ql-list" value="ordered" />
 | 
					 | 
				
			||||||
              <button className="ql-list" value="bullet" />
 | 
					 | 
				
			||||||
              {/* <button className="ql-image" value="file" /> */}
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <span className="ql-formats">
 | 
					 | 
				
			||||||
              <button className="ql-link" />
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <ReactQuill
 | 
					 | 
				
			||||||
        value={value}
 | 
					 | 
				
			||||||
        onChange={onChange}
 | 
					 | 
				
			||||||
        modules={modules}
 | 
					 | 
				
			||||||
        formats={formats}
 | 
					 | 
				
			||||||
        theme="snow"
 | 
					 | 
				
			||||||
        placeholder={placeholder}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      {/* Right: Submit + Cancel Buttons */}
 | 
					 | 
				
			||||||
      <div className="d-flex justify-content-end  gap-2 p-1">
 | 
					 | 
				
			||||||
        <span
 | 
					 | 
				
			||||||
          className="btn btn-xs btn-secondary"
 | 
					 | 
				
			||||||
          aria-disabled={loading}
 | 
					 | 
				
			||||||
          onClick={onCancel}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          Cancel
 | 
					 | 
				
			||||||
        </span>
 | 
					 | 
				
			||||||
        <span
 | 
					 | 
				
			||||||
          type="submit"
 | 
					 | 
				
			||||||
          className="btn  btn-xs btn-primary"
 | 
					 | 
				
			||||||
          onClick={onSubmit}
 | 
					 | 
				
			||||||
          aria-disabled={loading}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          {loading ? "Please Wait..." : "Submit"}
 | 
					 | 
				
			||||||
        </span>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default Editor;
 | 
					 | 
				
			||||||
@ -1,113 +0,0 @@
 | 
				
			|||||||
import React, { useEffect,useState } from 'react'
 | 
					 | 
				
			||||||
import { useForm } from 'react-hook-form';
 | 
					 | 
				
			||||||
import { z } from 'zod';
 | 
					 | 
				
			||||||
import { zodResolver } from '@hookform/resolvers/zod';
 | 
					 | 
				
			||||||
import { MasterRespository } from '../../repositories/MastersRepository';
 | 
					 | 
				
			||||||
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
 | 
					 | 
				
			||||||
import { getCachedData,cacheData } from '../../slices/apiDataManager';
 | 
					 | 
				
			||||||
import showToast from '../../services/toastService';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const schema = z.object({
 | 
					 | 
				
			||||||
  name: z.string().min(1, { message: "Category name is required" }),
 | 
					 | 
				
			||||||
  description: z.string().min(1, { message: "Description is required" })
 | 
					 | 
				
			||||||
  .max(255, { message: "Description cannot exceed 255 characters" }),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const CreateContactCategory = ({onClose}) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const[isLoading,setIsLoading] = useState(false)
 | 
					 | 
				
			||||||
     const {
 | 
					 | 
				
			||||||
      register,
 | 
					 | 
				
			||||||
      handleSubmit,
 | 
					 | 
				
			||||||
      formState: { errors },reset
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    } = useForm({
 | 
					 | 
				
			||||||
      resolver: zodResolver(schema),
 | 
					 | 
				
			||||||
      defaultValues: {
 | 
					 | 
				
			||||||
        name: "",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    const onSubmit = (data) => {
 | 
					 | 
				
			||||||
      setIsLoading(true)    
 | 
					 | 
				
			||||||
      MasterRespository.createContactCategory(data).then((resp)=>{ 
 | 
					 | 
				
			||||||
        setIsLoading(false)
 | 
					 | 
				
			||||||
        resetForm()
 | 
					 | 
				
			||||||
        const cachedData = getCachedData("Contact Category"); 
 | 
					 | 
				
			||||||
        const updatedData = [...cachedData, resp?.data]; 
 | 
					 | 
				
			||||||
        cacheData("Contact Category", updatedData); 
 | 
					 | 
				
			||||||
        showToast("Contact Category Added successfully.", "success");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        onClose()
 | 
					 | 
				
			||||||
      }).catch((error)=>{
 | 
					 | 
				
			||||||
        showToast(error?.response?.data?.message, "error");
 | 
					 | 
				
			||||||
        setIsLoading(false)
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const resetForm = () => {
 | 
					 | 
				
			||||||
      reset({
 | 
					 | 
				
			||||||
        name: "",
 | 
					 | 
				
			||||||
        description: ""
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      setDescriptionLength(0);
 | 
					 | 
				
			||||||
    }    
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    useEffect(()=>{
 | 
					 | 
				
			||||||
        return ()=>resetForm()
 | 
					 | 
				
			||||||
    },[])
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    const [descriptionLength, setDescriptionLength] = useState(0);
 | 
					 | 
				
			||||||
    const maxDescriptionLength = 255;    
 | 
					 | 
				
			||||||
  return (<>
 | 
					 | 
				
			||||||
    <form  className="row g-2" onSubmit={handleSubmit(onSubmit)}>
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label">Category Name</label>
 | 
					 | 
				
			||||||
          <input type="text" 
 | 
					 | 
				
			||||||
           {...register("name")} 
 | 
					 | 
				
			||||||
             className={`form-control ${errors.name ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          {errors.name && <p className="text-danger">{errors.name.message}</p>}
 | 
					 | 
				
			||||||
        </div> 
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label" htmlFor="description">Description</label>
 | 
					 | 
				
			||||||
        <textarea
 | 
					 | 
				
			||||||
          rows="3"
 | 
					 | 
				
			||||||
          {...register("description")}
 | 
					 | 
				
			||||||
          className={`form-control ${errors.description ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          onChange={(e) => {
 | 
					 | 
				
			||||||
            setDescriptionLength(e.target.value.length);
 | 
					 | 
				
			||||||
            register("description").onChange(e);
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        ></textarea>
 | 
					 | 
				
			||||||
        <div className="text-end small text-muted">
 | 
					 | 
				
			||||||
          {maxDescriptionLength - descriptionLength} characters left
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
          {errors.description && (
 | 
					 | 
				
			||||||
            <p className="text-danger">{errors.description.message}</p>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-center">
 | 
					 | 
				
			||||||
        <button type="submit" className="btn btn-sm btn-primary me-3">           
 | 
					 | 
				
			||||||
         {isLoading? "Please Wait...":"Submit"}       
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
        <button
 | 
					 | 
				
			||||||
          type="reset"
 | 
					 | 
				
			||||||
          className="btn btn-sm btn-label-secondary "
 | 
					 | 
				
			||||||
          data-bs-dismiss="modal"
 | 
					 | 
				
			||||||
          aria-label="Close"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          Cancel
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default CreateContactCategory;
 | 
					 | 
				
			||||||
@ -1,114 +0,0 @@
 | 
				
			|||||||
import React, { useEffect,useState } from 'react'
 | 
					 | 
				
			||||||
import { useForm } from 'react-hook-form';
 | 
					 | 
				
			||||||
import { z } from 'zod';
 | 
					 | 
				
			||||||
import { zodResolver } from '@hookform/resolvers/zod';
 | 
					 | 
				
			||||||
import { MasterRespository } from '../../repositories/MastersRepository';
 | 
					 | 
				
			||||||
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
 | 
					 | 
				
			||||||
import { getCachedData,cacheData } from '../../slices/apiDataManager';
 | 
					 | 
				
			||||||
import showToast from '../../services/toastService';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const schema = z.object({
 | 
					 | 
				
			||||||
  name: z.string().min(1, { message: "Tag name is required" }),
 | 
					 | 
				
			||||||
  description: z.string().min(1, { message: "Description is required" })
 | 
					 | 
				
			||||||
  .max(255, { message: "Description cannot exceed 255 characters" }),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const CreateContactTag = ({onClose}) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const[isLoading,setIsLoading] = useState(false)
 | 
					 | 
				
			||||||
     const {
 | 
					 | 
				
			||||||
      register,
 | 
					 | 
				
			||||||
      handleSubmit,
 | 
					 | 
				
			||||||
      formState: { errors },reset
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    } = useForm({
 | 
					 | 
				
			||||||
      resolver: zodResolver(schema),
 | 
					 | 
				
			||||||
      defaultValues: {
 | 
					 | 
				
			||||||
        name: "",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    const onSubmit = (data) => {
 | 
					 | 
				
			||||||
      setIsLoading(true)    
 | 
					 | 
				
			||||||
      MasterRespository.createContactTag(data).then((resp)=>{ 
 | 
					 | 
				
			||||||
        setIsLoading(false)
 | 
					 | 
				
			||||||
        resetForm()
 | 
					 | 
				
			||||||
        debugger
 | 
					 | 
				
			||||||
        const cachedData = getCachedData("Contact Tag"); 
 | 
					 | 
				
			||||||
        const updatedData = [...cachedData, resp?.data]; 
 | 
					 | 
				
			||||||
        cacheData("Contact Tag", updatedData); 
 | 
					 | 
				
			||||||
        showToast("Contact Tag Added successfully.", "success");
 | 
					 | 
				
			||||||
    console.log(getCachedData("Contact Tag"))
 | 
					 | 
				
			||||||
        onClose()
 | 
					 | 
				
			||||||
      }).catch((error)=>{
 | 
					 | 
				
			||||||
        showToast(error?.response?.data?.message, "error");
 | 
					 | 
				
			||||||
        setIsLoading(false)
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const resetForm = () => {
 | 
					 | 
				
			||||||
      reset({
 | 
					 | 
				
			||||||
        name: "",
 | 
					 | 
				
			||||||
        description: ""
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      setDescriptionLength(0);
 | 
					 | 
				
			||||||
    }    
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    useEffect(()=>{
 | 
					 | 
				
			||||||
        return ()=>resetForm()
 | 
					 | 
				
			||||||
    },[])
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    const [descriptionLength, setDescriptionLength] = useState(0);
 | 
					 | 
				
			||||||
    const maxDescriptionLength = 255;    
 | 
					 | 
				
			||||||
  return (<>
 | 
					 | 
				
			||||||
    <form  className="row g-2" onSubmit={handleSubmit(onSubmit)}>
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label">Tag Name</label>
 | 
					 | 
				
			||||||
          <input type="text" 
 | 
					 | 
				
			||||||
           {...register("name")} 
 | 
					 | 
				
			||||||
             className={`form-control ${errors.name ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          {errors.name && <p className="text-danger">{errors.name.message}</p>}
 | 
					 | 
				
			||||||
        </div> 
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label" htmlFor="description">Description</label>
 | 
					 | 
				
			||||||
        <textarea
 | 
					 | 
				
			||||||
          rows="3"
 | 
					 | 
				
			||||||
          {...register("description")}
 | 
					 | 
				
			||||||
          className={`form-control ${errors.description ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          onChange={(e) => {
 | 
					 | 
				
			||||||
            setDescriptionLength(e.target.value.length);
 | 
					 | 
				
			||||||
            register("description").onChange(e);
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        ></textarea>
 | 
					 | 
				
			||||||
        <div className="text-end small text-muted">
 | 
					 | 
				
			||||||
          {maxDescriptionLength - descriptionLength} characters left
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
          {errors.description && (
 | 
					 | 
				
			||||||
            <p className="text-danger">{errors.description.message}</p>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-center">
 | 
					 | 
				
			||||||
        <button type="submit" className="btn btn-sm btn-primary me-3">           
 | 
					 | 
				
			||||||
         {isLoading? "Please Wait...":"Submit"}       
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
        <button
 | 
					 | 
				
			||||||
          type="reset"
 | 
					 | 
				
			||||||
          className="btn btn-sm btn-label-secondary "
 | 
					 | 
				
			||||||
          data-bs-dismiss="modal"
 | 
					 | 
				
			||||||
          aria-label="Close"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          Cancel
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default CreateContactTag;
 | 
					 | 
				
			||||||
@ -1,126 +0,0 @@
 | 
				
			|||||||
import React, { useEffect,useState } from 'react'
 | 
					 | 
				
			||||||
import { useForm } from 'react-hook-form';
 | 
					 | 
				
			||||||
import { z } from 'zod';
 | 
					 | 
				
			||||||
import { zodResolver } from '@hookform/resolvers/zod';
 | 
					 | 
				
			||||||
import { MasterRespository } from '../../repositories/MastersRepository';
 | 
					 | 
				
			||||||
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
 | 
					 | 
				
			||||||
import { getCachedData,cacheData } from '../../slices/apiDataManager';
 | 
					 | 
				
			||||||
import showToast from '../../services/toastService';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const schema = z.object({
 | 
					 | 
				
			||||||
  name: z.string().min(1, { message: "Category name is required" }),
 | 
					 | 
				
			||||||
  description: z.string().min(1, { message: "Description is required" })
 | 
					 | 
				
			||||||
  .max(255, { message: "Description cannot exceed 255 characters" }),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const EditContactCategory= ({data,onClose}) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const[isLoading,setIsLoading] = useState(false)
 | 
					 | 
				
			||||||
     const {
 | 
					 | 
				
			||||||
      register,
 | 
					 | 
				
			||||||
      handleSubmit,
 | 
					 | 
				
			||||||
      formState: { errors },reset
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    } = useForm({
 | 
					 | 
				
			||||||
      resolver: zodResolver(schema),
 | 
					 | 
				
			||||||
      defaultValues: {
 | 
					 | 
				
			||||||
       name: data?.name || "",
 | 
					 | 
				
			||||||
        description:data?.description || "",
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
  const onSubmit = (formdata) => {
 | 
					 | 
				
			||||||
      setIsLoading(true)
 | 
					 | 
				
			||||||
      const result = {
 | 
					 | 
				
			||||||
        id:data?.id,
 | 
					 | 
				
			||||||
        name: formdata?.name,
 | 
					 | 
				
			||||||
        description: formdata.description,  
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
      MasterRespository.updateContactCategory(data?.id,result).then((resp)=>{
 | 
					 | 
				
			||||||
        setIsLoading(false) 
 | 
					 | 
				
			||||||
        showToast("Contact Category Updated successfully.", "success");
 | 
					 | 
				
			||||||
        const cachedData = getCachedData("Contact Category");
 | 
					 | 
				
			||||||
        if (cachedData) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          const updatedData = cachedData.map((category) =>
 | 
					 | 
				
			||||||
            category.id === data?.id ? { ...category, ...resp.data } : category
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          cacheData("Contact Category", updatedData);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        onClose()
 | 
					 | 
				
			||||||
      }).catch((error)=>{
 | 
					 | 
				
			||||||
         showToast(error?.response?.data?.message, "error")
 | 
					 | 
				
			||||||
        setIsLoading(false)
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const resetForm = () => {
 | 
					 | 
				
			||||||
      reset({
 | 
					 | 
				
			||||||
        name: "",
 | 
					 | 
				
			||||||
        description: ""
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      setDescriptionLength(0);
 | 
					 | 
				
			||||||
    }    
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    useEffect(()=>{
 | 
					 | 
				
			||||||
        return ()=>resetForm()
 | 
					 | 
				
			||||||
    },[])
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    const [descriptionLength, setDescriptionLength] = useState(0);
 | 
					 | 
				
			||||||
    const maxDescriptionLength = 255;    
 | 
					 | 
				
			||||||
  return (<>
 | 
					 | 
				
			||||||
    <form  className="row g-2" onSubmit={handleSubmit(onSubmit)}>
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label">Category Name</label>
 | 
					 | 
				
			||||||
          <input type="text" 
 | 
					 | 
				
			||||||
           {...register("name")} 
 | 
					 | 
				
			||||||
             className={`form-control ${errors.name ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          {errors.name && <p className="text-danger">{errors.name.message}</p>}
 | 
					 | 
				
			||||||
        </div> 
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label" htmlFor="description">Description</label>
 | 
					 | 
				
			||||||
        <textarea
 | 
					 | 
				
			||||||
          rows="3"
 | 
					 | 
				
			||||||
          {...register("description")}
 | 
					 | 
				
			||||||
          className={`form-control ${errors.description ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          onChange={(e) => {
 | 
					 | 
				
			||||||
            setDescriptionLength(e.target.value.length);
 | 
					 | 
				
			||||||
            register("description").onChange(e);
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        ></textarea>
 | 
					 | 
				
			||||||
        <div className="text-end small text-muted">
 | 
					 | 
				
			||||||
          {maxDescriptionLength - descriptionLength} characters left
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
          {errors.description && (
 | 
					 | 
				
			||||||
            <p className="text-danger">{errors.description.message}</p>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-center">
 | 
					 | 
				
			||||||
        <button type="submit" className="btn btn-sm btn-primary me-3">           
 | 
					 | 
				
			||||||
         {isLoading? "Please Wait...":"Submit"}       
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
        <button
 | 
					 | 
				
			||||||
          type="reset"
 | 
					 | 
				
			||||||
          className="btn btn-sm btn-label-secondary "
 | 
					 | 
				
			||||||
          data-bs-dismiss="modal"
 | 
					 | 
				
			||||||
          aria-label="Close"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          Cancel
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default EditContactCategory;
 | 
					 | 
				
			||||||
@ -1,126 +0,0 @@
 | 
				
			|||||||
import React,{useState,useEffect} from 'react'
 | 
					 | 
				
			||||||
import {useForm} from 'react-hook-form';
 | 
					 | 
				
			||||||
import { z } from 'zod';
 | 
					 | 
				
			||||||
import { zodResolver } from '@hookform/resolvers/zod';
 | 
					 | 
				
			||||||
import { MasterRespository } from '../../repositories/MastersRepository';
 | 
					 | 
				
			||||||
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
 | 
					 | 
				
			||||||
import { getCachedData,cacheData } from '../../slices/apiDataManager';
 | 
					 | 
				
			||||||
import showToast from '../../services/toastService';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const schema = z.object({
 | 
					 | 
				
			||||||
  name: z.string().min(1, { message: "Tag name is required" }),
 | 
					 | 
				
			||||||
  description: z.string().min(1, { message: "Description is required" })
 | 
					 | 
				
			||||||
  .max(255, { message: "Description cannot exceed 255 characters" }),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const EditContactTag= ({data,onClose}) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const[isLoading,setIsLoading] = useState(false)
 | 
					 | 
				
			||||||
     const {
 | 
					 | 
				
			||||||
      register,
 | 
					 | 
				
			||||||
      handleSubmit,
 | 
					 | 
				
			||||||
      formState: { errors },reset
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    } = useForm({
 | 
					 | 
				
			||||||
      resolver: zodResolver(schema),
 | 
					 | 
				
			||||||
      defaultValues: {
 | 
					 | 
				
			||||||
       name: data?.name || "",
 | 
					 | 
				
			||||||
        description:data?.description || "",
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
  const onSubmit = (formdata) => {
 | 
					 | 
				
			||||||
      setIsLoading(true)
 | 
					 | 
				
			||||||
      const result = {
 | 
					 | 
				
			||||||
        id:data?.id,
 | 
					 | 
				
			||||||
        name: formdata?.name,
 | 
					 | 
				
			||||||
        description: formdata.description,  
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
      MasterRespository.updateContactTag(data?.id,result).then((resp)=>{
 | 
					 | 
				
			||||||
        setIsLoading(false) 
 | 
					 | 
				
			||||||
        showToast("Contact Tag Updated successfully.", "success");
 | 
					 | 
				
			||||||
        const cachedData = getCachedData("Contact Tag");
 | 
					 | 
				
			||||||
        if (cachedData) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          const updatedData = cachedData.map((category) =>
 | 
					 | 
				
			||||||
            category.id === data?.id ? { ...category, ...resp.data } : category
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          cacheData("Contact Tag", updatedData);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        onClose()
 | 
					 | 
				
			||||||
      }).catch((error)=>{
 | 
					 | 
				
			||||||
         showToast(error?.response?.data?.message, "error")
 | 
					 | 
				
			||||||
        setIsLoading(false)
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const resetForm = () => {
 | 
					 | 
				
			||||||
      reset({
 | 
					 | 
				
			||||||
        name: "",
 | 
					 | 
				
			||||||
        description: ""
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      setDescriptionLength(0);
 | 
					 | 
				
			||||||
    }    
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    useEffect(()=>{
 | 
					 | 
				
			||||||
        return ()=>resetForm()
 | 
					 | 
				
			||||||
    },[])
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    const [descriptionLength, setDescriptionLength] = useState(0);
 | 
					 | 
				
			||||||
    const maxDescriptionLength = 255;    
 | 
					 | 
				
			||||||
  return (<>
 | 
					 | 
				
			||||||
    <form  className="row g-2" onSubmit={handleSubmit(onSubmit)}>
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label">Tag Name</label>
 | 
					 | 
				
			||||||
          <input type="text" 
 | 
					 | 
				
			||||||
           {...register("name")} 
 | 
					 | 
				
			||||||
             className={`form-control ${errors.name ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          {errors.name && <p className="text-danger">{errors.name.message}</p>}
 | 
					 | 
				
			||||||
        </div> 
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-12">
 | 
					 | 
				
			||||||
          <label className="form-label" htmlFor="description">Description</label>
 | 
					 | 
				
			||||||
        <textarea
 | 
					 | 
				
			||||||
          rows="3"
 | 
					 | 
				
			||||||
          {...register("description")}
 | 
					 | 
				
			||||||
          className={`form-control ${errors.description ? 'is-invalids' : ''}`}
 | 
					 | 
				
			||||||
          onChange={(e) => {
 | 
					 | 
				
			||||||
            setDescriptionLength(e.target.value.length);
 | 
					 | 
				
			||||||
            register("description").onChange(e);
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        ></textarea>
 | 
					 | 
				
			||||||
        <div className="text-end small text-muted">
 | 
					 | 
				
			||||||
          {maxDescriptionLength - descriptionLength} characters left
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
          {errors.description && (
 | 
					 | 
				
			||||||
            <p className="text-danger">{errors.description.message}</p>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div className="col-12 text-center">
 | 
					 | 
				
			||||||
        <button type="submit" className="btn btn-sm btn-primary me-3">           
 | 
					 | 
				
			||||||
         {isLoading? "Please Wait...":"Submit"}       
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
        <button
 | 
					 | 
				
			||||||
          type="reset"
 | 
					 | 
				
			||||||
          className="btn btn-sm btn-label-secondary "
 | 
					 | 
				
			||||||
          data-bs-dismiss="modal"
 | 
					 | 
				
			||||||
          aria-label="Close"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          Cancel
 | 
					 | 
				
			||||||
        </button>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default EditContactTag;
 | 
					 | 
				
			||||||
@ -13,10 +13,6 @@ import {cacheData, getCachedData} from "../../slices/apiDataManager";
 | 
				
			|||||||
import showToast from "../../services/toastService";
 | 
					import showToast from "../../services/toastService";
 | 
				
			||||||
import CreateWorkCategory from "./CreateWorkCategory";
 | 
					import CreateWorkCategory from "./CreateWorkCategory";
 | 
				
			||||||
import EditWorkCategory from "./EditWorkCategory";
 | 
					import EditWorkCategory from "./EditWorkCategory";
 | 
				
			||||||
import CreateCategory from "./CreateContactCategory";
 | 
					 | 
				
			||||||
import CreateContactTag from "./CreateContactTag";
 | 
					 | 
				
			||||||
import EditContactCategory from "./EditContactCategory";
 | 
					 | 
				
			||||||
import EditContactTag from "./EditContactTag";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MasterModal = ({ modaldata, closeModal }) => {
 | 
					const MasterModal = ({ modaldata, closeModal }) => {
 | 
				
			||||||
@ -25,6 +21,7 @@ const MasterModal = ({ modaldata, closeModal }) => {
 | 
				
			|||||||
  const handleSelectedMasterDeleted = async () =>
 | 
					  const handleSelectedMasterDeleted = async () =>
 | 
				
			||||||
  { 
 | 
					  { 
 | 
				
			||||||
    const deleteFn = MasterRespository[modaldata.masterType];
 | 
					    const deleteFn = MasterRespository[modaldata.masterType];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!deleteFn) {
 | 
					    if (!deleteFn) {
 | 
				
			||||||
      showToast(`No delete strategy defined for master type`,"error");
 | 
					      showToast(`No delete strategy defined for master type`,"error");
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
@ -77,6 +74,7 @@ const MasterModal = ({ modaldata, closeModal }) => {
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      className="modal fade"
 | 
					      className="modal fade"
 | 
				
			||||||
@ -95,8 +93,6 @@ const MasterModal = ({ modaldata, closeModal }) => {
 | 
				
			|||||||
      >
 | 
					      >
 | 
				
			||||||
        <div className="modal-content">
 | 
					        <div className="modal-content">
 | 
				
			||||||
          <div className="modal-body p-sm-4 p-0">
 | 
					          <div className="modal-body p-sm-4 p-0">
 | 
				
			||||||
            <div className="d-flex justify-content-between">
 | 
					 | 
				
			||||||
              <h6>{ `${modaldata?.modalType} `}</h6>
 | 
					 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
              type="button"
 | 
					              type="button"
 | 
				
			||||||
              className="btn-close"
 | 
					              className="btn-close"
 | 
				
			||||||
@ -104,7 +100,6 @@ const MasterModal = ({ modaldata, closeModal }) => {
 | 
				
			|||||||
              aria-label="Close"
 | 
					              aria-label="Close"
 | 
				
			||||||
              onClick={closeModal}
 | 
					              onClick={closeModal}
 | 
				
			||||||
            ></button>
 | 
					            ></button>
 | 
				
			||||||
           </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {modaldata.modalType === "Application Role" && (
 | 
					            {modaldata.modalType === "Application Role" && (
 | 
				
			||||||
              <CreateRole masmodalType={modaldata.masterType} onClose={closeModal} />
 | 
					              <CreateRole masmodalType={modaldata.masterType} onClose={closeModal} />
 | 
				
			||||||
@ -130,18 +125,6 @@ const MasterModal = ({ modaldata, closeModal }) => {
 | 
				
			|||||||
            {modaldata.modalType === "Edit-Work Category" && (
 | 
					            {modaldata.modalType === "Edit-Work Category" && (
 | 
				
			||||||
              <EditWorkCategory data={modaldata.item} onClose={closeModal} />
 | 
					              <EditWorkCategory data={modaldata.item} onClose={closeModal} />
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
            {modaldata.modalType === "Contact Category" && (
 | 
					 | 
				
			||||||
              <CreateCategory data={modaldata.item} onClose={closeModal} />
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
             {modaldata.modalType === "Edit-Contact Category" && (
 | 
					 | 
				
			||||||
              <EditContactCategory data={modaldata.item} onClose={closeModal} />
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
             {modaldata.modalType === "Contact Tag" && (
 | 
					 | 
				
			||||||
              <CreateContactTag data={modaldata.item} onClose={closeModal} />
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
            {modaldata.modalType === "Edit-Contact Tag" && (
 | 
					 | 
				
			||||||
              <EditContactTag data={modaldata.item} onClose={closeModal} />
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
// it important ------
 | 
					// it important ------
 | 
				
			||||||
export const mastersList = [ {id: 1, name: "Application Role"}, {id: 2, name: "Job Role"}, {id: 3, name: "Activity"},{id: 4, name:"Work Category"},{id:5,name:"Contact Category"},{id:6,name:"Contact Tag"}]
 | 
					export const mastersList = [ {id: 1, name: "Application Role"}, {id: 2, name: "Job Role"}, {id: 3, name: "Activity"},{id: 4, name:"Work Category"} ]
 | 
				
			||||||
// -------------------
 | 
					// -------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const dailyTask = [
 | 
					export const dailyTask = [
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,11 @@
 | 
				
			|||||||
                        "text": "Employees",
 | 
					                        "text": "Employees",
 | 
				
			||||||
                        "available": true,
 | 
					                        "available": true,
 | 
				
			||||||
                        "link": "/employees"
 | 
					                        "link": "/employees"
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "text": "Directory",
 | 
				
			||||||
 | 
					                        "available": true,
 | 
				
			||||||
 | 
					                        "link": "/directory"
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -63,12 +68,6 @@
 | 
				
			|||||||
                        "link": "/activities/gallary"
 | 
					                        "link": "/activities/gallary"
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
                "text": "Directory",
 | 
					 | 
				
			||||||
                "icon": "bx bx-group",
 | 
					 | 
				
			||||||
                "available": true,
 | 
					 | 
				
			||||||
                "link": "/directory"
 | 
					 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                "text": "Administration",
 | 
					                "text": "Administration",
 | 
				
			||||||
 | 
				
			|||||||
@ -51,14 +51,6 @@ const useMaster = (isMa) => {
 | 
				
			|||||||
              response = await MasterRespository.getWorkCategory();
 | 
					              response = await MasterRespository.getWorkCategory();
 | 
				
			||||||
              response = response.data
 | 
					              response = response.data
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
            case "Contact Category":
 | 
					 | 
				
			||||||
              response = await MasterRespository.getContactCategory();
 | 
					 | 
				
			||||||
              response = response.data
 | 
					 | 
				
			||||||
              break;
 | 
					 | 
				
			||||||
            case "Contact Tag":
 | 
					 | 
				
			||||||
              response = await MasterRespository.getContactTag();
 | 
					 | 
				
			||||||
              response = response.data
 | 
					 | 
				
			||||||
              break;
 | 
					 | 
				
			||||||
            case "Status":
 | 
					            case "Status":
 | 
				
			||||||
              response = [{description: null,featurePermission: null,id: "02dd4761-363c-49ed-8851-3d2489a3e98d",status:"status 1"},{description: null,featurePermission: null,id: "03dy9761-363c-49ed-8851-3d2489a3e98d",status:"status 2"},{description: null,featurePermission: null,id: "03dy7761-263c-49ed-8851-3d2489a3e98d",status:"Status 3"}];
 | 
					              response = [{description: null,featurePermission: null,id: "02dd4761-363c-49ed-8851-3d2489a3e98d",status:"status 1"},{description: null,featurePermission: null,id: "03dy9761-363c-49ed-8851-3d2489a3e98d",status:"status 2"},{description: null,featurePermission: null,id: "03dy7761-263c-49ed-8851-3d2489a3e98d",status:"Status 3"}];
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
@ -157,67 +149,4 @@ export const useActivitiesMaster = () =>
 | 
				
			|||||||
      }, [] )
 | 
					      }, [] )
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      return {categories,categoryLoading,categoryError}
 | 
					      return {categories,categoryLoading,categoryError}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
export const useContactCategory = () =>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  const [ contactCategory, setContactCategory ] = useState( [] )
 | 
					 | 
				
			||||||
  const [ loading, setLoading ] = useState( false )
 | 
					 | 
				
			||||||
  const [ Error, setError ] = useState()
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  const fetchConatctCategory = async() =>
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    const cache_Category = getCachedData( "Contact Category" );
 | 
					 | 
				
			||||||
    if ( !cache_Category )
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      try
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        let resp = await MasterRespository.getContactCategory();
 | 
					 | 
				
			||||||
        setContactCategory( resp.data );
 | 
					 | 
				
			||||||
        cacheData("Contact Category",resp.data)
 | 
					 | 
				
			||||||
      } catch ( error )
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        setError(error)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    } else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      setContactCategory(cache_Category)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect( () =>
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    fetchConatctCategory()
 | 
					 | 
				
			||||||
  }, [] )
 | 
					 | 
				
			||||||
  return { contactCategory,loading,Error}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export const useContactTags = () => {
 | 
					 | 
				
			||||||
  const [contactTags, setContactTags] = useState([]);
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [error, setError] = useState(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const fetchContactTag = async () => {
 | 
					 | 
				
			||||||
      const cache_Tags = getCachedData("Contact Tag");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (!cache_Tags) {
 | 
					 | 
				
			||||||
        setLoading(true);
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
          const resp = await MasterRespository.getContactTag();
 | 
					 | 
				
			||||||
          setContactTags(resp.data);
 | 
					 | 
				
			||||||
          cacheData("Contact Tag", resp.data);
 | 
					 | 
				
			||||||
        } catch (err) {
 | 
					 | 
				
			||||||
          setError(err);
 | 
					 | 
				
			||||||
        } finally {
 | 
					 | 
				
			||||||
          setLoading(false);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        setContactTags(cache_Tags);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fetchContactTag();
 | 
					 | 
				
			||||||
  }, []);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { contactTags, loading, error };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -1,179 +0,0 @@
 | 
				
			|||||||
import { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import { DirectoryRepository } from "../repositories/DirectoryRepository";
 | 
					 | 
				
			||||||
import { cacheData, getCachedData } from "../slices/apiDataManager";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useDirectory = (isActive,prefernceContacts) => {
 | 
					 | 
				
			||||||
  const [contacts, setContacts] = useState([]);
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [error, setError] = useState(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const fetch = async (activeParam = isActive) => {
 | 
					 | 
				
			||||||
    setLoading(true);
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      const response = await DirectoryRepository.GetContacts(activeParam,prefernceContacts);
 | 
					 | 
				
			||||||
      setContacts(response.data);
 | 
					 | 
				
			||||||
      cacheData("contacts", { data: response.data, isActive: activeParam });
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      setError(error);
 | 
					 | 
				
			||||||
    } finally {
 | 
					 | 
				
			||||||
      setLoading(false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const cachedContacts = getCachedData("contacts");
 | 
					 | 
				
			||||||
    if (!cachedContacts?.data || cachedContacts.isActive !== isActive || prefernceContacts) {
 | 
					 | 
				
			||||||
      fetch(isActive,prefernceContacts);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      setContacts(cachedContacts.data);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [isActive,prefernceContacts]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    contacts,
 | 
					 | 
				
			||||||
    loading,
 | 
					 | 
				
			||||||
    error,
 | 
					 | 
				
			||||||
    refetch: fetch,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useBuckets = () => {
 | 
					 | 
				
			||||||
  const [buckets, setBuckets] = useState([]);
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [error, setError] = useState("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const fetchBuckets = async () => {
 | 
					 | 
				
			||||||
    setLoading(true);
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      const resp = await DirectoryRepository.GetBucktes();
 | 
					 | 
				
			||||||
      setBuckets(resp.data);
 | 
					 | 
				
			||||||
      cacheData("buckets", resp.data);
 | 
					 | 
				
			||||||
      setLoading(false);
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      const msg =
 | 
					 | 
				
			||||||
        error?.response?.data?.message ||
 | 
					 | 
				
			||||||
        error?.message ||
 | 
					 | 
				
			||||||
        "Something went wrong";
 | 
					 | 
				
			||||||
      setError( msg );
 | 
					 | 
				
			||||||
      setLoading(false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const cacheBuckets = getCachedData("buckets");
 | 
					 | 
				
			||||||
    if (!cacheBuckets) {
 | 
					 | 
				
			||||||
      fetchBuckets();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      setBuckets(cacheBuckets);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, []);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { buckets, loading, error, refetch: fetchBuckets };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useContactProfile = (id) => {
 | 
					 | 
				
			||||||
  const [contactProfile, setContactProfile] = useState(null);
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [Error, setError] = useState("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const fetchContactProfile = async () => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setLoading(true);
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        const resp = await DirectoryRepository.GetContactProfile(id);
 | 
					 | 
				
			||||||
        setContactProfile(resp.data);
 | 
					 | 
				
			||||||
        cacheData("Contact Profile", { data: resp.data, contactId: id });
 | 
					 | 
				
			||||||
      } catch (err) {
 | 
					 | 
				
			||||||
        const msg =
 | 
					 | 
				
			||||||
          err?.response?.data?.message ||
 | 
					 | 
				
			||||||
          err?.message ||
 | 
					 | 
				
			||||||
          "Something went wrong";
 | 
					 | 
				
			||||||
        setError(msg);
 | 
					 | 
				
			||||||
      } finally {
 | 
					 | 
				
			||||||
        setLoading(false);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect( () =>
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    const cached = getCachedData("Contact Profile");
 | 
					 | 
				
			||||||
       if (!cached || cached.contactId !== id) {
 | 
					 | 
				
			||||||
      fetchContactProfile(id);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      setContactProfile(cached.data);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [id]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { contactProfile, loading, Error ,refetch:fetchContactProfile};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useContactNotes = (id, IsActive) => {
 | 
					 | 
				
			||||||
  const [contactNotes, setContactNotes] = useState([]);
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [Error, setError] = useState("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const fetchContactNotes = async (id,IsActive) => {
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setLoading(true);
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        const resp = await DirectoryRepository.GetNote(id, IsActive);
 | 
					 | 
				
			||||||
        setContactNotes(resp.data);
 | 
					 | 
				
			||||||
        cacheData("Contact Notes", { data: resp.data, contactId: id });
 | 
					 | 
				
			||||||
      } catch (err) {
 | 
					 | 
				
			||||||
        const msg =
 | 
					 | 
				
			||||||
          err?.response?.data?.message ||
 | 
					 | 
				
			||||||
          err?.message ||
 | 
					 | 
				
			||||||
          "Something went wrong";
 | 
					 | 
				
			||||||
        setError(msg);
 | 
					 | 
				
			||||||
      } finally {
 | 
					 | 
				
			||||||
        setLoading(false);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const cached = getCachedData("Contact Notes");
 | 
					 | 
				
			||||||
    if (!cached || cached.contactId !== id) {
 | 
					 | 
				
			||||||
      id && fetchContactNotes(id,IsActive);
 | 
					 | 
				
			||||||
     } else {
 | 
					 | 
				
			||||||
      setContactNotes(cached.data);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [id,IsActive]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { contactNotes, loading, Error,refetch:fetchContactNotes };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useOrganization = () => {
 | 
					 | 
				
			||||||
  const [organizationList, setOrganizationList] = useState([]);
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [error, setError] = useState("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const fetchOrg = async () => {
 | 
					 | 
				
			||||||
    const cacheOrg = getCachedData("organizations");
 | 
					 | 
				
			||||||
    if (cacheOrg?.length != 0) {
 | 
					 | 
				
			||||||
      setLoading(true);
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        const resp = await DirectoryRepository.GetOrganizations();
 | 
					 | 
				
			||||||
        cacheData("organizations", resp.data);
 | 
					 | 
				
			||||||
        setOrganizationList(resp.data);
 | 
					 | 
				
			||||||
        setLoading(false);
 | 
					 | 
				
			||||||
      } catch (error) {
 | 
					 | 
				
			||||||
        const msg =
 | 
					 | 
				
			||||||
          error?.response?.data?.message ||
 | 
					 | 
				
			||||||
          error?.message ||
 | 
					 | 
				
			||||||
          "Something went wrong";
 | 
					 | 
				
			||||||
        setError(msg);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      setOrganizationList(cacheOrg);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    fetchOrg();
 | 
					 | 
				
			||||||
  }, []);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { organizationList, loading, error };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -4,7 +4,6 @@ import ProjectRepository from "../repositories/ProjectRepository";
 | 
				
			|||||||
import { useProfile } from "./useProfile";
 | 
					import { useProfile } from "./useProfile";
 | 
				
			||||||
import { useDispatch, useSelector } from "react-redux";
 | 
					import { useDispatch, useSelector } from "react-redux";
 | 
				
			||||||
import { setProjectId } from "../slices/localVariablesSlice";
 | 
					import { setProjectId } from "../slices/localVariablesSlice";
 | 
				
			||||||
import EmployeeList from "../components/Directory/EmployeeList";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useProjects = () => {
 | 
					export const useProjects = () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -131,48 +130,3 @@ export const useProjectDetails = (projectId) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return { projects_Details, loading, error, refetch: fetchData }
 | 
					  return { projects_Details, loading, error, refetch: fetchData }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useProjectsByEmployee = ( employeeId ) =>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  const [projectList, setProjectList] = useState([]);
 | 
					 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					 | 
				
			||||||
  const [error, setError] = useState('');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const fetchProjects = async (id) => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      setLoading(true);
 | 
					 | 
				
			||||||
      setError(''); // clear previous error
 | 
					 | 
				
			||||||
      const res = await ProjectRepository.getProjectsByEmployee(id);
 | 
					 | 
				
			||||||
      setProjectList(res.data);
 | 
					 | 
				
			||||||
      cacheData( 'ProjectsByEmployee', {data: res.data, employeeId: id} );
 | 
					 | 
				
			||||||
      setLoading(false)
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
      setError( err?.message || 'Failed to fetch projects' );
 | 
					 | 
				
			||||||
      setLoading(false)
 | 
					 | 
				
			||||||
    } 
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (!employeeId) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const cache_project = getCachedData('ProjectsByEmployee');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (
 | 
					 | 
				
			||||||
      !cache_project?.data ||
 | 
					 | 
				
			||||||
      cache_project?.employeeId !== employeeId
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
      fetchProjects(employeeId);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      setProjectList(cache_project.data);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [employeeId]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    projectList,
 | 
					 | 
				
			||||||
    loading,
 | 
					 | 
				
			||||||
    error,
 | 
					 | 
				
			||||||
    refetch : fetchProjects
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
import { useState, useMemo } from 'react';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useSortableData = (items, config = null) => {
 | 
					 | 
				
			||||||
  const [sortConfig, setSortConfig] = useState(config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const sortedItems = useMemo(() => {
 | 
					 | 
				
			||||||
    let sortableItems = [...items];
 | 
					 | 
				
			||||||
    if (sortConfig !== null) {
 | 
					 | 
				
			||||||
      sortableItems.sort((a, b) => {
 | 
					 | 
				
			||||||
        const aValue = sortConfig.key(a).toLowerCase();
 | 
					 | 
				
			||||||
        const bValue = sortConfig.key(b).toLowerCase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (aValue < bValue) return sortConfig.direction === 'asc' ? -1 : 1;
 | 
					 | 
				
			||||||
        if (aValue > bValue) return sortConfig.direction === 'asc' ? 1 : -1;
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return sortableItems;
 | 
					 | 
				
			||||||
  }, [items, sortConfig]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const requestSort = (keyFn) => {
 | 
					 | 
				
			||||||
    let direction = 'asc';
 | 
					 | 
				
			||||||
    if (
 | 
					 | 
				
			||||||
      sortConfig &&
 | 
					 | 
				
			||||||
      sortConfig.key.toString() === keyFn.toString() &&
 | 
					 | 
				
			||||||
      sortConfig.direction === 'asc'
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
      direction = 'desc';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    setSortConfig({ key: keyFn, direction });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { items: sortedItems, requestSort, sortConfig };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -165,6 +165,3 @@ padding: 1px !important;
 | 
				
			|||||||
.accordion-button:not(.collapsed) .toggle-icon {
 | 
					.accordion-button:not(.collapsed) .toggle-icon {
 | 
				
			||||||
  content: "\f146"; /* minus-circle */
 | 
					  content: "\f146"; /* minus-circle */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.hoverBox:hover{
 | 
					 | 
				
			||||||
  background-color: #f1f3f5;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -4,30 +4,25 @@ import Header from "../components/Layout/Header";
 | 
				
			|||||||
import Sidebar from "../components/Layout/Sidebar";
 | 
					import Sidebar from "../components/Layout/Sidebar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Footer from "../components/Layout/Footer";
 | 
					import Footer from "../components/Layout/Footer";
 | 
				
			||||||
import FloatingMenu from "../components/common/FloatingMenu";
 | 
					 | 
				
			||||||
import { FabProvider } from "../Context/FabContext";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const HomeLayout = () => {
 | 
					const HomeLayout = () => {
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    Main();
 | 
					    Main();
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <FabProvider>
 | 
					    <div className="layout-wrapper layout-content-navbar" >
 | 
				
			||||||
      <div className="layout-wrapper layout-content-navbar">
 | 
					      <div className="layout-container" >
 | 
				
			||||||
        <div className="layout-container">
 | 
					 | 
				
			||||||
        <Sidebar />
 | 
					        <Sidebar />
 | 
				
			||||||
        <div className="layout-page ">
 | 
					        <div className="layout-page ">
 | 
				
			||||||
          <Header />
 | 
					          <Header />
 | 
				
			||||||
            <div className="content-wrapper">
 | 
					          <div className="content-wrapper"  >
 | 
				
			||||||
            <Outlet />
 | 
					            <Outlet />
 | 
				
			||||||
            <Footer />
 | 
					            <Footer />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
          <FloatingMenu />
 | 
					 | 
				
			||||||
        <div className="layout-overlay layout-menu-toggle"></div>
 | 
					        <div className="layout-overlay layout-menu-toggle"></div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    </FabProvider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -141,7 +141,7 @@ const AttendancePage = () => {
 | 
				
			|||||||
          ]}
 | 
					          ]}
 | 
				
			||||||
        ></Breadcrumb>
 | 
					        ></Breadcrumb>
 | 
				
			||||||
        <div className="nav-align-top nav-tabs-shadow">
 | 
					        <div className="nav-align-top nav-tabs-shadow">
 | 
				
			||||||
          <ul className="nav nav-tabs align-items-center" role="tablist">
 | 
					          <ul className="nav nav-tabs" role="tablist">
 | 
				
			||||||
            <div
 | 
					            <div
 | 
				
			||||||
              className="dataTables_length text-start py-2 px-2 d-flex "
 | 
					              className="dataTables_length text-start py-2 px-2 d-flex "
 | 
				
			||||||
              id="DataTables_Table_0_length"
 | 
					              id="DataTables_Table_0_length"
 | 
				
			||||||
@ -175,25 +175,6 @@ const AttendancePage = () => {
 | 
				
			|||||||
                </label>
 | 
					                </label>
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <li
 | 
					 | 
				
			||||||
              className={`nav-item ms-auto ${
 | 
					 | 
				
			||||||
                activeTab === "regularization" ? "d-none" : ""
 | 
					 | 
				
			||||||
              }`}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <label className="switch switch-primary">
 | 
					 | 
				
			||||||
                <input
 | 
					 | 
				
			||||||
                  type="checkbox"
 | 
					 | 
				
			||||||
                  className="switch-input"
 | 
					 | 
				
			||||||
                  checked={showOnlyCheckout}
 | 
					 | 
				
			||||||
                  onChange={handleToggle}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <span className="switch-toggle-slider">
 | 
					 | 
				
			||||||
                  <span className="switch-on"></span>
 | 
					 | 
				
			||||||
                  <span className="switch-off"></span>
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
                <span className="switch-label m-2">Pending Actions</span>
 | 
					 | 
				
			||||||
              </label>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
          </ul>
 | 
					          </ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <ul className="nav nav-tabs" role="tablist">
 | 
					          <ul className="nav nav-tabs" role="tablist">
 | 
				
			||||||
@ -233,9 +214,27 @@ const AttendancePage = () => {
 | 
				
			|||||||
              </button>
 | 
					              </button>
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            
 | 
					            <li
 | 
				
			||||||
 | 
					              className={`nav-item ms-auto ${
 | 
				
			||||||
 | 
					                activeTab === "regularization" ? "d-none" : ""
 | 
				
			||||||
 | 
					              }`}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <label className="switch switch-primary">
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  type="checkbox"
 | 
				
			||||||
 | 
					                  className="switch-input"
 | 
				
			||||||
 | 
					                  checked={showOnlyCheckout}
 | 
				
			||||||
 | 
					                  onChange={handleToggle}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <span className="switch-toggle-slider">
 | 
				
			||||||
 | 
					                  <span className="switch-on"></span>
 | 
				
			||||||
 | 
					                  <span className="switch-off"></span>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					                <span className="switch-label m-2">Pending Actions</span>
 | 
				
			||||||
 | 
					              </label>
 | 
				
			||||||
 | 
					            </li>
 | 
				
			||||||
          </ul>
 | 
					          </ul>
 | 
				
			||||||
          <div className="tab-content attedanceTabs py-2 px-1 px-sm-3">
 | 
					          <div className="tab-content attedanceTabs py-2">
 | 
				
			||||||
            {projectLoading && <span>Loading..</span>}
 | 
					            {projectLoading && <span>Loading..</span>}
 | 
				
			||||||
            {!projectLoading && !attendances && <span>Not Found</span>}
 | 
					            {!projectLoading && !attendances && <span>Not Found</span>}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -26,17 +26,20 @@ const DailyTask = () => {
 | 
				
			|||||||
  const [initialized, setInitialized] = useState(false);
 | 
					  const [initialized, setInitialized] = useState(false);
 | 
				
			||||||
  const dispatch = useDispatch();
 | 
					  const dispatch = useDispatch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // State for filters (moved to FilterIcon, but we need to receive them here)
 | 
				
			||||||
  const [filters, setFilters] = useState({
 | 
					  const [filters, setFilters] = useState({
 | 
				
			||||||
    selectedBuilding: "",
 | 
					    selectedBuilding: "",
 | 
				
			||||||
    selectedFloors: [],
 | 
					    selectedFloors: [],
 | 
				
			||||||
    selectedActivities: [],
 | 
					    selectedActivities: [],
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Sync projectId (either from URL or pick first accessible one)
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (!project_loading && projects.length > 0 && !initialized) {
 | 
					    if (!project_loading && projects.length > 0 && !initialized) {
 | 
				
			||||||
      if (projectIdFromUrl) {
 | 
					      if (projectIdFromUrl) {
 | 
				
			||||||
        dispatch(setProjectId(projectIdFromUrl));
 | 
					        dispatch(setProjectId(projectIdFromUrl));
 | 
				
			||||||
      } else if (selectedProject === 1 || selectedProject === undefined) {
 | 
					      } else if (selectedProject === 1 || selectedProject === undefined) {
 | 
				
			||||||
 | 
					        // If no project from URL or default/undefined, pick the first project
 | 
				
			||||||
        dispatch(setProjectId(projects[0].id));
 | 
					        dispatch(setProjectId(projects[0].id));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      setInitialized(true);
 | 
					      setInitialized(true);
 | 
				
			||||||
@ -54,7 +57,7 @@ const DailyTask = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
    TaskList,
 | 
					    TaskList,
 | 
				
			||||||
    loading: task_loading, 
 | 
					    loading: task_loading, // This `loading` state indicates if task data is being fetched
 | 
				
			||||||
    error: task_error,
 | 
					    error: task_error,
 | 
				
			||||||
    refetch,
 | 
					    refetch,
 | 
				
			||||||
  } = useTaskList(
 | 
					  } = useTaskList(
 | 
				
			||||||
@ -63,11 +66,13 @@ const DailyTask = () => {
 | 
				
			|||||||
    initialized ? dateRange.endDate : null
 | 
					    initialized ? dateRange.endDate : null
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [TaskLists, setTaskLists] = useState([]); 
 | 
					  const [TaskLists, setTaskLists] = useState([]); // This state holds the *filtered* tasks for display
 | 
				
			||||||
  const [dates, setDates] = useState([]);
 | 
					  const [dates, setDates] = useState([]);
 | 
				
			||||||
  const popoverRefs = useRef([]);
 | 
					  const popoverRefs = useRef([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Effect to apply filters to TaskList (from useTaskList) and update TaskLists (filtered display)
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    // Only filter if TaskList is available (not null or undefined)
 | 
				
			||||||
    if (TaskList) {
 | 
					    if (TaskList) {
 | 
				
			||||||
      let filteredTasks = TaskList;
 | 
					      let filteredTasks = TaskList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -96,6 +101,8 @@ const DailyTask = () => {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      setTaskLists(filteredTasks);
 | 
					      setTaskLists(filteredTasks);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					      // If TaskList is null (e.g., during initial load or project change before data arrives),
 | 
				
			||||||
 | 
					      // ensure TaskLists is also empty to avoid displaying stale data.
 | 
				
			||||||
      setTaskLists([]);
 | 
					      setTaskLists([]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [
 | 
					  }, [
 | 
				
			||||||
@ -130,9 +137,19 @@ const DailyTask = () => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    // Ensure Bootstrap's Popover is initialized correctly
 | 
				
			||||||
    popoverRefs.current.forEach((el) => {
 | 
					    popoverRefs.current.forEach((el) => {
 | 
				
			||||||
      if (el) {
 | 
					      if (
 | 
				
			||||||
        new bootstrap.Popover(el, {
 | 
					        el &&
 | 
				
			||||||
 | 
					        window.bootstrap &&
 | 
				
			||||||
 | 
					        typeof window.bootstrap.Popover === "function"
 | 
				
			||||||
 | 
					      ) {
 | 
				
			||||||
 | 
					        // Dispose existing popovers to prevent duplicates if component re-renders
 | 
				
			||||||
 | 
					        const existingPopover = window.bootstrap.Popover.getInstance(el);
 | 
				
			||||||
 | 
					        if (existingPopover) {
 | 
				
			||||||
 | 
					          existingPopover.dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        new window.bootstrap.Popover(el, {
 | 
				
			||||||
          trigger: "focus",
 | 
					          trigger: "focus",
 | 
				
			||||||
          placement: "left",
 | 
					          placement: "left",
 | 
				
			||||||
          html: true,
 | 
					          html: true,
 | 
				
			||||||
@ -140,12 +157,32 @@ const DailyTask = () => {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  },[dates, TaskLists]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Cleanup function for popovers when component unmounts or dependencies change
 | 
				
			||||||
 | 
					    return () => {
 | 
				
			||||||
 | 
					      popoverRefs.current.forEach((el) => {
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					          el &&
 | 
				
			||||||
 | 
					          window.bootstrap &&
 | 
				
			||||||
 | 
					          typeof window.bootstrap.Popover === "function"
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					          const existingPopover = window.bootstrap.Popover.getInstance(el);
 | 
				
			||||||
 | 
					          if (existingPopover) {
 | 
				
			||||||
 | 
					            existingPopover.dispose();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      popoverRefs.current = []; // Clear the refs array
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }, [dates, TaskLists]); // Re-initialize popovers when tasks or dates change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Handler for project selection
 | 
				
			||||||
  const handleProjectChange = (e) => {
 | 
					  const handleProjectChange = (e) => {
 | 
				
			||||||
    const newProjectId = e.target.value;
 | 
					    const newProjectId = e.target.value;
 | 
				
			||||||
    dispatch(setProjectId(newProjectId));
 | 
					    dispatch(setProjectId(newProjectId));
 | 
				
			||||||
    setTaskLists([]); 
 | 
					    // --- IMPORTANT: Clear old data immediately to show loading state ---
 | 
				
			||||||
 | 
					    setTaskLists([]); // This makes the table empty, allowing the spinner to show
 | 
				
			||||||
 | 
					    // Reset filters when project changes (communicate to FilterIcon to clear)
 | 
				
			||||||
    setFilters({
 | 
					    setFilters({
 | 
				
			||||||
      selectedBuilding: "",
 | 
					      selectedBuilding: "",
 | 
				
			||||||
      selectedFloors: [],
 | 
					      selectedFloors: [],
 | 
				
			||||||
@ -155,6 +192,7 @@ const DailyTask = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
 | 
					      {/* Report Task Modal */}
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        className={`modal fade ${isModalOpen ? "show d-block" : ""}`}
 | 
					        className={`modal fade ${isModalOpen ? "show d-block" : ""}`}
 | 
				
			||||||
        tabIndex="-1"
 | 
					        tabIndex="-1"
 | 
				
			||||||
@ -168,8 +206,10 @@ const DailyTask = () => {
 | 
				
			|||||||
          refetch={refetch}
 | 
					          refetch={refetch}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        {isModalOpen && <div className="modal-backdrop fade show"></div>}{" "}
 | 
					        {isModalOpen && <div className="modal-backdrop fade show"></div>}{" "}
 | 
				
			||||||
 | 
					        {/* Add backdrop */}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {/* Report Task Comments Modal */}
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        className={`modal fade ${isModalOpenComment ? "show d-block" : ""}`}
 | 
					        className={`modal fade ${isModalOpenComment ? "show d-block" : ""}`}
 | 
				
			||||||
        tabIndex="-1"
 | 
					        tabIndex="-1"
 | 
				
			||||||
@ -182,6 +222,7 @@ const DailyTask = () => {
 | 
				
			|||||||
          closeModal={closeCommentModal}
 | 
					          closeModal={closeCommentModal}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        {isModalOpenComment && <div className="modal-backdrop fade show"></div>}{" "}
 | 
					        {isModalOpenComment && <div className="modal-backdrop fade show"></div>}{" "}
 | 
				
			||||||
 | 
					        {/* Add backdrop */}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div className="container-xxl flex-grow-1 container-p-y">
 | 
					      <div className="container-xxl flex-grow-1 container-p-y">
 | 
				
			||||||
@ -201,12 +242,15 @@ const DailyTask = () => {
 | 
				
			|||||||
                  DateDifference="6"
 | 
					                  DateDifference="6"
 | 
				
			||||||
                  dateFormat="DD-MM-YYYY"
 | 
					                  dateFormat="DD-MM-YYYY"
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
 | 
					                {/* FilterIcon component now manages its own filter states and logic */}
 | 
				
			||||||
                <FilterIcon
 | 
					                <FilterIcon
 | 
				
			||||||
                  taskListData={TaskList} 
 | 
					                  taskListData={TaskList} // Pass the raw TaskList to FilterIcon
 | 
				
			||||||
                  onApplyFilters={setFilters}
 | 
					                  onApplyFilters={setFilters} // Callback to receive the filtered states from FilterIcon
 | 
				
			||||||
                  currentSelectedBuilding={filters.selectedBuilding}
 | 
					                  currentSelectedBuilding={filters.selectedBuilding}
 | 
				
			||||||
                  currentSelectedFloors={filters.selectedFloors}
 | 
					                  currentSelectedFloors={filters.selectedFloors}
 | 
				
			||||||
                  currentSelectedActivities={filters.selectedActivities}
 | 
					                  currentSelectedActivities={filters.selectedActivities}
 | 
				
			||||||
 | 
					                  // You can pass the project_loading state here if you want to disable filter during project load
 | 
				
			||||||
 | 
					                  // isProjectLoading={project_loading}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              <div className="col-md-4 col-12 text-center mb-2 mb-md-0">
 | 
					              <div className="col-md-4 col-12 text-center mb-2 mb-md-0">
 | 
				
			||||||
@ -217,7 +261,7 @@ const DailyTask = () => {
 | 
				
			|||||||
                  value={selectedProject || ""}
 | 
					                  value={selectedProject || ""}
 | 
				
			||||||
                  onChange={handleProjectChange}
 | 
					                  onChange={handleProjectChange}
 | 
				
			||||||
                  aria-label="Select Project"
 | 
					                  aria-label="Select Project"
 | 
				
			||||||
                  disabled={project_loading}
 | 
					                  disabled={project_loading} // Disable dropdown while projects are loading
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  {project_loading && (
 | 
					                  {project_loading && (
 | 
				
			||||||
                    <option value="" disabled>
 | 
					                    <option value="" disabled>
 | 
				
			||||||
@ -252,6 +296,7 @@ const DailyTask = () => {
 | 
				
			|||||||
                    <tr>
 | 
					                    <tr>
 | 
				
			||||||
                      <td colSpan={6} className="text-center">
 | 
					                      <td colSpan={6} className="text-center">
 | 
				
			||||||
                        {" "}
 | 
					                        {" "}
 | 
				
			||||||
 | 
					                        {/* ColSpan set to 6 based on your table headers */}
 | 
				
			||||||
                        <div className="mt-10 mb-10 pt-5  pb-10">
 | 
					                        <div className="mt-10 mb-10 pt-5  pb-10">
 | 
				
			||||||
                          <div
 | 
					                          <div
 | 
				
			||||||
                            className="spinner-border text-primary"
 | 
					                            className="spinner-border text-primary"
 | 
				
			||||||
@ -264,6 +309,7 @@ const DailyTask = () => {
 | 
				
			|||||||
                      </td>
 | 
					                      </td>
 | 
				
			||||||
                    </tr>
 | 
					                    </tr>
 | 
				
			||||||
                  )}
 | 
					                  )}
 | 
				
			||||||
 | 
					                  {/* --- "No Reports Found" message only if not loading and no tasks --- */}
 | 
				
			||||||
                  {!task_loading &&
 | 
					                  {!task_loading &&
 | 
				
			||||||
                    !project_loading &&
 | 
					                    !project_loading &&
 | 
				
			||||||
                    TaskLists.length === 0 && (
 | 
					                    TaskLists.length === 0 && (
 | 
				
			||||||
@ -271,17 +317,20 @@ const DailyTask = () => {
 | 
				
			|||||||
                        <td colSpan={6} className="text-center">
 | 
					                        <td colSpan={6} className="text-center">
 | 
				
			||||||
                          <div className="mt-10 mb-10 pt-10 pb-10">
 | 
					                          <div className="mt-10 mb-10 pt-10 pb-10">
 | 
				
			||||||
                            {" "}
 | 
					                            {" "}
 | 
				
			||||||
 | 
					                            {/* ColSpan set to 6 */}
 | 
				
			||||||
                            <p>No Reports Found</p>
 | 
					                            <p>No Reports Found</p>
 | 
				
			||||||
                          </div>
 | 
					                          </div>
 | 
				
			||||||
                        </td>
 | 
					                        </td>
 | 
				
			||||||
                      </tr>
 | 
					                      </tr>
 | 
				
			||||||
                    )}
 | 
					                    )}
 | 
				
			||||||
 | 
					                  {/* --- Render tasks when not loading and tasks exist --- */}
 | 
				
			||||||
                  {!task_loading &&
 | 
					                  {!task_loading &&
 | 
				
			||||||
                    TaskLists.length > 0 &&
 | 
					                    TaskLists.length > 0 &&
 | 
				
			||||||
                    dates.map((date, i) => {
 | 
					                    dates.map((date, i) => {
 | 
				
			||||||
                      const tasksForDate = TaskLists.filter((task) =>
 | 
					                      const tasksForDate = TaskLists.filter((task) =>
 | 
				
			||||||
                        task.assignmentDate.includes(date)
 | 
					                        task.assignmentDate.includes(date)
 | 
				
			||||||
                      );
 | 
					                      );
 | 
				
			||||||
 | 
					                      // Only render the date header if there are tasks for that date after filtering
 | 
				
			||||||
                      if (tasksForDate.length === 0) return null;
 | 
					                      if (tasksForDate.length === 0) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                      return (
 | 
					                      return (
 | 
				
			||||||
@ -289,13 +338,14 @@ const DailyTask = () => {
 | 
				
			|||||||
                          <tr className="table-row-header">
 | 
					                          <tr className="table-row-header">
 | 
				
			||||||
                            <td colSpan={6} className="text-start">
 | 
					                            <td colSpan={6} className="text-start">
 | 
				
			||||||
                              {" "}
 | 
					                              {" "}
 | 
				
			||||||
 | 
					                              {/* ColSpan set to 6 */}
 | 
				
			||||||
                              <strong>
 | 
					                              <strong>
 | 
				
			||||||
                                {moment(date).format("DD-MM-YYYY")}
 | 
					                                {moment(date).format("DD-MM-YYYY")}
 | 
				
			||||||
                              </strong>
 | 
					                              </strong>
 | 
				
			||||||
                            </td>
 | 
					                            </td>
 | 
				
			||||||
                          </tr>
 | 
					                          </tr>
 | 
				
			||||||
                          {tasksForDate.map((task, index) => {
 | 
					                          {tasksForDate.map((task, index) => {
 | 
				
			||||||
                            const refIndex = index * 10 + i;
 | 
					                            const refIndex = `${i}-${index}`;
 | 
				
			||||||
                            return (
 | 
					                            return (
 | 
				
			||||||
                              <React.Fragment key={refIndex}>
 | 
					                              <React.Fragment key={refIndex}>
 | 
				
			||||||
                                <tr>
 | 
					                                <tr>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,478 +1,137 @@
 | 
				
			|||||||
import React, { useEffect, useMemo, useState } from "react";
 | 
					import React, { useState } from "react";
 | 
				
			||||||
import Breadcrumb from "../../components/common/Breadcrumb";
 | 
					import Breadcrumb from "../../components/common/Breadcrumb";
 | 
				
			||||||
import IconButton from "../../components/common/IconButton";
 | 
					import IconButton from "../../components/common/IconButton";
 | 
				
			||||||
import GlobalModel from "../../components/common/GlobalModel";
 | 
					import GlobalModel from "../../components/common/GlobalModel";
 | 
				
			||||||
import ManageDirectory from "../../components/Directory/ManageDirectory";
 | 
					import ManageDirectory from "../../components/Directory/ManageDirectory";
 | 
				
			||||||
import ListViewDirectory from "../../components/Directory/ListViewDirectory";
 | 
					 | 
				
			||||||
import { useBuckets, useDirectory } from "../../hooks/useDirectory";
 | 
					 | 
				
			||||||
import { DirectoryRepository } from "../../repositories/DirectoryRepository";
 | 
					 | 
				
			||||||
import { cacheData, getCachedData } from "../../slices/apiDataManager";
 | 
					 | 
				
			||||||
import showToast from "../../services/toastService";
 | 
					 | 
				
			||||||
import UpdateContact from "../../components/Directory/UpdateContact";
 | 
					 | 
				
			||||||
import CardViewDirectory from "../../components/Directory/CardViewDirectory";
 | 
					 | 
				
			||||||
import { useContactCategory } from "../../hooks/masterHook/useMaster";
 | 
					 | 
				
			||||||
import usePagination from "../../hooks/usePagination";
 | 
					 | 
				
			||||||
import { ITEMS_PER_PAGE } from "../../utils/constants";
 | 
					 | 
				
			||||||
import ProfileContactDirectory from "../../components/Directory/ProfileContactDirectory";
 | 
					 | 
				
			||||||
import ConfirmModal from "../../components/common/ConfirmModal";
 | 
					 | 
				
			||||||
import DirectoryListTableHeader from "./DirectoryListTableHeader";
 | 
					 | 
				
			||||||
import DirectoryPageHeader from "./DirectoryPageHeader";
 | 
					 | 
				
			||||||
import ManageBucket from "../../components/Directory/ManageBucket";
 | 
					 | 
				
			||||||
import { useFab } from "../../Context/FabContext";
 | 
					 | 
				
			||||||
import { DireProvider, useDir } from "../../Context/DireContext";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Directory = ({ IsPage = true, prefernceContacts }) => {
 | 
					const Directory = () => {
 | 
				
			||||||
  const [projectPrefernce, setPerfence] = useState(null);
 | 
					 | 
				
			||||||
  const [IsActive, setIsActive] = useState(true);
 | 
					 | 
				
			||||||
  const [isOpenModal, setIsOpenModal] = useState(false);
 | 
					  const [isOpenModal, setIsOpenModal] = useState(false);
 | 
				
			||||||
  const [isOpenModalNote, setIsOpenModalNote] = useState(false);
 | 
					  const closedModel = () => setIsOpenModal(false);
 | 
				
			||||||
  const [selectedContact, setSelectedContact] = useState(null);
 | 
					 | 
				
			||||||
  const [open_contact, setOpen_contact] = useState(null);
 | 
					 | 
				
			||||||
  const [ContactList, setContactList] = useState([]);
 | 
					 | 
				
			||||||
  const [contactCategories, setContactCategories] = useState([]);
 | 
					 | 
				
			||||||
  const [searchText, setSearchText] = useState("");
 | 
					 | 
				
			||||||
  const [listView, setListView] = useState(false);
 | 
					 | 
				
			||||||
  const [selectedBucketIds, setSelectedBucketIds] = useState([]);
 | 
					 | 
				
			||||||
  const [deleteContact, setDeleteContact] = useState(null);
 | 
					 | 
				
			||||||
  const [IsDeleting, setDeleting] = useState(false);
 | 
					 | 
				
			||||||
  const [openBucketModal, setOpenBucketModal] = useState(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const [tempSelectedBucketIds, setTempSelectedBucketIds] = useState([]);
 | 
					 | 
				
			||||||
  const [tempSelectedCategoryIds, setTempSelectedCategoryIds] = useState([]);
 | 
					 | 
				
			||||||
  const { setActions } = useFab();
 | 
					 | 
				
			||||||
  const { dirActions, setDirActions } = useDir();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const { contacts, loading, refetch } = useDirectory(
 | 
					 | 
				
			||||||
    IsActive,
 | 
					 | 
				
			||||||
    projectPrefernce
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  const { contactCategory, loading: contactCategoryLoading } =
 | 
					 | 
				
			||||||
    useContactCategory();
 | 
					 | 
				
			||||||
  const { buckets, refetch: refetchBucket } = useBuckets();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const submitContact = async (data) => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      let response;
 | 
					 | 
				
			||||||
      let updatedContacts;
 | 
					 | 
				
			||||||
      const contacts_cache = getCachedData("contacts")?.data || [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (selectedContact) {
 | 
					 | 
				
			||||||
        response = await DirectoryRepository.UpdateContact(data.id, data);
 | 
					 | 
				
			||||||
        updatedContacts = contacts_cache.map((contact) =>
 | 
					 | 
				
			||||||
          contact.id === data.id ? response.data : contact
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        showToast("Contact updated successfully", "success");
 | 
					 | 
				
			||||||
        setIsOpenModal(false);
 | 
					 | 
				
			||||||
        setSelectedContact(null);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        response = await DirectoryRepository.CreateContact(data);
 | 
					 | 
				
			||||||
        updatedContacts = [...contacts_cache, response.data];
 | 
					 | 
				
			||||||
        showToast("Contact created successfully", "success");
 | 
					 | 
				
			||||||
        setIsOpenModal(false);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // cacheData("Contacts", {data:updatedContacts,isActive:IsActive});
 | 
					 | 
				
			||||||
      // setContactList(updatedContacts);
 | 
					 | 
				
			||||||
      refetch(IsActive, prefernceContacts);
 | 
					 | 
				
			||||||
      refetchBucket();
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      const msg =
 | 
					 | 
				
			||||||
        error.response?.data?.message ||
 | 
					 | 
				
			||||||
        error.message ||
 | 
					 | 
				
			||||||
        "Error occurred during API call!";
 | 
					 | 
				
			||||||
      showToast(msg, "error");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleDeleteContact = async (overrideId = null) => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      if (!IsActive) {
 | 
					 | 
				
			||||||
        setDirActions((prev) => ({ ...prev, action: true }));
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        setDeleting(true);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      const id = overrideId || (!IsActive ? dirActions.id : deleteContact);
 | 
					 | 
				
			||||||
      if (!id) {
 | 
					 | 
				
			||||||
        showToast("No contact selected for deletion", "error");
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      await DirectoryRepository.DeleteContact(id, !IsActive);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const updatedContacts = ContactList.filter((c) => c.id !== id);
 | 
					 | 
				
			||||||
      setContactList(updatedContacts);
 | 
					 | 
				
			||||||
      cacheData("Contacts", { data: updatedContacts, isActive: IsActive });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      showToast(
 | 
					 | 
				
			||||||
        `Contact ${IsActive ? "Deleted" : "Restored"} successfully`,
 | 
					 | 
				
			||||||
        "success"
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setDeleteContact(null);
 | 
					 | 
				
			||||||
      refetchBucket();
 | 
					 | 
				
			||||||
      setDirActions({ action: false, id: null });
 | 
					 | 
				
			||||||
      setDeleting(false);
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      const msg =
 | 
					 | 
				
			||||||
        error?.response?.data?.message ||
 | 
					 | 
				
			||||||
        error.message ||
 | 
					 | 
				
			||||||
        "Error occurred during API call";
 | 
					 | 
				
			||||||
      showToast(msg, "error");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setDeleting(false);
 | 
					 | 
				
			||||||
      setDirActions({ action: false, id: null });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const closedModel = () => {
 | 
					 | 
				
			||||||
    setIsOpenModal(false);
 | 
					 | 
				
			||||||
    setSelectedContact(null);
 | 
					 | 
				
			||||||
    setOpen_contact(null);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const [selectedCategoryIds, setSelectedCategoryIds] = useState(
 | 
					 | 
				
			||||||
    contactCategory.map((category) => category.id)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    setContactList(contacts);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setTempSelectedCategoryIds([]);
 | 
					 | 
				
			||||||
    setTempSelectedBucketIds([]);
 | 
					 | 
				
			||||||
  }, [contacts]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const usedCategoryIds = [
 | 
					 | 
				
			||||||
    ...new Set(contacts.map((c) => c.contactCategory?.id)),
 | 
					 | 
				
			||||||
  ];
 | 
					 | 
				
			||||||
  const filteredCategories = contactCategory.filter((category) =>
 | 
					 | 
				
			||||||
    usedCategoryIds.includes(category.id)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  const handleTempBucketChange = (id) => {
 | 
					 | 
				
			||||||
    setTempSelectedBucketIds((prev) =>
 | 
					 | 
				
			||||||
      prev.includes(id) ? prev.filter((bid) => bid !== id) : [...prev, id]
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleTempCategoryChange = (id) => {
 | 
					 | 
				
			||||||
    setTempSelectedCategoryIds((prev) =>
 | 
					 | 
				
			||||||
      prev.includes(id) ? prev.filter((cid) => cid !== id) : [...prev, id]
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const usedBucketIds = [
 | 
					 | 
				
			||||||
    ...new Set(contacts.flatMap((c) => c.bucketIds || [])),
 | 
					 | 
				
			||||||
  ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const filteredBuckets = buckets.filter((bucket) =>
 | 
					 | 
				
			||||||
    usedBucketIds.includes(bucket.id)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const filteredContacts = useMemo(() => {
 | 
					 | 
				
			||||||
    return ContactList.filter((c) => {
 | 
					 | 
				
			||||||
      const matchesSearch =
 | 
					 | 
				
			||||||
        c.name.toLowerCase().includes(searchText.toLowerCase()) ||
 | 
					 | 
				
			||||||
        c.organization.toLowerCase().includes(searchText.toLowerCase());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const matchesCategory =
 | 
					 | 
				
			||||||
        selectedCategoryIds.length === 0 ||
 | 
					 | 
				
			||||||
        selectedCategoryIds.includes(c.contactCategory?.id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const matchesBucket =
 | 
					 | 
				
			||||||
        selectedBucketIds.length === 0 ||
 | 
					 | 
				
			||||||
        (c.bucketIds || []).some((id) => selectedBucketIds.includes(id));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return matchesSearch && matchesCategory && matchesBucket;
 | 
					 | 
				
			||||||
    }).sort((a, b) => a.name.localeCompare(b.name));
 | 
					 | 
				
			||||||
  }, [
 | 
					 | 
				
			||||||
    ContactList,
 | 
					 | 
				
			||||||
    searchText,
 | 
					 | 
				
			||||||
    selectedCategoryIds,
 | 
					 | 
				
			||||||
    selectedBucketIds,
 | 
					 | 
				
			||||||
    selectedContact,
 | 
					 | 
				
			||||||
  ]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const applyFilter = () => {
 | 
					 | 
				
			||||||
    setSelectedBucketIds(tempSelectedBucketIds);
 | 
					 | 
				
			||||||
    setSelectedCategoryIds(tempSelectedCategoryIds);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const clearFilter = () => {
 | 
					 | 
				
			||||||
    setTempSelectedBucketIds([]);
 | 
					 | 
				
			||||||
    setTempSelectedCategoryIds([]);
 | 
					 | 
				
			||||||
    setSelectedBucketIds([]);
 | 
					 | 
				
			||||||
    setSelectedCategoryIds([]);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const { currentPage, totalPages, currentItems, paginate } = usePagination(
 | 
					 | 
				
			||||||
    filteredContacts,
 | 
					 | 
				
			||||||
    ITEMS_PER_PAGE
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const renderModalContent = () => {
 | 
					 | 
				
			||||||
    if (selectedContact) {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        <UpdateContact
 | 
					 | 
				
			||||||
          existingContact={selectedContact}
 | 
					 | 
				
			||||||
          submitContact={submitContact}
 | 
					 | 
				
			||||||
          onCLosed={closedModel}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!open_contact) {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        <ManageDirectory submitContact={submitContact} onCLosed={closedModel} />
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const actions = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (IsPage) {
 | 
					 | 
				
			||||||
      actions.push({
 | 
					 | 
				
			||||||
        label: "Manage Bucket",
 | 
					 | 
				
			||||||
        icon: "fa-solid fa-bucket fs-5",
 | 
					 | 
				
			||||||
        color: "primary",
 | 
					 | 
				
			||||||
        onClick: () => setOpenBucketModal(true),
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (buckets?.length > 0) {
 | 
					 | 
				
			||||||
      actions.push({
 | 
					 | 
				
			||||||
        label: "New Contact",
 | 
					 | 
				
			||||||
        icon: "bx bx-plus-circle",
 | 
					 | 
				
			||||||
        color: "warning",
 | 
					 | 
				
			||||||
        onClick: () => setIsOpenModal(true),
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setActions(actions);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return () => setActions([]);
 | 
					 | 
				
			||||||
  }, [IsPage, buckets]);
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    setPerfence(prefernceContacts);
 | 
					 | 
				
			||||||
  }, [prefernceContacts]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="container-xxl flex-grow-1 container-p-y">
 | 
					    <div className="container-xxl flex-grow-1 container-p-y">
 | 
				
			||||||
      {IsPage && (
 | 
					 | 
				
			||||||
      <Breadcrumb
 | 
					      <Breadcrumb
 | 
				
			||||||
        data={[
 | 
					        data={[
 | 
				
			||||||
          { label: "Home", link: "/dashboard" },
 | 
					          { label: "Home", link: "/dashboard" },
 | 
				
			||||||
            { label: "Directory", link: null },
 | 
					          { label: "Directory (Comming Soon)", link: null },
 | 
				
			||||||
        ]}
 | 
					        ]}
 | 
				
			||||||
      ></Breadcrumb>
 | 
					      ></Breadcrumb>
 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {isOpenModal && (
 | 
					      <GlobalModel isOpen={isOpenModal} closeModal={closedModel}>
 | 
				
			||||||
        <GlobalModel
 | 
					        <ManageDirectory />
 | 
				
			||||||
          isOpen={isOpenModal}
 | 
					 | 
				
			||||||
          closeModal={() => {
 | 
					 | 
				
			||||||
            setSelectedContact(null);
 | 
					 | 
				
			||||||
            setIsOpenModal(false);
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
          size="xl"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          {renderModalContent()}
 | 
					 | 
				
			||||||
      </GlobalModel>
 | 
					      </GlobalModel>
 | 
				
			||||||
      )}
 | 
					
 | 
				
			||||||
      {isOpenModalNote && (
 | 
					      <div className="row">
 | 
				
			||||||
        <GlobalModel
 | 
					        <div className="row mx-0 px-0">
 | 
				
			||||||
          isOpen={isOpenModalNote}
 | 
					          <div className="col-md-4 col-6 flex-grow-1 mb-2 px-1">
 | 
				
			||||||
          closeModal={() => {
 | 
					            <input
 | 
				
			||||||
            setOpen_contact(null);
 | 
					              type="search"
 | 
				
			||||||
            setIsOpenModalNote(false);
 | 
					              className="form-control form-control-sm"
 | 
				
			||||||
          }}
 | 
					              placeholder="Search projects..."
 | 
				
			||||||
          size="xl"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          {open_contact && (
 | 
					 | 
				
			||||||
            <ProfileContactDirectory
 | 
					 | 
				
			||||||
              contact={open_contact}
 | 
					 | 
				
			||||||
              setOpen_contact={setOpen_contact}
 | 
					 | 
				
			||||||
              closeModal={() => setIsOpenModalNote(false)}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </GlobalModel>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
      {deleteContact && (
 | 
					 | 
				
			||||||
        <div
 | 
					 | 
				
			||||||
          className={`modal fade  ${deleteContact ? "show" : ""}`}
 | 
					 | 
				
			||||||
          tabIndex="-1"
 | 
					 | 
				
			||||||
          role="dialog"
 | 
					 | 
				
			||||||
          style={{
 | 
					 | 
				
			||||||
            display: deleteContact ? "block" : "none",
 | 
					 | 
				
			||||||
            backgroundColor: deleteContact ? "rgba(0,0,0,0.5)" : "transparent",
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
          aria-hidden="false"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <ConfirmModal
 | 
					 | 
				
			||||||
            type={"delete"}
 | 
					 | 
				
			||||||
            header={"Delete Contact"}
 | 
					 | 
				
			||||||
            message={"Are you sure you want delete?"}
 | 
					 | 
				
			||||||
            onSubmit={handleDeleteContact}
 | 
					 | 
				
			||||||
            onClose={() => setDeleteContact(null)}
 | 
					 | 
				
			||||||
            loading={IsDeleting}
 | 
					 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
      )}
 | 
					          <div className="col-md-8 col-6 text-end flex-grow-1 mb-2 px-1">
 | 
				
			||||||
 | 
					 | 
				
			||||||
      {openBucketModal && (
 | 
					 | 
				
			||||||
        <GlobalModel
 | 
					 | 
				
			||||||
          isOpen={openBucketModal}
 | 
					 | 
				
			||||||
          closeModal={() => setOpenBucketModal(false)}
 | 
					 | 
				
			||||||
          size="lg"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <ManageBucket buckets={buckets} />
 | 
					 | 
				
			||||||
        </GlobalModel>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div className="card p-2 card-minHeight">
 | 
					 | 
				
			||||||
        <DirectoryPageHeader
 | 
					 | 
				
			||||||
          searchText={searchText}
 | 
					 | 
				
			||||||
          setSearchText={setSearchText}
 | 
					 | 
				
			||||||
          setIsActive={setIsActive}
 | 
					 | 
				
			||||||
          listView={listView}
 | 
					 | 
				
			||||||
          setListView={setListView}
 | 
					 | 
				
			||||||
          filteredBuckets={filteredBuckets}
 | 
					 | 
				
			||||||
          tempSelectedBucketIds={tempSelectedBucketIds}
 | 
					 | 
				
			||||||
          handleTempBucketChange={handleTempBucketChange}
 | 
					 | 
				
			||||||
          filteredCategories={filteredCategories}
 | 
					 | 
				
			||||||
          tempSelectedCategoryIds={tempSelectedCategoryIds}
 | 
					 | 
				
			||||||
          handleTempCategoryChange={handleTempCategoryChange}
 | 
					 | 
				
			||||||
          clearFilter={clearFilter}
 | 
					 | 
				
			||||||
          applyFilter={applyFilter}
 | 
					 | 
				
			||||||
          loading={loading}
 | 
					 | 
				
			||||||
          IsActive={IsActive}
 | 
					 | 
				
			||||||
          setOpenBucketModal={setOpenBucketModal}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {/* Messages when listView is false */}
 | 
					 | 
				
			||||||
        {!listView && (
 | 
					 | 
				
			||||||
          <div className="d-flex flex-column justify-content-center align-items-center text-center ">
 | 
					 | 
				
			||||||
            {loading && <p className="mt-10">Loading...</p>}
 | 
					 | 
				
			||||||
            {!loading && contacts?.length === 0 && (
 | 
					 | 
				
			||||||
              <p className="mt-10">No contact found</p>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
            {!loading && contacts?.length > 0 && currentItems.length === 0 && (
 | 
					 | 
				
			||||||
              <p className="mt-10">No matching contact found</p>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {/* Table view (listView === true) */}
 | 
					 | 
				
			||||||
        {listView ? (
 | 
					 | 
				
			||||||
          <DirectoryListTableHeader>
 | 
					 | 
				
			||||||
            {loading && (
 | 
					 | 
				
			||||||
              <tr>
 | 
					 | 
				
			||||||
                <td colSpan={10}>
 | 
					 | 
				
			||||||
                  {" "}
 | 
					 | 
				
			||||||
                  <p className="mt-10">Loading...</p>{" "}
 | 
					 | 
				
			||||||
                </td>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            {!loading && contacts?.length === 0 && (
 | 
					 | 
				
			||||||
              <tr>
 | 
					 | 
				
			||||||
                <td colSpan={10}>
 | 
					 | 
				
			||||||
                  <p className="mt-10">No contact found</p>
 | 
					 | 
				
			||||||
                </td>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            {!loading && currentItems.length === 0 && contacts?.length > 0 && (
 | 
					 | 
				
			||||||
              <tr>
 | 
					 | 
				
			||||||
                <td colSpan={10}>
 | 
					 | 
				
			||||||
                  <p className="mt-10">No matching contact found</p>
 | 
					 | 
				
			||||||
                </td>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            {!loading &&
 | 
					 | 
				
			||||||
              currentItems.map((contact) => (
 | 
					 | 
				
			||||||
                <ListViewDirectory
 | 
					 | 
				
			||||||
                  key={contact.id}
 | 
					 | 
				
			||||||
                  IsActive={IsActive}
 | 
					 | 
				
			||||||
                  contact={contact}
 | 
					 | 
				
			||||||
                  setSelectedContact={setSelectedContact}
 | 
					 | 
				
			||||||
                  setIsOpenModal={setIsOpenModal}
 | 
					 | 
				
			||||||
                  setOpen_contact={setOpen_contact}
 | 
					 | 
				
			||||||
                  setIsOpenModalNote={setIsOpenModalNote}
 | 
					 | 
				
			||||||
                  IsDeleted={setDeleteContact}
 | 
					 | 
				
			||||||
                  restore={handleDeleteContact}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
              ))}
 | 
					 | 
				
			||||||
          </DirectoryListTableHeader>
 | 
					 | 
				
			||||||
        ) : (
 | 
					 | 
				
			||||||
          <div className="row mt-5">
 | 
					 | 
				
			||||||
            {!loading &&
 | 
					 | 
				
			||||||
              currentItems.map((contact) => (
 | 
					 | 
				
			||||||
                <div
 | 
					 | 
				
			||||||
                  key={contact.id}
 | 
					 | 
				
			||||||
                  className="col-12 col-sm-6 col-md-4 col-lg-4 mb-4"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  <CardViewDirectory
 | 
					 | 
				
			||||||
                    IsActive={IsActive}
 | 
					 | 
				
			||||||
                    contact={contact}
 | 
					 | 
				
			||||||
                    setSelectedContact={setSelectedContact}
 | 
					 | 
				
			||||||
                    setIsOpenModal={setIsOpenModal}
 | 
					 | 
				
			||||||
                    setOpen_contact={setOpen_contact}
 | 
					 | 
				
			||||||
                    setIsOpenModalNote={setIsOpenModalNote}
 | 
					 | 
				
			||||||
                    IsDeleted={setDeleteContact}
 | 
					 | 
				
			||||||
                    restore={handleDeleteContact}
 | 
					 | 
				
			||||||
                  />
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              ))}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {/* Pagination */}
 | 
					 | 
				
			||||||
        {!loading &&
 | 
					 | 
				
			||||||
          contacts?.length > 0 &&
 | 
					 | 
				
			||||||
          currentItems.length > ITEMS_PER_PAGE && (
 | 
					 | 
				
			||||||
            <nav aria-label="Page navigation">
 | 
					 | 
				
			||||||
              <ul className="pagination pagination-sm justify-content-end py-1">
 | 
					 | 
				
			||||||
                <li
 | 
					 | 
				
			||||||
                  className={`page-item ${currentPage === 1 ? "disabled" : ""}`}
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
                    className="page-link btn-xs"
 | 
					              type="button"
 | 
				
			||||||
                    onClick={() => paginate(currentPage - 1)}
 | 
					              className={`btn btn-sm btn-primary `}
 | 
				
			||||||
 | 
					              onClick={() => setIsOpenModal(true)}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
                    «
 | 
					              <i className="bx bx-plus-circle me-2"></i>
 | 
				
			||||||
 | 
					              New Contact
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
                </li>
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
                {[...Array(totalPages)].map((_, index) => (
 | 
					        <div className="table-responsive text-nowrap py-2 ">
 | 
				
			||||||
                  <li
 | 
					          <table className="table px-2">
 | 
				
			||||||
                    key={index}
 | 
					            <thead>
 | 
				
			||||||
                    className={`page-item ${
 | 
					              <tr>
 | 
				
			||||||
                      currentPage === index + 1 ? "active" : ""
 | 
					                <th className="text-start" colSpan="2">
 | 
				
			||||||
                    }`}
 | 
					                  Name
 | 
				
			||||||
 | 
					                </th>
 | 
				
			||||||
 | 
					                <th className="px-2">
 | 
				
			||||||
 | 
					                  <div className="d-flex align-items-center gap-1">
 | 
				
			||||||
 | 
					                    <IconButton
 | 
				
			||||||
 | 
					                      size={12}
 | 
				
			||||||
 | 
					                      iconClass="bx bx-envelope"
 | 
				
			||||||
 | 
					                      color="primary"
 | 
				
			||||||
 | 
					                      onClick={() => alert("User icon clicked")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <span>Email</span>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </th>
 | 
				
			||||||
 | 
					                <th className="mx-2">
 | 
				
			||||||
 | 
					                  <div className="d-flex align-items-center m-0 p-0 gap-1">
 | 
				
			||||||
 | 
					                    <IconButton
 | 
				
			||||||
 | 
					                      size={12}
 | 
				
			||||||
 | 
					                      iconClass="bx bx-phone"
 | 
				
			||||||
 | 
					                      color="warning"
 | 
				
			||||||
 | 
					                      onClick={() => alert("User icon clicked")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <span>Phone</span>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </th>
 | 
				
			||||||
 | 
					                <th className="mx-2">
 | 
				
			||||||
 | 
					                  <div className="d-flex align-items-center gap-1">
 | 
				
			||||||
 | 
					                    <IconButton
 | 
				
			||||||
 | 
					                      size={12}
 | 
				
			||||||
 | 
					                      iconClass="bx bxs-grid-alt"
 | 
				
			||||||
 | 
					                      color="info"
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <span>Organization</span>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </th>
 | 
				
			||||||
 | 
					                <th className="mx-2">
 | 
				
			||||||
 | 
					                  <div className="dropdown">
 | 
				
			||||||
 | 
					                    <a
 | 
				
			||||||
 | 
					                      className="dropdown-toggle hide-arrow cursor-pointer align-items-center"
 | 
				
			||||||
 | 
					                      data-bs-toggle="dropdown"
 | 
				
			||||||
 | 
					                      aria-expanded="false"
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                    <button
 | 
					                      Type <i className="bx bx-filter bx-sm"></i>
 | 
				
			||||||
                      className="page-link"
 | 
					                    </a>
 | 
				
			||||||
                      onClick={() => paginate(index + 1)}
 | 
					                    {/* <ul className="dropdown-menu p-2 text-capitalize">
 | 
				
			||||||
                    >
 | 
					                          {[
 | 
				
			||||||
                      {index + 1}
 | 
					                            { id: 1, label: "Active" },
 | 
				
			||||||
                    </button>
 | 
					                            { id: 2, label: "On Hold" },
 | 
				
			||||||
 | 
					                            { id: 3, label: "Inactive" },
 | 
				
			||||||
 | 
					                            { id: 4, label: "Completed" },
 | 
				
			||||||
 | 
					                          ].map(({ id, label }) => (
 | 
				
			||||||
 | 
					                            <li key={id}>
 | 
				
			||||||
 | 
					                              <div className="form-check">
 | 
				
			||||||
 | 
					                                <input
 | 
				
			||||||
 | 
					                                  className="form-check-input  "
 | 
				
			||||||
 | 
					                                  type="checkbox"
 | 
				
			||||||
 | 
					                                  checked={selectedStatuses.includes(id)}
 | 
				
			||||||
 | 
					                                  onChange={() => handleStatusChange(id)}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                                <label className="form-check-label">
 | 
				
			||||||
 | 
					                                  {label}
 | 
				
			||||||
 | 
					                                </label>
 | 
				
			||||||
 | 
					                              </div>
 | 
				
			||||||
                            </li>
 | 
					                            </li>
 | 
				
			||||||
                          ))}
 | 
					                          ))}
 | 
				
			||||||
 | 
					 | 
				
			||||||
                <li
 | 
					 | 
				
			||||||
                  className={`page-item ${
 | 
					 | 
				
			||||||
                    currentPage === totalPages ? "disabled" : ""
 | 
					 | 
				
			||||||
                  }`}
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  <button
 | 
					 | 
				
			||||||
                    className="page-link"
 | 
					 | 
				
			||||||
                    onClick={() => paginate(currentPage + 1)}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    »
 | 
					 | 
				
			||||||
                  </button>
 | 
					 | 
				
			||||||
                </li>
 | 
					 | 
				
			||||||
                        </ul> 
 | 
					                        </ul> 
 | 
				
			||||||
            </nav>
 | 
					                    */}
 | 
				
			||||||
          )}
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </th>
 | 
				
			||||||
 | 
					                <th
 | 
				
			||||||
 | 
					                //   className={`mx-2 ${
 | 
				
			||||||
 | 
					                //     HasManageProject ? "d-sm-table-cell" : "d-none"
 | 
				
			||||||
 | 
					                //   }`}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  Action
 | 
				
			||||||
 | 
					                </th>
 | 
				
			||||||
 | 
					              </tr>
 | 
				
			||||||
 | 
					            </thead>
 | 
				
			||||||
 | 
					            <tbody className="table-border-bottom-0 overflow-auto ">
 | 
				
			||||||
 | 
					              <tr>
 | 
				
			||||||
 | 
					                <td colSpan="12" className="text-center py-4">
 | 
				
			||||||
 | 
					                  comming soon....
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					              </tr>
 | 
				
			||||||
 | 
					            </tbody>
 | 
				
			||||||
 | 
					          </table>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
				
			|||||||
@ -1,39 +0,0 @@
 | 
				
			|||||||
import React from "react";
 | 
					 | 
				
			||||||
import IconButton from "../../components/common/IconButton";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const DirectoryListTableHeader = ({ children }) => {
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="table-responsive text-nowrap py-2">
 | 
					 | 
				
			||||||
      <table className="table px-2">
 | 
					 | 
				
			||||||
        <thead>
 | 
					 | 
				
			||||||
          <tr>
 | 
					 | 
				
			||||||
            <th colSpan={2}>
 | 
					 | 
				
			||||||
              <div className="d-flex align-items-center gap-1">
 | 
					 | 
				
			||||||
                <span>Name</span>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            </th>
 | 
					 | 
				
			||||||
            <th className="px-2 text-start">
 | 
					 | 
				
			||||||
              <div className="d-flex text-center align-items-center gap-1 justify-content-start">
 | 
					 | 
				
			||||||
                <span>Email</span>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            </th>
 | 
					 | 
				
			||||||
            <th className="mx-2">
 | 
					 | 
				
			||||||
              <div className="d-flex align-items-center m-0 p-0 gap-1">
 | 
					 | 
				
			||||||
                <span>Phone</span>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            </th>
 | 
					 | 
				
			||||||
            <th colSpan={2} className="mx-2 ps-20">
 | 
					 | 
				
			||||||
              Organization
 | 
					 | 
				
			||||||
            </th>
 | 
					 | 
				
			||||||
            <th className="mx-2">Category</th>
 | 
					 | 
				
			||||||
            <th>Action</th>
 | 
					 | 
				
			||||||
          </tr>
 | 
					 | 
				
			||||||
        </thead>
 | 
					 | 
				
			||||||
        <tbody className="table-border-bottom-0 overflow-auto">
 | 
					 | 
				
			||||||
          {children}
 | 
					 | 
				
			||||||
        </tbody>
 | 
					 | 
				
			||||||
      </table>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
export default DirectoryListTableHeader;
 | 
					 | 
				
			||||||
@ -1,196 +0,0 @@
 | 
				
			|||||||
import React, { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const DirectoryPageHeader = ({
 | 
					 | 
				
			||||||
  searchText,
 | 
					 | 
				
			||||||
  setSearchText,
 | 
					 | 
				
			||||||
  setIsActive,
 | 
					 | 
				
			||||||
  listView,
 | 
					 | 
				
			||||||
  setListView,
 | 
					 | 
				
			||||||
  filteredBuckets,
 | 
					 | 
				
			||||||
  tempSelectedBucketIds,
 | 
					 | 
				
			||||||
  handleTempBucketChange,
 | 
					 | 
				
			||||||
  filteredCategories,
 | 
					 | 
				
			||||||
  tempSelectedCategoryIds,
 | 
					 | 
				
			||||||
  handleTempCategoryChange,
 | 
					 | 
				
			||||||
  clearFilter,
 | 
					 | 
				
			||||||
  applyFilter,
 | 
					 | 
				
			||||||
  loading,
 | 
					 | 
				
			||||||
  IsActive,
 | 
					 | 
				
			||||||
  setOpenBucketModal,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const [filtered, setFiltered] = useState();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    setFiltered(
 | 
					 | 
				
			||||||
      tempSelectedBucketIds?.length + tempSelectedCategoryIds?.length
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }, [tempSelectedBucketIds, tempSelectedCategoryIds]);
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      {/* <div className="row">vikas</div> */}
 | 
					 | 
				
			||||||
      <div className="row mx-0 px-0 align-items-center mt-2">
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-6 mb-2 px-1 d-flex align-items-center gap-4 ">
 | 
					 | 
				
			||||||
          <input
 | 
					 | 
				
			||||||
            type="search"
 | 
					 | 
				
			||||||
            className="form-control me-2"
 | 
					 | 
				
			||||||
            placeholder="Search Contact..."
 | 
					 | 
				
			||||||
            value={searchText}
 | 
					 | 
				
			||||||
            onChange={(e) => setSearchText(e.target.value)}
 | 
					 | 
				
			||||||
            style={{ width: "200px" }}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
          <div className="d-flex gap-2 ">
 | 
					 | 
				
			||||||
            <button
 | 
					 | 
				
			||||||
              type="button"
 | 
					 | 
				
			||||||
              className={`btn btn-xs ${
 | 
					 | 
				
			||||||
                !listView ? "btn-primary" : "btn-outline-primary"
 | 
					 | 
				
			||||||
              }`}
 | 
					 | 
				
			||||||
              onClick={() => setListView(false)}
 | 
					 | 
				
			||||||
              data-bs-toggle="tooltip"
 | 
					 | 
				
			||||||
              data-bs-offset="0,8"
 | 
					 | 
				
			||||||
              data-bs-placement="top"
 | 
					 | 
				
			||||||
              data-bs-custom-class="tooltip"
 | 
					 | 
				
			||||||
              title="Card View"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <i className="bx bx-grid-alt"></i>
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
            <button
 | 
					 | 
				
			||||||
              type="button"
 | 
					 | 
				
			||||||
              className={`btn btn-xs ${
 | 
					 | 
				
			||||||
                listView ? "btn-primary" : "btn-outline-primary"
 | 
					 | 
				
			||||||
              }`}
 | 
					 | 
				
			||||||
              onClick={() => setListView(true)}
 | 
					 | 
				
			||||||
              data-bs-toggle="tooltip"
 | 
					 | 
				
			||||||
              data-bs-offset="0,8"
 | 
					 | 
				
			||||||
              data-bs-placement="top"
 | 
					 | 
				
			||||||
              data-bs-custom-class="tooltip"
 | 
					 | 
				
			||||||
              title="List View"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <i className="bx bx-list-ul "></i>
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div className="dropdown" style={{ width: "fit-content" }}>
 | 
					 | 
				
			||||||
            <div className="dropdown" style={{ width: "fit-content" }}>
 | 
					 | 
				
			||||||
              <a
 | 
					 | 
				
			||||||
                className="dropdown-toggle hide-arrow cursor-pointer d-flex align-items-center position-relative"
 | 
					 | 
				
			||||||
                data-bs-toggle="dropdown"
 | 
					 | 
				
			||||||
                aria-expanded="false"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <i
 | 
					 | 
				
			||||||
                  className={`fa-solid fa-filter ms-1 fs-5 ${
 | 
					 | 
				
			||||||
                    filtered > 0 ? "text-primary" : "text-muted"
 | 
					 | 
				
			||||||
                  }`}
 | 
					 | 
				
			||||||
                ></i>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                {filtered > 0 && (
 | 
					 | 
				
			||||||
                  <span
 | 
					 | 
				
			||||||
                    className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-warning"
 | 
					 | 
				
			||||||
                    style={{ fontSize: "0.4rem" }}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    {filtered}
 | 
					 | 
				
			||||||
                  </span>
 | 
					 | 
				
			||||||
                )}
 | 
					 | 
				
			||||||
              </a>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              <ul className="dropdown-menu p-3" style={{ width: "320px" }}>
 | 
					 | 
				
			||||||
                <div>
 | 
					 | 
				
			||||||
                  <p className="text-muted m-0 h6 ">Filter by</p>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                  {/* Bucket Filter */}
 | 
					 | 
				
			||||||
                  <div className="mt-1">
 | 
					 | 
				
			||||||
                    <p className="text-small mb-1 ">Buckets</p>
 | 
					 | 
				
			||||||
                    <div className="d-flex flex-wrap">
 | 
					 | 
				
			||||||
                      {filteredBuckets.map(({ id, name }) => (
 | 
					 | 
				
			||||||
                        <div
 | 
					 | 
				
			||||||
                          className="form-check me-3 mb-1"
 | 
					 | 
				
			||||||
                          style={{ minWidth: "33.33%" }}
 | 
					 | 
				
			||||||
                          key={id}
 | 
					 | 
				
			||||||
                        >
 | 
					 | 
				
			||||||
                          <input
 | 
					 | 
				
			||||||
                            className="form-check-input"
 | 
					 | 
				
			||||||
                            type="checkbox"
 | 
					 | 
				
			||||||
                            id={`bucket-${id}`}
 | 
					 | 
				
			||||||
                            checked={tempSelectedBucketIds.includes(id)}
 | 
					 | 
				
			||||||
                            onChange={() => handleTempBucketChange(id)}
 | 
					 | 
				
			||||||
                          />
 | 
					 | 
				
			||||||
                          <label
 | 
					 | 
				
			||||||
                            className="form-check-label text-nowrap text-small "
 | 
					 | 
				
			||||||
                            htmlFor={`bucket-${id}`}
 | 
					 | 
				
			||||||
                          >
 | 
					 | 
				
			||||||
                            {name}
 | 
					 | 
				
			||||||
                          </label>
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                      ))}
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                  <hr className="m-0" />
 | 
					 | 
				
			||||||
                  {/* Category Filter */}
 | 
					 | 
				
			||||||
                  <div className="mt-1">
 | 
					 | 
				
			||||||
                    <p className="text-small mb-1 ">Categories</p>
 | 
					 | 
				
			||||||
                    <div className="d-flex flex-wrap">
 | 
					 | 
				
			||||||
                      {filteredCategories.map(({ id, name }) => (
 | 
					 | 
				
			||||||
                        <div
 | 
					 | 
				
			||||||
                          className="form-check me-3 mb-1"
 | 
					 | 
				
			||||||
                          style={{ minWidth: "33.33%" }}
 | 
					 | 
				
			||||||
                          key={id}
 | 
					 | 
				
			||||||
                        >
 | 
					 | 
				
			||||||
                          <input
 | 
					 | 
				
			||||||
                            className="form-check-input"
 | 
					 | 
				
			||||||
                            type="checkbox"
 | 
					 | 
				
			||||||
                            id={`cat-${id}`}
 | 
					 | 
				
			||||||
                            checked={tempSelectedCategoryIds.includes(id)}
 | 
					 | 
				
			||||||
                            onChange={() => handleTempCategoryChange(id)}
 | 
					 | 
				
			||||||
                          />
 | 
					 | 
				
			||||||
                          <label
 | 
					 | 
				
			||||||
                            className="form-check-label text-nowrap text-small"
 | 
					 | 
				
			||||||
                            htmlFor={`cat-${id}`}
 | 
					 | 
				
			||||||
                          >
 | 
					 | 
				
			||||||
                            {name}
 | 
					 | 
				
			||||||
                          </label>
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                      ))}
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                  <div className="d-flex justify-content-end gap-2 mt-1">
 | 
					 | 
				
			||||||
                    <button
 | 
					 | 
				
			||||||
                      className="btn btn-xs btn-secondary"
 | 
					 | 
				
			||||||
                      onClick={clearFilter}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      Clear
 | 
					 | 
				
			||||||
                    </button>
 | 
					 | 
				
			||||||
                    <button
 | 
					 | 
				
			||||||
                      className="btn btn-xs btn-primary"
 | 
					 | 
				
			||||||
                      onClick={applyFilter}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      Apply Filter
 | 
					 | 
				
			||||||
                    </button>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </ul>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className="col-12 col-md-6 mb-2 px-1 d-flex justify-content-end gap-2 align-items-center text-end">
 | 
					 | 
				
			||||||
          <label className="switch switch-primary align-self-start mb-2">
 | 
					 | 
				
			||||||
            <input
 | 
					 | 
				
			||||||
              type="checkbox"
 | 
					 | 
				
			||||||
              className="switch-input me-3"
 | 
					 | 
				
			||||||
              onChange={() => setIsActive(!IsActive)}
 | 
					 | 
				
			||||||
              value={IsActive}
 | 
					 | 
				
			||||||
              disabled={loading}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <span className="switch-toggle-slider">
 | 
					 | 
				
			||||||
              <span className="switch-on"></span>
 | 
					 | 
				
			||||||
              <span className="switch-off"></span>
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
            <span className=" list-inline-item ms-12 ">
 | 
					 | 
				
			||||||
              Show Inactive Contacts
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
          </label>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default DirectoryPageHeader;
 | 
					 | 
				
			||||||
@ -212,16 +212,15 @@ const ChangePasswordPage = ({ onClose }) => {
 | 
				
			|||||||
              <p className="p-0 m-0">Password must be:</p>
 | 
					              <p className="p-0 m-0">Password must be:</p>
 | 
				
			||||||
              <p className="p-0 m-0">- at least 8 characters long</p>
 | 
					              <p className="p-0 m-0">- at least 8 characters long</p>
 | 
				
			||||||
              <p className="p-0 m-0">
 | 
					              <p className="p-0 m-0">
 | 
				
			||||||
                - must contain one uppercase, one lowercase letter, at least one
 | 
					                - must contain at least one uppercase letter
 | 
				
			||||||
                number, at least one special character
 | 
					 | 
				
			||||||
              </p>
 | 
					              </p>
 | 
				
			||||||
              {/* <p className="p-0 m-0">
 | 
					              <p className="p-0 m-0">
 | 
				
			||||||
                - must contain at least one lowercase letter
 | 
					                - must contain at least one lowercase letter
 | 
				
			||||||
              </p>
 | 
					              </p>
 | 
				
			||||||
              <p className="p-0 m-0">- must contain at least one number</p>
 | 
					              <p className="p-0 m-0">- must contain at least one number</p>
 | 
				
			||||||
              <p className="p-0 m-0">
 | 
					              <p className="p-0 m-0">
 | 
				
			||||||
                - must contain at least one special character
 | 
					                - must contain at least one special character
 | 
				
			||||||
              </p> */}
 | 
					              </p>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </form>
 | 
					          </form>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,182 +0,0 @@
 | 
				
			|||||||
import React, { useState, useEffect } from "react";
 | 
					 | 
				
			||||||
import { useProjects, useProjectsByEmployee } from "../../hooks/useProjects";
 | 
					 | 
				
			||||||
import EmployeeList from "./EmployeeList";
 | 
					 | 
				
			||||||
import showToast from "../../services/toastService";
 | 
					 | 
				
			||||||
import ProjectRepository from "../../repositories/ProjectRepository";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const AssignToProject = ({ employee, onClose }) => {
 | 
					 | 
				
			||||||
  const { projects, loading } = useProjects();
 | 
					 | 
				
			||||||
  const { projectList,loading:selectedProjectLoding ,refetch} = useProjectsByEmployee(employee?.id);
 | 
					 | 
				
			||||||
  const [isSubmitting,setSubmitting] = useState(false)
 | 
					 | 
				
			||||||
  const [searchTerm, setSearchTerm] = useState("");
 | 
					 | 
				
			||||||
  const [checkedProjects, setCheckedProjects] = useState({});
 | 
					 | 
				
			||||||
  const [selectedEmployees, setSelectedEmployees] = useState([]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (projectList && projectList.length > 0) {
 | 
					 | 
				
			||||||
      const initialChecked = {};
 | 
					 | 
				
			||||||
      const initialSelected = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      projectList.forEach((project) => {
 | 
					 | 
				
			||||||
        initialChecked[project.id] = true;
 | 
					 | 
				
			||||||
        initialSelected.push({
 | 
					 | 
				
			||||||
          jobRoleId: employee.jobRoleId,
 | 
					 | 
				
			||||||
          projectId: project.id,
 | 
					 | 
				
			||||||
          status: true,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setCheckedProjects(initialChecked);
 | 
					 | 
				
			||||||
      setSelectedEmployees(initialSelected);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      setCheckedProjects({});
 | 
					 | 
				
			||||||
      setSelectedEmployees([]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [projectList, employee?.id]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleSearchChange = (e) => {
 | 
					 | 
				
			||||||
    setSearchTerm(e.target.value.toLowerCase());
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const handleCheckboxChange = (projectId) => {
 | 
					 | 
				
			||||||
  const isChecked = !checkedProjects[projectId];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  setCheckedProjects((prev) => ({
 | 
					 | 
				
			||||||
    ...prev,
 | 
					 | 
				
			||||||
    [projectId]: isChecked,
 | 
					 | 
				
			||||||
  }));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const handleSubmit = async () => {
 | 
					 | 
				
			||||||
  const initiallyAssigned = new Set(projectList.map((p) => p.id.toString()));
 | 
					 | 
				
			||||||
  const changes = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Object.entries(checkedProjects).forEach(([projectId, isChecked]) => {
 | 
					 | 
				
			||||||
    const wasAssigned = initiallyAssigned.has(projectId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (wasAssigned && !isChecked) {
 | 
					 | 
				
			||||||
      changes.push({
 | 
					 | 
				
			||||||
        projectId: projectId,
 | 
					 | 
				
			||||||
        jobRoleId: employee.jobRoleId,
 | 
					 | 
				
			||||||
        status: false,
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!wasAssigned && isChecked) {
 | 
					 | 
				
			||||||
      changes.push({
 | 
					 | 
				
			||||||
        projectId: projectId,
 | 
					 | 
				
			||||||
        jobRoleId: employee.jobRoleId,
 | 
					 | 
				
			||||||
        status: true,
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (changes.length === 0) {
 | 
					 | 
				
			||||||
    showToast("Make change before.", "info");
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    setSubmitting(true)
 | 
					 | 
				
			||||||
    await ProjectRepository.updateProjectsByEmployee(employee.id, changes)
 | 
					 | 
				
			||||||
    showToast( "Project assignments updated.", "success" );
 | 
					 | 
				
			||||||
    setSubmitting(false)
 | 
					 | 
				
			||||||
    onClose();
 | 
					 | 
				
			||||||
    refetch(employee.id)
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    const msg = error.response?.data?.message || error.message || "Error during API call.";
 | 
					 | 
				
			||||||
    showToast( msg, "error" );
 | 
					 | 
				
			||||||
    setSubmitting(false)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleClosedModal = () => {
 | 
					 | 
				
			||||||
    onClose();
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const filteredProjects = projects.filter((project) =>
 | 
					 | 
				
			||||||
    project.name.toLowerCase().includes(searchTerm)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="p-2 p-md-0">
 | 
					 | 
				
			||||||
      <p className="fw-semibold fs-6 m-0">Assign to Project</p>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div className="row my-1">
 | 
					 | 
				
			||||||
        <div className="col-12 col-sm-6 col-md-6 mt-2">
 | 
					 | 
				
			||||||
          <input
 | 
					 | 
				
			||||||
            type="text"
 | 
					 | 
				
			||||||
            className="form-control form-control-sm"
 | 
					 | 
				
			||||||
            placeholder="Search projects..."
 | 
					 | 
				
			||||||
            value={searchTerm}
 | 
					 | 
				
			||||||
            onChange={handleSearchChange}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {loading ? (
 | 
					 | 
				
			||||||
        <div className="text-center py-4">
 | 
					 | 
				
			||||||
          <div className="spinner-border text-primary" role="status" />
 | 
					 | 
				
			||||||
          <p className="mt-2">Loading projects...</p>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      ) : (
 | 
					 | 
				
			||||||
        <>
 | 
					 | 
				
			||||||
          <table className="table mt-2 mb-2">
 | 
					 | 
				
			||||||
            <thead>
 | 
					 | 
				
			||||||
              <tr className="text-start">
 | 
					 | 
				
			||||||
                <th>Select Project</th>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            </thead>
 | 
					 | 
				
			||||||
            <tbody>
 | 
					 | 
				
			||||||
              {filteredProjects.length > 0 ? (
 | 
					 | 
				
			||||||
                filteredProjects.map((project) => (
 | 
					 | 
				
			||||||
                  <tr key={project.id}>
 | 
					 | 
				
			||||||
                    <td className="d-flex align-items-center">
 | 
					 | 
				
			||||||
                      <div className="form-check d-flex justify-content-start align-items-center">
 | 
					 | 
				
			||||||
                        <input
 | 
					 | 
				
			||||||
                          className="form-check-input"
 | 
					 | 
				
			||||||
                          type="checkbox"
 | 
					 | 
				
			||||||
                          id={`project-${project.id}`}
 | 
					 | 
				
			||||||
                          checked={checkedProjects[project.id] || false}
 | 
					 | 
				
			||||||
                          onChange={() => handleCheckboxChange( project.id )}
 | 
					 | 
				
			||||||
                          disabled={selectedProjectLoding}
 | 
					 | 
				
			||||||
                          
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        <label
 | 
					 | 
				
			||||||
                          className="form-check-label ms-2"
 | 
					 | 
				
			||||||
                          htmlFor={`project-${project.id}`}
 | 
					 | 
				
			||||||
                        >
 | 
					 | 
				
			||||||
                          {project.name}
 | 
					 | 
				
			||||||
                        </label>
 | 
					 | 
				
			||||||
                      </div>
 | 
					 | 
				
			||||||
                    </td>
 | 
					 | 
				
			||||||
                  </tr>
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
              ) : (
 | 
					 | 
				
			||||||
                <tr>
 | 
					 | 
				
			||||||
                  <td className="text-center text-muted py-3">No projects found.</td>
 | 
					 | 
				
			||||||
                </tr>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </tbody>
 | 
					 | 
				
			||||||
          </table>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          <div className="d-flex justify-content-center gap-2 mt-2">
 | 
					 | 
				
			||||||
            <button onClick={handleSubmit} className="btn btn-primary btn-sm" disabled={selectedProjectLoding || loading || isSubmitting }>
 | 
					 | 
				
			||||||
              {isSubmitting ? "Please Wait...":"Submit"}
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
            <button onClick={handleClosedModal} className="btn btn-secondary btn-sm" disabled={isSubmitting}>
 | 
					 | 
				
			||||||
              Cancel
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default AssignToProject;
 | 
					 | 
				
			||||||
@ -22,8 +22,6 @@ import {
 | 
				
			|||||||
import EmployeeRepository from "../../repositories/EmployeeRepository";
 | 
					import EmployeeRepository from "../../repositories/EmployeeRepository";
 | 
				
			||||||
import ManageEmployee from "../../components/Employee/ManageEmployee";
 | 
					import ManageEmployee from "../../components/Employee/ManageEmployee";
 | 
				
			||||||
import ConfirmModal from "../../components/common/ConfirmModal";
 | 
					import ConfirmModal from "../../components/common/ConfirmModal";
 | 
				
			||||||
import GlobalModel from "../../components/common/GlobalModel";
 | 
					 | 
				
			||||||
import AssignToProject from "./AssignToProject";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EmployeeList = () => {
 | 
					const EmployeeList = () => {
 | 
				
			||||||
  const { profile: loginUser } = useProfile();
 | 
					  const { profile: loginUser } = useProfile();
 | 
				
			||||||
@ -49,8 +47,7 @@ const EmployeeList = () => {
 | 
				
			|||||||
  const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
 | 
					  const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
 | 
				
			||||||
  const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null);
 | 
					  const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null);
 | 
				
			||||||
  const [employeeLodaing, setemployeeLodaing] = useState(false);
 | 
					  const [employeeLodaing, setemployeeLodaing] = useState(false);
 | 
				
			||||||
  const [ selectedEmployee, setSelectEmployee ] = useState( null )
 | 
					
 | 
				
			||||||
  const [IsOpenAsssingModal,setOpenAssignModal] = useState(false)
 | 
					 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleSearch = (e) => {
 | 
					  const handleSearch = (e) => {
 | 
				
			||||||
@ -192,11 +189,7 @@ const EmployeeList = () => {
 | 
				
			|||||||
    setSelectedEmpFordelete(employee);
 | 
					    setSelectedEmpFordelete(employee);
 | 
				
			||||||
    setIsDeleteModalOpen(true);
 | 
					    setIsDeleteModalOpen(true);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  const handleCloseAssignModal = () =>
 | 
					
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    setOpenAssignModal( false )
 | 
					 | 
				
			||||||
    setSelectEmployee(null)
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      {isCreateModalOpen && (
 | 
					      {isCreateModalOpen && (
 | 
				
			||||||
@ -220,8 +213,7 @@ const EmployeeList = () => {
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div> )}
 | 
					      </div>)}
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {IsDeleteModalOpen && (
 | 
					      {IsDeleteModalOpen && (
 | 
				
			||||||
        <div
 | 
					        <div
 | 
				
			||||||
@ -248,11 +240,6 @@ const EmployeeList = () => {
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {IsOpenAsssingModal && ( <GlobalModel isOpen={IsOpenAsssingModal} closeModal={()=>setOpenAssignModal(false)}>
 | 
					 | 
				
			||||||
        <AssignToProject employee={selectedEmployee} onClose={() => setOpenAssignModal( false )} />
 | 
					 | 
				
			||||||
      </GlobalModel>)}
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div className="container-xxl flex-grow-1 container-p-y">
 | 
					      <div className="container-xxl flex-grow-1 container-p-y">
 | 
				
			||||||
        <Breadcrumb
 | 
					        <Breadcrumb
 | 
				
			||||||
          data={[
 | 
					          data={[
 | 
				
			||||||
@ -655,19 +642,6 @@ const EmployeeList = () => {
 | 
				
			|||||||
                                        <i className="bx bx-cog bx-sm"></i>{" "}
 | 
					                                        <i className="bx bx-cog bx-sm"></i>{" "}
 | 
				
			||||||
                                        Manage Role
 | 
					                                        Manage Role
 | 
				
			||||||
                                      </button>
 | 
					                                      </button>
 | 
				
			||||||
                                      <button
 | 
					 | 
				
			||||||
                                        className="dropdown-item py-1"
 | 
					 | 
				
			||||||
                                     
 | 
					 | 
				
			||||||
                                        onClick={() =>
 | 
					 | 
				
			||||||
                                        {
 | 
					 | 
				
			||||||
                                          setSelectEmployee( item ),
 | 
					 | 
				
			||||||
                                          setOpenAssignModal(true)
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                      >
 | 
					 | 
				
			||||||
                                        <i className='bx bx-select-multiple'></i>{" "}
 | 
					 | 
				
			||||||
                                       Assign Project
 | 
					 | 
				
			||||||
                                      </button>
 | 
					 | 
				
			||||||
                                    </>
 | 
					                                    </>
 | 
				
			||||||
                                  )}
 | 
					                                  )}
 | 
				
			||||||
                                </div>
 | 
					                                </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -10,8 +10,6 @@ import {
 | 
				
			|||||||
  useEmployees,
 | 
					  useEmployees,
 | 
				
			||||||
  useEmployeesByProject,
 | 
					  useEmployeesByProject,
 | 
				
			||||||
} from "../../hooks/useEmployees";
 | 
					} from "../../hooks/useEmployees";
 | 
				
			||||||
import { useProfile } from "../../hooks/useProfile";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { useSelector } from "react-redux";
 | 
					import { useSelector } from "react-redux";
 | 
				
			||||||
import EmployeeRepository from "../../repositories/EmployeeRepository";
 | 
					import EmployeeRepository from "../../repositories/EmployeeRepository";
 | 
				
			||||||
import { ComingSoonPage } from "../Misc/ComingSoonPage";
 | 
					import { ComingSoonPage } from "../Misc/ComingSoonPage";
 | 
				
			||||||
@ -19,11 +17,7 @@ import { useNavigate } from "react-router-dom";
 | 
				
			|||||||
import Avatar from "../../components/common/Avatar";
 | 
					import Avatar from "../../components/common/Avatar";
 | 
				
			||||||
import AttendancesEmployeeRecords from "./AttendancesEmployeeRecords";
 | 
					import AttendancesEmployeeRecords from "./AttendancesEmployeeRecords";
 | 
				
			||||||
import ManageEmployee from "../../components/Employee/ManageEmployee";
 | 
					import ManageEmployee from "../../components/Employee/ManageEmployee";
 | 
				
			||||||
import { useChangePassword } from "../../components/Context/ChangePasswordContext";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const EmployeeProfile = () => {
 | 
					const EmployeeProfile = () => {
 | 
				
			||||||
  const { profile } = useProfile();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const projectID = useSelector((store) => store.localVariables.projectId);
 | 
					  const projectID = useSelector((store) => store.localVariables.projectId);
 | 
				
			||||||
  const { employeeId } = useParams();
 | 
					  const { employeeId } = useParams();
 | 
				
			||||||
  // const {employee,loading} = useEmployeeProfile(employeeId)
 | 
					  // const {employee,loading} = useEmployeeProfile(employeeId)
 | 
				
			||||||
@ -101,12 +95,9 @@ const EmployeeProfile = () => {
 | 
				
			|||||||
  if (loading) {
 | 
					  if (loading) {
 | 
				
			||||||
    return <div>Loading...</div>;
 | 
					    return <div>Loading...</div>;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  const { openChangePassword } = useChangePassword();
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>    {showModal && (<div
 | 
				
			||||||
      {" "}
 | 
					 | 
				
			||||||
      {showModal && (
 | 
					 | 
				
			||||||
        <div
 | 
					 | 
				
			||||||
        className={`modal fade ${showModal ? "show" : ""} `}
 | 
					        className={`modal fade ${showModal ? "show" : ""} `}
 | 
				
			||||||
        tabIndex="-1"
 | 
					        tabIndex="-1"
 | 
				
			||||||
        role="dialog"
 | 
					        role="dialog"
 | 
				
			||||||
@ -118,11 +109,14 @@ const EmployeeProfile = () => {
 | 
				
			|||||||
            className="modal-content overflow-y-auto overflow-x-hidden"
 | 
					            className="modal-content overflow-y-auto overflow-x-hidden"
 | 
				
			||||||
            style={{ maxHeight: "90vh" }}
 | 
					            style={{ maxHeight: "90vh" }}
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
              <ManageEmployee employeeId={employeeId} onClosed={closeModal} />
 | 
					            <ManageEmployee
 | 
				
			||||||
 | 
					              employeeId={employeeId}
 | 
				
			||||||
 | 
					              onClosed={closeModal}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        </div>
 | 
					      </div>)}
 | 
				
			||||||
      )}
 | 
					
 | 
				
			||||||
    <div className="container-xxl flex-grow-1 container-p-y">
 | 
					    <div className="container-xxl flex-grow-1 container-p-y">
 | 
				
			||||||
      <Breadcrumb
 | 
					      <Breadcrumb
 | 
				
			||||||
        data={[
 | 
					        data={[
 | 
				
			||||||
@ -192,9 +186,7 @@ const EmployeeProfile = () => {
 | 
				
			|||||||
                            </tr>
 | 
					                            </tr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <tr>
 | 
					                            <tr>
 | 
				
			||||||
                                <td className="fw-medium text-start">
 | 
					                              <td className="fw-medium text-start">Gender:</td>
 | 
				
			||||||
                                  Gender:
 | 
					 | 
				
			||||||
                                </td>
 | 
					 | 
				
			||||||
                              <td className="text-start">
 | 
					                              <td className="text-start">
 | 
				
			||||||
                                {currentEmployee?.gender || <em>NA</em>}
 | 
					                                {currentEmployee?.gender || <em>NA</em>}
 | 
				
			||||||
                              </td>
 | 
					                              </td>
 | 
				
			||||||
@ -237,13 +229,9 @@ const EmployeeProfile = () => {
 | 
				
			|||||||
                              </td>
 | 
					                              </td>
 | 
				
			||||||
                            </tr>
 | 
					                            </tr>
 | 
				
			||||||
                            <tr>
 | 
					                            <tr>
 | 
				
			||||||
                                <td className="fw-medium text-start">
 | 
					                              <td className="fw-medium text-start">Address:</td>
 | 
				
			||||||
                                  Address:
 | 
					 | 
				
			||||||
                                </td>
 | 
					 | 
				
			||||||
                              <td className="text-start">
 | 
					                              <td className="text-start">
 | 
				
			||||||
                                  {currentEmployee?.currentAddress || (
 | 
					                                {currentEmployee?.currentAddress || <em>NA</em>}
 | 
				
			||||||
                                    <em>NA</em>
 | 
					 | 
				
			||||||
                                  )}
 | 
					 | 
				
			||||||
                              </td>
 | 
					                              </td>
 | 
				
			||||||
                            </tr>
 | 
					                            </tr>
 | 
				
			||||||
                          </tbody>
 | 
					                          </tbody>
 | 
				
			||||||
@ -251,18 +239,12 @@ const EmployeeProfile = () => {
 | 
				
			|||||||
                      </div>
 | 
					                      </div>
 | 
				
			||||||
                      <button
 | 
					                      <button
 | 
				
			||||||
                        className="btn btn-primary btn-block"
 | 
					                        className="btn btn-primary btn-block"
 | 
				
			||||||
                          onClick={() => handleShow()}
 | 
					                        onClick={() =>
 | 
				
			||||||
 | 
					                          handleShow()
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                      >
 | 
					                      >
 | 
				
			||||||
                        Edit Profile
 | 
					                        Edit Profile
 | 
				
			||||||
                      </button>
 | 
					                      </button>
 | 
				
			||||||
                        {currentEmployee?.id == profile?.employeeInfo?.id && (
 | 
					 | 
				
			||||||
                          <button
 | 
					 | 
				
			||||||
                            className="btn btn-outline-primary btn-block mt-2"
 | 
					 | 
				
			||||||
                            onClick={() => openChangePassword()}
 | 
					 | 
				
			||||||
                          >
 | 
					 | 
				
			||||||
                            Change Password
 | 
					 | 
				
			||||||
                          </button>
 | 
					 | 
				
			||||||
                        )}
 | 
					 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                  </div>
 | 
					                  </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
@ -285,6 +267,7 @@ const EmployeeProfile = () => {
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import React, { useEffect, useState } from "react";
 | 
					import React, { useEffect, useState } from "react";
 | 
				
			||||||
import { useSelector } from "react-redux";
 | 
					import { useSelector } from "react-redux";
 | 
				
			||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
					import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
				
			||||||
import { ITEMS_PER_PAGE, MANAGE_MASTER } from "../../utils/constants";
 | 
					import { MANAGE_MASTER } from "../../utils/constants";
 | 
				
			||||||
import showToast from "../../services/toastService";
 | 
					import showToast from "../../services/toastService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MasterTable = ({ data, columns, loading, handleModalData }) => {
 | 
					const MasterTable = ({ data, columns, loading, handleModalData }) => {
 | 
				
			||||||
@ -21,7 +21,7 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => {
 | 
				
			|||||||
  const safeData = Array.isArray(data) ? data : [];
 | 
					  const safeData = Array.isArray(data) ? data : [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [currentPage, setCurrentPage] = useState(1);
 | 
					  const [currentPage, setCurrentPage] = useState(1);
 | 
				
			||||||
  const [itemsPerPage] = useState(ITEMS_PER_PAGE);
 | 
					  const [itemsPerPage] = useState(20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const sortKeys = {
 | 
					  const sortKeys = {
 | 
				
			||||||
    "Application Role": "role",
 | 
					    "Application Role": "role",
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,6 @@ import {
 | 
				
			|||||||
import { useDispatch } from "react-redux";
 | 
					import { useDispatch } from "react-redux";
 | 
				
			||||||
import { setProjectId } from "../../slices/localVariablesSlice";
 | 
					import { setProjectId } from "../../slices/localVariablesSlice";
 | 
				
			||||||
import { ComingSoonPage } from "../Misc/ComingSoonPage";
 | 
					import { ComingSoonPage } from "../Misc/ComingSoonPage";
 | 
				
			||||||
import Directory from "../Directory/Directory";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectDetails = () => {
 | 
					const ProjectDetails = () => {
 | 
				
			||||||
  let { projectId } = useParams();
 | 
					  let { projectId } = useParams();
 | 
				
			||||||
@ -118,10 +117,12 @@ const ProjectDetails = () => {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      case "directory": {
 | 
					      case "activities": {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
          <div className="row">
 | 
					          <div className="row">
 | 
				
			||||||
              <Directory IsPage={ false} prefernceContacts={projectDetails.id} />
 | 
					            <div className="col-lg-12 col-xl-12">
 | 
				
			||||||
 | 
					              <ActivityTimeline></ActivityTimeline>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@ import showToast from "../../services/toastService";
 | 
				
			|||||||
import { getCachedData, cacheData } from "../../slices/apiDataManager";
 | 
					import { getCachedData, cacheData } from "../../slices/apiDataManager";
 | 
				
			||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
					import { useHasUserPermission } from "../../hooks/useHasUserPermission";
 | 
				
			||||||
import { useProfile } from "../../hooks/useProfile";
 | 
					import { useProfile } from "../../hooks/useProfile";
 | 
				
			||||||
import { ITEMS_PER_PAGE, MANAGE_PROJECT } from "../../utils/constants";
 | 
					import { MANAGE_PROJECT } from "../../utils/constants";
 | 
				
			||||||
import ProjectListView from "./ProjectListView";
 | 
					import ProjectListView from "./ProjectListView";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectList = () => {
 | 
					const ProjectList = () => {
 | 
				
			||||||
@ -25,7 +25,7 @@ const ProjectList = () => {
 | 
				
			|||||||
  const dispatch = useDispatch();
 | 
					  const dispatch = useDispatch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [currentPage, setCurrentPage] = useState(1);
 | 
					  const [currentPage, setCurrentPage] = useState(1);
 | 
				
			||||||
  const [itemsPerPage] = useState(ITEMS_PER_PAGE);
 | 
					  const [itemsPerPage] = useState(10);
 | 
				
			||||||
  const [searchTerm, setSearchTerm] = useState("");
 | 
					  const [searchTerm, setSearchTerm] = useState("");
 | 
				
			||||||
  const [selectedStatuses, setSelectedStatuses] = useState([
 | 
					  const [selectedStatuses, setSelectedStatuses] = useState([
 | 
				
			||||||
    "b74da4c2-d07e-46f2-9919-e75e49b12731",
 | 
					    "b74da4c2-d07e-46f2-9919-e75e49b12731",
 | 
				
			||||||
@ -37,7 +37,7 @@ const ProjectList = () => {
 | 
				
			|||||||
  const handleShow = () => setShowModal(true);
 | 
					  const handleShow = () => setShowModal(true);
 | 
				
			||||||
  const handleClose = () => setShowModal(false);
 | 
					  const handleClose = () => setShowModal(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const sortingProject = (projects) =>{
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (!loading && Array.isArray(projects)) {
 | 
					    if (!loading && Array.isArray(projects)) {
 | 
				
			||||||
      const grouped = {};
 | 
					      const grouped = {};
 | 
				
			||||||
      projects.forEach((project) => {
 | 
					      projects.forEach((project) => {
 | 
				
			||||||
@ -56,10 +56,6 @@ const ProjectList = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      setProjectList(sortedGrouped);
 | 
					      setProjectList(sortedGrouped);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    sortingProject(projects)
 | 
					 | 
				
			||||||
  }, [projects, loginUser?.projects, loading]);
 | 
					  }, [projects, loginUser?.projects, loading]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
@ -79,7 +75,6 @@ const ProjectList = () => {
 | 
				
			|||||||
        setProjectList( ( prev ) => [ ...prev, response.data ] );
 | 
					        setProjectList( ( prev ) => [ ...prev, response.data ] );
 | 
				
			||||||
        setloading( false )
 | 
					        setloading( false )
 | 
				
			||||||
        reset()
 | 
					        reset()
 | 
				
			||||||
        sortingProject(getCachedData("projectslist"))
 | 
					 | 
				
			||||||
        showToast("Project Created successfully.", "success");
 | 
					        showToast("Project Created successfully.", "success");
 | 
				
			||||||
        setShowModal(false);
 | 
					        setShowModal(false);
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
@ -273,7 +268,7 @@ const ProjectList = () => {
 | 
				
			|||||||
                    <th className="text-start" colSpan={5}>
 | 
					                    <th className="text-start" colSpan={5}>
 | 
				
			||||||
                      Project Name
 | 
					                      Project Name
 | 
				
			||||||
                    </th>
 | 
					                    </th>
 | 
				
			||||||
                    <th className="mx-2 text-start">Contact Person</th>
 | 
					                    <th className="mx-2 text-start">Project Manger</th>
 | 
				
			||||||
                    <th className="mx-2">START DATE</th>
 | 
					                    <th className="mx-2">START DATE</th>
 | 
				
			||||||
                    <th className="mx-2">DEADLINE</th>
 | 
					                    <th className="mx-2">DEADLINE</th>
 | 
				
			||||||
                    <th className="mx-2">Task</th>
 | 
					                    <th className="mx-2">Task</th>
 | 
				
			||||||
@ -341,7 +336,7 @@ const ProjectList = () => {
 | 
				
			|||||||
                    </tr>
 | 
					                    </tr>
 | 
				
			||||||
                  ) : (
 | 
					                  ) : (
 | 
				
			||||||
                    currentItems.map((project) => (
 | 
					                    currentItems.map((project) => (
 | 
				
			||||||
                      <ProjectListView key={project.id} projectData={project} recall={sortingProject} />
 | 
					                      <ProjectListView key={project.id} projectData={project} />
 | 
				
			||||||
                    ))
 | 
					                    ))
 | 
				
			||||||
                  )}
 | 
					                  )}
 | 
				
			||||||
                </tbody>
 | 
					                </tbody>
 | 
				
			||||||
@ -349,7 +344,7 @@ const ProjectList = () => {
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          ) : (
 | 
					          ) : (
 | 
				
			||||||
            currentItems.map((project) => (
 | 
					            currentItems.map((project) => (
 | 
				
			||||||
              <ProjectCard key={project.id} projectData={project} recall={sortingProject} />
 | 
					              <ProjectCard key={project.id} projectData={project} />
 | 
				
			||||||
            ))
 | 
					            ))
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ import ManageProjectInfo from "../../components/Project/ManageProjectInfo";
 | 
				
			|||||||
import showToast from "../../services/toastService";
 | 
					import showToast from "../../services/toastService";
 | 
				
			||||||
import { getCachedData, cacheData } from "../../slices/apiDataManager";
 | 
					import { getCachedData, cacheData } from "../../slices/apiDataManager";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectListView = ({ projectData, recall }) => {
 | 
					const ProjectListView = ({ projectData }) => {
 | 
				
			||||||
  const [projectInfo, setProjectInfo] = useState(projectData);
 | 
					  const [projectInfo, setProjectInfo] = useState(projectData);
 | 
				
			||||||
  const [projectDetails, setProjectDetails] = useState(null);
 | 
					  const [projectDetails, setProjectDetails] = useState(null);
 | 
				
			||||||
  const [showModal, setShowModal] = useState(false);
 | 
					  const [showModal, setShowModal] = useState(false);
 | 
				
			||||||
@ -76,7 +76,6 @@ const ProjectListView = ({ projectData, recall }) => {
 | 
				
			|||||||
            );
 | 
					            );
 | 
				
			||||||
            cacheData("projectslist", updatedProjectsList);
 | 
					            cacheData("projectslist", updatedProjectsList);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          recall(getCachedData("projectslist"));
 | 
					 | 
				
			||||||
          showToast("Project updated successfully.", "success");
 | 
					          showToast("Project updated successfully.", "success");
 | 
				
			||||||
          setShowModal(false);
 | 
					          setShowModal(false);
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
@ -88,8 +87,7 @@ const ProjectListView = ({ projectData, recall }) => {
 | 
				
			|||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      {showModal && projectDetails && (
 | 
					      {showModal && projectDetails && (
 | 
				
			||||||
        <tr>
 | 
					        <div
 | 
				
			||||||
          <td
 | 
					 | 
				
			||||||
          className="modal fade show"
 | 
					          className="modal fade show"
 | 
				
			||||||
          tabIndex="-1"
 | 
					          tabIndex="-1"
 | 
				
			||||||
          role="dialog"
 | 
					          role="dialog"
 | 
				
			||||||
@ -101,8 +99,7 @@ const ProjectListView = ({ projectData, recall }) => {
 | 
				
			|||||||
            handleSubmitForm={handleFormSubmit}
 | 
					            handleSubmitForm={handleFormSubmit}
 | 
				
			||||||
            onClose={handleClose}
 | 
					            onClose={handleClose}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          </td>
 | 
					        </div>
 | 
				
			||||||
        </tr>
 | 
					 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <tr className="py-8">
 | 
					      <tr className="py-8">
 | 
				
			||||||
@ -111,9 +108,7 @@ const ProjectListView = ({ projectData, recall }) => {
 | 
				
			|||||||
            className="text-primary cursor-pointer"
 | 
					            className="text-primary cursor-pointer"
 | 
				
			||||||
            onClick={() => navigate(`/projects/${projectInfo.id}`)}
 | 
					            onClick={() => navigate(`/projects/${projectInfo.id}`)}
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            {projectInfo.shortName
 | 
					            {projectInfo.name}
 | 
				
			||||||
              ? `${projectInfo.name} (${projectInfo.shortName})`
 | 
					 | 
				
			||||||
              : projectInfo.name}
 | 
					 | 
				
			||||||
          </strong>
 | 
					          </strong>
 | 
				
			||||||
        </td>
 | 
					        </td>
 | 
				
			||||||
        <td className="text-start small">{projectInfo.contactPerson}</td>
 | 
					        <td className="text-start small">{projectInfo.contactPerson}</td>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
import { api } from "../utils/axiosClient";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const DirectoryRepository = {
 | 
					 | 
				
			||||||
  GetOrganizations: () => api.get("/api/directory/organization"),
 | 
					 | 
				
			||||||
  GetContacts: (isActive, projectId) => {
 | 
					 | 
				
			||||||
    const params = new URLSearchParams();
 | 
					 | 
				
			||||||
    params.append("active", isActive);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (projectId) {
 | 
					 | 
				
			||||||
      params.append("projectId", projectId);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return api.get(`/api/Directory?${params.toString()}`);
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  CreateContact: (data) => api.post("/api/directory", data),
 | 
					 | 
				
			||||||
  UpdateContact: (id, data) => api.put(`/api/directory/${id}`, data),
 | 
					 | 
				
			||||||
  DeleteContact: (id, isActive) =>
 | 
					 | 
				
			||||||
    api.delete(`/api/directory/${id}/?active=${isActive}`),
 | 
					 | 
				
			||||||
  AssignedBuckets: (id, data) =>
 | 
					 | 
				
			||||||
    api.post(`/api/directory/assign-bucket/${id}`, data),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GetBucktes: () => api.get(`/api/directory/buckets`),
 | 
					 | 
				
			||||||
  CreateBuckets: (data) => api.post(`/api/Directory/bucket`, data),
 | 
					 | 
				
			||||||
  UpdateBuckets: (id, data) => api.put(`/api/Directory/bucket/${id}`, data),
 | 
					 | 
				
			||||||
  DeleteBucket: (id) => api.delete(`/api/directory/bucket/${id}`),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GetContactProfile: (id) => api.get(`/api/directory/profile/${id}`),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  CreateNote: (data) => api.post("/api/directory/note", data),
 | 
					 | 
				
			||||||
  GetNote: (id, isActive) =>
 | 
					 | 
				
			||||||
    api.get(`/api/directory/notes/${id}?active=${isActive}`),
 | 
					 | 
				
			||||||
  UpdateNote: (id, data) => api.put(`/api/directory/note/${id}`, data),
 | 
					 | 
				
			||||||
  DeleteNote: (id, isActive) =>
 | 
					 | 
				
			||||||
    api.delete(`/api/directory/note/${id}?active=${isActive}`),
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -40,20 +40,10 @@ export const MasterRespository = {
 | 
				
			|||||||
  "Job Role": ( id ) => api.delete( `/api/roles/jobrole/${ id }` ),
 | 
					  "Job Role": ( id ) => api.delete( `/api/roles/jobrole/${ id }` ),
 | 
				
			||||||
  "Activity": ( id ) => api.delete( `/api/master/activity/delete/${ id }` ),
 | 
					  "Activity": ( id ) => api.delete( `/api/master/activity/delete/${ id }` ),
 | 
				
			||||||
  "Application Role":(id)=>api.delete(`/api/roles/${id}`),
 | 
					  "Application Role":(id)=>api.delete(`/api/roles/${id}`),
 | 
				
			||||||
  "Work Category": ( id ) => api.delete( `api/master/work-category/${ id }` ),
 | 
					  "Work Category": (id) => api.delete(`api/master/work-category/${id}`),
 | 
				
			||||||
  "Contact Category": ( id ) => api.delete( `/api/master/contact-category` ),
 | 
					 | 
				
			||||||
  "Contact Tag" :(id)=>api.delete(`/api/master/contact-tag/${id}`),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getWorkCategory:() => api.get(`/api/master/work-categories`),
 | 
					  getWorkCategory:() => api.get(`/api/master/work-categories`),
 | 
				
			||||||
  createWorkCategory: (data) => api.post(`/api/master/work-category`,data),
 | 
					  createWorkCategory: (data) => api.post(`/api/master/work-category`,data),
 | 
				
			||||||
  updateWorkCategory: ( id, data ) => api.post( `/api/master/work-category/edit/${ id }`, data ),
 | 
					  updateWorkCategory: (id,data) => api.post(`/api/master/work-category/edit/${id}`,data),
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  getContactCategory: () => api.get( `/api/master/contact-categories` ),
 | 
					 | 
				
			||||||
  createContactCategory: (data ) => api.post( `/api/master/contact-category`, data ),
 | 
					 | 
				
			||||||
  updateContactCategory: ( id, data ) => api.post( `/api/master/contact-category/edit/${ id }`, data ),
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  getContactTag: () => api.get( `/api/master/contact-tags` ),
 | 
					 | 
				
			||||||
  createContactTag: (data ) => api.post( `/api/master/contact-tag`, data ),
 | 
					 | 
				
			||||||
  updateContactTag: ( id, data ) => api.post( `/api/master/contact-tag/edit/${ id }`, data )
 | 
					 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -20,9 +20,7 @@ const ProjectRepository = {
 | 
				
			|||||||
  deleteProjectTask:(id)=> api.delete(`/api/project/task/${id}`),
 | 
					  deleteProjectTask:(id)=> api.delete(`/api/project/task/${id}`),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateProject: (id, data) => api.put(`/api/project/update/${id}`, data),
 | 
					  updateProject: (id, data) => api.put(`/api/project/update/${id}`, data),
 | 
				
			||||||
  deleteProject: ( id ) => api.delete( `/projects/${ id }` ),
 | 
					  deleteProject: (id) => api.delete(`/projects/${id}`),
 | 
				
			||||||
  getProjectsByEmployee: ( id ) => api.get( `/api/project/assigned-projects/${ id }` ),
 | 
					 | 
				
			||||||
  updateProjectsByEmployee:(id,data)=>api.post(`/api/project/assign-projects/${id}`,data)
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TasksRepository = {
 | 
					export const TasksRepository = {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
export const THRESH_HOLD = 48;  //  hours
 | 
					export const THRESH_HOLD = 48;  //  hours
 | 
				
			||||||
export const DURATION_TIME = 10; // minutes
 | 
					export const DURATION_TIME = 10; // minutes
 | 
				
			||||||
export const ITEMS_PER_PAGE = 20;
 | 
					 | 
				
			||||||
export const OTP_EXPIRY_SECONDS = 600  // OTP time
 | 
					export const OTP_EXPIRY_SECONDS = 600  // OTP time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323";
 | 
					export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323";
 | 
				
			||||||
@ -28,8 +27,3 @@ export const VIEW_TASK = "9fcc5f87-25e3-4846-90ac-67a71ab92e3c"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const ASSIGN_REPORT_TASK = "6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"
 | 
					export const ASSIGN_REPORT_TASK = "6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DIRECTORY_ADMIN = "4286a13b-bb40-4879-8c6d-18e9e393beda"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const DIRECTORY_MANAGER = "62668630-13ce-4f52-a0f0-db38af2230c5"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const DIRECTORY_USER = "0f919170-92d4-4337-abd3-49b66fc871bb"
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user