From 8c7b52b8819fdbfed0411049ad9cfd89148ec8d4 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Thu, 1 Feb 2024 16:40:43 +0530
Subject: [PATCH 01/83] FIxed build issue by Updating dependency version in
package.json
---
micro-ui/web/core/package.json | 7 +++++++
micro-ui/web/package.json | 7 +++++++
micro-ui/web/workbench/package.json | 7 +++++++
3 files changed, 21 insertions(+)
diff --git a/micro-ui/web/core/package.json b/micro-ui/web/core/package.json
index 4923cc2afe0..554071f4f79 100644
--- a/micro-ui/web/core/package.json
+++ b/micro-ui/web/core/package.json
@@ -51,6 +51,13 @@
"npm-run-all": "4.1.5",
"prettier": "2.1.2"
},
+ "resolutions": {
+ "**/babel-loader": "8.2.2",
+ "**/@babel/core": "7.14.0",
+ "**/@babel/preset-env": "7.14.0",
+ "**/@babel/plugin-transform-modules-commonjs": "7.14.0",
+ "**/polished":"4.2.2"
+ },
"scripts": {
"start": "react-scripts start",
"build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build",
diff --git a/micro-ui/web/package.json b/micro-ui/web/package.json
index 9788619c404..dfb709accbb 100644
--- a/micro-ui/web/package.json
+++ b/micro-ui/web/package.json
@@ -55,6 +55,13 @@
"npm-run-all": "4.1.5",
"prettier": "2.1.2"
},
+ "resolutions": {
+ "**/babel-loader": "8.2.2",
+ "**/@babel/core": "7.14.0",
+ "**/@babel/preset-env": "7.14.0",
+ "**/@babel/plugin-transform-modules-commonjs": "7.14.0",
+ "**/polished":"4.2.2"
+ },
"scripts": {
"start": "react-scripts start",
"build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build",
diff --git a/micro-ui/web/workbench/package.json b/micro-ui/web/workbench/package.json
index 098a6aac640..2a01e85bd81 100644
--- a/micro-ui/web/workbench/package.json
+++ b/micro-ui/web/workbench/package.json
@@ -45,6 +45,13 @@
"npm-run-all": "4.1.5",
"prettier": "2.1.2"
},
+ "resolutions": {
+ "**/babel-loader": "8.2.2",
+ "**/@babel/core": "7.14.0",
+ "**/@babel/preset-env": "7.14.0",
+ "**/@babel/plugin-transform-modules-commonjs": "7.14.0",
+ "**/polished":"4.2.2"
+ },
"scripts": {
"start": "react-scripts start",
"build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build",
From a990445f944450c48e7251bd125fddaa45c6dc9a Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Mon, 5 Feb 2024 14:56:48 +0530
Subject: [PATCH 02/83] Added the Build configs for the Microfrontend Apps
---
build/build-config.yml | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/build/build-config.yml b/build/build-config.yml
index e243dfec3cc..a6ae87042db 100644
--- a/build/build-config.yml
+++ b/build/build-config.yml
@@ -53,3 +53,31 @@ config:
build:
- work-dir: utilities/egov-bff
image-name: egov-bff
+
+
+ #micro frontends
+ - name: builds/Digit-Frontend/modules/core-digit-ui
+ build:
+ - work-dir: micro-ui/
+ dockerfile: micro-ui/web/docker/Dockerfile
+ image-name: core-digit-ui
+
+ - name: builds/Digit-Frontend/modules/dss-ui
+ build:
+ - work-dir: micro-ui/
+ dockerfile: micro-ui/web/docker/Dockerfile
+ image-name: dss-ui
+
+
+ - name: builds/Digit-Frontend/modules/workbench-ui
+ build:
+ - work-dir: micro-ui/
+ dockerfile: micro-ui/web/docker/Dockerfile
+ image-name: workbench-ui
+
+
+ - name: builds/Digit-Frontend/modules/hrms-ui
+ build:
+ - work-dir: micro-ui/
+ dockerfile: micro-ui/web/docker/Dockerfile
+ image-name: hrms-ui
From dbaf47d0fdabeddee9fd189d64646fa1cb64de87 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Tue, 12 Mar 2024 09:51:08 +0530
Subject: [PATCH 03/83] Update build-config.yml
---
build/build-config.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/build/build-config.yml b/build/build-config.yml
index a6ae87042db..7fcfd624e35 100644
--- a/build/build-config.yml
+++ b/build/build-config.yml
@@ -24,6 +24,12 @@ config:
- work-dir: micro-ui/
dockerfile: micro-ui/web/workbench/Dockerfile
image-name: workbench-ui
+
+ - name: builds/Digit-Frontend/microplan-ui
+ build:
+ - work-dir: micro-ui/
+ dockerfile: micro-ui/web/microplan/Dockerfile
+ image-name: microplan-ui
- name: builds/Digit-Frontend/storybook-svg
build:
From 2873b1f2fe6adca134749ffcc141bee2c6e62cf2 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Thu, 2 May 2024 14:23:50 +0530
Subject: [PATCH 04/83] Added PGR code from OSS (Urban) (#431)
* enabled hrms,pgr with workbench
* Added the pgr module code
* added module enable codes
* core 1.8.1 sidebar null check fixes
* updated pgr versions
---
micro-ui/package.json | 2 +-
micro-ui/web/core/App.js | 5 +-
micro-ui/web/core/inter-package.json | 2 +
micro-ui/web/core/package.json | 3 +-
.../micro-ui-internals/example/package.json | 3 +-
.../micro-ui-internals/example/src/index.js | 8 +-
micro-ui/web/micro-ui-internals/package.json | 2 +
.../packages/modules/core/README.md | 1 +
.../packages/modules/core/package.json | 2 +-
.../TopBarSideBar/SideBar/EmployeeSideBar.js | 25 +-
.../TopBarSideBar/SideBar/SideBar.js | 265 +++++++--
.../packages/modules/pgr/README.md | 77 +++
.../packages/modules/pgr/package.json | 33 ++
.../packages/modules/pgr/src/EmployeeApp.js | 13 +
.../packages/modules/pgr/src/Icons.js | 8 +
.../packages/modules/pgr/src/Module.js | 85 +++
.../modules/pgr/src/components/Complaint.js | 41 ++
.../pgr/src/components/DesktopInbox.js | 143 +++++
.../pgr/src/components/FormComposer.js | 86 +++
.../modules/pgr/src/components/MobileInbox.js | 64 +++
.../modules/pgr/src/components/PGRCard.js | 58 ++
.../modules/pgr/src/components/TimeLine.js | 162 ++++++
.../pgr/src/components/inbox/ComplaintCard.js | 75 +++
.../src/components/inbox/ComplaintLinks.js | 68 +++
.../src/components/inbox/ComplaintTable.js | 19 +
.../pgr/src/components/inbox/Filter.js | 227 ++++++++
.../pgr/src/components/inbox/Status.js | 27 +
.../pgr/src/components/inbox/search.js | 110 ++++
.../timelineInstances/PendingForAssignment.js | 8 +
.../PendingForReassignment.js | 5 +
.../components/timelineInstances/StarRated.js | 6 +
.../timelineInstances/pendingAtLme.js | 15 +
.../components/timelineInstances/rejected.js | 55 ++
.../components/timelineInstances/reopen.js | 14 +
.../components/timelineInstances/resolved.js | 55 ++
.../modules/pgr/src/constants/Citizen.js | 3 +
.../modules/pgr/src/constants/Employee.js | 2 +
.../modules/pgr/src/constants/Localization.js | 20 +
.../modules/pgr/src/constants/Routes.js | 37 ++
.../pgr/src/pages/citizen/ComplaintDetails.js | 186 +++++++
.../pgr/src/pages/citizen/ComplaintsList.js | 68 +++
.../pgr/src/pages/citizen/Create/Response.js | 51 ++
.../pages/citizen/Create/Steps/Response.js | 39 ++
.../citizen/Create/Steps/SelectAddress.js | 74 +++
.../Create/Steps/SelectComplaintType.js | 37 ++
.../citizen/Create/Steps/SelectDetails.js | 18 +
.../citizen/Create/Steps/SelectGeolocation.js | 19 +
.../citizen/Create/Steps/SelectImages.js | 36 ++
.../citizen/Create/Steps/SelectLandmark.js | 19 +
.../citizen/Create/Steps/SelectPincode.js | 56 ++
.../citizen/Create/Steps/SelectSubType.js | 34 ++
.../pgr/src/pages/citizen/Create/config.js | 98 ++++
.../src/pages/citizen/Create/defaultConfig.js | 114 ++++
.../pgr/src/pages/citizen/Create/index.js | 129 +++++
.../pgr/src/pages/citizen/Rating/Rating.js | 76 +++
.../src/pages/citizen/Rating/SelectRating.js | 62 +++
.../ReopenComplaint/AddtionalDetails.js | 97 ++++
.../pages/citizen/ReopenComplaint/Reason.js | 57 ++
.../citizen/ReopenComplaint/UploadPhoto.js | 71 +++
.../pages/citizen/ReopenComplaint/index.js | 28 +
.../modules/pgr/src/pages/citizen/Response.js | 59 ++
.../modules/pgr/src/pages/citizen/index.js | 48 ++
.../src/pages/employee/ComplaintDetails.js | 504 ++++++++++++++++++
.../pages/employee/CreateComplaint/index.js | 261 +++++++++
.../modules/pgr/src/pages/employee/Inbox.js | 82 +++
.../pgr/src/pages/employee/Response.js | 48 ++
.../modules/pgr/src/pages/employee/index.js | 89 ++++
.../pgr/src/redux/actions/complaint.js | 41 ++
.../modules/pgr/src/redux/actions/index.js | 52 ++
.../modules/pgr/src/redux/actions/types.js | 16 +
.../src/redux/reducers/complaintReducer.js | 18 +
.../modules/pgr/src/redux/reducers/index.js | 9 +
.../packages/modules/pgr/src/redux/store.js | 14 +
.../modules/pgr/src/selectors/complaint.js | 3 +
.../pgr/src/selectors/processInstance.js | 1 +
micro-ui/web/micro-ui-internals/publish.sh | 5 +-
micro-ui/web/package.json | 5 +-
micro-ui/web/src/App.js | 9 +-
micro-ui/web/workbench/App.js | 15 +-
micro-ui/web/workbench/package.json | 5 +-
micro-ui/web/workbench/webpack.config.js | 4 +
81 files changed, 4410 insertions(+), 81 deletions(-)
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/README.md
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/EmployeeApp.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Icons.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Module.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/Complaint.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/DesktopInbox.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/FormComposer.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/MobileInbox.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/PGRCard.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/TimeLine.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintCard.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintLinks.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintTable.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Filter.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Status.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/search.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForAssignment.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForReassignment.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/StarRated.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/pendingAtLme.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/rejected.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/reopen.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/resolved.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Citizen.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Employee.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Localization.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Routes.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintDetails.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintsList.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Response.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/Response.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectAddress.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectComplaintType.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectDetails.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectGeolocation.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectImages.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectLandmark.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectPincode.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectSubType.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/config.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/defaultConfig.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/index.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/Rating.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/SelectRating.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/AddtionalDetails.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/Reason.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/UploadPhoto.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/index.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Response.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/index.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/ComplaintDetails.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/CreateComplaint/index.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Inbox.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Response.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/index.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/complaint.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/index.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/types.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/complaintReducer.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/index.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/store.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/complaint.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/processInstance.js
diff --git a/micro-ui/package.json b/micro-ui/package.json
index 19a3c47d6ee..b87ac65e859 100644
--- a/micro-ui/package.json
+++ b/micro-ui/package.json
@@ -1,4 +1,4 @@
{
"name": "workbench-ui",
- "version": "1.0.0"
+ "version": "1.8.0"
}
\ No newline at end of file
diff --git a/micro-ui/web/core/App.js b/micro-ui/web/core/App.js
index df812819252..5f6261e53b5 100644
--- a/micro-ui/web/core/App.js
+++ b/micro-ui/web/core/App.js
@@ -4,6 +4,8 @@ import { DigitUI } from "@egovernments/digit-ui-module-core";
import { UICustomizations } from "./Customisations/UICustomizations";
import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
+import { initPGRComponents,PGRReducers } from "@egovernments/digit-ui-module-pgr";
+
window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
const enabledModules = [
@@ -15,7 +17,7 @@ const enabledModules = [
];
const moduleReducers = (initData) => ({
- initData,
+ initData, pgr: PGRReducers(initData),
});
const initDigitUI = () => {
@@ -26,6 +28,7 @@ const initDigitUI = () => {
};
initUtilitiesComponents();
initWorkbenchComponents();
+ initPGRComponents();
};
initLibraries().then(() => {
diff --git a/micro-ui/web/core/inter-package.json b/micro-ui/web/core/inter-package.json
index db4893077d1..db6e884f6ce 100644
--- a/micro-ui/web/core/inter-package.json
+++ b/micro-ui/web/core/inter-package.json
@@ -25,6 +25,7 @@
"dev:example": "cd example && yarn start",
"dev:core": "cd packages/modules/core && yarn start",
"dev:dss": "cd packages/modules/dss && yarn start",
+ "dev:pgr": "cd packages/modules/pgr && yarn start",
"dev:hrms": "cd packages/modules/hrms && yarn start",
"devD:common": "cd packages/modules/common && yarn start",
"devD:utilities": "cd packages/modules/utilities && yarn start",
@@ -36,6 +37,7 @@
"build:svgcomponents": "cd packages/svg-components && yarn build",
"buildD:dss": "cd packages/modules/dss && yarn build",
"buildD:core": "cd packages/modules/core && yarn build",
+ "buildD:pgr": "cd packages/modules/pgr && yarn build",
"buildD:hrms": "cd packages/modules/hrms && yarn build",
"buildD:common": "cd packages/modules/common && yarn build",
"buildD:utilities": "cd packages/modules/utilities && yarn build",
diff --git a/micro-ui/web/core/package.json b/micro-ui/web/core/package.json
index 554071f4f79..264a386922e 100644
--- a/micro-ui/web/core/package.json
+++ b/micro-ui/web/core/package.json
@@ -16,7 +16,8 @@
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.0",
"@egovernments/digit-ui-module-workbench": "1.0.1",
- "@egovernments/digit-ui-module-core": "1.8.0",
+ "@egovernments/digit-ui-module-core": "1.8.1",
+ "@egovernments/digit-ui-module-pgr": "1.8.0",
"@egovernments/digit-ui-react-components": "1.8.0",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"babel-loader": "8.1.0",
diff --git a/micro-ui/web/micro-ui-internals/example/package.json b/micro-ui/web/micro-ui-internals/example/package.json
index bb5f657d59c..236dc6960a4 100644
--- a/micro-ui/web/micro-ui-internals/example/package.json
+++ b/micro-ui/web/micro-ui-internals/example/package.json
@@ -12,8 +12,9 @@
"@egovernments/digit-ui-libraries": "1.8.0",
"@egovernments/digit-ui-module-workbench": "1.0.1",
"@egovernments/digit-ui-module-dss": "1.8.0",
- "@egovernments/digit-ui-module-core": "1.8.0",
+ "@egovernments/digit-ui-module-core": "1.8.1",
"@egovernments/digit-ui-module-common": "1.8.0",
+ "@egovernments/digit-ui-module-pgr": "1.8.0",
"@egovernments/digit-ui-module-hrms": "1.8.0",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"@egovernments/digit-ui-module-engagement": "1.8.0",
diff --git a/micro-ui/web/micro-ui-internals/example/src/index.js b/micro-ui/web/micro-ui-internals/example/src/index.js
index e2946604fc0..a815cae05e7 100644
--- a/micro-ui/web/micro-ui-internals/example/src/index.js
+++ b/micro-ui/web/micro-ui-internals/example/src/index.js
@@ -9,6 +9,7 @@ import { initEngagementComponents } from "@egovernments/digit-ui-module-engageme
import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms";
// import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
import {initWorkbenchComponents} from "@egovernments/digit-ui-module-workbench";
+import { PGRReducers , initPGRComponents} from "@egovernments/digit-ui-module-pgr";
import "@egovernments/digit-ui-css/example/index.css";
@@ -19,6 +20,7 @@ var Digit = window.Digit || {};
const enabledModules = [ "DSS", "HRMS",
"Workbench"
+,"PGR"
// "Engagement", "NDSS","QuickPayLinks", "Payment",
// "Utilities",
//added to check fsm
@@ -68,10 +70,12 @@ const initDigitUI = () => {
initEngagementComponents();
// initUtilitiesComponents();
initWorkbenchComponents();
+ initPGRComponents();
- const moduleReducers = (initData) => initData;
-
+ const moduleReducers = (initData) => ({
+ pgr: PGRReducers(initData),
+ });
const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb";
initTokens(stateCode);
diff --git a/micro-ui/web/micro-ui-internals/package.json b/micro-ui/web/micro-ui-internals/package.json
index e6d9e47afb2..19a69c78172 100644
--- a/micro-ui/web/micro-ui-internals/package.json
+++ b/micro-ui/web/micro-ui-internals/package.json
@@ -26,6 +26,7 @@
"dev:components": "cd packages/react-components && yarn start",
"dev:example": "cd example && yarn start",
"dev:core": "cd packages/modules/core && yarn start",
+ "dev:pgr": "cd packages/modules/pgr && yarn start",
"dev:dss": "cd packages/modules/dss && yarn start",
"dev:hrms": "cd packages/modules/hrms && yarn start",
"devD:common": "cd packages/modules/common && yarn start",
@@ -39,6 +40,7 @@
"build:dss": "cd packages/modules/dss && yarn build",
"build:core": "cd packages/modules/core && yarn build",
"build:hrms": "cd packages/modules/hrms && yarn build",
+ "build:pgr": "cd packages/modules/pgr && yarn build",
"build:common": "cd packages/modules/common && yarn build",
"build:utilities": "cd packages/modules/utilities && yarn build",
"build:engagement": "cd packages/modules/engagement && yarn build",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/core/README.md b/micro-ui/web/micro-ui-internals/packages/modules/core/README.md
index e8ad329acf0..0b5a1d4d023 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/core/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/modules/core/README.md
@@ -65,6 +65,7 @@ with
### Changelog
```bash
+1.8.1 sidebar null check fixes
1.8.0 workbench v1.0
1.8.0-beta.5 fix for login screen alignments
1.8.0-beta.4 made the default localisation in globalconfig
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/core/package.json b/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
index 3720d255b0f..7d9a8ef9b01 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-module-core",
- "version": "1.8.0",
+ "version": "1.8.1",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.modern.js",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/EmployeeSideBar.js b/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/EmployeeSideBar.js
index 3314ef65184..1386aa5c5ce 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/EmployeeSideBar.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/EmployeeSideBar.js
@@ -40,12 +40,7 @@ const EmployeeSideBar = () => {
}
mergeObjects(obj1[key], obj2[key]);
} else {
- if (obj1[key]) {
- if (!Array.isArray(obj1[key])) {
- obj1[key] = [obj1[key]];
- }
- obj1[key].push(obj2[key]);
- } else {
+ if (!obj1[key]) {
obj1[key] = obj2[key];
}
}
@@ -96,14 +91,18 @@ const EmployeeSideBar = () => {
const objectArray = Object.entries(configEmployeeSideBar);
// Sort the array based on the 'orderNumber' or the length of the object if 'orderNumber' is not present
+ // sort logic updated to sort the parent item by alphabetical
objectArray.sort((a, b) => {
- const orderNumberA = a[1].item
- ? a[1].item.orderNumber || Object.keys(configEmployeeSideBar).length + 1
- : Object.keys(configEmployeeSideBar).length + 1;
- const orderNumberB = b[1].item
- ? b[1].item.orderNumber || Object.keys(configEmployeeSideBar).length + 1
- : Object.keys(configEmployeeSideBar).length + 1;
- return orderNumberA - orderNumberB;
+ if (a[0] < b[0]) { return -1; }
+ if (a[0] > b[0]) { return 1; }
+ return 0;
+ // const orderNumberA = a[1].item
+ // ? a[1].item.orderNumber || Object.keys(configEmployeeSideBar).length + 1
+ // : Object.keys(configEmployeeSideBar).length + 1;
+ // const orderNumberB = b[1].item
+ // ? b[1].item.orderNumber || Object.keys(configEmployeeSideBar).length + 1
+ // : Object.keys(configEmployeeSideBar).length + 1;
+ // return orderNumberA - orderNumberB;
});
const sortedObject = Object.fromEntries(objectArray);
configEmployeeSideBar = sortedObject;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/SideBar.js b/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/SideBar.js
index 9a38a79a4a8..e17e61c81fd 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/SideBar.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/SideBar/SideBar.js
@@ -6,29 +6,78 @@ import {
HomeIcon,
ComplaintIcon,
BPAHomeIcon,
+ CollectionIcon,
+ FinanceChartIcon,
+ CollectionsBookmarIcons,
+ DropIcon,
+ DocumentIconSolid,
+ PersonIcon,
PropertyHouse,
- CaseIcon,
ReceiptIcon,
- PersonIcon,
- DocumentIconSolid,
- DropIcon,
- CollectionsBookmarIcons,
- FinanceChartIcon,
- CollectionIcon,
+ CaseIcon,
} from "@egovernments/digit-ui-react-components";
import ReactTooltip from "react-tooltip";
import { set } from "lodash";
import { useHistory, useLocation, Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
-const DIGIT_UI_CONTEXTS = ["digit-ui", "works-ui", "workbench-ui", "health-ui", "sanitation-ui", "core-ui","mgramseva-web"];
+const DIGIT_UI_CONTEXTS = [
+ "digit-ui",
+ "works-ui",
+ "workbench-ui",
+ "health-ui",
+ "sanitation-ui",
+ "core-ui",
+ "microplan-ui",
+ "pucar-ui",
+ "selco-ui",
+ "mgramseva-web",
+];
+
+// Function to recursively get the key of a nested object based on a parent key
+const getKey = (obj, parent) => {
+ if (typeof obj !== "object" || obj === null) {
+ // If obj is not an object or is null, return null
+ return null;
+ }
+ // Use Object.keys to get an array of keys in the object
+ const key = Object.keys(obj).map((key) => {
+ // Check if the object has an 'item' property with a 'path' property
+ if (typeof obj[key]?.item?.path === "string") {
+ return (
+ obj[key]?.item?.path?.split(parent ? `${parent}.${key}` : `.${key}`) ||
+ getKey(obj[key], key)
+ );
+ }
+ return null; // or return some default value if neither condition is met
+ });
+ // Return the first element of the array (the key)
+ return key?.[0];
+};
+
+// Function to find the last key in a dot-separated key string
+const findKey = (key = "") => {
+ // Split the key string into an array using dot as a separator
+ const newSplitedList = key?.split(".");
+ // Check if the key string ends with a dot
+ return key?.endsWith?.(".")
+ ? // If it ends with a dot, return the first element of the array
+ newSplitedList[0]
+ : // If not, return the last element of the array
+ newSplitedList[newSplitedList?.length - 1];
+};
+
/*
Used to navigate to other mission's ui if user has access
*/
const navigateToRespectiveURL = (history = {}, url = "") => {
if (url?.indexOf(`/${window?.contextPath}`) === -1) {
const hostUrl = window.location.origin;
- const updatedURL = DIGIT_UI_CONTEXTS?.every((e) => url?.indexOf(`/${e}`) === -1) ? hostUrl + "/employee/" + url : hostUrl + url;
+ const updatedURL = DIGIT_UI_CONTEXTS?.every(
+ (e) => url?.indexOf(`/${e}`) === -1
+ )
+ ? hostUrl + "/employee/" + url
+ : hostUrl + url;
window.location.href = updatedURL;
} else {
history.push(url);
@@ -85,8 +134,8 @@ const Sidebar = ({ data }) => {
if (key === "item" && item?.leftIcon !== "") {
return {
- isDynamic: item.leftIcon.split(":")[0],
- leftIconArray: item.leftIcon.split(":")[1],
+ iconKey: item?.leftIcon?.split(":")?.[0],
+ iconName: item?.leftIcon?.split(":")?.[1],
};
}
@@ -100,54 +149,105 @@ const Sidebar = ({ data }) => {
return null; // Return null if no non-empty leftIcon is found
}
- const renderSidebarItems = (items, parentKey = null, flag = true, level = 0) => {
+ const renderSidebarItems = (
+ items,
+ parentKey = null,
+ flag = true,
+ level = 0
+ ) => {
+ /* added the logic to sort the side bar items based on the ordernumber */
+ const keysArray = Object.values(items)
+ .sort((x, y) => {
+ if (x?.item && y?.item) {
+ return x?.item?.orderNumber - y?.item?.orderNumber;
+ } else {
+ if (x?.[0] < y?.[0]) {
+ return -1;
+ }
+ if (x?.[0] > y?.[0]) {
+ return 1;
+ }
+ return 0;
+ }
+ })
+ .map(
+ (x) =>
+ (x?.item?.path && findKey(x?.item?.path)) || findKey(getKey(x)?.[0])
+ );
+
return (
- {Object.keys(items).map((key, index) => {
+ {keysArray.map((key, index) => {
const subItems = items[key];
- const subItemKeys = Object.keys(subItems)[0] === "item";
+ const subItemKeys = subItems
+ ? Object.keys(subItems)[0] === "item"
+ : null;
const isSubItemOpen = openItems[key] || false;
var itemKey = parentKey ? `${parentKey}` : key;
const getModuleName = key?.replace(/[ -]/g, "_");
- const appendTranslate = t(Digit.Utils.locale.getTransformedLocale(`ACTION_TEST_${getModuleName}`));
- const trimModuleName = t(appendTranslate?.length > 20 ? appendTranslate.substring(0, 20) + "..." : appendTranslate);
+ const appendTranslate = t(
+ Digit.Utils.locale.getTransformedLocale(
+ `ACTION_TEST_${getModuleName}`
+ )
+ );
+ const trimModuleName = t(
+ appendTranslate?.length > 20
+ ? appendTranslate.substring(0, 20) + "..."
+ : appendTranslate
+ );
if (!subItemKeys && subItems && Object.keys(subItems).length > 0) {
// If the item has sub-items, render a dropdown with toggle button
- const { leftIconArray, isDynamic } = extractLeftIcon(subItems) || {};
- let leftIcon = IconsObject[leftIconArray] || IconsObject.collections;
- if (isDynamic === "dynamic") {
- var IconComp = require("@egovernments/digit-ui-react-components")?.[leftIconArray];
+ const { iconKey,iconName } = extractLeftIcon(subItems) || {};
+ let leftIcon =
+ IconsObject[iconName] || IconsObject.collections;
+ if (iconKey === "dynamic") {
+ var IconComp = require("@egovernments/digit-ui-react-components")?.[
+ iconName
+ ];
leftIcon = IconComp ?
: leftIcon;
}
+ if (iconKey === "svg") {
+ var IconComp = require("@egovernments/digit-ui-react-components")?.SVG?.[iconName];
+ leftIcon = IconComp ?
: leftIcon;
+ }
const isParentActive = selectedParent === itemKey;
const isChildActive = selectedChildLevelOne === trimModuleName;
//we need to have a heirarchy such as parent -> child1 -> child2 to differentiate b/w different levels in the sidebar
return (
{
toggleSidebar(key);
- setSelectedParent((prevItem)=> {
- if(prevItem===itemKey ){
- return null
- }
- else return itemKey
-
+ setSelectedParent((prevItem) => {
+ if (prevItem === itemKey) {
+ return null;
+ } else return itemKey;
});
- const itemToHighlight = e.target.innerText
- setSelectedChildLevelOne((prevItem)=>{
- if(prevItem===itemToHighlight || isSubItemOpen){
- return null
- }
- else return itemToHighlight
+ const itemToHighlight = e.target.innerText;
+ setSelectedChildLevelOne((prevItem) => {
+ if (prevItem === itemToHighlight || isSubItemOpen) {
+ return null;
+ } else return itemToHighlight;
});
setSelectedChild(null);
// setOpenItems(prevState => {
@@ -158,57 +258,112 @@ const Sidebar = ({ data }) => {
// }
// })
}}
- style={{ display: "flex", flexDirection: "row", width: "100%" }}
+ style={{
+ display: "flex",
+ flexDirection: "row",
+ width: "100%",
+ }}
>
{flag &&
{leftIcon}
}
{trimModuleName}
{trimModuleName?.includes("...") && (
-
- {t(Digit.Utils.locale.getTransformedLocale(`ACTION_TEST_${key}`))}
+
+ {t(
+ Digit.Utils.locale.getTransformedLocale(
+ `ACTION_TEST_${key}`
+ )
+ )}
)}
-
- {isSubItemOpen ?
:
}
+
+ {isSubItemOpen ? (
+
+ ) : (
+
+ )}
- {subNav &&
{isSubItemOpen && renderSidebarItems(subItems, itemKey, false, level + 1)}
}
+ {subNav && (
+
+ {isSubItemOpen &&
+ renderSidebarItems(subItems, itemKey, false, level + 1)}
+
+ )}
);
} else if (subItemKeys) {
// If the item is a link, render it
- const { leftIconArray, isDynamic } = extractLeftIcon(subItems) || {};
- let leftIcon = IconsObject[leftIconArray] || IconsObject.collections;
- if (isDynamic === "dynamic") {
- var IconComp = require("@egovernments/digit-ui-react-components")?.[leftIconArray];
+ const { iconName, iconKey } =
+ extractLeftIcon(subItems) || {};
+ let leftIcon =
+ IconsObject[iconName] || IconsObject.collections;
+ if (iconKey === "dynamic") {
+ var IconComp = require("@egovernments/digit-ui-react-components")?.[
+ iconName
+ ];
leftIcon = IconComp ?
: leftIcon;
}
+ if (iconKey === "svg") {
+ var IconComp = require("@egovernments/digit-ui-react-components")?.SVG?.[iconName];
+ leftIcon = IconComp ?
: leftIcon;
+ }
const isChildActive = selectedChild === subItems.item.path;
return (
{
const keyToHighlight = subItems.item.path;
setSelectedParent(parentKey); // Update the selected parent when a child is clicked
setSelectedChild(keyToHighlight);
- setSelectedChildLevelOne(null)
+ setSelectedChildLevelOne(null);
// setOpenItems({});
// setSelectedChildLevelOne(null)
- navigateToRespectiveURL(history, `${subItems?.item?.navigationURL}`);
+ navigateToRespectiveURL(
+ history,
+ `${subItems?.item?.navigationURL}`
+ );
}}
>
{flag &&
{leftIcon}
}
{trimModuleName}
{trimModuleName?.includes("...") && (
-
- {t(Digit.Utils.locale.getTransformedLocale(`ACTION_TEST_${key}`))}
+
+ {t(
+ Digit.Utils.locale.getTransformedLocale(
+ `ACTION_TEST_${key}`
+ )
+ )}
)}
@@ -221,7 +376,11 @@ const Sidebar = ({ data }) => {
};
return (
-
+
{renderSidebarItems(data)}
);
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/README.md b/micro-ui/web/micro-ui-internals/packages/modules/pgr/README.md
new file mode 100644
index 00000000000..429486f43b6
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/README.md
@@ -0,0 +1,77 @@
+
+# digit-ui-module-pgr
+
+## Install
+
+```bash
+npm install --save @egovernments/digit-ui-module-pgr
+```
+
+## Limitation
+
+```bash
+This Package is more specific to DIGIT-UI's can be used across mission's
+```
+
+## Usage
+
+After adding the dependency make sure you have this dependency in
+
+```bash
+frontend/micro-ui/web/package.json
+```
+
+```json
+"@egovernments/digit-ui-module-pgr":"1.7.6",
+```
+
+then navigate to App.js
+
+```bash
+ frontend/micro-ui/web/src/App.js
+```
+
+
+```jsx
+/** add this import **/
+
+import { initPGRComponents } from "@egovernments/digit-ui-module-pgr";
+
+/** inside enabledModules add this new module key **/
+
+const enabledModules = ["PGR"];
+
+/** inside init Function call this function **/
+
+const initDigitUI = () => {
+ initPGRComponents();
+};
+```
+
+### Changelog
+
+```bash
+1.8.0 base urban version released
+1.7.8 added some null checks to improve stability
+1.7.7 used new color constants
+1.7.6 fixed routing issue
+1.7.5 base urban version
+```
+
+### Contributors
+
+[jagankumar-egov] [Tulika-eGov]
+
+## Documentation
+
+Documentation Site (https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui)
+
+## Maintainer
+
+- [jagankumar-egov](https://www.github.com/jagankumar-egov)
+
+
+### Published from DIGIT Frontend
+DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/master)
+
+![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png)
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json b/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
new file mode 100644
index 00000000000..e89bc077589
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "@egovernments/digit-ui-module-pgr",
+ "version": "1.8.0",
+ "license": "MIT",
+ "main": "dist/index.js",
+ "module": "dist/index.modern.js",
+ "source": "src/Module.js",
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "start": "microbundle-crl watch --no-compress --format modern,cjs",
+ "build": "microbundle-crl --compress --no-sourcemap --format cjs",
+ "prepublish": "yarn build"
+ },
+ "peerDependencies": {
+ "react": "17.0.2",
+ "react-router-dom": "5.3.0"
+ },
+ "dependencies": {
+ "@egovernments/digit-ui-react-components": "1.8.0",
+ "lodash.merge": "^4.6.2",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-redux": "7.2.8",
+ "react-router-dom": "5.3.0",
+ "redux": "4.1.2",
+ "redux-thunk": "2.4.1"
+ }
+}
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/EmployeeApp.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/EmployeeApp.js
new file mode 100644
index 00000000000..3cbbdc4f52a
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/EmployeeApp.js
@@ -0,0 +1,13 @@
+import React from "react";
+import { AppContainer, EmployeeAppContainer } from "@egovernments/digit-ui-react-components";
+
+import Complaint from "./pages/employee/index";
+const App = () => {
+ return (
+
+
+
+ );
+};
+
+export default App;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Icons.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Icons.js
new file mode 100644
index 00000000000..c932e7ad466
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Icons.js
@@ -0,0 +1,8 @@
+import React from "react";
+
+export const Close = () => (
+
+);
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Module.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Module.js
new file mode 100644
index 00000000000..430b1e75e27
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/Module.js
@@ -0,0 +1,85 @@
+import React, { useEffect } from "react";
+import PGRCard from "./components/PGRCard";
+
+import getRootReducer from "./redux/reducers";
+import CitizenApp from "./pages/citizen";
+
+import EmployeeApp from "./EmployeeApp";
+import { ComplaintIcon, CitizenHomeCard, Loader } from "@egovernments/digit-ui-react-components";
+import { PGR_CITIZEN_CREATE_COMPLAINT } from "./constants/Citizen";
+import { useTranslation } from "react-i18next";
+import { LOCALE } from "./constants/Localization";
+import { ComplaintDetails } from "./pages/employee/ComplaintDetails";
+import { CreateComplaint as CreateComplaintEmp } from "./pages/employee/CreateComplaint";
+import Inbox from "./pages/employee/Inbox";
+import ResponseEmp from "./pages/employee/Response";
+
+import { CreateComplaint as CreateComplaintCitizen } from "./pages/citizen/Create";
+import { ComplaintsList } from "./pages/citizen/ComplaintsList";
+import ComplaintDetailsPage from "./pages/citizen/ComplaintDetails";
+import SelectRating from "./pages/citizen/Rating/SelectRating";
+import ResponseCitizen from "./pages/citizen/Response";
+
+
+export const PGRReducers = getRootReducer;
+
+const PGRModule = ({ stateCode, userType, tenants }) => {
+ const moduleCode = "PGR";
+ const language = Digit.StoreData.getCurrentLanguage();
+ const { isLoading, data: store } = Digit.Services.useStore({ stateCode, moduleCode, language });
+
+ if (isLoading) {
+ return
;
+ }
+
+ Digit.SessionStorage.set("PGR_TENANTS", tenants);
+
+ if (userType === "citizen") {
+ return
;
+ } else {
+ return
;
+ }
+};
+
+const PGRLinks = ({ matchPath }) => {
+ const { t } = useTranslation();
+ const [params, setParams, clearParams] = Digit.Hooks.useSessionStorage(PGR_CITIZEN_CREATE_COMPLAINT, {});
+
+ useEffect(() => {
+ clearParams();
+ }, []);
+
+ const links = [
+ {
+ link: `${matchPath}/create-complaint/complaint-type`,
+ i18nKey: t("CS_COMMON_FILE_A_COMPLAINT"),
+ },
+ {
+ link: `${matchPath}/complaints`,
+ i18nKey: t(LOCALE.MY_COMPLAINTS),
+ },
+ ];
+
+ return
;
+};
+
+const componentsToRegister = {
+ PGRModule,
+ PGRLinks,
+ PGRCard,
+ PGRComplaintDetails : ComplaintDetails,
+ PGRCreateComplaintEmp : CreateComplaintEmp,
+ PGRInbox : Inbox,
+ PGRResponseEmp : ResponseEmp,
+ PGRCreateComplaintCitizen : CreateComplaintCitizen,
+ PGRComplaintsList : ComplaintsList,
+ PGRComplaintDetailsPage : ComplaintDetailsPage,
+ PGRSelectRating : SelectRating,
+ PGRResponseCitzen : ResponseCitizen
+};
+
+export const initPGRComponents = () => {
+ Object.entries(componentsToRegister).forEach(([key, value]) => {
+ Digit.ComponentRegistryService.setComponent(key, value);
+ });
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/Complaint.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/Complaint.js
new file mode 100644
index 00000000000..3583fa17aad
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/Complaint.js
@@ -0,0 +1,41 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { useHistory } from "react-router-dom";
+import { Card, DateWrap, KeyNote } from "@egovernments/digit-ui-react-components";
+import { CardSubHeader } from "@egovernments/digit-ui-react-components";
+import { LOCALIZATION_KEY } from "../constants/Localization";
+
+// import { ConvertTimestampToDate } from "../@egovernments/digit-utils/services/date";
+
+const Complaint = ({ data, path }) => {
+ let { serviceCode, serviceRequestId, applicationStatus } = data;
+
+ const history = useHistory();
+ const { t } = useTranslation();
+
+ const handleClick = () => {
+ history.push(`${path}/${serviceRequestId}`);
+ };
+
+ const closedStatus = ["RESOLVED", "REJECTED", "CLOSEDAFTERREJECTION", "CLOSEDAFTERRESOLUTION"];
+
+ return (
+
+
+ {t(`SERVICEDEFS.${serviceCode.toUpperCase()}`)}
+
+
+
+
+
+
+
{(closedStatus.includes(applicationStatus) ? t("CS_COMMON_CLOSED") : t("CS_COMMON_OPEN")).toUpperCase()}
+
+
+ {t(`${LOCALIZATION_KEY.CS_COMMON}_${applicationStatus}`)}
+
+
+ );
+};
+
+export default Complaint;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/DesktopInbox.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/DesktopInbox.js
new file mode 100644
index 00000000000..ee2b1f75c8f
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/DesktopInbox.js
@@ -0,0 +1,143 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { Link } from "react-router-dom";
+import { Card, Loader } from "@egovernments/digit-ui-react-components";
+import ComplaintsLink from "./inbox/ComplaintLinks";
+import ComplaintTable from "./inbox/ComplaintTable";
+import Filter from "./inbox/Filter";
+import SearchComplaint from "./inbox/search";
+import { LOCALE } from "../constants/Localization";
+
+const DesktopInbox = ({
+ data,
+ onFilterChange,
+ onSearch,
+ isLoading,
+ searchParams,
+ onNextPage,
+ onPrevPage,
+ currentPage,
+ pageSizeLimit,
+ onPageSizeChange,
+ totalRecords,
+}) => {
+ const { t } = useTranslation();
+ const GetCell = (value) =>
{value};
+ const GetSlaCell = (value) => {
+ return value < 0 ?
{value || ""} :
{value || ""};
+ };
+
+ const columns = React.useMemo(
+ () => [
+ {
+ Header: t("CS_COMMON_COMPLAINT_NO"),
+ Cell: ({ row }) => {
+ return (
+
+ );
+ },
+ },
+ {
+ Header: t("WF_INBOX_HEADER_LOCALITY"),
+ Cell: ({ row }) => {
+ return GetCell(t(Digit.Utils.locale.getLocalityCode(row.original["locality"], row.original["tenantId"])));
+ },
+ },
+ {
+ Header: t("CS_COMPLAINT_DETAILS_CURRENT_STATUS"),
+ Cell: ({ row }) => {
+ return GetCell(t(`CS_COMMON_${row.original["status"]}`));
+ },
+ },
+ {
+ Header: t("WF_INBOX_HEADER_CURRENT_OWNER"),
+ Cell: ({ row }) => {
+ return GetCell(row.original["taskOwner"]);
+ },
+ },
+ {
+ Header: t("WF_INBOX_HEADER_SLA_DAYS_REMAINING"),
+ Cell: ({ row }) => {
+ return GetSlaCell(row.original["sla"]);
+ },
+ },
+ ],
+ [t]
+ );
+
+ let result;
+ if (isLoading) {
+ result =
;
+ } else if (data && data?.length === 0) {
+ result = (
+
+ {t(LOCALE.NO_COMPLAINTS_EMPLOYEE)
+ .split("\\n")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+ );
+ } else if (data?.length > 0) {
+ result = (
+
{
+ return {
+ style: {
+ minWidth: cellInfo.column.Header === t("CS_COMMON_COMPLAINT_NO") ? "240px" : "",
+ padding: "20px 18px",
+ fontSize: "16px",
+ },
+ };
+ }}
+ onNextPage={onNextPage}
+ onPrevPage={onPrevPage}
+ totalRecords={totalRecords}
+ onPageSizeChagne={onPageSizeChange}
+ currentPage={currentPage}
+ pageSizeLimit={pageSizeLimit}
+ />
+ );
+ } else {
+ result = (
+
+ {t(LOCALE.ERROR_LOADING_RESULTS)
+ .split("\\n")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+ );
+ }
+
+ return (
+
+ );
+};
+
+export default DesktopInbox;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/FormComposer.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/FormComposer.js
new file mode 100644
index 00000000000..785f9cde039
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/FormComposer.js
@@ -0,0 +1,86 @@
+import React, { useMemo } from "react";
+import { useForm } from "react-hook-form";
+import {
+ BreakLine,
+ Card,
+ CardLabel,
+ CardLabelError,
+ CardSubHeader,
+ CardSectionHeader,
+ TextArea,
+ TextInput,
+ ActionBar,
+ SubmitBar,
+ LabelFieldPair,
+} from "@egovernments/digit-ui-react-components";
+
+import { useTranslation } from "react-i18next";
+
+export const FormComposer = (props) => {
+ const { register, handleSubmit, errors } = useForm();
+ const { t } = useTranslation();
+
+ function onSubmit(data) {
+ props.onSubmit(data);
+ }
+
+ const fieldSelector = (type, populators) => {
+ switch (type) {
+ case "text":
+ return (
+
+ {populators.componentInFront ? populators.componentInFront : null}
+
+
+ );
+ case "textarea":
+ return ;
+ default:
+ return populators.dependency !== false ? populators : null;
+ }
+ };
+
+ const formFields = useMemo(
+ () =>
+ props.config?.map((section, index, array) => {
+ return (
+
+ {section.head}
+ {section.body.map((field, index) => {
+ return (
+
+ {errors[field.populators.name] && (field.populators?.validate ? errors[field.populators.validate] : true) && (
+ {field.populators.error}
+ )}
+
+
+ {field.label}
+ {field.isMandatory ? " * " : null}
+
+ {fieldSelector(field.type, field.populators)}
+
+
+ );
+ })}
+ {array.length - 1 === index ? null : }
+
+ );
+ }),
+ [props.config, errors]
+ );
+
+ const isDisabled = props.isDisabled || false;
+
+ return (
+
+ );
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/MobileInbox.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/MobileInbox.js
new file mode 100644
index 00000000000..34e8f9eadbf
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/MobileInbox.js
@@ -0,0 +1,64 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { Loader, Card } from "@egovernments/digit-ui-react-components";
+import { ComplaintCard } from "./inbox/ComplaintCard";
+import ComplaintsLink from "./inbox/ComplaintLinks";
+import { LOCALE } from "../constants/Localization";
+import PropTypes from "prop-types";
+
+const GetSlaCell = (value) => {
+ return value < 0 ? {value} : {value};
+};
+
+const MobileInbox = ({ data, onFilterChange, onSearch, isLoading, searchParams }) => {
+ const { t } = useTranslation();
+ const localizedData = data?.map(({ locality, tenantId, serviceRequestId, complaintSubType, sla, status, taskOwner }) => ({
+ [t("CS_COMMON_COMPLAINT_NO")]: serviceRequestId,
+ [t("CS_ADDCOMPLAINT_COMPLAINT_SUB_TYPE")]: t(`SERVICEDEFS.${complaintSubType.toUpperCase()}`),
+ [t("WF_INBOX_HEADER_LOCALITY")]: t(Digit.Utils.locale.getLocalityCode(locality, tenantId)),
+ [t("CS_COMPLAINT_DETAILS_CURRENT_STATUS")]: t(`CS_COMMON_${status}`),
+ [t("WF_INBOX_HEADER_CURRENT_OWNER")]: taskOwner,
+ [t("WF_INBOX_HEADER_SLA_DAYS_REMAINING")]: GetSlaCell(sla),
+ // status,
+ }));
+
+ let result;
+ if (isLoading) {
+ result = ;
+ } else {
+ result = (
+
+ );
+ }
+
+ return (
+
+ );
+};
+MobileInbox.propTypes = {
+ data: PropTypes.any,
+ onFilterChange: PropTypes.func,
+ onSearch: PropTypes.func,
+ isLoading: PropTypes.bool,
+ searchParams: PropTypes.any,
+};
+
+MobileInbox.defaultProps = {
+ onFilterChange: () => {},
+ searchParams: {},
+};
+
+export default MobileInbox;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/PGRCard.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/PGRCard.js
new file mode 100644
index 00000000000..55b9b3726d5
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/PGRCard.js
@@ -0,0 +1,58 @@
+import React, { useEffect, useState } from "react";
+import { Link } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import { EmployeeModuleCard } from "@egovernments/digit-ui-react-components";
+
+
+const PGRCard = () => {
+ const { t } = useTranslation();
+
+ const allLinks = [
+ { text: t("ES_PGR_INBOX"), link: `/${window?.contextPath}/employee/pgr/inbox` },
+ { text: t("ES_PGR_NEW_COMPLAINT"), link: `/${window?.contextPath}/employee/pgr/complaint/create`, accessTo: ["CSR"] },
+ ];
+
+ if (!Digit.Utils.pgrAccess()) {
+ return null;
+ }
+
+ const Icon = () =>
+
+ let propsForCSR =[
+ {
+ label: t("ES_PGR_NEW_COMPLAINT"),
+ link: `/${window?.contextPath}/employee/pgr/complaint/create`,
+ role: "CSR"
+ }
+ ]
+
+ propsForCSR = propsForCSR.filter(link => link.role && Digit.Utils.didEmployeeHasRole(link.role) );
+
+ const propsForModuleCard = {
+ Icon: ,
+ moduleName: t("ES_PGR_HEADER_COMPLAINT"),
+ kpis: [
+ {
+ label: t("TOTAL_PGR"),
+ link: `/${window?.contextPath}/employee/pgr/inbox`
+ },
+ {
+ label: t("TOTAL_NEARING_SLA"),
+ link: `/${window?.contextPath}/employee/pgr/inbox`
+ }
+ ],
+ links: [
+ {
+ label: t("ES_PGR_INBOX"),
+ link: `/${window?.contextPath}/employee/pgr/inbox`
+ },
+ ...propsForCSR
+ ]
+}
+
+ return
+};
+export default PGRCard;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/TimeLine.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/TimeLine.js
new file mode 100644
index 00000000000..a9cee1246ce
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/TimeLine.js
@@ -0,0 +1,162 @@
+import { Card, CardSubHeader, CheckPoint, ConnectingCheckPoints, GreyOutText, Loader, DisplayPhotos } from "@egovernments/digit-ui-react-components";
+import React, {Fragment, useEffect, useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import { LOCALIZATION_KEY } from "../constants/Localization";
+import PendingAtLME from "./timelineInstances/pendingAtLme";
+import PendingForAssignment from "./timelineInstances/PendingForAssignment";
+import PendingForReassignment from "./timelineInstances/PendingForReassignment";
+import Reopen from "./timelineInstances/reopen";
+import Resolved from "./timelineInstances/resolved";
+import Rejected from "./timelineInstances/rejected";
+import StarRated from "./timelineInstances/StarRated";
+
+const TLCaption = ({ data , comments}) => {
+ const { t } = useTranslation()
+ return (
+
+ {data?.date &&
{data?.date}
}
+
{data?.name}
+
{data?.mobileNumber}
+ {data?.source &&
{t("ES_COMMON_FILED_VIA_" + data?.source.toUpperCase())}
}
+
+ );
+};
+
+const TimeLine = ({ isLoading, data, serviceRequestId, complaintWorkflow, rating, zoomImage, complaintDetails, ComplainMaxIdleTime }) => {
+ const { t } = useTranslation();
+
+ function zoomImageWrapper(imageSource, index,thumbnailsToShow){
+ let newIndex=thumbnailsToShow.thumbs?.findIndex(link=>link===imageSource);
+ zoomImage((newIndex>-1&&thumbnailsToShow?.fullImage?.[newIndex])||imageSource);
+ }
+
+ let { timeline } = data;
+ const totalTimelineLength = useMemo(()=> timeline?.length ,[timeline])
+
+ useEffect(() => {
+ let filteredTimeline = timeline?.filter((status, index, array) => {
+ if (index === array.length - 1 && status.status === "PENDINGFORASSIGNMENT") {
+ return true;
+ } else {
+ return false;
+ }
+ });
+ const [{auditDetails}] = filteredTimeline?.length>0 ? filteredTimeline : [{}];
+
+ const onlyPendingForAssignmentStatusArray = timeline?.filter( e => e?.status === "PENDINGFORASSIGNMENT")
+ const duplicateCheckpointOfPendingForAssignment = onlyPendingForAssignmentStatusArray.at(-1)
+ timeline?.push({
+ ...duplicateCheckpointOfPendingForAssignment,
+ performedAction: "FILED",
+ status: "COMPLAINT_FILED",
+ });
+ }, [timeline]);
+
+ const getCommentsInCustomChildComponent = ({comment, thumbnailsToShow, auditDetails, assigner, status}) => {
+ const captionDetails = {
+ date: auditDetails?.lastModified,
+ name: assigner?.name,
+ mobileNumber: assigner?.mobileNumber,
+ source: status == "COMPLAINT_FILED" ? complaintDetails?.audit.source : ""
+ }
+ return <>
+ {comment ? {comment?.map( e =>
+
+
{t("WF_COMMON_COMMENTS")}
+
{e}
+
+ )}
: null}
+ {thumbnailsToShow?.thumbs?.length > 0 ?
+
{t("CS_COMMON_ATTACHMENTS")}
+ {zoomImageWrapper(src, index,thumbnailsToShow)}} />
+ : null}
+ {captionDetails?.date ? : null}
+ >
+ }
+
+ const getCheckPoint = ({ status, caption, auditDetails, timeLineActions, index, array, performedAction, comment, thumbnailsToShow, assigner, totalTimelineLength }) => {
+ const isCurrent = 0 === index;
+ switch (status) {
+ case "PENDINGFORREASSIGNMENT":
+ return ;
+
+ case "PENDINGFORASSIGNMENT":
+ const isFirstPendingForAssignment = totalTimelineLength - (index + 1) === 0 ? true : false
+ return ;
+
+ case "PENDINGFORASSIGNMENT_AFTERREOPEN":
+ return ;
+
+ case "PENDINGATLME":
+ let { name, mobileNumber } = caption && caption.length > 0 ? caption[0] : { name: "", mobileNumber: "" };
+ const assignedTo = `${t(`CS_COMMON_${status}`)}`;
+ return ;
+
+ case "RESOLVED":
+ return (
+
+ );
+ case "REJECTED":
+ return (
+
+ );
+ case "CLOSEDAFTERRESOLUTION":
+ return {getCommentsInCustomChildComponent({comment, thumbnailsToShow, auditDetails, assigner})}{rating ? : null} } />;
+
+ // case "RESOLVE":
+ // return (
+ //
+ // );
+ case "COMPLAINT_FILED":
+ return ;
+
+ default:
+ return ;
+ }
+ };
+
+ return (
+
+ {t(`${LOCALIZATION_KEY.CS_COMPLAINT_DETAILS}_COMPLAINT_TIMELINE`)}
+ {timeline && totalTimelineLength > 0 ? (
+
+ {timeline.map(({ status, caption, auditDetails, timeLineActions, performedAction, wfComment: comment, thumbnailsToShow, assigner }, index, array) => {
+ return getCheckPoint({ status, caption, auditDetails, timeLineActions, index, array, performedAction, comment, thumbnailsToShow, assigner, totalTimelineLength });
+ })}
+
+ ) : (
+
+ )}
+
+ );
+};
+
+export default TimeLine;
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintCard.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintCard.js
new file mode 100644
index 00000000000..604e7cb4135
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintCard.js
@@ -0,0 +1,75 @@
+import React, { useState } from "react";
+
+import { FilterAction, Card, DetailsCard, PopUp, SearchAction } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import Filter from "./Filter";
+import SearchComplaint from "./search";
+import { LOCALE } from "../../constants/Localization";
+
+export const ComplaintCard = ({ data, onFilterChange, onSearch, serviceRequestIdKey, searchParams }) => {
+ const { t } = useTranslation();
+ const [popup, setPopup] = useState(false);
+ const [selectedComponent, setSelectedComponent] = useState(null);
+ const [filterCount, setFilterCount] = useState(Digit.inboxFilterCount || 1);
+
+ const handlePopupAction = (type) => {
+ if (type === "SEARCH") {
+ setSelectedComponent();
+ } else if (type === "FILTER") {
+ setSelectedComponent(
+
+ );
+ }
+ setPopup(true);
+ };
+
+ const handlePopupClose = () => {
+ setPopup(false);
+ setSelectedComponent(null);
+ };
+
+ let result;
+ if (data && data?.length === 0) {
+ result = (
+
+ {t(LOCALE.NO_COMPLAINTS_EMPLOYEE)
+ .split("\\n")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+ );
+ } else if (data && data?.length > 0) {
+ result = ;
+ } else {
+ result = (
+
+ {t(LOCALE.ERROR_LOADING_RESULTS)
+ .split("\\n")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+ );
+ }
+
+ return (
+
+
+ handlePopupAction("SEARCH")} />
+ handlePopupAction("FILTER")} />
+ {/* */}
+
+ {result}
+ {popup && (
+
+ {selectedComponent}
+
+ )}
+
+ );
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintLinks.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintLinks.js
new file mode 100644
index 00000000000..758ea774f2e
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintLinks.js
@@ -0,0 +1,68 @@
+import { Card } from "@egovernments/digit-ui-react-components";
+import React, { useEffect, useState } from "react";
+import { Link } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+
+const ComplaintsLink = ({ isMobile, data }) => {
+ const { t } = useTranslation();
+
+ const allLinks = [
+ { text: "ES_PGR_NEW_COMPLAINT", link: `/${window?.contextPath}/employee/pgr/complaint/create`, accessTo: ["CSR"] },
+ // { text: "Reports", link: "/employee" },
+ // { text: "Dashboard", link: "/employee" },
+ ];
+
+ const [links, setLinks] = useState([]);
+
+ useEffect(() => {
+ let linksToShow = [];
+ allLinks.forEach((link) => {
+ if (link.accessTo) {
+ if (Digit.UserService.hasAccess(link.accessTo)) {
+ linksToShow.push(link);
+ }
+ } else {
+ linksToShow.push(link);
+ }
+ });
+ setLinks(linksToShow);
+ }, []);
+
+ // useEffect(() => {
+ // if (isMobile) {
+ // const mobileLinks = links.filter((link) => {
+ // return link.text !== "Dashboard";
+ // });
+ // setLinks(mobileLinks);
+ // }
+ // }, []);
+
+ const GetLogo = () => (
+
+
+
+ {" "}
+
{t("ES_PGR_HEADER_COMPLAINT")}
+
+ );
+
+ return (
+
+
+ {GetLogo()}
+
+ {links.map(({ link, text }, index) => (
+
+ {t(text)}
+
+ ))}
+
+
+
+ );
+};
+
+export default ComplaintsLink;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintTable.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintTable.js
new file mode 100644
index 00000000000..7facec2f239
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/ComplaintTable.js
@@ -0,0 +1,19 @@
+import React from "react";
+import { Table } from "@egovernments/digit-ui-react-components";
+
+const ComplaintTable = ({ t, columns, data, getCellProps, onNextPage, onPrevPage, currentPage, totalRecords, pageSizeLimit, onPageSizeChange }) => (
+
+);
+
+export default ComplaintTable;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Filter.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Filter.js
new file mode 100644
index 00000000000..42516ecf35a
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Filter.js
@@ -0,0 +1,227 @@
+import React, { useEffect, useMemo, useState } from "react";
+import { Dropdown, RadioButtons, ActionBar, RemoveableTag, RoundedLabel } from "@egovernments/digit-ui-react-components";
+import { ApplyFilterBar, CloseSvg } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import Status from "./Status";
+
+let pgrQuery = {};
+let wfQuery = {};
+
+const Filter = (props) => {
+ let { uuid } = Digit.UserService.getUser().info;
+ const { searchParams } = props;
+ const { t } = useTranslation();
+ const isAssignedToMe = searchParams?.filters?.wfFilters?.assignee && searchParams?.filters?.wfFilters?.assignee[0]?.code ? true : false;
+
+ const assignedToOptions = useMemo(
+ () => [
+ { code: "ASSIGNED_TO_ME", name: t("ASSIGNED_TO_ME") },
+ { code: "ASSIGNED_TO_ALL", name: t("ASSIGNED_TO_ALL") },
+ ],
+ [t]
+ );
+
+ const [selectAssigned, setSelectedAssigned] = useState(isAssignedToMe ? assignedToOptions[0] : assignedToOptions[1]);
+
+ useEffect(() => setSelectedAssigned(isAssignedToMe ? assignedToOptions[0] : assignedToOptions[1]), [t]);
+
+ const [selectedComplaintType, setSelectedComplaintType] = useState(null);
+ const [selectedLocality, setSelectedLocality] = useState(null);
+ const [pgrfilters, setPgrFilters] = useState(
+ searchParams?.filters?.pgrfilters || {
+ serviceCode: [],
+ locality: [],
+ applicationStatus: [],
+ }
+ );
+
+ const [wfFilters, setWfFilters] = useState(
+ searchParams?.filters?.wfFilters || {
+ assignee: [{ code: uuid }],
+ }
+ );
+
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ // let localities = Digit.Hooks.pgr.useLocalities({ city: tenantId });
+ const { data: localities } = Digit.Hooks.useBoundaryLocalities(tenantId, "admin", {}, t);
+ let serviceDefs = Digit.Hooks.pgr.useServiceDefs(tenantId, "PGR");
+
+ const onRadioChange = (value) => {
+ setSelectedAssigned(value);
+ uuid = value.code === "ASSIGNED_TO_ME" ? uuid : "";
+ setWfFilters({ ...wfFilters, assignee: [{ code: uuid }] });
+ };
+
+ useEffect(() => {
+ let count = 0;
+ for (const property in pgrfilters) {
+ if (Array.isArray(pgrfilters[property])) {
+ count += pgrfilters[property].length;
+ let params = pgrfilters[property].map((prop) => prop.code).join();
+ if (params) {
+ pgrQuery[property] = params;
+ }
+ else{
+ delete pgrQuery?.[property]
+ }
+ }
+ }
+ for (const property in wfFilters) {
+ if (Array.isArray(wfFilters[property])) {
+ let params = wfFilters[property].map((prop) => prop.code).join();
+ if (params) {
+ wfQuery[property] = params;
+ } else {
+ wfQuery = {};
+ }
+ }
+ }
+ count += wfFilters?.assignee?.length || 0;
+
+ if (props.type !== "mobile") {
+ handleFilterSubmit();
+ }
+
+ Digit.inboxFilterCount = count;
+ }, [pgrfilters, wfFilters]);
+
+ const ifExists = (list, key) => {
+ return list.filter((object) => object.code === key.code).length;
+ };
+ function applyFiltersAndClose() {
+ handleFilterSubmit();
+ props.onClose();
+ }
+ function complaintType(_type) {
+ const type = { i18nKey: t("SERVICEDEFS." + _type.serviceCode.toUpperCase()), code: _type.serviceCode };
+ if (!ifExists(pgrfilters.serviceCode, type)) {
+ setPgrFilters({ ...pgrfilters, serviceCode: [...pgrfilters.serviceCode, type] });
+ }
+ }
+
+ function onSelectLocality(value, type) {
+ if (!ifExists(pgrfilters.locality, value)) {
+ setPgrFilters({ ...pgrfilters, locality: [...pgrfilters.locality, value] });
+ }
+ }
+
+ useEffect(() => {
+ if (pgrfilters.serviceCode.length > 1) {
+ setSelectedComplaintType({ i18nKey: `${pgrfilters.serviceCode.length} selected` });
+ } else {
+ setSelectedComplaintType(pgrfilters.serviceCode[0]);
+ }
+ }, [pgrfilters.serviceCode]);
+
+ useEffect(() => {
+ if (pgrfilters.locality.length > 1) {
+ setSelectedLocality({ name: `${pgrfilters.locality.length} selected` });
+ } else {
+ setSelectedLocality(pgrfilters.locality[0]);
+ }
+ }, [pgrfilters.locality]);
+
+ const onRemove = (index, key) => {
+ let afterRemove = pgrfilters[key].filter((value, i) => {
+ return i !== index;
+ });
+ setPgrFilters({ ...pgrfilters, [key]: afterRemove });
+ };
+
+ const handleAssignmentChange = (e, type) => {
+ if (e.target.checked) {
+ setPgrFilters({ ...pgrfilters, applicationStatus: [...pgrfilters.applicationStatus, { code: type.code }] });
+ } else {
+ const filteredStatus = pgrfilters.applicationStatus.filter((value) => {
+ return value.code !== type.code;
+ });
+ setPgrFilters({ ...pgrfilters, applicationStatus: filteredStatus });
+ }
+ };
+
+ function clearAll() {
+ let pgrReset = { serviceCode: [], locality: [], applicationStatus: [] };
+ let wfRest = { assigned: [{ code: [] }] };
+ setPgrFilters(pgrReset);
+ setWfFilters(wfRest);
+ pgrQuery = {};
+ wfQuery = {};
+ setSelectedAssigned("");
+ setSelectedComplaintType(null);
+ setSelectedLocality(null);
+ }
+
+ const handleFilterSubmit = () => {
+ props.onFilterChange({ pgrQuery: pgrQuery, wfQuery: wfQuery, wfFilters, pgrfilters });
+ };
+
+ const GetSelectOptions = (lable, options, selected = null, select, optionKey, onRemove, key) => {
+ selected = selected || { [optionKey]: " ", code: "" };
+ return (
+
+
{lable}
+ {
select(value, key)} optionKey={optionKey} />}
+
+
+ {pgrfilters[key].length > 0 &&
+ pgrfilters[key].map((value, index) => {
+ return onRemove(index, key)} />;
+ })}
+
+
+ );
+ };
+
+ return (
+
+
+
+
+
{t("ES_COMMON_FILTER_BY")}:
+
+ {t("ES_COMMON_CLEAR_ALL")}
+
+ {props.type === "desktop" && (
+
+ {t("ES_COMMON_CLEAR_ALL")}
+
+ )}
+ {props.type === "mobile" && (
+
+
+
+ )}
+
+
+
+
+ {GetSelectOptions(
+ t("CS_COMPLAINT_DETAILS_COMPLAINT_SUBTYPE"),
+ serviceDefs,
+ selectedComplaintType,
+ complaintType,
+ "i18nKey",
+ onRemove,
+ "serviceCode"
+ )}
+
+
{GetSelectOptions(t("CS_PGR_LOCALITY"), localities, selectedLocality, onSelectLocality, "i18nkey", onRemove, "locality")}
+ {
}
+
+
+
+
+ {props.type === "mobile" && (
+
+ )}
+
+
+ );
+};
+
+export default Filter;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Status.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Status.js
new file mode 100644
index 00000000000..1980ab00ae3
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/Status.js
@@ -0,0 +1,27 @@
+import React from "react";
+import { CheckBox, Loader } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+
+const Status = ({ complaints, onAssignmentChange, pgrfilters }) => {
+ const { t } = useTranslation();
+ const complaintsWithCount = Digit.Hooks.pgr.useComplaintStatusCount(complaints);
+ let hasFilters = pgrfilters?.applicationStatus?.length;
+ return (
+
+
{t("ES_PGR_FILTER_STATUS")}
+ {complaintsWithCount.length === 0 &&
}
+ {complaintsWithCount.map((option, index) => {
+ return (
+
onAssignmentChange(e, option)}
+ checked={hasFilters ? (pgrfilters.applicationStatus.filter((e) => e.code === option.code).length !== 0 ? true : false) : false}
+ label={`${option.name} (${option.count || 0})`}
+ />
+ );
+ })}
+
+ );
+};
+
+export default Status;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/search.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/search.js
new file mode 100644
index 00000000000..3bbcc4213e1
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/inbox/search.js
@@ -0,0 +1,110 @@
+import React, { useState } from "react";
+import { useForm } from "react-hook-form";
+import { useTranslation } from "react-i18next";
+import { TextInput, Label, SubmitBar, LinkLabel, ActionBar, CloseSvg } from "@egovernments/digit-ui-react-components";
+
+const SearchComplaint = ({ onSearch, type, onClose, searchParams }) => {
+ const [complaintNo, setComplaintNo] = useState(searchParams?.search?.serviceRequestId || "");
+ const [mobileNo, setMobileNo] = useState(searchParams?.search?.mobileNumber || "");
+ const { register, errors, handleSubmit, reset } = useForm();
+ const { t } = useTranslation();
+
+ const onSubmitInput = (data) => {
+ if (!Object.keys(errors).filter((i) => errors[i]).length) {
+ if (data.serviceRequestId !== "") {
+ onSearch({ serviceRequestId: data.serviceRequestId });
+ } else if (data.mobileNumber !== "") {
+ onSearch({ mobileNumber: data.mobileNumber });
+ } else {
+ onSearch({});
+ }
+
+ if (type === "mobile") {
+ onClose();
+ }
+ }
+ };
+
+ function clearSearch() {
+ reset();
+ onSearch({});
+ setComplaintNo("");
+ setMobileNo("");
+ }
+
+ const clearAll = () => {
+ return (
+
+ {t("ES_COMMON_CLEAR_SEARCH")}
+
+ );
+ };
+
+ function setComplaint(e) {
+ setComplaintNo(e.target.value);
+ }
+
+ function setMobile(e) {
+ setMobileNo(e.target.value);
+ }
+
+ return (
+
+ );
+};
+
+export default SearchComplaint;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForAssignment.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForAssignment.js
new file mode 100644
index 00000000000..489c1de0f38
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForAssignment.js
@@ -0,0 +1,8 @@
+import React from "react";
+import { CheckPoint } from "@egovernments/digit-ui-react-components";
+
+const PendingForAssignment = ({ isCompleted, text, complaintFiledDate, customChild }) => {
+ return
;
+};
+
+export default PendingForAssignment;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForReassignment.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForReassignment.js
new file mode 100644
index 00000000000..ba50b8aa136
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/PendingForReassignment.js
@@ -0,0 +1,5 @@
+import React from "react";
+
+const PendingForReassignment = ({ text }) =>
{text};
+
+export default PendingForReassignment;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/StarRated.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/StarRated.js
new file mode 100644
index 00000000000..23efde2d31a
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/StarRated.js
@@ -0,0 +1,6 @@
+import React from "react";
+import { Rating } from "@egovernments/digit-ui-react-components";
+
+const StarRated = ({ text, rating }) =>
{}} />;
+
+export default StarRated;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/pendingAtLme.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/pendingAtLme.js
new file mode 100644
index 00000000000..e55ddac2c11
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/pendingAtLme.js
@@ -0,0 +1,15 @@
+import { TelePhone, CheckPoint } from "@egovernments/digit-ui-react-components";
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+const PendingAtLME = ({ name, isCompleted, mobile, text, customChild }) => {
+ let { t } = useTranslation();
+ return
+ {name && mobile ? : null }
+ {customChild}
+
+ } />
+};
+
+export default PendingAtLME;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/rejected.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/rejected.js
new file mode 100644
index 00000000000..07606d1a8d6
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/rejected.js
@@ -0,0 +1,55 @@
+import React from "react";
+import { ActionLinks, CheckPoint } from "@egovernments/digit-ui-react-components";
+import { Link } from "react-router-dom";
+import StarRated from "./StarRated";
+import { useTranslation } from "react-i18next";
+import Reopen from "./reopen";
+//const GetTranslatedAction = (action, t) => t(`CS_COMMON_${action}`);
+
+const Rejected = ({ action, nextActions, complaintDetails, ComplainMaxIdleTime=3600000, rating, serviceRequestId, reopenDate, isCompleted }) => {
+ const { t } = useTranslation();
+
+ if (action === "REJECTED") {
+ let actions =
+ nextActions &&
+ nextActions.map((action, index) => {
+ if (action && action !== "COMMENT") {
+ return (
+
+
{t(`CS_COMMON_${action}`)}
+
+ );
+ }
+ });
+ return
{actions} } />;
+ } else if (action === "RATE" && rating) {
+ return (
+
+ {rating ? : null}
+ {customChild}
+ }
+ />
+ );
+ } else if (action === "REOPEN") {
+ return ;
+ } else {
+ let actions =
+ nextActions &&
+ nextActions.map((action, index) => {
+ if (action && (action !== "COMMENT") ) {
+ if((action!== "REOPEN" || (action === "REOPEN" && (Date?.now() - complaintDetails?.service?.auditDetails?.lastModifiedTime) < ComplainMaxIdleTime)))
+ return (
+
+ {t(`CS_COMMON_${action}`)}
+
+ );
+ }
+ });
+ return {actions}} />;
+ }
+};
+
+export default Rejected;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/reopen.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/reopen.js
new file mode 100644
index 00000000000..59b1bd8681e
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/reopen.js
@@ -0,0 +1,14 @@
+import { GreyOutText } from "@egovernments/digit-ui-react-components";
+import React from "react";
+const Reopen = ({ text, reopenDate }) => {
+ // let { t } = useTranslation();
+ // let reopenDate = ConvertTimestampToDate(obj.auditDetails.createdTime);
+ return (
+
+ {text}
+ {reopenDate}
+
+ );
+};
+
+export default Reopen;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/resolved.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/resolved.js
new file mode 100644
index 00000000000..7d51132ba3b
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/timelineInstances/resolved.js
@@ -0,0 +1,55 @@
+import React from "react";
+import { ActionLinks, CheckPoint } from "@egovernments/digit-ui-react-components";
+import { Link } from "react-router-dom";
+import StarRated from "./StarRated";
+import { useTranslation } from "react-i18next";
+import Reopen from "./reopen";
+//const GetTranslatedAction = (action, t) => t(`CS_COMMON_${action}`);
+
+const Resolved = ({ action, nextActions,complaintDetails, ComplainMaxIdleTime=3600000, rating, serviceRequestId, reopenDate, isCompleted, customChild }) => {
+ const { t } = useTranslation();
+
+ if (action === "RESOLVE") {
+ let actions =
+ nextActions &&
+ nextActions.map((action, index) => {
+ if (action && action !== "COMMENT") {
+ return (
+
+ {t(`CS_COMMON_${action}`)}
+
+ );
+ }
+ });
+ return {actions}{customChild}} />;
+ } else if (action === "RATE") {
+ return (
+
+ {/* {rating ? : null} */}
+ {customChild}
+ }
+ />
+ );
+ } else if (action === "REOPEN") {
+ return ;
+ } else {
+ let actions =
+ nextActions &&
+ nextActions.map((action, index) => {
+ if (action && action !== "COMMENT") {
+ if((action!== "REOPEN" || (action === "REOPEN" && (Date?.now() - complaintDetails?.service?.auditDetails?.lastModifiedTime) < ComplainMaxIdleTime)))
+ return (
+
+ {t(`CS_COMMON_${action}`)}
+
+ );
+ }
+ });
+ return {actions}{customChild}} />;
+ }
+};
+
+export default Resolved;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Citizen.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Citizen.js
new file mode 100644
index 00000000000..2c550d45bc5
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Citizen.js
@@ -0,0 +1,3 @@
+// Session Storage Keys
+export const PGR_CITIZEN_CREATE_COMPLAINT = "PGR_CITIZEN_CREATE_COMPLAINT";
+export const PGR_CITIZEN_COMPLAINT_CONFIG = "PGR_CITIZEN_COMPLAINT_CONFIG";
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Employee.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Employee.js
new file mode 100644
index 00000000000..46173a9a280
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Employee.js
@@ -0,0 +1,2 @@
+export const PGR_EMPLOYEE_COMPLAINT_DETAILS = "/complaint/details/";
+export const PGR_EMPLOYEE_CREATE_COMPLAINT = "/complaint/create";
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Localization.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Localization.js
new file mode 100644
index 00000000000..91e8479942a
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Localization.js
@@ -0,0 +1,20 @@
+export const LOCALIZATION_KEY = {
+ CS_COMPLAINT_DETAILS: "CS_COMPLAINT_DETAILS",
+ CS_COMMON: "CS_COMMON",
+ CS_COMPLAINT: "CS_COMPLAINT",
+ CS_FEEDBACK: "CS_FEEDBACK",
+ CS_HEADER: "CS_HEADER",
+ CS_HOME: "CS_HOME",
+ CS_ADDCOMPLAINT: "CS_ADDCOMPLAINT",
+ CS_REOPEN: "CS_REOPEN",
+ CS_CREATECOMPLAINT: "CS_CREATECOMPLAINT",
+ PT_COMMONS: "PT_COMMONS",
+ CORE_COMMON: "CORE_COMMON",
+};
+
+export const LOCALE = {
+ MY_COMPLAINTS: "CS_HOME_MY_COMPLAINTS",
+ NO_COMPLAINTS: "CS_MYCOMPLAINTS_NO_COMPLAINTS",
+ NO_COMPLAINTS_EMPLOYEE: "CS_MYCOMPLAINTS_NO_COMPLAINTS_EMPLOYEE",
+ ERROR_LOADING_RESULTS: "CS_COMMON_ERROR_LOADING_RESULTS",
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Routes.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Routes.js
new file mode 100644
index 00000000000..6f0614f5ce0
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/constants/Routes.js
@@ -0,0 +1,37 @@
+export const PGR_BASE = `/${window?.contextPath}/pgr/citizen/`;
+
+const CREATE_COMPLAINT_PATH = "/create-complaint/";
+const REOPEN_COMPLAINT_PATH = "/reopen/";
+import { PGR_EMPLOYEE_COMPLAINT_DETAILS, PGR_EMPLOYEE_CREATE_COMPLAINT } from "./Employee";
+
+export const PgrRoutes = {
+ ComplaintsPage: "/complaints",
+ RatingAndFeedBack: "/rate/:id*",
+ ComplaintDetailsPage: "/complaint/details/:id",
+ ReasonPage: `/:id`,
+ UploadPhoto: `/upload-photo/:id`,
+ AddtionalDetails: `/addional-details/:id`,
+ CreateComplaint: "/create-complaint",
+ ReopenComplaint: "/reopen",
+ Response: "/response",
+
+ CreateComplaintStart: "",
+ SubType: `/subtype`,
+ LocationSearch: `/location`,
+ Pincode: `/pincode`,
+ Address: `/address`,
+ Landmark: `/landmark`,
+ UploadPhotos: `/upload-photos`,
+ Details: `/details`,
+ CreateComplaintResponse: `/response`,
+};
+
+export const Employee = {
+ Inbox: "/inbox",
+ ComplaintDetails: PGR_EMPLOYEE_COMPLAINT_DETAILS,
+ CreateComplaint: PGR_EMPLOYEE_CREATE_COMPLAINT,
+ Response: "/response",
+ Home: `/${window?.contextPath}/employee`,
+};
+
+export const getRoute = (match, route) => `${match.path}${route}`;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintDetails.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintDetails.js
new file mode 100644
index 00000000000..c4fd9bc9b65
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintDetails.js
@@ -0,0 +1,186 @@
+import React, { useEffect, useState } from "react";
+import { useParams } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+
+import { LOCALIZATION_KEY } from "../../constants/Localization";
+
+import {
+ Card,
+ Header,
+ CardSubHeader,
+ StatusTable,
+ Row,
+ TextArea,
+ SubmitBar,
+ DisplayPhotos,
+ ImageViewer,
+ Loader,
+ Toast,
+} from "@egovernments/digit-ui-react-components";
+
+import TimeLine from "../../components/TimeLine";
+
+const WorkflowComponent = ({ complaintDetails, id, getWorkFlow, zoomImage }) => {
+ const tenantId = Digit.SessionStorage.get("CITIZEN.COMMON.HOME.CITY")?.code || complaintDetails.service.tenantId;
+ let workFlowDetails = Digit.Hooks.useWorkflowDetails({ tenantId: tenantId, id, moduleCode: "PGR" });
+ const { data: ComplainMaxIdleTime, isLoading: ComplainMaxIdleTimeLoading } = Digit.Hooks.pgr.useMDMS.ComplainClosingTime(tenantId?.split(".")[0]);
+
+ useEffect(() => {
+ getWorkFlow(workFlowDetails.data);
+ }, [workFlowDetails.data]);
+
+ useEffect(() => {
+ workFlowDetails.revalidate();
+ }, []);
+
+ return (
+ !workFlowDetails.isLoading && (
+
+ )
+ );
+};
+
+const ComplaintDetailsPage = (props) => {
+ let { t } = useTranslation();
+ let { id } = useParams();
+
+ let tenantId = Digit.SessionStorage.get("CITIZEN.COMMON.HOME.CITY")?.code || Digit.ULBService.getCurrentTenantId(); // ToDo: fetch from state
+ const { isLoading, error, isError, complaintDetails, revalidate } = Digit.Hooks.pgr.useComplaintDetails({ tenantId, id });
+
+ const [imageShownBelowComplaintDetails, setImageToShowBelowComplaintDetails] = useState({});
+
+ const [imageZoom, setImageZoom] = useState(null);
+
+ const [comment, setComment] = useState("");
+
+ const [toast, setToast] = useState(false);
+
+ const [commentError, setCommentError] = useState(null);
+
+ const [disableComment, setDisableComment] = useState(true);
+
+ const [loader, setLoader] = useState(false);
+
+ useEffect(() => {
+ (async () => {
+ if (complaintDetails) {
+ setLoader(true);
+ await revalidate();
+ setLoader(false);
+ }
+ })();
+ }, []);
+
+ function zoomImage(imageSource, index) {
+ setImageZoom(imageSource);
+ }
+ function zoomImageWrapper(imageSource, index) {
+ zoomImage(imageShownBelowComplaintDetails?.fullImage[index]);
+ }
+
+ function onCloseImageZoom() {
+ setImageZoom(null);
+ }
+
+ const onWorkFlowChange = (data) => {
+ let timeline = data?.timeline;
+ timeline && timeline[0].timeLineActions?.filter((e) => e === "COMMENT").length ? setDisableComment(false) : setDisableComment(true);
+ if (timeline) {
+ const actionByCitizenOnComplaintCreation = timeline.find((e) => e?.performedAction === "APPLY");
+ const { thumbnailsToShow } = actionByCitizenOnComplaintCreation;
+ setImageToShowBelowComplaintDetails(thumbnailsToShow);
+ }
+ };
+
+ const submitComment = async () => {
+ let detailsToSend = { ...complaintDetails };
+ delete detailsToSend.audit;
+ delete detailsToSend.details;
+ detailsToSend.workflow = { action: "COMMENT", comments: comment };
+ let tenantId = Digit.ULBService.getCurrentTenantId();
+ try {
+ setCommentError(null);
+ const res = await Digit.PGRService.update(detailsToSend, tenantId);
+ if (res.ServiceWrappers.length) setComment("");
+ else throw true;
+ } catch (er) {
+ setCommentError(true);
+ }
+ setToast(true);
+ setTimeout(() => {
+ setToast(false);
+ }, 30000);
+ };
+
+ if (isLoading || loader) {
+ return ;
+ }
+
+ if (isError) {
+ return Error
;
+ }
+
+ return (
+
+
+ {t(`${LOCALIZATION_KEY.CS_HEADER}_COMPLAINT_SUMMARY`)}
+
+ {Object.keys(complaintDetails).length > 0 ? (
+
+
+ {t(`SERVICEDEFS.${complaintDetails.audit.serviceCode.toUpperCase()}`)}
+
+ {Object.keys(complaintDetails.details).map((flag, index, arr) => (
+ (typeof val === "object" ? t(val?.code) : t(val)))
+ : t(complaintDetails.details[flag]) || "N/A"
+ }
+ last={index === arr.length - 1}
+ />
+ ))}
+
+ {imageShownBelowComplaintDetails?.thumbs ? (
+ zoomImageWrapper(source, index)} />
+ ) : null}
+ {imageZoom ? : null}
+
+
+ {complaintDetails?.service && (
+
+ )}
+
+ {/*
+ {t(`${LOCALIZATION_KEY.CS_COMMON}_COMMENTS`)}
+ */}
+ {toast && (
+ setToast(false)}
+ />
+ )}{" "}
+
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export default ComplaintDetailsPage;
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintsList.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintsList.js
new file mode 100644
index 00000000000..805ebb5941b
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ComplaintsList.js
@@ -0,0 +1,68 @@
+import React, { useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { useRouteMatch } from "react-router-dom";
+
+import { Card, Header, Loader } from "@egovernments/digit-ui-react-components";
+import { LOCALE } from "../../constants/Localization";
+import Complaint from "../../components/Complaint";
+
+export const ComplaintsList = (props) => {
+ const User = Digit.UserService.getUser();
+ const mobileNumber = User.mobileNumber || User?.info?.mobileNumber || User?.info?.userInfo?.mobileNumber;
+ const tenantId = Digit.SessionStorage.get("CITIZEN.COMMON.HOME.CITY")?.code || Digit.ULBService.getCurrentTenantId();
+ const { t } = useTranslation();
+ const { path, url } = useRouteMatch();
+ let { isLoading, error, data, revalidate } = Digit.Hooks.pgr.useComplaintsListByMobile(tenantId, mobileNumber);
+
+ useEffect(() => {
+ revalidate();
+ }, []);
+
+ if (isLoading) {
+ return (
+
+ {t(LOCALE.MY_COMPLAINTS)}
+
+
+ );
+ }
+
+ let complaints = data?.ServiceWrappers;
+ let complaintsList;
+ if (error) {
+ complaintsList = (
+
+ {t(LOCALE.ERROR_LOADING_RESULTS)
+ .split("\\n")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+ );
+ } else if (complaints.length === 0) {
+ complaintsList = (
+
+ {t(LOCALE.NO_COMPLAINTS)
+ .split("\\n")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+ );
+ } else {
+ complaintsList = complaints.map(({ service }, index) => );
+ }
+
+ return (
+
+
+ {t(LOCALE.MY_COMPLAINTS)}
+ {complaintsList}
+
+
+ );
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Response.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Response.js
new file mode 100644
index 00000000000..dd6f2415448
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Response.js
@@ -0,0 +1,51 @@
+import React from "react";
+import { Card, Banner, CardText, SubmitBar } from "@egovernments/digit-ui-react-components";
+import { Link } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { PgrRoutes, getRoute } from "../../../constants/Routes";
+import { useTranslation } from "react-i18next";
+
+const GetActionMessage = ({ action }) => {
+ const { t } = useTranslation();
+ switch (action) {
+ case "REOPEN":
+ return t(`CS_COMMON_COMPLAINT_REOPENED`);
+ case "RATE":
+ return t("CS_COMMON_THANK_YOU");
+ default:
+ return t(`CS_COMMON_COMPLAINT_SUBMITTED`);
+ }
+};
+
+const BannerPicker = ({ response }) => {
+ const { complaints } = response;
+
+ if (complaints && complaints.response && complaints.response.responseInfo) {
+ return (
+
+ );
+ } else {
+ return ;
+ }
+};
+
+const Response = (props) => {
+ const { t } = useTranslation();
+ const appState = useSelector((state) => state)["pgr"];
+
+ return (
+
+ {appState.complaints.response && }
+ {t("CS_COMMON_TRACK_COMPLAINT_TEXT")}
+
+
+
+
+ );
+};
+
+export default Response;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/Response.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/Response.js
new file mode 100644
index 00000000000..9e14b599eab
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/Response.js
@@ -0,0 +1,39 @@
+import React from "react";
+import { FormStep, Banner } from "@egovernments/digit-ui-react-components";
+import { useSelector } from "react-redux";
+import { useTranslation } from "react-i18next";
+
+const GetActionMessage = ({ action }) => {
+ const { t } = useTranslation();
+ if (action === "REOPEN") {
+ return t(`CS_COMMON_COMPLAINT_REOPENED`);
+ } else {
+ return t(`CS_COMMON_COMPLAINT_SUBMITTED`);
+ }
+};
+
+const BannerPicker = ({ complaints }) => {
+ const { t } = useTranslation();
+ if (complaints && complaints.response && complaints.response.responseInfo) {
+ return (
+
+ );
+ } else {
+ return ;
+ }
+};
+
+const Response = ({ t, config, onSelect }) => {
+ const complaints = useSelector((state) => state["pgr"].complaints);
+ return (
+
+ {complaints.response ? : null}
+
+ );
+};
+
+export default Response;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectAddress.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectAddress.js
new file mode 100644
index 00000000000..9741b1bd34b
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectAddress.js
@@ -0,0 +1,74 @@
+import React, { useEffect, useState, useRef } from "react";
+import { CardLabel, Dropdown, FormStep, RadioButtons } from "@egovernments/digit-ui-react-components";
+
+const SelectAddress = ({ t, config, onSelect, value }) => {
+ const allCities = Digit.Hooks.pgr.useTenants();
+ const cities = value?.pincode ? allCities.filter((city) => city?.pincode?.some((pin) => pin == value["pincode"])) : allCities;
+
+ const [selectedCity, setSelectedCity] = useState(() => {
+ const { city_complaint } = value;
+ return city_complaint ? city_complaint : null;
+ });
+ const { data: fetchedLocalities } = Digit.Hooks.useBoundaryLocalities(
+ selectedCity?.code,
+ "admin",
+ {
+ enabled: !!selectedCity,
+ },
+ t
+ );
+ const [localities, setLocalities] = useState(null);
+
+ const [selectedLocality, setSelectedLocality] = useState(() => {
+ const { locality_complaint } = value;
+ return locality_complaint ? locality_complaint : null;
+ });
+
+ useEffect(() => {
+ if (selectedCity && fetchedLocalities) {
+ const { pincode } = value;
+ let __localityList = pincode ? fetchedLocalities.filter((city) => city["pincode"] == pincode) : fetchedLocalities;
+ setLocalities(__localityList);
+ }
+ }, [selectedCity, fetchedLocalities]);
+
+ function selectCity(city) {
+ setSelectedLocality(null);
+ setLocalities(null);
+ setSelectedCity(city);
+ // Digit.SessionStorage.set("city_complaint", city);
+ }
+
+ function selectLocality(locality) {
+ setSelectedLocality(locality);
+ // Digit.SessionStorage.set("locality_complaint", locality);
+ }
+
+ function onSubmit() {
+ onSelect({ city_complaint: selectedCity, locality_complaint: selectedLocality });
+ }
+ return (
+
+
+ {t("MYCITY_CODE_LABEL")}
+ {cities?.length < 5 ? (
+
+ ) : (
+
+ )}
+ {selectedCity && localities && {t("CS_CREATECOMPLAINT_MOHALLA")}}
+ {selectedCity && localities && (
+
+ {localities?.length < 5 ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+
+ );
+};
+
+export default SelectAddress;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectComplaintType.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectComplaintType.js
new file mode 100644
index 00000000000..bacaeb161a5
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectComplaintType.js
@@ -0,0 +1,37 @@
+import React, { useState } from "react";
+import { useForm } from "react-hook-form";
+import { TypeSelectCard } from "@egovernments/digit-ui-react-components";
+
+const SelectComplaintType = ({ t, config, onSelect, value }) => {
+ const [complaintType, setComplaintType] = useState(() => {
+ const { complaintType } = value;
+ return complaintType ? complaintType : {};
+ });
+
+ const goNext = () => {
+ onSelect({ complaintType });
+ };
+
+ const textParams = config.texts;
+
+ const menu = Digit.Hooks.pgr.useComplaintTypes({ stateCode: Digit.ULBService.getCurrentTenantId() });
+
+ function selectedValue(value) {
+ setComplaintType(value);
+ // SessionStorage.set("complaintType", value);
+ }
+ return (
+
+ );
+};
+
+export default SelectComplaintType;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectDetails.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectDetails.js
new file mode 100644
index 00000000000..377ca2cb4f2
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectDetails.js
@@ -0,0 +1,18 @@
+import React, { useState } from "react";
+import { FormStep } from "@egovernments/digit-ui-react-components";
+
+const SelectDetails = ({ t, config, onSelect, value }) => {
+ const [details, setDetails] = useState(() => {
+ const { details } = value;
+ return details ? details : "";
+ });
+
+ const onChange = (event) => {
+ const { value } = event.target;
+ setDetails(value);
+ };
+
+ return onSelect({ details })} value={details} t={t} />;
+};
+
+export default SelectDetails;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectGeolocation.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectGeolocation.js
new file mode 100644
index 00000000000..d16efff8e6b
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectGeolocation.js
@@ -0,0 +1,19 @@
+import React from "react";
+import { LocationSearchCard } from "@egovernments/digit-ui-react-components";
+
+const SelectGeolocation = ({ onSelect, onSkip, value, t }) => {
+ let pincode = "";
+ return (
+ onSelect()}
+ onSave={() => onSelect({ pincode })}
+ onChange={(code) => (pincode = code)}
+ />
+ );
+};
+
+export default SelectGeolocation;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectImages.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectImages.js
new file mode 100644
index 00000000000..1cc1fd67d0b
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectImages.js
@@ -0,0 +1,36 @@
+import React, { useState } from "react";
+import { FormStep, ImageUploadHandler, Loader } from "@egovernments/digit-ui-react-components";
+
+const SelectImages = ({ t, config, onSelect, onSkip, value }) => {
+ // const __initImages = Digit.SessionStorage.get("PGR_CREATE_IMAGES");
+ const [uploadedImages, setUploadedImagesIds] = useState(() => {
+ // __initImages ? __initImages : null
+ const { uploadedImages } = value;
+ return uploadedImages ? uploadedImages : null;
+ });
+
+ const handleUpload = (ids) => {
+ setUploadedImagesIds(ids);
+ // Digit.SessionStorage.set("PGR_CREATE_IMAGES", ids);
+ };
+
+ // const onSkip = () => onSelect();
+ const handleSubmit = () => {
+ if (!uploadedImages || uploadedImages.length === 0) return onSkip();
+ // const _uploadImages = uploadedImages.map((url) => ({
+ // documentType: "PHOTO",
+ // fileStore: url,
+ // documentUid: "",
+ // additionalDetails: {},
+ // }));
+ onSelect({ uploadedImages });
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default SelectImages;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectLandmark.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectLandmark.js
new file mode 100644
index 00000000000..ae293bc7dfb
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectLandmark.js
@@ -0,0 +1,19 @@
+import React, { useState } from "react";
+import { FormStep } from "@egovernments/digit-ui-react-components";
+
+const SelectLandmark = ({ t, config, onSelect, value }) => {
+ const [landmark, setLandmark] = useState(() => {
+ const { landmark } = value;
+ return landmark ? landmark : "";
+ });
+
+ function onChange(e) {
+ setLandmark(e.target.value);
+ }
+
+ const onSkip = () => onSelect();
+
+ return onSelect(data)} onSkip={onSkip} t={t}>;
+};
+
+export default SelectLandmark;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectPincode.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectPincode.js
new file mode 100644
index 00000000000..a4d94e68bc5
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectPincode.js
@@ -0,0 +1,56 @@
+import { FormStep } from "@egovernments/digit-ui-react-components";
+import React, { useState } from "react";
+
+const SelectPincode = ({ t, config, onSelect, value }) => {
+ const tenants = Digit.Hooks.pgr.useTenants();
+ // const __initPincode = Digit.SessionStorage.get("PGR_CREATE_PINCODE");
+ const [pincode, setPincode] = useState(() => {
+ const { pincode } = value;
+ return pincode;
+ });
+ let isNextDisabled = pincode ? false : true;
+ const [pincodeServicability, setPincodeServicability] = useState(null);
+
+ function onChange(e) {
+ setPincode(e.target.value);
+
+ if (!e.target.value) {
+ isNextDisabled = true;
+ } else {
+ isNextDisabled = false;
+ }
+ // Digit.SessionStorage.set("PGR_CREATE_PINCODE", e.target.value);
+ setPincodeServicability(null);
+ }
+
+ const goNext = async (data) => {
+ var foundValue = tenants.find((obj) => obj.pincode?.find((item) => item == data?.pincode));
+ if (foundValue) {
+ Digit.SessionStorage.set("city_complaint", foundValue);
+ let response = await Digit.LocationService.getLocalities(foundValue.code);
+ let __localityList = Digit.LocalityService.get(response.TenantBoundary[0]);
+ const filteredLocalities = __localityList.filter((obj) => obj.pincode?.find((item) => item == data.pincode));
+ onSelect({ ...data, city_complaint: foundValue });
+ } else {
+ Digit.SessionStorage.set("city_complaint", undefined);
+ Digit.SessionStorage.set("selected_localities", undefined);
+ setPincodeServicability("CS_COMMON_PINCODE_NOT_SERVICABLE");
+ }
+ };
+
+ const onSkip = () => onSelect();
+ return (
+
+ );
+};
+
+export default SelectPincode;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectSubType.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectSubType.js
new file mode 100644
index 00000000000..9b6d34fa77c
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/Steps/SelectSubType.js
@@ -0,0 +1,34 @@
+import { TypeSelectCard } from "@egovernments/digit-ui-react-components";
+import React, { useState } from "react";
+
+const SelectSubType = ({ t, config, onSelect, value }) => {
+ const [subType, setSubType] = useState(() => {
+ const { subType } = value;
+ return subType ? subType : {};
+ });
+ const { complaintType } = value;
+ const menu = Digit.Hooks.pgr.useComplaintSubType(complaintType, t);
+
+
+ const goNext = () => {
+ // const serviceCode = subType.key;
+ onSelect({ subType });
+ };
+
+ function selectedValue(value) {
+ setSubType(value);
+ }
+
+ const configNew = {
+ ...config.texts,
+ ...{ headerCaption: t(`SERVICEDEFS.${complaintType.key.toUpperCase()}`) },
+ ...{ menu: menu },
+ ...{ optionsKey: "name" },
+ ...{ selected: selectedValue },
+ ...{ selectedOption: subType },
+ ...{ onSave: goNext },
+ };
+
+ return ;
+};
+export default SelectSubType;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/config.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/config.js
new file mode 100644
index 00000000000..2571cdfa849
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/config.js
@@ -0,0 +1,98 @@
+export const newComplaintSteps = [
+ {
+ path: "/complaint-type",
+ texts: {
+ headerCaption: "",
+ header: "CS_ADDCOMPLAINT_COMPLAINT_TYPE_PLACEHOLDER",
+ cardText: "CS_COMPLAINT_TYPE_TEXT",
+ submitBarLabel: "PT_COMMONS_NEXT",
+ },
+ },
+ {
+ path: "/sub-type",
+ texts: {
+ header: "CS_ADDCOMPLAINT_COMPLAINT_SUBTYPE_PLACEHOLDER",
+ cardText: "CS_COMPLAINT_SUBTYPE_TEXT",
+ submitBarLabel: "PT_COMMONS_NEXT",
+ },
+ },
+ {
+ path: "/pincode",
+ texts: {
+ headerCaption: "CS_ADDCOMPLAINT_COMPLAINT_LOCATION",
+ header: "CS_FILE_APPLICATION_PINCODE_LABEL",
+ cardText: "CS_ADDCOMPLAINT_CHANGE_PINCODE_TEXT",
+ nextText: "PT_COMMONS_NEXT",
+ skipText: "CORE_COMMON_SKIP_CONTINUE",
+ },
+ inputs: [
+ {
+ label: "CORE_COMMON_PINCODE",
+ type: "text",
+ name: "pincode",
+ validation: {
+ minLength: 6,
+ maxLength: 7,
+ },
+ error: "CORE_COMMON_PINCODE_INVALID",
+ },
+ ],
+ },
+ {
+ path: "/address",
+ texts: {
+ headerCaption: "CS_ADDCOMPLAINT_COMPLAINT_LOCATION",
+ header: "CS_ADDCOMPLAINT_PROVIDE_COMPLAINT_ADDRESS",
+ cardText: "CS_ADDCOMPLAINT_CITY_MOHALLA_TEXT",
+ nextText: "PT_COMMONS_NEXT",
+ },
+ },
+ {
+ path: "/landmark",
+ texts: {
+ headerCaption: "CS_ADDCOMPLAINT_COMPLAINT_LOCATION",
+ header: "CS_FILE_APPLICATION_PROPERTY_LOCATION_PROVIDE_LANDMARK_TITLE",
+ cardText: "CS_FILE_APPLICATION_PROPERTY_LOCATION_PROVIDE_LANDMARK_TITLE_TEXT",
+ nextText: "PT_COMMONS_NEXT",
+ skipText: "CORE_COMMON_SKIP_CONTINUE",
+ },
+ inputs: [
+ {
+ label: "CS_ADDCOMPLAINT_LANDMARK",
+ type: "textarea",
+ name: "landmark",
+ },
+ ],
+ },
+ {
+ path: "/upload-photos",
+ texts: {
+ header: "CS_ADDCOMPLAINT_UPLOAD_PHOTO",
+ cardText: "CS_ADDCOMPLAINT_UPLOAD_PHOTO_TEXT",
+ nextText: "PT_COMMONS_NEXT",
+ skipText: "CORE_COMMON_SKIP_CONTINUE",
+ },
+ },
+ {
+ path: "/additional-details",
+ texts: {
+ header: "CS_ADDCOMPLAINT_PROVIDE_ADDITIONAL_DETAILS",
+ cardText: "CS_ADDCOMPLAINT_ADDITIONAL_DETAILS_TEXT",
+ nextText: "PT_COMMONS_NEXT",
+ },
+ inputs: [
+ {
+ label: "CS_ADDCOMPLAINT_ADDITIONAL_DETAILS",
+ type: "textarea",
+ name: "details",
+ },
+ ],
+ },
+ {
+ path: "/response",
+ texts: {
+ cardText: "CS_COMMON_TRACK_COMPLAINT_TEXT",
+ nextText: "CORE_COMMON_GO_TO_HOME",
+ },
+ },
+];
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/defaultConfig.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/defaultConfig.js
new file mode 100644
index 00000000000..0dc0fbda572
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/defaultConfig.js
@@ -0,0 +1,114 @@
+import SelectAddress from "./Steps/SelectAddress";
+import SelectComplaintType from "./Steps/SelectComplaintType";
+import SelectDetails from "./Steps/SelectDetails";
+import SelectImages from "./Steps/SelectImages";
+import SelectLandmark from "./Steps/SelectLandmark";
+import SelectPincode from "./Steps/SelectPincode";
+import SelectSubType from "./Steps/SelectSubType";
+import SelectGeolocation from "./Steps/SelectGeolocation";
+
+export const config = {
+ routes: {
+ "complaint-type": {
+ component: SelectComplaintType,
+ texts: {
+ headerCaption: "",
+ header: "CS_ADDCOMPLAINT_COMPLAINT_TYPE_PLACEHOLDER",
+ cardText: "CS_COMPLAINT_TYPE_TEXT",
+ submitBarLabel: "CS_COMMON_NEXT",
+ },
+ nextStep: "sub-type",
+ },
+ "sub-type": {
+ component: SelectSubType,
+ texts: {
+ header: "CS_ADDCOMPLAINT_COMPLAINT_SUBTYPE_PLACEHOLDER",
+ cardText: "CS_COMPLAINT_SUBTYPE_TEXT",
+ submitBarLabel: "CS_COMMON_NEXT",
+ },
+ nextStep: "map",
+ },
+ map: {
+ component: SelectGeolocation,
+ nextStep: "pincode",
+ },
+ pincode: {
+ component: SelectPincode,
+ texts: {
+ headerCaption: "CS_ADDCOMPLAINT_COMPLAINT_LOCATION",
+ header: "CS_FILE_APPLICATION_PINCODE_LABEL",
+ cardText: "CS_ADDCOMPLAINT_CHANGE_PINCODE_TEXT",
+ submitBarLabel: "CS_COMMON_NEXT",
+ skipText: "CORE_COMMON_SKIP_CONTINUE",
+ },
+ inputs: [
+ {
+ label: "CORE_COMMON_PINCODE",
+ type: "text",
+ name: "pincode",
+ validation: {
+ minLength: 6,
+ maxLength: 7,
+ },
+ error: "CORE_COMMON_PINCODE_INVALID",
+ },
+ ],
+ nextStep: "address",
+ },
+ address: {
+ component: SelectAddress,
+ texts: {
+ headerCaption: "CS_ADDCOMPLAINT_COMPLAINT_LOCATION",
+ header: "CS_ADDCOMPLAINT_PROVIDE_COMPLAINT_ADDRESS",
+ cardText: "CS_ADDCOMPLAINT_CITY_MOHALLA_TEXT",
+ submitBarLabel: "CS_COMMON_NEXT",
+ },
+ nextStep: "landmark",
+ },
+ landmark: {
+ component: SelectLandmark,
+ texts: {
+ headerCaption: "CS_ADDCOMPLAINT_COMPLAINT_LOCATION",
+ header: "CS_FILE_APPLICATION_PROPERTY_LOCATION_PROVIDE_LANDMARK_TITLE",
+ cardText: "CS_FILE_APPLICATION_PROPERTY_LOCATION_PROVIDE_LANDMARK_TITLE_TEXT",
+ submitBarLabel: "CS_COMMON_NEXT",
+ skipText: "CORE_COMMON_SKIP_CONTINUE",
+ },
+ inputs: [
+ {
+ label: "CS_ADDCOMPLAINT_LANDMARK",
+ type: "textarea",
+ name: "landmark",
+ },
+ ],
+ nextStep: "upload-photos",
+ },
+ "upload-photos": {
+ component: SelectImages,
+ texts: {
+ header: "CS_ADDCOMPLAINT_UPLOAD_PHOTO",
+ cardText: "CS_ADDCOMPLAINT_UPLOAD_PHOTO_TEXT",
+ submitBarLabel: "CS_COMMON_NEXT",
+ skipText: "CORE_COMMON_SKIP_CONTINUE",
+ },
+ nextStep: "additional-details",
+ },
+ "additional-details": {
+ component: SelectDetails,
+ texts: {
+ header: "CS_ADDCOMPLAINT_PROVIDE_ADDITIONAL_DETAILS",
+ cardText: "CS_ADDCOMPLAINT_ADDITIONAL_DETAILS_TEXT",
+ submitBarLabel: "CS_COMMON_NEXT",
+ },
+ inputs: [
+ {
+ label: "CS_ADDCOMPLAINT_ADDITIONAL_DETAILS",
+ type: "textarea",
+ name: "details",
+ },
+ ],
+ nextStep: null,
+ },
+ },
+ indexRoute: "complaint-type",
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/index.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/index.js
new file mode 100644
index 00000000000..740de4a682f
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Create/index.js
@@ -0,0 +1,129 @@
+import React, { useContext, useEffect, useMemo, useState } from "react";
+import { useTranslation } from "react-i18next";
+import merge from "lodash.merge";
+import { useDispatch } from "react-redux";
+import { createComplaint } from "../../../redux/actions/index";
+import { PGR_CITIZEN_COMPLAINT_CONFIG, PGR_CITIZEN_CREATE_COMPLAINT } from "../../../constants/Citizen";
+import Response from "./Response";
+
+import { config as defaultConfig } from "./defaultConfig";
+import { Redirect, Route, Switch, useHistory, useRouteMatch, useLocation } from "react-router-dom";
+import { useQueryClient } from "react-query";
+
+export const CreateComplaint = () => {
+ const ComponentProvider = Digit.Contexts.ComponentProvider;
+ const { t } = useTranslation();
+ const { pathname } = useLocation();
+ const match = useRouteMatch();
+ const history = useHistory();
+ const registry = useContext(ComponentProvider);
+ const dispatch = useDispatch();
+ const { data: storeData, isLoading } = Digit.Hooks.useStore.getInitData();
+ const { stateInfo } = storeData || {};
+ const [params, setParams, clearParams] = Digit.Hooks.useSessionStorage(PGR_CITIZEN_CREATE_COMPLAINT, {});
+ // const [customConfig, setConfig] = Digit.Hooks.useSessionStorage(PGR_CITIZEN_COMPLAINT_CONFIG, {});
+ const config = useMemo(() => merge(defaultConfig, Digit.Customizations.PGR.complaintConfig), [Digit.Customizations.PGR.complaintConfig]);
+ const [paramState, setParamState] = useState(params);
+ const [nextStep, setNextStep] = useState("");
+ const [canSubmit, setCanSubmit] = useState(false);
+
+ const [rerender, setRerender] = useState(0);
+ const client = useQueryClient();
+ useEffect(() => {
+ setCanSubmit(false);
+ }, []);
+
+ useEffect(() => {
+ setParamState(params);
+ if (nextStep === null) {
+ wrapperSubmit();
+ } else {
+ history.push(`${match.path}/${nextStep}`);
+ }
+ }, [params, nextStep]);
+
+ const goNext = () => {
+ const currentPath = pathname.split("/").pop();
+
+ let { nextStep } = config.routes[currentPath];
+ let compType = Digit.SessionStorage.get(PGR_CITIZEN_CREATE_COMPLAINT);
+ if (nextStep === "sub-type" && compType.complaintType.key === "Others") {
+ setParams({
+ ...params,
+ complaintType: { key: "Others", name: t("SERVICEDEFS.OTHERS") },
+ subType: { key: "Others", name: t("SERVICEDEFS.OTHERS") },
+ });
+ nextStep = config.routes[nextStep].nextStep;
+ }
+ setNextStep(nextStep);
+ };
+
+ const wrapperSubmit = () => {
+ if (!canSubmit) {
+ setCanSubmit(true);
+ submitComplaint();
+ }
+ };
+ const submitComplaint = async () => {
+ if (paramState?.complaintType) {
+ const { city_complaint, locality_complaint, uploadedImages, complaintType, subType, details, ...values } = paramState;
+ const { code: cityCode, name: city } = city_complaint;
+ const { code: localityCode, name: localityName } = locality_complaint;
+ const _uploadImages = uploadedImages?.map((url) => ({
+ documentType: "PHOTO",
+ fileStoreId: url,
+ documentUid: "",
+ additionalDetails: {},
+ }));
+
+ const data = {
+ ...values,
+ complaintType: subType.key,
+ cityCode,
+ city,
+ description: details,
+ district: city,
+ region: city,
+ localityCode,
+ localityName,
+ state: stateInfo.name,
+ uploadedImages: _uploadImages,
+ };
+
+ await dispatch(createComplaint(data));
+ await client.refetchQueries(["complaintsList"]);
+ history.push(`${match.path}/response`);
+ }
+ };
+
+ const handleSelect = (data) => {
+ setParams({ ...params, ...data });
+ goNext();
+ };
+
+ const handleSkip = () => {
+ goNext();
+ };
+
+ if (isLoading) return null;
+
+ return (
+
+ {Object.keys(config.routes).map((route, index) => {
+ const { component, texts, inputs } = config.routes[route];
+ const Component = typeof component === "string" ? Digit.ComponentRegistryService.getComponent(component) : component;
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+
+
+ );
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/Rating.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/Rating.js
new file mode 100644
index 00000000000..6516c89b1ab
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/Rating.js
@@ -0,0 +1,76 @@
+import React, { useCallback, useState } from "react";
+import { useParams } from "react-router-dom";
+import { useForm } from "react-hook-form";
+import { useDispatch } from "react-redux";
+import { useTranslation } from "react-i18next";
+
+import { Card, CardHeader, CardLabel, Rating, CheckBox, TextArea, SubmitBar } from "@egovernments/digit-ui-react-components";
+import { updateComplaints } from "../../../redux/actions/index";
+
+import { LOCALIZATION_KEY } from "../../../constants/Localization";
+//import { Storage } from "../../@egovernments/digit-utils/services/Storage";
+
+const RatingAndFeedBack = () => {
+ const { id } = useParams();
+ const { handleSubmit } = useForm();
+ const { t } = useTranslation();
+
+ const dispatch = useDispatch();
+
+ const [selection, setSelection] = useState([]);
+ const [comment, setComment] = useState("");
+ const [rating, setRating] = useState(0);
+
+ let complaintDetails = Digit.SessionStorage.get(`complaint.${id}`);
+
+ const onSelect = (e) => {
+ setSelection([...selection, e.target.value]);
+ };
+
+ const onComments = (e) => {
+ setComment(e.target.value);
+ };
+
+ const feedback = (e, ref, index) => {
+ setRating(index);
+ };
+
+ const onSubmit = () => {
+ let complaintDetails = Digit.SessionStorage.get(`complaint.${id}`);
+ complaintDetails.service.rating = rating;
+ complaintDetails.service.additionalDetail = selection;
+ complaintDetails.workflow = {
+ action: "RATE",
+ comments: comment,
+ verificationDocuments: [],
+ };
+ updateComplaint(complaintDetails);
+ };
+
+ const updateComplaint = useCallback((complaintDetails) => dispatch(updateComplaints(complaintDetails)), [dispatch]);
+
+ let lables = ["_SERVICES", "_RESOLUTION_TIME", "_QUALITY_OF_WORK", "_OTHERS"];
+
+ return (
+
+
+
+ );
+};
+
+export default RatingAndFeedBack;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/SelectRating.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/SelectRating.js
new file mode 100644
index 00000000000..c24bce32f20
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Rating/SelectRating.js
@@ -0,0 +1,62 @@
+import React, { useCallback, useState } from "react";
+import { useDispatch } from "react-redux";
+import { RatingCard, CardLabelError } from "@egovernments/digit-ui-react-components";
+import { useParams, Redirect, useHistory } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import { updateComplaints } from "../../../redux/actions/index";
+
+const SelectRating = ({ parentRoute }) => {
+ const { t } = useTranslation();
+ const { id } = useParams();
+ const dispatch = useDispatch();
+ const history = useHistory();
+
+ let tenantId = Digit.SessionStorage.get("CITIZEN.COMMON.HOME.CITY")?.code || Digit.ULBService.getCurrentTenantId();
+ const complaintDetails = Digit.Hooks.pgr.useComplaintDetails({ tenantId: tenantId, id: id }).complaintDetails;
+ const updateComplaint = useCallback((complaintDetails) => dispatch(updateComplaints(complaintDetails)), [dispatch]);
+ const [submitError, setError] = useState(false)
+
+ function log(data) {
+ if (complaintDetails && data.rating > 0 ) {
+ complaintDetails.service.rating = data.rating;
+ complaintDetails.service.additionalDetail = data.CS_FEEDBACK_WHAT_WAS_GOOD.join(",");
+ complaintDetails.workflow = {
+ action: "RATE",
+ comments: data.comments,
+ verificationDocuments: [],
+ };
+ updateComplaint({ service: complaintDetails.service, workflow: complaintDetails.workflow });
+ history.push(`${parentRoute}/response`);
+ }
+ else{
+ setError(true)
+ }
+ }
+
+ const config = {
+ texts: {
+ header: "CS_COMPLAINT_RATE_HELP_TEXT",
+ submitBarLabel: "CS_COMMONS_NEXT",
+ },
+ inputs: [
+ {
+ type: "rate",
+ maxRating: 5,
+ label: t("CS_COMPLAINT_RATE_TEXT"),
+ error: submitError ? {t("CS_FEEDBACK_ENTER_RATING_ERROR")} : null
+ },
+ {
+ type: "checkbox",
+ label: "CS_FEEDBACK_WHAT_WAS_GOOD",
+ checkLabels: [t("CS_FEEDBACK_SERVICES"), t("CS_FEEDBACK_RESOLUTION_TIME"), t("CS_FEEDBACK_QUALITY_OF_WORK"), t("CS_FEEDBACK_OTHERS")],
+ },
+ {
+ type: "textarea",
+ label: t("CS_COMMON_COMMENTS"),
+ name: "comments",
+ },
+ ],
+ };
+ return ;
+};
+export default SelectRating;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/AddtionalDetails.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/AddtionalDetails.js
new file mode 100644
index 00000000000..7c9ae3f20ac
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/AddtionalDetails.js
@@ -0,0 +1,97 @@
+import React, { useCallback, useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch, useSelector } from "react-redux";
+import { useParams, useHistory, Redirect } from "react-router-dom";
+
+import { BackButton, Card, CardHeader, CardText, TextArea, SubmitBar } from "@egovernments/digit-ui-react-components";
+
+import { updateComplaints } from "../../../redux/actions/index";
+import { LOCALIZATION_KEY } from "../../../constants/Localization";
+
+const AddtionalDetails = (props) => {
+ // const [details, setDetails] = useState(null);
+ const history = useHistory();
+ let { id } = useParams();
+ const dispatch = useDispatch();
+ const appState = useSelector((state) => state)["common"];
+ let { t } = useTranslation();
+
+ const {complaintDetails} = props
+ useEffect(() => {
+ if (appState.complaints) {
+ const { response } = appState.complaints;
+ if (response && response.responseInfo.status === "successful") {
+ history.push(`${props.match.path}/response/:${id}`);
+ }
+ }
+ }, [appState.complaints, props.history]);
+
+ const updateComplaint = useCallback(
+ async (complaintDetails) => {
+ await dispatch(updateComplaints(complaintDetails));
+ history.push(`${props.match.path}/response/${id}`);
+ },
+ [dispatch]
+ );
+
+ const getUpdatedWorkflow = (reopenDetails, type) => {
+ switch (type) {
+ case "REOPEN":
+ return {
+ action: "REOPEN",
+ comments: reopenDetails.addtionalDetail,
+ assignes: [],
+ verificationDocuments: reopenDetails.verificationDocuments,
+ };
+ default:
+ return "";
+ }
+ };
+
+ function reopenComplaint() {
+ let reopenDetails = Digit.SessionStorage.get(`reopen.${id}`);
+ if (complaintDetails) {
+ complaintDetails.workflow = getUpdatedWorkflow(
+ reopenDetails,
+ // complaintDetails,
+ "REOPEN"
+ );
+ complaintDetails.service.additionalDetail = {
+ REOPEN_REASON: reopenDetails.reason,
+ };
+ updateComplaint({ service: complaintDetails.service, workflow: complaintDetails.workflow });
+ }
+ return (
+
+ );
+ }
+
+ function textInput(e) {
+ // setDetails(e.target.value);
+ let reopenDetails = Digit.SessionStorage.get(`reopen.${id}`);
+ Digit.SessionStorage.set(`reopen.${id}`, {
+ ...reopenDetails,
+ addtionalDetail: e.target.value,
+ });
+ }
+
+ return (
+
+
+ {t(`${LOCALIZATION_KEY.CS_ADDCOMPLAINT}_PROVIDE_ADDITIONAL_DETAILS`)}
+ {t(`${LOCALIZATION_KEY.CS_ADDCOMPLAINT}_ADDITIONAL_DETAILS_TEXT`)}
+
+
+
+
+
+
+ );
+};
+
+export default AddtionalDetails;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/Reason.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/Reason.js
new file mode 100644
index 00000000000..a67b9b52c1c
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/Reason.js
@@ -0,0 +1,57 @@
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { Link, useHistory, useParams } from "react-router-dom";
+import { BackButton, Card, CardHeader, CardLabelError, CardText, RadioButtons, SubmitBar } from "@egovernments/digit-ui-react-components";
+
+import { LOCALIZATION_KEY } from "../../../constants/Localization";
+import { getRoute, PgrRoutes, PGR_BASE } from "../../../constants/Routes";
+
+const ReasonPage = (props) => {
+ const history = useHistory();
+ const { t } = useTranslation();
+ const { id } = useParams();
+ const [selected, setSelected] = useState(null);
+ const [valid, setValid] = useState(true);
+
+ const onRadioChange = (value) => {
+ let reopenDetails = Digit.SessionStorage.get(`reopen.${id}`);
+ Digit.SessionStorage.set(`reopen.${id}`, { ...reopenDetails, reason: value });
+ setSelected(value);
+ };
+
+ function onSave() {
+ if (selected === null) {
+ setValid(false);
+ } else {
+ history.push(`${props.match.path}/upload-photo/${id}`);
+ }
+ }
+
+ return (
+
+ {t(`${LOCALIZATION_KEY.CS_REOPEN}_COMPLAINT`)}
+
+ {/* Select the option related to your complaint from the list given below.
+ If the complaint type you are looking for is not listed select others.{" "} */}
+ {/* {t(`${TRANSLATION_KEY}_OPTION_ONE`)} */}
+
+ {valid ? null : {t(`${LOCALIZATION_KEY.CS_ADDCOMPLAINT}_ERROR_REOPEN_REASON`)}}
+ setSelected(value)}
+ options={[
+ t(`${LOCALIZATION_KEY.CS_REOPEN}_OPTION_ONE`),
+ t(`${LOCALIZATION_KEY.CS_REOPEN}_OPTION_TWO`),
+ t(`${LOCALIZATION_KEY.CS_REOPEN}_OPTION_THREE`),
+ t(`${LOCALIZATION_KEY.CS_REOPEN}_OPTION_FOUR`),
+ ]}
+ />
+
+
+
+ );
+};
+
+export default ReasonPage;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/UploadPhoto.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/UploadPhoto.js
new file mode 100644
index 00000000000..a50ae8af67f
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/UploadPhoto.js
@@ -0,0 +1,71 @@
+import React, { useEffect, useState } from "react";
+import { Link, useHistory, useParams } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+
+import { Card, SubmitBar, BackButton, ImageUploadHandler, CardLabelError, LinkButton } from "@egovernments/digit-ui-react-components";
+
+import { LOCALIZATION_KEY } from "../../../constants/Localization";
+
+const UploadPhoto = (props) => {
+ const { t } = useTranslation();
+ const history = useHistory();
+ let { id } = useParams();
+ const [verificationDocuments, setVerificationDocuments] = useState(null);
+ const [valid, setValid] = useState(true);
+
+ const handleUpload = (ids) => {
+ setDocState(ids);
+ };
+
+ const setDocState = (ids) => {
+ if (ids?.length) {
+ const documents = ids.map((id) => ({
+ documentType: "PHOTO",
+ fileStoreId: id,
+ documentUid: "",
+ additionalDetails: {},
+ }));
+ setVerificationDocuments(documents);
+ }
+ };
+
+ function save() {
+ if (verificationDocuments === null) {
+ setValid(false);
+ } else {
+ history.push(`${props.match.path}/addional-details/${id}`);
+ }
+ }
+
+ function skip() {
+ history.push(`${props.match.path}/addional-details/${id}`);
+ }
+
+ useEffect(() => {
+ let reopenDetails = Digit.SessionStorage.get(`reopen.${id}`);
+ Digit.SessionStorage.set(`reopen.${id}`, { ...reopenDetails, verificationDocuments });
+ }, [verificationDocuments, id]);
+
+ return (
+
+
+
+ {/*
+
+ */}
+
+ {valid ? null : {t(`${LOCALIZATION_KEY.CS_ADDCOMPLAINT}_UPLOAD_ERROR_MESSAGE`)}}
+
+ {props.skip ? : null}
+
+
+ );
+};
+
+export default UploadPhoto;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/index.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/index.js
new file mode 100644
index 00000000000..ddd9dab9acd
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/ReopenComplaint/index.js
@@ -0,0 +1,28 @@
+import React, { useMemo } from "react";
+
+import { Route, Switch, useRouteMatch } from "react-router-dom";
+// import UserOnboarding from "../UserOnboarding/index";
+import { PgrRoutes, getRoute } from "../../../constants/Routes";
+import ReasonPage from "./Reason";
+import UploadPhoto from "./UploadPhoto";
+import AddtionalDetails from "./AddtionalDetails";
+import Response from "../Response";
+
+const ReopenComplaint = ({ match, history, parentRoute }) => {
+
+ const allParams = window.location.pathname.split("/")
+ const id = allParams[allParams.length - 1]
+ const tenantId = Digit.SessionStorage.get("CITIZEN.COMMON.HOME.CITY")?.code || Digit.ULBService.getCurrentTenantId();
+
+ const complaintDetails = Digit.Hooks.pgr.useComplaintDetails({ tenantId: tenantId, id: id }).complaintDetails;
+ return (
+
+ } />
+ } />
+ } />
+ } />
+
+ );
+};
+
+export { ReopenComplaint };
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Response.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Response.js
new file mode 100644
index 00000000000..7712051c928
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/Response.js
@@ -0,0 +1,59 @@
+import React from "react";
+import { Card, Banner, CardText, SubmitBar } from "@egovernments/digit-ui-react-components";
+import { Link } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { PgrRoutes, getRoute } from "../../constants/Routes";
+import { useTranslation } from "react-i18next";
+
+const GetActionMessage = ({ action }) => {
+ const { t } = useTranslation();
+ switch (action) {
+ case "REOPEN":
+ return t(`CS_COMMON_COMPLAINT_REOPENED`);
+ case "RATE":
+ return t("CS_COMMON_THANK_YOU");
+ default:
+ return t(`CS_COMMON_COMPLAINT_SUBMITTED`);
+ }
+};
+
+const BannerPicker = ({ response }) => {
+ const { complaints } = response;
+ const { t } = useTranslation();
+ if (complaints && complaints.response && complaints.response.responseInfo) {
+ return (
+
+ );
+ } else {
+ return ;
+ }
+};
+
+const TextPicker = ({ response }) => {
+ const { complaints } = response;
+ const { t } = useTranslation();
+ if (complaints && complaints.response && complaints.response.responseInfo) {
+ const { action } = complaints.response.ServiceWrappers[0].workflow;
+ return action === "RATE" ? {t("CS_COMMON_RATING_SUBMIT_TEXT")} : {t("CS_COMMON_TRACK_COMPLAINT_TEXT")};
+ }
+};
+
+const Response = (props) => {
+ const { t } = useTranslation();
+ const appState = useSelector((state) => state)["pgr"];
+ return (
+
+ {appState.complaints.response && }
+ {appState.complaints.response && }
+
+
+
+
+ );
+};
+
+export default Response;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/index.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/index.js
new file mode 100644
index 00000000000..9319f81beb7
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/citizen/index.js
@@ -0,0 +1,48 @@
+import React from "react";
+import { ReopenComplaint } from "./ReopenComplaint/index";
+import SelectRating from "./Rating/SelectRating";
+import { PgrRoutes, getRoute } from "../../constants/Routes";
+import { useRouteMatch, Switch, useLocation } from "react-router-dom";
+import { AppContainer, BackButton, PrivateRoute } from "@egovernments/digit-ui-react-components";
+
+import { CreateComplaint } from "./Create";
+import { ComplaintsList } from "./ComplaintsList";
+import ComplaintDetailsPage from "./ComplaintDetails";
+import Response from "./Response";
+import { useTranslation } from "react-i18next";
+
+const App = () => {
+ const { t } = useTranslation();
+ const { path, url, ...match } = useRouteMatch();
+ const location = useLocation();
+
+ const CreateComplaint = Digit?.ComponentRegistryService?.getComponent("PGRCreateComplaintCitizen");
+ const ComplaintsList = Digit?.ComponentRegistryService?.getComponent("PGRComplaintsList");
+ const ComplaintDetailsPage = Digit?.ComponentRegistryService?.getComponent("PGRComplaintDetailsPage");
+ const SelectRating = Digit?.ComponentRegistryService?.getComponent("PGRSelectRating");
+ const Response = Digit?.ComponentRegistryService?.getComponent("PGRResponseCitzen");
+
+ return (
+
+
+ {!location.pathname.includes("/response") &&
{t("CS_COMMON_BACK")}}
+
+ {/* */}
+
+
+
+ }
+ />
+ } />
+ } />
+
+ {/* */}
+
+
+
+ );
+};
+
+export default App;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/ComplaintDetails.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/ComplaintDetails.js
new file mode 100644
index 00000000000..91641378146
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/ComplaintDetails.js
@@ -0,0 +1,504 @@
+import React, { useState, useEffect, Fragment } from "react";
+import { useParams } from "react-router-dom";
+import {
+ BreakLine,
+ Card,
+ CardLabel,
+ CardLabelDesc,
+ CardSubHeader,
+ ConnectingCheckPoints,
+ CheckPoint,
+ DisplayPhotos,
+ MediaRow,
+ LastRow,
+ Row,
+ StatusTable,
+ PopUp,
+ HeaderBar,
+ ImageViewer,
+ TextInput,
+ TextArea,
+ UploadFile,
+ ButtonSelector,
+ Toast,
+ ActionBar,
+ Menu,
+ SubmitBar,
+ Dropdown,
+ Loader,
+ Modal,
+ SectionalDropdown,
+} from "@egovernments/digit-ui-react-components";
+
+import { Close } from "../../Icons";
+import { useTranslation } from "react-i18next";
+import { isError, useQueryClient } from "react-query";
+import StarRated from "../../components/timelineInstances/StarRated";
+
+const MapView = (props) => {
+ return (
+
+
+
+ );
+};
+
+const Heading = (props) => {
+ return {props.label}
;
+};
+
+const CloseBtn = (props) => {
+ return (
+
+
+
+ );
+};
+
+const TLCaption = ({ data, comments }) => {
+ const { t } = useTranslation()
+ return (
+
+ {data?.date &&
{data?.date}
}
+
{data?.name}
+
{data?.mobileNumber}
+ {data?.source &&
{t("ES_COMMON_FILED_VIA_" + data?.source.toUpperCase())}
}
+ {comments?.map( e =>
+
+
{t("WF_COMMON_COMMENTS")}
+
{e}
+
+ )}
+
+ );
+};
+
+const ComplaintDetailsModal = ({ workflowDetails, complaintDetails, close, popup, selectedAction, onAssign, tenantId, t }) => {
+
+ // RAIN-5692 PGR : GRO is assigning complaint, Selecting employee and assign. Its not getting assigned.
+ // Fix for next action assignee dropdown issue
+ const stateArray = workflowDetails?.data?.initialActionState?.nextActions?.filter( ele => ele?.action == selectedAction );
+ const useEmployeeData = Digit.Hooks.pgr.useEmployeeFilter(
+ tenantId,
+ stateArray?.[0]?.assigneeRoles?.length > 0 ? stateArray?.[0]?.assigneeRoles?.join(",") : "",
+ complaintDetails
+ );
+ const employeeData = useEmployeeData
+ ? useEmployeeData.map((departmentData) => {
+ return { heading: departmentData.department, options: departmentData.employees };
+ })
+ : null;
+
+ const [selectedEmployee, setSelectedEmployee] = useState(null);
+ const [comments, setComments] = useState("");
+ const [file, setFile] = useState(null);
+ const [uploadedFile, setUploadedFile] = useState(null);
+ const [error, setError] = useState(null);
+ const cityDetails = Digit.ULBService.getCurrentUlb();
+ const [selectedReopenReason, setSelectedReopenReason] = useState(null);
+
+ useEffect(() => {
+ (async () => {
+ setError(null);
+ if (file) {
+ if (file.size >= 5242880) {
+ setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED"));
+ } else {
+ try {
+ // TODO: change module in file storage
+ const response = await Digit.UploadServices.Filestorage("property-upload", file, cityDetails.code);
+ if (response?.data?.files?.length > 0) {
+ setUploadedFile(response?.data?.files[0]?.fileStoreId);
+ } else {
+ setError(t("CS_FILE_UPLOAD_ERROR"));
+ }
+ } catch (err) {
+ setError(t("CS_FILE_UPLOAD_ERROR"));
+ }
+ }
+ }
+ })();
+ }, [file]);
+
+ const reopenReasonMenu = [t(`CS_REOPEN_OPTION_ONE`), t(`CS_REOPEN_OPTION_TWO`), t(`CS_REOPEN_OPTION_THREE`), t(`CS_REOPEN_OPTION_FOUR`)];
+ // const uploadFile = useCallback( () => {
+
+ // }, [file]);
+
+ function onSelectEmployee(employee) {
+ setSelectedEmployee(employee);
+ }
+
+ function addComment(e) {
+ setError(null);
+ setComments(e.target.value);
+ }
+
+ function selectfile(e) {
+ setFile(e.target.files[0]);
+ }
+
+ function onSelectReopenReason(reason) {
+ setSelectedReopenReason(reason);
+ }
+
+ return (
+
+ }
+ headerBarEnd={ close(popup)} />}
+ actionCancelLabel={t("CS_COMMON_CANCEL")}
+ actionCancelOnSubmit={() => close(popup)}
+ actionSaveLabel={
+ selectedAction === "ASSIGN" || selectedAction === "REASSIGN"
+ ? t("CS_COMMON_ASSIGN")
+ : selectedAction === "REJECT"
+ ? t("CS_COMMON_REJECT")
+ : selectedAction === "REOPEN"
+ ? t("CS_COMMON_REOPEN")
+ : t("CS_COMMON_RESOLVE")
+ }
+ actionSaveOnSubmit={() => {
+ if(selectedAction === "REJECT" && !comments)
+ setError(t("CS_MANDATORY_COMMENTS"));
+ else
+ onAssign(selectedEmployee, comments, uploadedFile);
+ }}
+ error={error}
+ setError={setError}
+ >
+
+ {selectedAction === "REJECT" || selectedAction === "RESOLVE" || selectedAction === "REOPEN" ? null : (
+
+ {t("CS_COMMON_EMPLOYEE_NAME")}
+ {employeeData && }
+
+ )}
+ {selectedAction === "REOPEN" ? (
+
+ {t("CS_REOPEN_COMPLAINT")}
+
+
+ ) : null}
+ {t("CS_COMMON_EMPLOYEE_COMMENTS")}
+
+ {t("CS_ACTION_SUPPORTING_DOCUMENTS")}
+ {t(`CS_UPLOAD_RESTRICTIONS`)}
+ {
+ setUploadedFile(null);
+ }}
+ message={uploadedFile ? `1 ${t(`CS_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)}
+ />
+
+
+ );
+};
+
+export const ComplaintDetails = (props) => {
+ let { id } = useParams();
+ const { t } = useTranslation();
+ const [fullscreen, setFullscreen] = useState(false);
+ const [imageZoom, setImageZoom] = useState(null);
+ // const [actionCalled, setActionCalled] = useState(false);
+ const [toast, setToast] = useState(false);
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const { isLoading, complaintDetails, revalidate: revalidateComplaintDetails } = Digit.Hooks.pgr.useComplaintDetails({ tenantId, id });
+ const workflowDetails = Digit.Hooks.useWorkflowDetails({ tenantId, id, moduleCode: "PGR", role: "EMPLOYEE" });
+ const [imagesToShowBelowComplaintDetails, setImagesToShowBelowComplaintDetails] = useState([])
+
+ // RAIN-5692 PGR : GRO is assigning complaint, Selecting employee and assign. Its not getting assigned.
+ // Fix for next action assignee dropdown issue
+ if (workflowDetails && workflowDetails?.data){
+ workflowDetails.data.initialActionState=workflowDetails?.data?.initialActionState || {...workflowDetails?.data?.actionState } || {} ;
+ workflowDetails.data.actionState = { ...workflowDetails.data };
+ }
+
+ useEffect(()=>{
+ if(workflowDetails){
+ const {data:{timeline: complaintTimelineData}={}} = workflowDetails
+ if(complaintTimelineData){
+ const actionByCitizenOnComplaintCreation = complaintTimelineData?.find( e => e?.performedAction === "APPLY")
+ const { thumbnailsToShow } = actionByCitizenOnComplaintCreation
+ thumbnailsToShow ? setImagesToShowBelowComplaintDetails(thumbnailsToShow) : null
+ }
+ }
+ },[workflowDetails])
+ const [displayMenu, setDisplayMenu] = useState(false);
+ const [popup, setPopup] = useState(false);
+ const [selectedAction, setSelectedAction] = useState(null);
+ const [assignResponse, setAssignResponse] = useState(null);
+ const [loader, setLoader] = useState(false);
+ const [rerender, setRerender] = useState(1);
+ const client = useQueryClient();
+ function popupCall(option) {
+ setDisplayMenu(false);
+ setPopup(true);
+ }
+
+ useEffect(() => {
+ (async () => {
+ const assignWorkflow = await Digit?.WorkflowService?.getByBusinessId(tenantId, id);
+ })();
+ }, [complaintDetails]);
+
+ const refreshData = async () => {
+ await client.refetchQueries(["fetchInboxData"]);
+ await workflowDetails.revalidate();
+ await revalidateComplaintDetails();
+ };
+
+ useEffect(() => {
+ (async () => {
+ if (complaintDetails) {
+ setLoader(true);
+ await refreshData();
+ setLoader(false);
+ }
+ })();
+ }, []);
+
+ function zoomView() {
+ setFullscreen(!fullscreen);
+ }
+
+ function close(state) {
+ switch (state) {
+ case fullscreen:
+ setFullscreen(!fullscreen);
+ break;
+ case popup:
+ setPopup(!popup);
+ break;
+ default:
+ break;
+ }
+ }
+
+ function zoomImage(imageSource, index) {
+ setImageZoom(imageSource);
+ }
+ function zoomImageWrapper(imageSource, index){
+ zoomImage(imagesToShowBelowComplaintDetails?.fullImage[index]);
+ }
+ function onCloseImageZoom() {
+ setImageZoom(null);
+ }
+
+ function onActionSelect(action) {
+ setSelectedAction(action);
+ switch (action) {
+ case "ASSIGN":
+ setPopup(true);
+ setDisplayMenu(false);
+ break;
+ case "REASSIGN":
+ setPopup(true);
+ setDisplayMenu(false);
+ break;
+ case "RESOLVE":
+ setPopup(true);
+ setDisplayMenu(false);
+ break;
+ case "REJECT":
+ setPopup(true);
+ setDisplayMenu(false);
+ break;
+ case "REOPEN":
+ setPopup(true);
+ setDisplayMenu(false);
+ break;
+ default:
+ setDisplayMenu(false);
+ }
+ }
+
+ async function onAssign(selectedEmployee, comments, uploadedFile) {
+ setPopup(false);
+ const response = await Digit.Complaint.assign(complaintDetails, selectedAction, selectedEmployee, comments, uploadedFile, tenantId);
+ setAssignResponse(response);
+ setToast(true);
+ setLoader(true);
+ await refreshData();
+ setLoader(false);
+ setRerender(rerender + 1);
+ setTimeout(() => setToast(false), 10000);
+ }
+
+ function closeToast() {
+ setToast(false);
+ }
+
+ if (isLoading || workflowDetails.isLoading || loader) {
+ return ;
+ }
+
+ if (workflowDetails.isError) return {workflowDetails.error};
+
+ const getTimelineCaptions = (checkpoint, index, arr) => {
+ const {wfComment: comment, thumbnailsToShow} = checkpoint;
+ function zoomImageTimeLineWrapper(imageSource, index,thumbnailsToShow){
+ let newIndex=thumbnailsToShow.thumbs?.findIndex(link=>link===imageSource);
+ zoomImage((newIndex>-1&&thumbnailsToShow?.fullImage?.[newIndex])||imageSource);
+ }
+ const captionForOtherCheckpointsInTL = {
+ date: checkpoint?.auditDetails?.lastModified,
+ name: checkpoint?.assigner?.name,
+ mobileNumber: checkpoint?.assigner?.mobileNumber,
+ ...checkpoint.status === "COMPLAINT_FILED" && complaintDetails?.audit ? {
+ source: complaintDetails.audit.source,
+ } : {}
+ }
+ const isFirstPendingForAssignment = arr.length - (index + 1) === 1 ? true : false
+ if (checkpoint.status === "PENDINGFORASSIGNMENT" && complaintDetails?.audit) {
+ if(isFirstPendingForAssignment){
+ const caption = {
+ date: Digit.DateUtils.ConvertTimestampToDate(complaintDetails.audit.details.createdTime),
+ };
+ return ;
+ } else {
+ const caption = {
+ date: Digit.DateUtils.ConvertTimestampToDate(complaintDetails.audit.details.createdTime),
+ };
+ return <>
+ {checkpoint?.wfComment ? {checkpoint?.wfComment?.map( e =>
+
+
{t("WF_COMMON_COMMENTS")}
+
{e}
+
+ )}
: null}
+ {checkpoint.status !== "COMPLAINT_FILED" && thumbnailsToShow?.thumbs?.length > 0 ?
+
{t("CS_COMMON_ATTACHMENTS")}
+ zoomImageTimeLineWrapper(src, index,thumbnailsToShow)} />
+ : null}
+ {caption?.date ? : null}
+ >
+ }
+ }
+ // return (checkpoint.caption && checkpoint.caption.length !== 0) || checkpoint?.wfComment?.length > 0 ? : null;
+ return <>
+ {comment ? {comment?.map( e =>
+
+
{t("WF_COMMON_COMMENTS")}
+
{e}
+
+ )}
: null}
+ {checkpoint.status !== "COMPLAINT_FILED" && thumbnailsToShow?.thumbs?.length > 0 ?
+
{t("CS_COMMON_ATTACHMENTS")}
+ zoomImageTimeLineWrapper(src, index,thumbnailsToShow)} />
+ : null}
+ {captionForOtherCheckpointsInTL?.date ? : null}
+ {(checkpoint.status == "CLOSEDAFTERRESOLUTION" && complaintDetails.workflow.action == "RATE" && index <= 1) && complaintDetails.audit.rating ? : null}
+ >
+ }
+
+ return (
+
+
+ {t(`CS_HEADER_COMPLAINT_SUMMARY`)}
+ {t(`CS_COMPLAINT_DETAILS_COMPLAINT_DETAILS`)}
+ {isLoading ? (
+
+ ) : (
+
+ {complaintDetails &&
+ Object.keys(complaintDetails?.details).map((k, i, arr) => (
+ (typeof val === "object" ? t(val?.code) : t(val)))
+ : t(complaintDetails?.details[k]) || "N/A"
+ }
+ last={arr.length - 1 === i}
+ />
+ ))}
+
+ {1 === 1 ? null : (
+
+
+
+ )}
+
+ )}
+ {imagesToShowBelowComplaintDetails?.thumbs ? (
+ zoomImageWrapper(source, index)} />
+ ) : null}
+
+ {workflowDetails?.isLoading && }
+ {!workflowDetails?.isLoading && (
+
+ {t(`CS_COMPLAINT_DETAILS_COMPLAINT_TIMELINE`)}
+
+ {workflowDetails?.data?.timeline && workflowDetails?.data?.timeline?.length === 1 ? (
+
+ ) : (
+
+ {workflowDetails?.data?.timeline &&
+ workflowDetails?.data?.timeline.map((checkpoint, index, arr) => {
+ return (
+
+
+
+ );
+ })}
+
+ )}
+
+ )}
+
+ {fullscreen ? (
+
+
+
} end={
close(fullscreen)} />} />
+
+
+
+
+
+ ) : null}
+ {imageZoom ? : null}
+ {popup ? (
+
+ ) : null}
+ {toast && }
+ {!workflowDetails?.isLoading && workflowDetails?.data?.nextActions?.length > 0 && (
+
+ {displayMenu && workflowDetails?.data?.nextActions ? (
+
+ )}
+
+ );
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/CreateComplaint/index.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/CreateComplaint/index.js
new file mode 100644
index 00000000000..a3313270966
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/CreateComplaint/index.js
@@ -0,0 +1,261 @@
+import React, { useState, useEffect, useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dropdown } from "@egovernments/digit-ui-react-components";
+import { useRouteMatch, useHistory } from "react-router-dom";
+import { useQueryClient } from "react-query";
+
+import { FormComposer } from "../../../components/FormComposer";
+import { createComplaint } from "../../../redux/actions/index";
+
+export const CreateComplaint = ({ parentUrl }) => {
+ const cities = Digit.Hooks.pgr.useTenants();
+ const { t } = useTranslation();
+
+ const getCities = () => cities?.filter((e) => e.code === Digit.ULBService.getCurrentTenantId()) || [];
+
+ const [complaintType, setComplaintType] = useState({});
+ const [subTypeMenu, setSubTypeMenu] = useState([]);
+ const [subType, setSubType] = useState({});
+ const [pincode, setPincode] = useState("");
+ const [selectedCity, setSelectedCity] = useState(getCities()[0] ? getCities()[0] : null);
+
+ const { data: fetchedLocalities } = Digit.Hooks.useBoundaryLocalities(
+ getCities()[0]?.code,
+ "admin",
+ {
+ enabled: !!getCities()[0],
+ },
+ t
+ );
+
+ const [localities, setLocalities] = useState(fetchedLocalities);
+ const [selectedLocality, setSelectedLocality] = useState(null);
+ const [canSubmit, setSubmitValve] = useState(false);
+ const [submitted, setSubmitted] = useState(false);
+
+ const [pincodeNotValid, setPincodeNotValid] = useState(false);
+ const [params, setParams] = useState({});
+ const tenantId = window.Digit.SessionStorage.get("Employee.tenantId");
+ const menu = Digit.Hooks.pgr.useComplaintTypes({ stateCode: tenantId });
+ const dispatch = useDispatch();
+ const match = useRouteMatch();
+ const history = useHistory();
+ const serviceDefinitions = Digit.GetServiceDefinitions;
+ const client = useQueryClient();
+
+ useEffect(() => {
+ if (complaintType?.key && subType?.key && selectedCity?.code && selectedLocality?.code) {
+ setSubmitValve(true);
+ } else {
+ setSubmitValve(false);
+ }
+ }, [complaintType, subType, selectedCity, selectedLocality]);
+
+ useEffect(() => {
+ setLocalities(fetchedLocalities);
+ }, [fetchedLocalities]);
+
+ useEffect(() => {
+ const city = cities.find((obj) => obj.pincode?.find((item) => item == pincode));
+ if (city?.code&&city?.code === getCities()[0]?.code) {
+ setPincodeNotValid(false);
+ setSelectedCity(city);
+ setSelectedLocality(null);
+ const __localityList = fetchedLocalities;
+ const __filteredLocalities = __localityList?.filter((city) => city["pincode"] == pincode);
+ setLocalities(__filteredLocalities);
+ } else if (pincode === "" || pincode === null) {
+ setPincodeNotValid(false);
+ setLocalities(fetchedLocalities);
+ } else {
+ setPincodeNotValid(true);
+ }
+ }, [pincode]);
+
+ async function selectedType(value) {
+ if (value.key !== complaintType.key) {
+ if (value.key === "Others") {
+ setSubType({ name: "" });
+ setComplaintType(value);
+ setSubTypeMenu([{ key: "Others", name: t("SERVICEDEFS.OTHERS") }]);
+ } else {
+ setSubType({ name: "" });
+ setComplaintType(value);
+ setSubTypeMenu(await serviceDefinitions.getSubMenu(tenantId, value, t));
+ }
+ }
+ }
+
+ function selectedSubType(value) {
+ setSubType(value);
+ }
+
+ // city locality logic
+ const selectCity = async (city) => {
+ // if (selectedCity?.code !== city.code) {}
+ return;
+ };
+
+ function selectLocality(locality) {
+ setSelectedLocality(locality);
+ }
+
+ const wrapperSubmit = (data) => {
+ if (!canSubmit) return;
+ setSubmitted(true);
+ !submitted && onSubmit(data);
+ };
+
+ //On SUbmit
+ const onSubmit = async (data) => {
+ if (!canSubmit) return;
+ const cityCode = selectedCity.code;
+ const city = selectedCity.city.name;
+ const district = selectedCity.city.name;
+ const region = selectedCity.city.name;
+ const localityCode = selectedLocality.code;
+ const localityName = selectedLocality.name;
+ const landmark = data.landmark;
+ const { key } = subType;
+ const complaintType = key;
+ const mobileNumber = data.mobileNumber;
+ const name = data.name;
+ const formData = { ...data, cityCode, city, district, region, localityCode, localityName, landmark, complaintType, mobileNumber, name };
+ await dispatch(createComplaint(formData));
+ await client.refetchQueries(["fetchInboxData"]);
+ history.push(parentUrl + "/response");
+ };
+
+ const handlePincode = (event) => {
+ const { value } = event.target;
+ setPincode(value);
+ if (!value) {
+ setPincodeNotValid(false);
+ }
+ };
+
+ const isPincodeValid = () => !pincodeNotValid;
+
+ const config = [
+ {
+ head: t("ES_CREATECOMPLAINT_PROVIDE_COMPLAINANT_DETAILS"),
+ body: [
+ {
+ label: t("ES_CREATECOMPLAINT_MOBILE_NUMBER"),
+ isMandatory: true,
+ type: "text",
+ populators: {
+ name: "mobileNumber",
+ validation: {
+ required: true,
+ pattern: /^[6-9]\d{9}$/,
+ },
+ componentInFront: +91
,
+ error: t("CORE_COMMON_MOBILE_ERROR"),
+ },
+ },
+ {
+ label: t("ES_CREATECOMPLAINT_COMPLAINT_NAME"),
+ isMandatory: true,
+ type: "text",
+ populators: {
+ name: "name",
+ validation: {
+ required: true,
+ pattern: /^[A-Za-z]/,
+ },
+ error: t("CS_ADDCOMPLAINT_NAME_ERROR"),
+ },
+ },
+ ],
+ },
+ {
+ head: t("CS_COMPLAINT_DETAILS_COMPLAINT_DETAILS"),
+ body: [
+ {
+ label: t("CS_COMPLAINT_DETAILS_COMPLAINT_TYPE"),
+ isMandatory: true,
+ type: "dropdown",
+ populators: ,
+ },
+ {
+ label: t("CS_COMPLAINT_DETAILS_COMPLAINT_SUBTYPE"),
+ isMandatory: true,
+ type: "dropdown",
+ menu: { ...subTypeMenu },
+ populators: ,
+ },
+ ],
+ },
+ {
+ head: t("CS_ADDCOMPLAINT_LOCATION"),
+ body: [
+ {
+ label: t("CORE_COMMON_PINCODE"),
+ type: "text",
+ populators: {
+ name: "pincode",
+ validation: { pattern: /^[1-9][0-9]{5}$/, validate: isPincodeValid },
+ error: t("CORE_COMMON_PINCODE_INVALID"),
+ onChange: handlePincode,
+ },
+ },
+ {
+ label: t("CS_COMPLAINT_DETAILS_CITY"),
+ isMandatory: true,
+ type: "dropdown",
+ populators: (
+
+ ),
+ },
+ {
+ label: t("CS_CREATECOMPLAINT_MOHALLA"),
+ type: "dropdown",
+ isMandatory: true,
+ dependency: selectedCity && localities ? true : false,
+ populators: (
+
+ ),
+ },
+ {
+ label: t("CS_COMPLAINT_DETAILS_LANDMARK"),
+ type: "textarea",
+ populators: {
+ name: "landmark",
+ },
+ },
+ ],
+ },
+ {
+ head: t("CS_COMPLAINT_DETAILS_ADDITIONAL_DETAILS"),
+ body: [
+ {
+ label: t("CS_COMPLAINT_DETAILS_ADDITIONAL_DETAILS"),
+ type: "textarea",
+ populators: {
+ name: "description",
+ },
+ },
+ ],
+ },
+ ];
+ return (
+
+ );
+};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Inbox.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Inbox.js
new file mode 100644
index 00000000000..a9be8e207da
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Inbox.js
@@ -0,0 +1,82 @@
+import React, { useCallback, useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { Loader, Header } from "@egovernments/digit-ui-react-components";
+
+import DesktopInbox from "../../components/DesktopInbox";
+import MobileInbox from "../../components/MobileInbox";
+
+const Inbox = () => {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const { uuid } = Digit.UserService.getUser().info;
+ const [pageOffset, setPageOffset] = useState(0);
+ const [pageSize, setPageSize] = useState(10);
+ const [totalRecords, setTotalRecords] = useState(0);
+ const [searchParams, setSearchParams] = useState({ filters: { wfFilters: { assignee: [{ code: uuid }] } }, search: "", sort: {} });
+
+ useEffect(() => {
+ (async () => {
+ const applicationStatus = searchParams?.filters?.pgrfilters?.applicationStatus?.map(e => e.code).join(",")
+ let response = await Digit.PGRService.count(tenantId, applicationStatus?.length > 0 ? {applicationStatus} : {} );
+ if (response?.count) {
+ setTotalRecords(response.count);
+ }
+ })();
+ }, [searchParams]);
+
+ const fetchNextPage = () => {
+ setPageOffset((prevState) => prevState + 10);
+ };
+
+ const fetchPrevPage = () => {
+ setPageOffset((prevState) => prevState - 10);
+ };
+
+ const handlePageSizeChange = (e) => {
+ setPageSize(Number(e.target.value));
+ };
+
+ const handleFilterChange = (filterParam) => {
+ setSearchParams({ ...searchParams, filters: filterParam });
+ };
+
+ const onSearch = (params = "") => {
+ setSearchParams({ ...searchParams, search: params });
+ };
+
+ // let complaints = Digit.Hooks.pgr.useInboxData(searchParams) || [];
+ let { data: complaints, isLoading } = Digit.Hooks.pgr.useInboxData({ ...searchParams, offset: pageOffset, limit: pageSize }) ;
+
+ let isMobile = Digit.Utils.browser.isMobile();
+
+ if (complaints?.length !== null) {
+ if (isMobile) {
+ return (
+
+ );
+ } else {
+ return (
+
+
+
+
+ );
+ }
+ } else {
+ return ;
+ }
+};
+
+export default Inbox;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Response.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Response.js
new file mode 100644
index 00000000000..71a0dedbdd1
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/Response.js
@@ -0,0 +1,48 @@
+import React from "react";
+import { Card, Banner, CardText, SubmitBar } from "@egovernments/digit-ui-react-components";
+import { Link, useRouteMatch } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { PgrRoutes, getRoute } from "../../constants/Routes";
+import { useTranslation } from "react-i18next";
+
+const GetActionMessage = ({ action }) => {
+ const { t } = useTranslation();
+ if (action === "REOPEN") {
+ return t(`CS_COMMON_COMPLAINT_REOPENED`);
+ } else {
+ return t(`CS_COMMON_COMPLAINT_SUBMITTED`);
+ }
+};
+
+const BannerPicker = ({ response }) => {
+ const { complaints } = response;
+
+ if (complaints && complaints.response && complaints.response.responseInfo) {
+ return (
+
+ );
+ } else {
+ return ;
+ }
+};
+
+const Response = (props) => {
+ const { t } = useTranslation();
+ const { match } = useRouteMatch();
+ const appState = useSelector((state) => state)["pgr"];
+ return (
+
+ {appState.complaints.response && }
+ {t("ES_COMMON_TRACK_COMPLAINT_TEXT")}
+
+
+
+
+ );
+};
+
+export default Response;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/index.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/index.js
new file mode 100644
index 00000000000..29d5772135e
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/index.js
@@ -0,0 +1,89 @@
+import React, { useState } from "react";
+import { Switch, Route, useRouteMatch, useLocation } from "react-router-dom";
+import { ActionBar, Menu, SubmitBar, BreadCrumb } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+// import { ComplaintDetails } from "./ComplaintDetails";
+// import { CreateComplaint } from "./CreateComplaint";
+// import Inbox from "./Inbox";
+import { Employee } from "../../constants/Routes";
+// import Response from "./Response";
+
+const Complaint = () => {
+ const [displayMenu, setDisplayMenu] = useState(false);
+ const [popup, setPopup] = useState(false);
+ const match = useRouteMatch();
+ const { t } = useTranslation();
+
+ const breadcrumConfig = {
+ home: {
+ content: t("CS_COMMON_HOME"),
+ path: Employee.Home,
+ },
+ inbox: {
+ content: t("CS_COMMON_INBOX"),
+ path: match.url + Employee.Inbox,
+ },
+ createComplaint: {
+ content: t("CS_PGR_CREATE_COMPLAINT"),
+ path: match.url + Employee.CreateComplaint,
+ },
+ complaintDetails: {
+ content: t("CS_PGR_COMPLAINT_DETAILS"),
+ path: match.url + Employee.ComplaintDetails + ":id",
+ },
+ response: {
+ content: t("CS_PGR_RESPONSE"),
+ path: match.url + Employee.Response,
+ },
+ };
+ function popupCall(option) {
+ setDisplayMenu(false);
+ setPopup(true);
+ }
+
+ let location = useLocation().pathname;
+
+ const CreateComplaint = Digit?.ComponentRegistryService?.getComponent('PGRCreateComplaintEmp');
+ const ComplaintDetails = Digit?.ComponentRegistryService?.getComponent('PGRComplaintDetails');
+ const Inbox = Digit?.ComponentRegistryService?.getComponent('PGRInbox');
+ const Response = Digit?.ComponentRegistryService?.getComponent('PGRResponseEmp');
+
+ return (
+
+
+ {!location.includes(Employee.Response) && (
+
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+
+ )}
+
+ } />
+ } />
+
+
+
+
+ {/*
+ {displayMenu ? : null}
+ setDisplayMenu(!displayMenu)} />
+ */}
+
+ );
+};
+
+export default Complaint;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/complaint.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/complaint.js
new file mode 100644
index 00000000000..c41760b87c5
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/complaint.js
@@ -0,0 +1,41 @@
+import { CREATE_COMPLAINT } from "./types";
+
+const createComplaint = ({
+ cityCode,
+ complaintType,
+ description,
+ landmark,
+ city,
+ district,
+ region,
+ state,
+ pincode,
+ localityCode,
+ localityName,
+ uploadedImages,
+ mobileNumber,
+ name,
+}) => async (dispatch, getState) => {
+ const response = await Digit.Complaint.create({
+ cityCode,
+ complaintType,
+ description,
+ landmark,
+ city,
+ district,
+ region,
+ state,
+ pincode,
+ localityCode,
+ localityName,
+ uploadedImages,
+ mobileNumber,
+ name,
+ });
+ dispatch({
+ type: CREATE_COMPLAINT,
+ payload: response,
+ });
+};
+
+export default createComplaint;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/index.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/index.js
new file mode 100644
index 00000000000..805c84dc097
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/index.js
@@ -0,0 +1,52 @@
+import {
+ APPLY_FILTER,
+ APPLY_INBOX_FILTER,
+ FETCH_BUSINESS_SERVICE_BY_ID,
+ FETCH_COMPLAINTS,
+ FETCH_LOCALITIES,
+ UPDATE_COMPLAINT,
+ FETCH_ALL_BUSINESSS_SERVICES,
+} from "./types";
+//import { LocalizationService } from "../../@egovernments/digit-utils/services/Localization/service";
+//import { LocationService } from "../../@egovernments/digit-utils/services/Location";
+//import { LocalityService } from "../../@egovernments/digit-utils/services/Localities";
+import createComplaint from "./complaint";
+
+export const fetchLocalities = (city) => async (dispatch, getState) => {
+ city = city.toLowerCase();
+ const { stateInfo } = getState();
+ let response = await Digit.LocationService.getLocalities(`${stateInfo.code}.${city}`);
+ let localityList = Digit.LocalityService.get(response.TenantBoundary[0]);
+ dispatch({
+ type: FETCH_LOCALITIES,
+ payload: { localityList },
+ });
+};
+
+export const updateComplaints = (data) => async (dispatch) => {
+ let ServiceWrappers = await Digit.PGRService.update(data);
+
+ dispatch({
+ type: UPDATE_COMPLAINT,
+ payload: ServiceWrappers,
+ });
+};
+
+export const fetchBusinessServiceByTenant = (tenantId, businessServices) => async (dispatch) => {
+ const businessServiceResponse = await Digit.WorkflowService.init(tenantId, businessServices);
+ const businessService = businessServiceResponse.BusinessServices;
+ dispatch({
+ type: FETCH_ALL_BUSINESSS_SERVICES,
+ payload: { businessService },
+ });
+};
+
+export const applyInboxFilters = (filters) => async (dispatch) => {
+ let response = await Digit.PGRService.inboxFilter(filters);
+ dispatch({
+ type: APPLY_INBOX_FILTER,
+ payload: { response },
+ });
+};
+
+export { createComplaint };
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/types.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/types.js
new file mode 100644
index 00000000000..0b706733621
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/actions/types.js
@@ -0,0 +1,16 @@
+//TODO: Make these immutable
+export const FETCH_CITIES = "FETCH_CITIES";
+export const FETCH_LOCALITIES = "FETCH_LOCALITIES";
+export const FETCH_LOCALIZATION_KEYS_PGR = "FETCH_LOCALIZATION_KEYS_PGR";
+export const UPDATE_I18NSTORE_CITY_PGR = "UPDATE_I18nStore_CITY_PGR";
+export const FETCH_LOCALITY_LOCALIZATION_KEYS_PGR = "FETCH_LOCALITY_LOCALIZATION_KEYS_PGR";
+export const CREATE_LOCALITY_DROPDOWN = "CREATE_LOCALITY_DROPDOWN";
+export const UPDATE_I18nStore_LOCALITY_PGR = "UPDATE_I18nStore_LOCALITY_PGR";
+export const CHANGE_LANGUAGE = "CHANGE_LANGUAGE";
+export const FETCH_LANGUAGES = "FETCH_LANGUAGES";
+export const FETCH_COMPLAINTS = "FETCH_COMPLAINTS";
+export const FETCH_ALL_BUSINESSS_SERVICES = "FETCH_ALL_BUSINESSS_SERVICES";
+export const FETCH_BUSINESS_SERVICE_BY_ID = "FETCH_BUSINESS_SERVICE_BY_ID";
+export const UPDATE_COMPLAINT = "UPDATE_COMPLAINT";
+export const CREATE_COMPLAINT = "CREATE_COMPLAINT";
+export const APPLY_INBOX_FILTER = "APPLY_INBOX_FILTER";
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/complaintReducer.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/complaintReducer.js
new file mode 100644
index 00000000000..92bffc66a43
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/complaintReducer.js
@@ -0,0 +1,18 @@
+import { APPLY_INBOX_FILTER, CREATE_COMPLAINT, FETCH_COMPLAINTS, UPDATE_COMPLAINT } from "../actions/types";
+
+function complaintReducer(state = {}, action) {
+ switch (action.type) {
+ case CREATE_COMPLAINT:
+ return { ...state, response: action.payload };
+ case FETCH_COMPLAINTS:
+ return { ...state, list: action.payload.complaints };
+ case UPDATE_COMPLAINT:
+ return { ...state, response: action.payload };
+ case APPLY_INBOX_FILTER:
+ return { ...state, response: action.payload.response.instances };
+ default:
+ return state;
+ }
+}
+
+export default complaintReducer;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/index.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/index.js
new file mode 100644
index 00000000000..40f634f19c8
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/reducers/index.js
@@ -0,0 +1,9 @@
+import { combineReducers } from "redux";
+import complaintReducer from "./complaintReducer";
+
+const getRootReducer = () =>
+ combineReducers({
+ complaints: complaintReducer,
+ });
+
+export default getRootReducer;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/store.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/store.js
new file mode 100644
index 00000000000..57eb63e5a60
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/redux/store.js
@@ -0,0 +1,14 @@
+import { createStore, compose, applyMiddleware } from "redux";
+// import { composeWithDevTools } from "redux-devtools-extension";
+import thunk from "redux-thunk";
+import getRootReducer from "./reducers";
+
+const middleware = [thunk];
+const getStore = (defaultStore) => {
+ return createStore(
+ getRootReducer(defaultStore),
+ // composeWithDevTools(applyMiddleware(...middleware)) // :
+ compose(applyMiddleware(...middleware))
+ );
+};
+export default getStore;
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/complaint.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/complaint.js
new file mode 100644
index 00000000000..cc3decc505e
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/complaint.js
@@ -0,0 +1,3 @@
+export const selectComplaints = (state) => state.pgr.complaints.list || [];
+
+export const selectComplaintById = (state, id) => state.pgr.complaints.list.filter((complaint) => complaint.service.serviceRequestId === id);
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/processInstance.js b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/processInstance.js
new file mode 100644
index 00000000000..d58cc569e48
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/selectors/processInstance.js
@@ -0,0 +1 @@
+export const selectWorkflow = (state) => (state.businessService && state.businessService.businessService) || {};
diff --git a/micro-ui/web/micro-ui-internals/publish.sh b/micro-ui/web/micro-ui-internals/publish.sh
index fd96469f4eb..55aa1126fd7 100644
--- a/micro-ui/web/micro-ui-internals/publish.sh
+++ b/micro-ui/web/micro-ui-internals/publish.sh
@@ -47,6 +47,9 @@ cd "$BASEDIR/packages/modules/core" && rm -rf dist && yarn&& npm publish --acc
# msg "Building and publishing Utilities module"
cd "$BASEDIR/packages/modules/utilities" && rm -rf dist && yarn&& npm publish --access public
+# msg "Building and publishing pgr module"
+cd "$BASEDIR/packages/modules/pgr" && rm -rf dist && yarn&& npm publish --access public
-# msg "Building and publishing Utilities module"
+
+# msg "Building and publishing workbench module"
cd "$BASEDIR/packages/modules/workbench" && rm -rf dist && yarn&& npm publish --access public
diff --git a/micro-ui/web/package.json b/micro-ui/web/package.json
index dfb709accbb..bb8ee1623ea 100644
--- a/micro-ui/web/package.json
+++ b/micro-ui/web/package.json
@@ -1,6 +1,6 @@
{
"name": "micro-ui",
- "version": "1.0.0",
+ "version": "1.8.0",
"author": "Jagankumar ",
"license": "MIT",
"private": true,
@@ -16,10 +16,11 @@
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.0",
"@egovernments/digit-ui-module-workbench": "1.0.1",
- "@egovernments/digit-ui-module-core": "1.8.0",
+ "@egovernments/digit-ui-module-core": "1.8.1",
"@egovernments/digit-ui-module-hrms": "1.8.0",
"@egovernments/digit-ui-react-components": "1.8.0",
"@egovernments/digit-ui-module-dss": "1.8.0",
+ "@egovernments/digit-ui-module-pgr": "1.8.0",
"@egovernments/digit-ui-module-common": "1.8.0",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"@egovernments/digit-ui-module-engagement": "1.8.0",
diff --git a/micro-ui/web/src/App.js b/micro-ui/web/src/App.js
index 26a4f11a8ed..58195d231f3 100644
--- a/micro-ui/web/src/App.js
+++ b/micro-ui/web/src/App.js
@@ -12,6 +12,10 @@ import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms";
import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
import { UICustomizations } from "./Customisations/UICustomizations";
import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
+import {
+ initPGRComponents,
+ PGRReducers,
+} from "@egovernments/digit-ui-module-pgr";
window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
@@ -22,10 +26,12 @@ const enabledModules = [
"HRMS",
"Engagement",
"Workbench",
+ "PGR"
+
];
const moduleReducers = (initData) => ({
- initData,
+ initData, pgr: PGRReducers(initData),
});
const initDigitUI = () => {
@@ -35,6 +41,7 @@ const initDigitUI = () => {
PaymentLinks,
});
+ initPGRComponents();
initDSSComponents();
initHRMSComponents();
initEngagementComponents();
diff --git a/micro-ui/web/workbench/App.js b/micro-ui/web/workbench/App.js
index 9942ec2866d..82e035e3dc7 100644
--- a/micro-ui/web/workbench/App.js
+++ b/micro-ui/web/workbench/App.js
@@ -1,10 +1,15 @@
import React from "react";
import { initLibraries } from "@egovernments/digit-ui-libraries";
import { DigitUI } from "@egovernments/digit-ui-module-core";
-// import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms";
+import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms";
import { UICustomizations } from "./Customisations/UICustomizations";
import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
+import {
+ initPGRComponents,
+ PGRReducers,
+} from "@egovernments/digit-ui-module-pgr";
+import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement";
window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
@@ -12,13 +17,14 @@ const enabledModules = [
"DSS",
"NDSS",
"Utilities",
- // "HRMS",
+ "HRMS",
"Engagement",
"Workbench",
+ "PGR"
];
const moduleReducers = (initData) => ({
- initData,
+ initData, pgr: PGRReducers(initData),
});
const initDigitUI = () => {
@@ -27,6 +33,9 @@ const initDigitUI = () => {
PGR: {},
commonUiConfig: UICustomizations,
};
+ initPGRComponents();
+ initEngagementComponents();
+ initHRMSComponents();
initUtilitiesComponents();
initWorkbenchComponents();
};
diff --git a/micro-ui/web/workbench/package.json b/micro-ui/web/workbench/package.json
index 2a01e85bd81..637d5b98905 100644
--- a/micro-ui/web/workbench/package.json
+++ b/micro-ui/web/workbench/package.json
@@ -16,9 +16,12 @@
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.0",
"@egovernments/digit-ui-module-workbench": "1.0.1",
- "@egovernments/digit-ui-module-core": "1.8.0",
+ "@egovernments/digit-ui-module-core": "1.8.1",
"@egovernments/digit-ui-react-components": "1.8.0",
"@egovernments/digit-ui-module-utilities": "1.0.0",
+ "@egovernments/digit-ui-module-hrms":"1.8.0",
+ "@egovernments/digit-ui-module-pgr":"1.8.0",
+ "@egovernments/digit-ui-module-engagement":"1.5.20",
"babel-loader": "8.1.0",
"react": "17.0.2",
"react-dom": "17.0.2",
diff --git a/micro-ui/web/workbench/webpack.config.js b/micro-ui/web/workbench/webpack.config.js
index 00292d9cc66..c19e631fe01 100644
--- a/micro-ui/web/workbench/webpack.config.js
+++ b/micro-ui/web/workbench/webpack.config.js
@@ -14,6 +14,10 @@ module.exports = {
exclude: /node_modules/,
use: ["babel-loader"],
},
+ {
+ test: /\.css$/i,
+ use: ["style-loader", "css-loader"],
+ }
],
},
output: {
From ae278356f1ee9d54ff147039a5b698c5a1434286 Mon Sep 17 00:00:00 2001
From: Anil Singha <99383116+anilsingha-eGov@users.noreply.github.com>
Date: Fri, 3 May 2024 10:03:30 +0530
Subject: [PATCH 05/83] ISTE-11: Fixed Redirect logout url, Fixed breadcrumb
need to hide (#424)
* ISTE-11: Fixed Redirect logout url, Fixed breadcrumb need to hide
* ISTE-11: Added or operator
* ISTE-11: Upgraded package.json , Removed inline css
* ISTE-11: Updated logout redirect url
* Update index.js
---------
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
---
micro-ui/web/core/package.json | 2 +-
.../micro-ui-internals/example/package.json | 2 +-
.../packages/libraries/README.md | 1 +
.../packages/libraries/package.json | 2 +-
.../src/services/elements/User/index.js | 30 +++++++++----------
micro-ui/web/package.json | 2 +-
micro-ui/web/workbench/package.json | 2 +-
7 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/micro-ui/web/core/package.json b/micro-ui/web/core/package.json
index 264a386922e..288a55de123 100644
--- a/micro-ui/web/core/package.json
+++ b/micro-ui/web/core/package.json
@@ -14,7 +14,7 @@
],
"homepage": "/core-ui",
"dependencies": {
- "@egovernments/digit-ui-libraries": "1.8.0",
+ "@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
"@egovernments/digit-ui-module-core": "1.8.1",
"@egovernments/digit-ui-module-pgr": "1.8.0",
diff --git a/micro-ui/web/micro-ui-internals/example/package.json b/micro-ui/web/micro-ui-internals/example/package.json
index 236dc6960a4..341e81fba1c 100644
--- a/micro-ui/web/micro-ui-internals/example/package.json
+++ b/micro-ui/web/micro-ui-internals/example/package.json
@@ -9,7 +9,7 @@
"start": "react-scripts start"
},
"devDependencies": {
- "@egovernments/digit-ui-libraries": "1.8.0",
+ "@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
"@egovernments/digit-ui-module-dss": "1.8.0",
"@egovernments/digit-ui-module-core": "1.8.1",
diff --git a/micro-ui/web/micro-ui-internals/packages/libraries/README.md b/micro-ui/web/micro-ui-internals/packages/libraries/README.md
index 8b632977f76..45dd849b233 100644
--- a/micro-ui/web/micro-ui-internals/packages/libraries/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/libraries/README.md
@@ -55,6 +55,7 @@ export default App;
### Changelog
```bash
+1.8.1 Added logoutRedirectURL for mgramseva workbench
1.8.0 Released as part of workbench v1.0
```
diff --git a/micro-ui/web/micro-ui-internals/packages/libraries/package.json b/micro-ui/web/micro-ui-internals/packages/libraries/package.json
index b63038f1dfb..a8da4ae0bd5 100644
--- a/micro-ui/web/micro-ui-internals/packages/libraries/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/libraries/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-libraries",
- "version": "1.8.0",
+ "version": "1.8.1",
"main": "dist/index.js",
"module": "dist/index.modern.js",
"source": "src/index.js",
diff --git a/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/User/index.js b/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/User/index.js
index 3cac213ee44..a370f09f5cd 100644
--- a/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/User/index.js
+++ b/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/User/index.js
@@ -3,26 +3,26 @@ import { Request, ServiceRequest } from "../../atoms/Utils/Request";
import { Storage } from "../../atoms/Utils/Storage";
export const UserService = {
- authenticate: async(details) => {
+ authenticate: async (details) => {
const data = new URLSearchParams();
Object.entries(details).forEach(([key, value]) => data.append(key, value));
data.append("scope", "read");
data.append("grant_type", "password");
-
- let authResponse= await ServiceRequest({
+
+ let authResponse = await ServiceRequest({
serviceName: "authenticate",
url: Urls.Authenticate,
data,
headers: {
- authorization: `Basic ${window?.globalConfigs?.getConfig("JWT_TOKEN")||"ZWdvdi11c2VyLWNsaWVudDo="}`,
+ authorization: `Basic ${window?.globalConfigs?.getConfig("JWT_TOKEN") || "ZWdvdi11c2VyLWNsaWVudDo="}`,
"Content-Type": "application/x-www-form-urlencoded",
},
});
- const invalidRoles = window?.globalConfigs?.getConfig("INVALIDROLES") || [];
- if (invalidRoles && invalidRoles.length > 0 && authResponse && authResponse?.UserRequest?.roles?.some((role) => invalidRoles.includes(role.code))) {
- throw new Error("ES_ERROR_USER_NOT_PERMITTED");
- }
- return authResponse;
+ const invalidRoles = window?.globalConfigs?.getConfig("INVALIDROLES") || [];
+ if (invalidRoles && invalidRoles.length > 0 && authResponse && authResponse?.UserRequest?.roles?.some((role) => invalidRoles.includes(role.code))) {
+ throw new Error("ES_ERROR_USER_NOT_PERMITTED");
+ }
+ return authResponse;
},
logoutUser: () => {
let user = UserService.getUser();
@@ -48,18 +48,16 @@ export const UserService = {
},
logout: async () => {
const userType = UserService.getType();
+ const logoutRedirectURL = window?.globalConfigs?.getConfig("LOGOUT_REDIRECT_URL") || `/${window?.contextPath}/${userType === "citizen"?"citizen":"employee/user/language-selection"}`;
try {
await UserService.logoutUser();
} catch (e) {
}
- finally{
+ finally {
window.localStorage.clear();
window.sessionStorage.clear();
- if (userType === "citizen") {
- window.location.replace(`/${window?.contextPath}/citizen`);
- } else {
- window.location.replace(`/${window?.contextPath}/employee/user/language-selection`);
- }
+ window.location.replace(`/${logoutRedirectURL}`);
+
}
},
sendOtp: (details, stateCode) =>
@@ -125,7 +123,7 @@ export const UserService = {
});
},
userSearch: async (tenantId, data, filters) => {
-
+
return ServiceRequest({
url: Urls.UserSearch,
params: { ...filters },
diff --git a/micro-ui/web/package.json b/micro-ui/web/package.json
index bb8ee1623ea..4eacdbc3e7d 100644
--- a/micro-ui/web/package.json
+++ b/micro-ui/web/package.json
@@ -14,7 +14,7 @@
],
"homepage": "/digit-ui",
"dependencies": {
- "@egovernments/digit-ui-libraries": "1.8.0",
+ "@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
"@egovernments/digit-ui-module-core": "1.8.1",
"@egovernments/digit-ui-module-hrms": "1.8.0",
diff --git a/micro-ui/web/workbench/package.json b/micro-ui/web/workbench/package.json
index 637d5b98905..b811085badc 100644
--- a/micro-ui/web/workbench/package.json
+++ b/micro-ui/web/workbench/package.json
@@ -14,7 +14,7 @@
],
"homepage": "/workbench-ui",
"dependencies": {
- "@egovernments/digit-ui-libraries": "1.8.0",
+ "@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
"@egovernments/digit-ui-module-core": "1.8.1",
"@egovernments/digit-ui-react-components": "1.8.0",
From 943abb3e2cc0744e835d0e33877ed2f736d51fa7 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Wed, 5 Jun 2024 10:13:36 +0530
Subject: [PATCH 06/83] fix: resolved AJV-related Jenkins build issue (#783)
* updated ajv for fasturi issue
* Update package.json
* Update package.json
* updated ajv
* check the ajv fixs
* try out for ,
"fast-uri":"2.1.0"
* Update package.json
* Update webpack.config.js
* revert all package change
* try build all packages
* Revert "revert all package change"
This reverts commit e25295129d32dc05f4e04c976b443e8cc0dd3164.
* updated the readme of core and components
* updted the core module version
---
micro-ui/web/core/inter-package.json | 6 ++++--
micro-ui/web/core/package.json | 7 ++++---
.../web/micro-ui-internals/example/package.json | 4 ++--
micro-ui/web/micro-ui-internals/package.json | 6 ++++--
.../packages/modules/core/README.md | 1 +
.../packages/modules/core/package.json | 4 ++--
.../packages/modules/pgr/package.json | 2 +-
.../packages/modules/workbench/package.json | 2 +-
.../packages/react-components/README.md | 1 +
.../packages/react-components/package.json | 16 ++++++++++------
micro-ui/web/package.json | 7 ++++---
micro-ui/web/workbench/inter-package.json | 6 ++++--
micro-ui/web/workbench/package.json | 7 ++++---
13 files changed, 42 insertions(+), 27 deletions(-)
diff --git a/micro-ui/web/core/inter-package.json b/micro-ui/web/core/inter-package.json
index db6e884f6ce..6d73a849610 100644
--- a/micro-ui/web/core/inter-package.json
+++ b/micro-ui/web/core/inter-package.json
@@ -48,7 +48,9 @@
},
"resolutions": {
"**/@babel/runtime": "7.20.1",
- "**/babel-preset-react-app": "10.0.0"
+ "**/babel-preset-react-app": "10.0.0",
+ "**/ajv": "8.11.2",
+ "fast-uri":"2.1.0"
},
"devDependencies": {
"husky": "7.0.4",
@@ -63,7 +65,7 @@
"dependencies": {
"lodash": "4.17.21",
"microbundle-crl": "0.13.11",
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-hook-form": "6.15.8",
diff --git a/micro-ui/web/core/package.json b/micro-ui/web/core/package.json
index 288a55de123..52eabb1f64c 100644
--- a/micro-ui/web/core/package.json
+++ b/micro-ui/web/core/package.json
@@ -16,9 +16,9 @@
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
- "@egovernments/digit-ui-module-core": "1.8.1",
+ "@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-pgr": "1.8.0",
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"babel-loader": "8.1.0",
"clean-webpack-plugin": "4.0.0",
@@ -57,7 +57,8 @@
"**/@babel/core": "7.14.0",
"**/@babel/preset-env": "7.14.0",
"**/@babel/plugin-transform-modules-commonjs": "7.14.0",
- "**/polished":"4.2.2"
+ "**/polished":"4.2.2",
+ "fast-uri":"2.1.0"
},
"scripts": {
"start": "react-scripts start",
diff --git a/micro-ui/web/micro-ui-internals/example/package.json b/micro-ui/web/micro-ui-internals/example/package.json
index 341e81fba1c..f8b03e3697b 100644
--- a/micro-ui/web/micro-ui-internals/example/package.json
+++ b/micro-ui/web/micro-ui-internals/example/package.json
@@ -12,13 +12,13 @@
"@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
"@egovernments/digit-ui-module-dss": "1.8.0",
- "@egovernments/digit-ui-module-core": "1.8.1",
+ "@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-common": "1.8.0",
"@egovernments/digit-ui-module-pgr": "1.8.0",
"@egovernments/digit-ui-module-hrms": "1.8.0",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"@egovernments/digit-ui-module-engagement": "1.8.0",
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"http-proxy-middleware": "^1.0.5",
"react": "17.0.2",
"react-dom": "17.0.2",
diff --git a/micro-ui/web/micro-ui-internals/package.json b/micro-ui/web/micro-ui-internals/package.json
index 19a69c78172..a21133ca9b0 100644
--- a/micro-ui/web/micro-ui-internals/package.json
+++ b/micro-ui/web/micro-ui-internals/package.json
@@ -50,7 +50,9 @@
},
"resolutions": {
"**/@babel/runtime": "7.20.1",
- "**/babel-preset-react-app": "10.0.0"
+ "**/babel-preset-react-app": "10.0.0",
+ "**/ajv": "8.11.2",
+ "fast-uri":"2.1.0"
},
"devDependencies": {
"husky": "7.0.4",
@@ -65,7 +67,7 @@
"dependencies": {
"lodash": "4.17.21",
"microbundle-crl": "0.13.11",
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-hook-form": "6.15.8",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/core/README.md b/micro-ui/web/micro-ui-internals/packages/modules/core/README.md
index 0b5a1d4d023..c65ad694c4f 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/core/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/modules/core/README.md
@@ -65,6 +65,7 @@ with
### Changelog
```bash
+1.8.2 build issue fix due to ajv library
1.8.1 sidebar null check fixes
1.8.0 workbench v1.0
1.8.0-beta.5 fix for login screen alignments
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/core/package.json b/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
index 7d9a8ef9b01..65e1ef85169 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-module-core",
- "version": "1.8.1",
+ "version": "1.8.2",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.modern.js",
@@ -14,7 +14,7 @@
"prepublish": "yarn build"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-i18next": "11.16.2",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json b/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
index e89bc077589..4e8082e21e9 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
@@ -18,7 +18,7 @@
"react-router-dom": "5.3.0"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"lodash.merge": "^4.6.2",
"react": "17.0.2",
"react-dom": "17.0.2",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
index 5942a6fa23b..ffdf9dd35a7 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
@@ -18,7 +18,7 @@
"react-router-dom": "5.3.0"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"@rjsf/core": "5.10.0",
"@rjsf/utils": "5.10.0",
"@rjsf/validator-ajv8": "5.10.0",
diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/README.md b/micro-ui/web/micro-ui-internals/packages/react-components/README.md
index fb84eb0778b..c74129fb3de 100644
--- a/micro-ui/web/micro-ui-internals/packages/react-components/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/react-components/README.md
@@ -88,6 +88,7 @@ Syntax for the FormComposersV2
### Changelog
```bash
+1.8.1 build issue fix due to ajv library
1.8.0 workbench v1.0 release
1.8.0-beta workbench base version beta release
1.7.0 urban 2.9
diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/package.json b/micro-ui/web/micro-ui-internals/packages/react-components/package.json
index c5ef738a7e6..3448a46eaa1 100644
--- a/micro-ui/web/micro-ui-internals/packages/react-components/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/react-components/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-react-components",
- "version": "1.8.0",
+ "version": "1.8.1",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.modern.js",
@@ -49,16 +49,20 @@
"@egovernments/digit-ui-svg-components":"1.0.0",
"@googlemaps/js-api-loader": "1.13.10",
"@hookform/resolvers": "1.3.7",
- "ajv": "^8.12.0",
- "ajv-errors": "^3.0.0",
- "ajv-formats": "^2.1.1",
- "json-schema-to-yup": "^1.8.8",
+ "ajv": "8.11.2",
+ "ajv-errors": "3.0.0",
+ "ajv-formats": "2.1.1",
+ "json-schema-to-yup": "1.8.8",
"react-date-range": "1.3.0",
- "react-drag-drop-files": "^2.3.10",
+ "react-drag-drop-files": "2.3.10",
"react-hook-form": "6.15.8",
"react-i18next": "11.16.2",
"react-table": "7.7.0"
},
+ "resolutions": {
+ "**/ajv": "8.11.2",
+ "fast-uri":"2.1.0"
+ },
"browserslist": {
"production": [
">0.2%",
diff --git a/micro-ui/web/package.json b/micro-ui/web/package.json
index 4eacdbc3e7d..211c97047b6 100644
--- a/micro-ui/web/package.json
+++ b/micro-ui/web/package.json
@@ -16,9 +16,9 @@
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
- "@egovernments/digit-ui-module-core": "1.8.1",
+ "@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-hrms": "1.8.0",
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"@egovernments/digit-ui-module-dss": "1.8.0",
"@egovernments/digit-ui-module-pgr": "1.8.0",
"@egovernments/digit-ui-module-common": "1.8.0",
@@ -61,7 +61,8 @@
"**/@babel/core": "7.14.0",
"**/@babel/preset-env": "7.14.0",
"**/@babel/plugin-transform-modules-commonjs": "7.14.0",
- "**/polished":"4.2.2"
+ "**/polished":"4.2.2",
+ "fast-uri":"2.1.0"
},
"scripts": {
"start": "react-scripts start",
diff --git a/micro-ui/web/workbench/inter-package.json b/micro-ui/web/workbench/inter-package.json
index ac0a3c86863..edf6246a62d 100644
--- a/micro-ui/web/workbench/inter-package.json
+++ b/micro-ui/web/workbench/inter-package.json
@@ -45,7 +45,9 @@
},
"resolutions": {
"**/@babel/runtime": "7.20.1",
- "**/babel-preset-react-app": "10.0.0"
+ "**/babel-preset-react-app": "10.0.0",
+ "**/ajv": "8.11.2",
+ "fast-uri":"2.1.0"
},
"devDependencies": {
"husky": "7.0.4",
@@ -60,7 +62,7 @@
"dependencies": {
"lodash": "4.17.21",
"microbundle-crl": "0.13.11",
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-hook-form": "6.15.8",
diff --git a/micro-ui/web/workbench/package.json b/micro-ui/web/workbench/package.json
index b811085badc..fa62e0594ee 100644
--- a/micro-ui/web/workbench/package.json
+++ b/micro-ui/web/workbench/package.json
@@ -16,8 +16,8 @@
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.1",
"@egovernments/digit-ui-module-workbench": "1.0.1",
- "@egovernments/digit-ui-module-core": "1.8.1",
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-module-core": "1.8.2",
+ "@egovernments/digit-ui-react-components": "1.8.1",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"@egovernments/digit-ui-module-hrms":"1.8.0",
"@egovernments/digit-ui-module-pgr":"1.8.0",
@@ -53,7 +53,8 @@
"**/@babel/core": "7.14.0",
"**/@babel/preset-env": "7.14.0",
"**/@babel/plugin-transform-modules-commonjs": "7.14.0",
- "**/polished":"4.2.2"
+ "**/polished":"4.2.2",
+ "fast-uri":"2.1.0"
},
"scripts": {
"start": "react-scripts start",
From 863d0190f90abf8da01047c03c9cde4963615b2e Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Sat, 8 Jun 2024 18:20:53 +0530
Subject: [PATCH 07/83] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 457872b5b21..d758d985c9c 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-# workbench ui
+# DIGIT UI
A React App built on top of DIGIT UI Core.
From a42bd28da7438219490deb1079fd23d502776b85 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Wed, 26 Jun 2024 20:51:17 +0530
Subject: [PATCH 08/83] HCM Admin console v0.1 release ui changes (#964)
* Updates the delivery rules logic for gender
* * info message for status creating (#644)
* success message if user cred sheet
* send id with key resourceid
* Send variant in sku also
Co-authored-by: nabeelmd-eGov
* Feat : added boundary validation (#643)
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
* Update campaignValidators.ts (#645)
* added delay in download (#646)
* Update campaignValidators.ts (#647)
* fixes (#649)
Co-authored-by: nabeelmd-eGov
* fixed header validation (#648)
* change in filter recursive (#650)
* Update genericUtils.ts (#652)
* fix (#651)
Co-authored-by: nabeelmd-eGov
* updated lowest level hierarchy validation for target HLM -5948 (#654)
* Update campaignValidators.ts (#655)
* fixes-> cyclenumber issue, hover issue, dropdown height issue,
* css
* fixes-> cyclenumber issue, hover issue, dropdown height issue, (#656)
* fixes-> cyclenumber issue, hover issue, dropdown height issue,
* css
---------
Co-authored-by: nabeelmd-eGov
* Update campaignUtils.ts
* fixed HLM-5970
* Feat : added boundary validation at data level
* fixes
* local add
* Added boundary validation
* Refactor
* fixed HLM-5935 and HLM-5749
* Refactor
* Feat : updated table
* change campaignid in payload
* Feat : added campaignId
* Update campaignApis.ts
* Update campaignValidators.ts
* refactored
* Refactor
* assigned campaignId
* Refactor
* updated createRequest Schema
* Feat : invalid Status Persist
* status fix
* version-fix
* Update CODEOWNERS
* core version updated and css fix for language dropdown
* refactor (#676)
* Uat signoff (#678)
* change in filter recursive
* lowest level
* added validation related to target sheet headers
* HLM-5916
* download button fixes in summary (#682)
Co-authored-by: nabeelmd-eGov
* Hlm 5927 (#687)
* change in filter recursive
* lowest level
* added validation for boundary codes to be invalid other than that selected from UI in target upload
* Added Delivery and cycle config for LLIN and SMC both (#688)
* no of cycle and deivery drafted changes
* fixes
* add localisation code for boundaries
* fixes
* fixes
* Value localise in summary screen, api error change
* fixes
* genarate api call fix
* font size change for summary
* login css change
* HLM-5718: SMC delivery config enhancement
* config update
* added config for in between
* fix config for llin
* added mdms integration
---------
Co-authored-by: nabeelmd-eGov
* Fixed HLM-5988_warning message (#689)
Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com>
* download filename fixes (#693)
* download button fixes in summary
* download filename with custom name changes added
---------
Co-authored-by: nabeelmd-eGov
* download filename fixes (#694)
* download button fixes in summary
* download filename with custom name changes added
* config fix for llin
---------
Co-authored-by: nabeelmd-eGov
* successful toast message is fixed (#695)
* successful toast message is fixed
* Update UploadData.js
* HLM-5991: Alert Pop UP CR (#696)
Co-authored-by: nabeelmd-eGov
* HLM-5718 changes (#703)
Co-authored-by: nabeelmd-eGov
* Localization cache (#706)
* change in filter recursive
* lowest level
* refactored localization cache logic
* Update README.md (#707)
* Update README.md
* Update README.md
* Update utilities/project-factory/README.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update README.md
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* HLM-5985_made lowest level changes (#708)
* HLM-5985_made lowest level changes
* resolved codeRabbit comments
* Create LOCALSETUP.md (#709)
* Create LOCALSETUP.md
* Refactored config
* Update LOCALSETUP.md
* Update utilities/project-factory/LOCALSETUP.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/LOCALSETUP.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/LOCALSETUP.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/LOCALSETUP.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update LOCALSETUP.md
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* updated the localisation module config
* Refactor config (#713)
* Refactor config
* Update utilities/project-factory/src/server/validators/campaignValidators.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/validators/campaignValidators.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/validators/campaignValidators.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update postman_collection.json (#714)
* Update postman_collection.json
* Update postman_collection.json
* Delete utilities/project-factory/project_factory_swagger.yml (#715)
* Feat : removed campaignId validation for boundary upload (#718)
* updated the delay for boundary relationship
* added logger for request TODO TEST
will be reverted
* Revert "added logger for request TODO TEST"
This reverts commit d5c2bf570400ada8183eebfec71f0a3449143117.
* Schema validation (#719)
* Feat : removed campaignId validation for boundary upload
* Feat : added schema validation
* Fixed mdms host
* updated the logger messages
* updated the loggers
* delivery new changes, toast fix, error fix (#716)
* delivery new changes, toast fix, error fix
* new fixes
* fixes
* change text component to field component
* added hierarchy
* fix
* fix
* fix
* fix
* passing hierarchy from props
---------
Co-authored-by: nabeelmd-eGov
* Schema validation2 (#721)
* Feat : removed campaignId validation for boundary upload
* Feat : added schema validation
* Fixed mdms host
* Feat : added boundary validation
* Feat : optimized product search
* Fix : project mapping fixed (#722)
* Fixed project search (#723)
* smc fixes (#724)
Co-authored-by: nabeelmd-eGov
* Feat : added boundary confirmation (#727)
* Fix: fixed processing boundary
* Refactor
* fixed HLM-6109 (#729)
* gate fixes validation, ui ux (#731)
Co-authored-by: nabeelmd-eGov
* integrated panelcard component (#732)
* integrated panelcard component
* Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update genericUtils.ts (#733)
* Create CHANGELOG.md (#717)
* Update request.ts (#735)
* fixed generate api issue (#734)
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
* Create CHANGELOG.md
* gate fixes (#736)
* gate fixes validation, ui ux
* gate fix
---------
Co-authored-by: nabeelmd-eGov
* added loader in the selecting boundaries (#737)
* Update createAndSearch.ts (#738)
* fix (#739)
* fix
* fix
---------
Co-authored-by: nabeelmd-eGov
* Patch 3 (#740)
* change in filter recursive
* lowest level
* trimmed underscore and empty spaces
* boundary fix (#742)
Co-authored-by: nabeelmd-eGov
* Update genericUtils.ts (#746)
* fixed the delivery products issue
* Fixed delivery conditions issue
* Update campaignApis.ts (#747)
* fixed warning toast (#748)
* fixed warning toast
* Update UploadData.js
* fix (#749)
* fix
* fx
* fix
---------
Co-authored-by: nabeelmd-eGov
* core -update (#751)
Co-authored-by: nabeelmd-eGov
* fixed stepper issue (#752)
* fixed stepper issue
* Update index.html
* Feat : added user validation via individual (#753)
* fixes (#754)
Co-authored-by: nabeelmd-eGov
* code fix nabeel (#756)
* fixes
* fix
---------
Co-authored-by: nabeelmd-eGov
* Updated few loggers (#759)
* updated few loggers flow
* Update utilities/project-factory/src/server/api/campaignApis.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/utils/campaignMappingUtils.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/utils/campaignUtils.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/validators/campaignValidators.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/api/campaignApis.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/utils/campaignMappingUtils.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update utilities/project-factory/src/server/utils/genericUtils.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Updated the user Password generation logic #761
* Update Listener.ts (#730)
* Update Listener.ts
* added try catch logic in producer
* Feat : added parallel batch execution (#767)
* Feat : added parallel batch execution
* Refactor
* Update utilities/project-factory/src/server/validators/campaignValidators.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* fixed the stepper (#765)
* changes config (#769)
* Project type config and added loggers for process of campaign (#772)
* Feat : added themes in generate template (#773)
* fixed the ajv package version for build issue
* Feat : removed xlsx (#776)
* HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT (#778)
Co-authored-by: nabeelmd-eGov
* css update (#780)
Co-authored-by: nabeelmd-eGov
* HLM-6179 and HLM-6180 (#777)
* HLM-6179 and HLM-6180
* campaign name changes
---------
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
* Feat : fixed target generation (#781)
* fixed tenantId issue (#784)
* fix: resolved AJV-related Jenkins build issue reference #783 #786 (#787)
* module ui fix
* updated all the package version for build fixes
* fixed kafka-error at target generation (#789)
* updated core version (#791)
* updated core version
* updated css also
* Update campaignValidators.ts (#794)
* Updated the excel generation logic and files
* added changes for configurable column in target sheet (#779)
* change in filter recursive
* lowest level
* made target headers genearte through mdms schema
* changed config index.ts
* changed config index.ts
* changes for now
* added configurable column logic from schema HLM-6169
* updated validate of target columns through schema
* added masterForColumnSchema in index.ts
* formatted dataManageService
* refactored lock TargetFields func
* removed console.log
* User creation performance improved (#800)
* Feat : Improved user creation performance
* Change status color
* Update utilities/project-factory/src/server/utils/campaignUtils.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update genericUtils.ts (#801)
* Hlm 6170 (#802)
* change in filter recursive
* lowest level
* HLM -6170 added logic for only village level data in target sheet and some refactoring
* updated css (#804)
* fixed button issue (#805)
* HLM 6177: Error card implementation in summary screen (#806)
* HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT
* Added Error Cards in summary screen and redirection
---------
Co-authored-by: nabeelmd-eGov
* added error button styles (#807)
Co-authored-by: nabeelmd-eGov
* updated popUp css (#808)
* HLM 6178: Implementing New Pop up screen in boundaries (#809)
* added error button styles
* Implementing New Pop up screen in boundaries
---------
Co-authored-by: nabeelmd-eGov
* Facility changes (#812)
* Feat : changed facility Template
* Feat : locked target templates
* fixed colour issue (#813)
* Updated the project type conversion logic for the "deliveryType" dont1 and n config
* Unique field added (#814)
* Feat : changed facility Template
* Feat : locked target templates
* Feat : added unique check logic
* Target schema update (#815)
* change in filter recursive
* lowest level
* updated shcema of target columns to be configurable
* removed empty spaces from config index.ts
* Active mapping (#817)
* Feat : changed facility Template
* Feat : locked target templates
* Feat : added unique check logic
* Feat : added mapping via active field
* changes in the schema validation (#816)
* Updated the workbench and css module version
* Feat : added active inactive boundary check (#818)
* Update campaignValidators.ts (#819)
* added active inactive validation (#820)
* changed api call time (#826)
* Feat : added target sum mapping (#825)
* added campaign type as filter (#827)
* Update genericApis.ts (#828)
* Update excelUtils.ts (#829)
* UI issue fixes, icon fix in summary error (#831)
Co-authored-by: nabeelmd-eGov
* Target columns (#830)
* change in filter recursive
* lowest level
* commit
* Feat : target flow fixed for LLIN-mz
* uat to dev
---------
Co-authored-by: admin1
* Feat : freezed target columns (#833)
* Target mr dn (#834)
* change in filter recursive
* lowest level
* Feat : skipped validation temporarily
* changes in the target validation (#835)
* fixed error info (#837)
* Added roboto font (#840)
* Feat : added roboto font
* Fixed config
* target validation based on diff campaign types (#843)
* change in filter recursive
* lowest level
* updated validation of target based on campaign type
* fixed validation issue (#844)
* Updated the workbench package version
* fixed validation logic (#846)
* fixed validation logic
* Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Error messages improved (#848)
* Feat : imporved error messages and initilised utils for tracking process
* Fix ; unused variables fixed
* Feat : improved error messages
* Fix : download error fix (#850)
* Update campaignUtils.ts (#851)
* Update campaignUtils.ts
* Update utilities/project-factory/src/server/utils/campaignUtils.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update campaignValidators.ts (#853)
* HLM 6210: Toast, error focus fix and project type reset delivery data fix (#854)
* HLM-6210: campaign type change reset delivery data fix, summary error focus fix
* summary error focus fix
---------
Co-authored-by: nabeelmd-eGov
* HLM-6225_added time out according to data (#855)
* Update campaignValidators.ts (#859)
* HLM 6210 (#858)
* HLM-6210: campaign type change reset delivery data fix, summary error focus fix
* summary error focus fix
* parallel search fixes
---------
Co-authored-by: nabeelmd-eGov
* Remove validation (#852)
* change in filter recursive
* lowest level
* removed unnecessary validation for target
* spacing refactor
* Update campaignValidators.ts (#863)
* Header validation (#861)
* change in filter recursive
* lowest level
* removed unnecessary validation for target
* changed the logic of header validation
* space refactor
* Update campaignUtils.ts (#864)
* fixed ui error (#865)
* Read me (#867)
* change in filter recursive
* lowest level
* removed unnecessary validation for target
* changed the logic of header validation
* fixed portugese language error
* space refactoring
* Update Dockerfile
* Update Dockerfile
* Update migrate.sh
* Update Dockerfile
* Update campaignValidators.ts (#868)
* HLM 6210:campaign type change reset fix (#869)
* HLM-6210: campaign type change reset delivery data fix, summary error focus fix
* summary error focus fix
* parallel search fixes
* campaign type change reset fix
---------
Co-authored-by: nabeelmd-eGov
* Update excelUtils.ts for sheetHeaders wraping (#870)
* Update package.json
* updated error messages (#871)
* feat : added jaeger-client tracing (#872)
* updated the table config
* Update campaignApis.ts (#875)
* removed the schema and updated the db name
* fixing generate API call, file auto delete, date error (#877)
Co-authored-by: nabeelmd-eGov
* Trim resource (#878)
* Feat : trimmed resource persist message
* Refactor
* Removed reject error in produce message
* fixed min time, draft logic (#879)
* Update index.ts (#880)
* added min ui error and facility usage (#883)
* added min ui error and facility usage
* changes
* Update campaignUtils.ts (#884)
* HLM 6007 (#885)
* fixing generate API call, file auto delete, date error
* generate api fix
---------
Co-authored-by: nabeelmd-eGov
* Update Dockerfile
* Feat : docker config update (#886)
* Update Dockerfile (#887)
* Create buildWorkbenchUI.yml
* Update README.md (#917)
* Update buildWorkbenchUI.yml
* Update README.md
* Updated the DB Schema issue of Project-factory
* fixed hierarchy order (#919)
* User flag hcm (#920)
* Feat : docker config update
* Feat : added user create flag
* Refactored
* Update campaignUtils.ts
* Update campaignMappingUtils.ts (#922)
* Ashish egov patch 2 (#921)
* Update index.ts
* Update campaignApis.ts
* Fixed the project type conversion and product duplicate issue
* Update campaignApis.ts (#924)
* Update campaignMappingUtils.ts (#925)
* Update campaignMappingUtils.ts
* Refactored
* Update publishProjectFactory.yml
* Update buildWorkbenchUI.yml
* Update campaignMappingUtils.ts (#926)
* Update request.ts (#928)
* Update request.ts
* Feat : updated httprequest
* Feat : warning response added
* Refactor
* added start and enddate in cycles
* Update campaignApis.ts (#930)
* Update request.ts (#932)
* fixed generate issue (#933)
* Fixed project-type resources duplication
* updated target error messages (#936)
* fixed stepper from draft (#937)
* Update Listener.ts
* delivery type disable fix, product sku name change (#939)
Co-authored-by: nabeelmd-eGov
* fixed error message issue (#941)
* Redis integration (#940)
* Feat : added redis
* Feat : added redis retry
* removed templates folder
* updated the folder structure for health ui and removed utilties
* Update publishAllPackages.yml
* Update buildWorkbenchUI.yml
---------
Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com>
Co-authored-by: nabeelmd-eGov
Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com>
Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com>
Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com>
Co-authored-by: Bhavya-egov
Co-authored-by: ashish-egov
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Swathi-eGov <137176788+Swathi-eGov@users.noreply.github.com>
Co-authored-by: admin1
---
.github/workflows/buildWorkbenchUI.yml | 64 +
.github/workflows/publishAllPackages.yml | 13 +-
.github/workflows/publishProjectFactory.yml | 77 +
.gitignore | 4 +-
.vscode/launch.json | 17 +
.vscode/settings.json | 3 +
README.md | 1 +
health/micro-ui/.gitignore | 32 +
health/micro-ui/Jenkinsfile | 3 +
health/micro-ui/README.md | 139 ++
health/micro-ui/package.json | 4 +
health/micro-ui/web/.babelrc | 5 +
health/micro-ui/web/.env.sample | 3 +
health/micro-ui/web/CHANGELOG.md | 7 +
health/micro-ui/web/docker/Dockerfile | 25 +
health/micro-ui/web/docker/nginx.conf | 12 +
health/micro-ui/web/envs.js | 0
health/micro-ui/web/install-deps.sh | 14 +
.../web/micro-ui-internals/.gitignore | 143 ++
.../web/micro-ui-internals/.prettierignore | 23 +
.../web/micro-ui-internals/.prettierrc.json | 3 +
.../micro-ui/web/micro-ui-internals/README.md | 100 ++
.../micro-ui/web/micro-ui-internals/clean.sh | 28 +
.../micro-ui-internals/example/.env-health-qa | 7 +
.../micro-ui-internals/example/.env-mz-prod | 7 +
.../micro-ui-internals/example/.env-mz-uat | 7 +
.../example/.env-unifieddev | 9 +
.../micro-ui-internals/example/package.json | 39 +
.../example/public/index.html | 34 +
.../example/src/ComponentRegistry.js | 11 +
.../example/src/UICustomizations.js | 663 ++++++++
.../example/src/complaintConfig.js | 31 +
.../example/src/components/SelectName.js | 8 +
.../web/micro-ui-internals/example/src/fsm.js | 38 +
.../micro-ui-internals/example/src/index.js | 84 +
.../web/micro-ui-internals/example/src/pgr.js | 15 +
.../example/src/setupProxy.js | 100 ++
.../web/micro-ui-internals/package.json | 57 +
.../micro-ui-internals/packages/css/README.md | 62 +
.../packages/css/gulpfile.js | 71 +
.../packages/css/package.json | 65 +
.../packages/css/postcss.config.js | 55 +
.../css/src/components/microplanning.scss | 363 ++++
.../packages/css/src/index.scss | 13 +
.../css/src/pages/employee/campaign.scss | 109 ++
.../css/src/pages/employee/campaignCycle.scss | 331 ++++
.../css/src/pages/employee/coreOverride.scss | 173 ++
.../css/src/pages/employee/index.scss | 481 ++++++
.../packages/css/src/typography.scss | 512 ++++++
.../packages/css/tailwind.config.js | 233 +++
.../modules/campaign-manager/README.md | 159 ++
.../modules/campaign-manager/package.json | 51 +
.../modules/campaign-manager/src/Module.js | 141 ++
.../src/components/AddProductField.js | 144 ++
.../src/components/BulkUpload.js | 202 +++
.../src/components/CampaignCard.js | 71 +
.../src/components/CampaignDates.js | 122 ++
.../components/CampaignDocumentsPreview.js | 92 +
.../src/components/CampaignHeader.js | 32 +
.../src/components/CampaignName.js | 66 +
.../components/CampaignResourceDocuments.js | 50 +
.../src/components/CampaignSummary.js | 484 ++++++
.../src/components/CampaignType.js | 143 ++
.../src/components/CycleDataPreview.js | 186 ++
.../src/components/CycleDetaisPreview.js | 143 ++
.../src/components/DetailsTable.js | 76 +
.../src/components/DocumentIcon.js | 29 +
.../src/components/PlusMinusInput.js | 47 +
.../src/components/RemovableTagNew.js | 16 +
.../src/components/SelectingBoundaries.js | 542 ++++++
.../src/components/TimelineCampaign.js | 46 +
.../src/components/UploadData.js | 1163 +++++++++++++
.../src/components/XlsPreview.js | 69 +
.../src/components/icons/DustbinIcon.js | 10 +
.../src/components/icons/XlsxFile.js | 32 +
.../src/configs/CampaignConfig.js | 267 +++
.../src/configs/UICustomizations.js | 472 ++++++
.../src/configs/addProductConfig.js | 19 +
.../src/configs/attributeConfig.js | 23 +
.../src/configs/baseTimeOut.js | 6 +
.../src/configs/deliveryConfig.js | 206 +++
.../src/configs/headerConfig.js | 20 +
.../src/configs/mailConfig.js | 5 +
.../src/configs/myCampaignConfig.js | 667 ++++++++
.../src/configs/operatorConfig.js | 27 +
.../src/configs/previewConfig.js | 124 ++
.../src/configs/productType.js | 15 +
.../src/configs/schemaConfig.js | 80 +
.../campaign-manager/src/hooks/index.js | 47 +
.../hooks/services/createCampaignService.js | 19 +
.../hooks/services/updateCampaignService.js | 20 +
.../src/hooks/services/useSearchCampaign.js | 21 +
.../src/hooks/useCreateCampaign.js | 10 +
.../src/hooks/useCreateProduct.js | 24 +
.../src/hooks/useCreateProductVariant.js | 24 +
.../src/hooks/useGenerateIdCampaign.js | 26 +
.../src/hooks/useParallelSearch.js | 88 +
.../src/hooks/useProductList.js | 53 +
.../src/hooks/useResourceData.js | 107 ++
.../src/hooks/useUpdateCampaign.js | 10 +
.../src/pages/employee/AddProduct.js | 161 ++
.../src/pages/employee/CycleConfiguration.js | 248 +++
.../src/pages/employee/MyCampaign.js | 80 +
.../src/pages/employee/Response.js | 65 +
.../src/pages/employee/SetupCampaign.js | 1491 +++++++++++++++++
.../deliveryRule/AddDeliverycontext.js | 813 +++++++++
.../deliveryRule/AddProductscontext.js | 290 ++++
.../employee/deliveryRule/MultiTabcontext.js | 265 +++
.../src/pages/employee/deliveryRule/index.js | 531 ++++++
.../src/pages/employee/index.js | 102 ++
.../campaign-manager/src/utils/TourSteps.js | 144 ++
.../src/utils/downloadExcel.js | 46 +
.../campaign-manager/src/utils/index.js | 6 +
.../web/micro-ui-internals/publish-develop.sh | 20 +
.../web/micro-ui-internals/publish.sh | 20 +
.../web/micro-ui-internals/scripts/create.sh | 3 +
.../web/micro-ui-internals/scripts/deploy.sh | 8 +
.../web/micro-ui-internals/scripts/jenkins.sh | 3 +
.../web/micro-ui-internals/scripts/run.sh | 32 +
.../micro-ui/web/micro-ui-internals/test.js | 31 +
health/micro-ui/web/package.json | 85 +
health/micro-ui/web/public/index.html | 37 +
health/micro-ui/web/public/robots.txt | 3 +
health/micro-ui/web/src/App.js | 74 +
health/micro-ui/web/src/ComponentRegistry.js | 11 +
.../src/Customisations/UICustomizations.js | 428 +++++
.../micro-ui/web/src/Customisations/index.js | 19 +
.../web/src/Customisations/pt/index.js | 13 +
.../pt/pageComponents/PTAllotmentDetails.js | 64 +
.../pt/pageComponents/PTBusinessDetails.js | 68 +
.../pt/pageComponents/PTVasikaDetails.js | 79 +
.../pt/pageComponents/PropertyUsageType.js | 134 ++
.../src/Customisations/tl/TLCustomisation.js | 5 +
.../web/src/Customisations/tl/index.js | 7 +
.../tl/pageComponents/PropertyUsageType.js | 136 ++
health/micro-ui/web/src/index.css | 0
health/micro-ui/web/src/index.js | 62 +
health/micro-ui/web/src/setupProxy.js | 30 +
health/micro-ui/web/webpack.config.js | 43 +
health/micro-ui/web/workbench/App.js | 72 +
health/micro-ui/web/workbench/Dockerfile | 29 +
health/micro-ui/web/workbench/install-deps.sh | 18 +
.../micro-ui/web/workbench/inter-package.json | 58 +
health/micro-ui/web/workbench/nginx.conf | 12 +
health/micro-ui/web/workbench/package.json | 89 +
.../micro-ui/web/workbench/webpack.config.js | 44 +
yarn.lock | 4 +
147 files changed, 16772 insertions(+), 5 deletions(-)
create mode 100644 .github/workflows/buildWorkbenchUI.yml
create mode 100644 .github/workflows/publishProjectFactory.yml
create mode 100644 .vscode/launch.json
create mode 100644 .vscode/settings.json
create mode 100644 health/micro-ui/.gitignore
create mode 100644 health/micro-ui/Jenkinsfile
create mode 100644 health/micro-ui/README.md
create mode 100644 health/micro-ui/package.json
create mode 100644 health/micro-ui/web/.babelrc
create mode 100644 health/micro-ui/web/.env.sample
create mode 100644 health/micro-ui/web/CHANGELOG.md
create mode 100644 health/micro-ui/web/docker/Dockerfile
create mode 100644 health/micro-ui/web/docker/nginx.conf
create mode 100644 health/micro-ui/web/envs.js
create mode 100755 health/micro-ui/web/install-deps.sh
create mode 100644 health/micro-ui/web/micro-ui-internals/.gitignore
create mode 100644 health/micro-ui/web/micro-ui-internals/.prettierignore
create mode 100644 health/micro-ui/web/micro-ui-internals/.prettierrc.json
create mode 100644 health/micro-ui/web/micro-ui-internals/README.md
create mode 100644 health/micro-ui/web/micro-ui-internals/clean.sh
create mode 100644 health/micro-ui/web/micro-ui-internals/example/.env-health-qa
create mode 100644 health/micro-ui/web/micro-ui-internals/example/.env-mz-prod
create mode 100644 health/micro-ui/web/micro-ui-internals/example/.env-mz-uat
create mode 100644 health/micro-ui/web/micro-ui-internals/example/.env-unifieddev
create mode 100644 health/micro-ui/web/micro-ui-internals/example/package.json
create mode 100644 health/micro-ui/web/micro-ui-internals/example/public/index.html
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/fsm.js
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/pgr.js
create mode 100644 health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
create mode 100644 health/micro-ui/web/micro-ui-internals/package.json
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/README.md
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/package.json
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/src/index.scss
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/publish-develop.sh
create mode 100644 health/micro-ui/web/micro-ui-internals/publish.sh
create mode 100755 health/micro-ui/web/micro-ui-internals/scripts/create.sh
create mode 100755 health/micro-ui/web/micro-ui-internals/scripts/deploy.sh
create mode 100755 health/micro-ui/web/micro-ui-internals/scripts/jenkins.sh
create mode 100755 health/micro-ui/web/micro-ui-internals/scripts/run.sh
create mode 100644 health/micro-ui/web/micro-ui-internals/test.js
create mode 100644 health/micro-ui/web/package.json
create mode 100644 health/micro-ui/web/public/index.html
create mode 100644 health/micro-ui/web/public/robots.txt
create mode 100644 health/micro-ui/web/src/App.js
create mode 100644 health/micro-ui/web/src/ComponentRegistry.js
create mode 100644 health/micro-ui/web/src/Customisations/UICustomizations.js
create mode 100644 health/micro-ui/web/src/Customisations/index.js
create mode 100644 health/micro-ui/web/src/Customisations/pt/index.js
create mode 100644 health/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js
create mode 100644 health/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js
create mode 100644 health/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js
create mode 100644 health/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js
create mode 100644 health/micro-ui/web/src/Customisations/tl/TLCustomisation.js
create mode 100644 health/micro-ui/web/src/Customisations/tl/index.js
create mode 100644 health/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js
create mode 100644 health/micro-ui/web/src/index.css
create mode 100644 health/micro-ui/web/src/index.js
create mode 100644 health/micro-ui/web/src/setupProxy.js
create mode 100644 health/micro-ui/web/webpack.config.js
create mode 100644 health/micro-ui/web/workbench/App.js
create mode 100644 health/micro-ui/web/workbench/Dockerfile
create mode 100755 health/micro-ui/web/workbench/install-deps.sh
create mode 100644 health/micro-ui/web/workbench/inter-package.json
create mode 100644 health/micro-ui/web/workbench/nginx.conf
create mode 100644 health/micro-ui/web/workbench/package.json
create mode 100644 health/micro-ui/web/workbench/webpack.config.js
create mode 100644 yarn.lock
diff --git a/.github/workflows/buildWorkbenchUI.yml b/.github/workflows/buildWorkbenchUI.yml
new file mode 100644
index 00000000000..53ad39bacf7
--- /dev/null
+++ b/.github/workflows/buildWorkbenchUI.yml
@@ -0,0 +1,64 @@
+name: Digit Admin Console Build workflow
+on:
+ push:
+ branches:
+ - campaign
+ paths:
+ - 'health/micro-ui/web/micro-ui-internals/**'
+ pull_request:
+ branches:
+ - campaign
+ workflow_dispatch:
+jobs:
+ docker_image-build:
+ outputs:
+ run_job_digit_ui: ${{ steps.check_files.outputs.run_job_digit_ui }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 2
+ - name: Setup Docker
+ uses: docker/setup-buildx-action@v1
+ - name: check modified files
+ id: check_files
+ run: |
+ echo "=============== list modified files ==============="
+ git diff --name-only HEAD^ HEAD
+
+ echo "========== check paths of modified files =========="
+ git diff --name-only HEAD^ HEAD > files.txt
+ run_job_digit_ui=false
+ while IFS= read -r file
+ do
+ if [[ $file == health/micro-ui/* ]]; then
+ echo "This modified file is under the 'digit_ui' folder."
+ run_job_digit_ui=true
+ fi
+ done < files.txt
+
+ # Set the output based on whether the job should run
+ echo "::set-output name=run_job_digit_ui::$run_job_digit_ui"
+ echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
+ echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA
+ echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
+
+
+
+
+ - name: Login to egovio docker Container Registry
+ env:
+ DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
+ run: |
+ # Authenticate with Docker Hub
+ echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
+
+ - name: Build and Push Docker image for digit-ui
+ if: ${{ steps.check_files.outputs.run_job_digit_ui == 'true' }}
+ run: |
+ docker build -t workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} -f web/workbench/Dockerfile .
+ docker tag workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }}
+ docker push egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }}
+ working-directory: micro-ui
diff --git a/.github/workflows/publishAllPackages.yml b/.github/workflows/publishAllPackages.yml
index ffaa1e6c016..f41ce8f9e72 100644
--- a/.github/workflows/publishAllPackages.yml
+++ b/.github/workflows/publishAllPackages.yml
@@ -1,10 +1,15 @@
-name: Node.js Publish UI Packages
+name: Node.js Publish Health UI Packages
on:
push:
- branches: [ 'develop' ]
+ branches: [ 'develop','campaign' ]
paths:
- - 'micro-ui/web/micro-ui-internals/**'
+ - 'health/micro-ui/web/micro-ui-internals/**'
+
+ pull_request:
+ branches:
+ - 'dev-hcm'
+ # Push events to branches matching refs/heads/mona/octocat
jobs:
build:
@@ -15,6 +20,6 @@ jobs:
with:
node-version: 14
registry-url: https://registry.npmjs.org/
- - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish-workbench.sh
+ - run: cd health/micro-ui/web/micro-ui-internals/ && bash ./publish-develop.sh
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
diff --git a/.github/workflows/publishProjectFactory.yml b/.github/workflows/publishProjectFactory.yml
new file mode 100644
index 00000000000..19fde98c7ab
--- /dev/null
+++ b/.github/workflows/publishProjectFactory.yml
@@ -0,0 +1,77 @@
+name: project factory service docker Image CI
+
+on:
+ push:
+ branches: [ "campaign" ]
+ paths:
+ - 'utilities/project-factory/**'
+ pull_request:
+ branches: [ "campaign" ]
+
+jobs:
+
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0 # Fetch all history for tags and branches
+
+ - name: Set up environment variables
+ id: env
+ run: |
+ echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
+ echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
+ echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA
+
+ - name: Build the service Docker image
+ id: docker_build
+ working-directory: ./utilities/project-factory
+ run: |
+ IMAGE_TAG=egovio/project-factory:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }}
+ docker build . \
+ --file Dockerfile \
+ --tag $IMAGE_TAG
+ echo "::set-output name=image_name::$IMAGE_TAG"
+
+
+ - name: Build the db migration Docker image
+ id: docker_db_build
+ working-directory: ./utilities/project-factory/migration
+ run: |
+ IMAGE_TAG=egovio/project-factory-db:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }}
+ docker build . \
+ --file Dockerfile \
+ --tag $IMAGE_TAG
+ echo "::set-output name=db_image_name::$IMAGE_TAG"
+
+
+ - name: Login to Docker Hub and Push Docker Image
+ working-directory: ./utilities/project-factory
+ env:
+ DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
+ IMAGE_NAME: ${{ steps.docker_build.outputs.image_name }}
+ run: |
+ # Authenticate with Docker Hub
+ echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
+
+ # Push the image to Docker Hub
+ docker push $IMAGE_NAME
+ echo "Docker image pushed: $IMAGE_NAME"
+
+ - name: Login to Docker Hub and Push DB Migration Docker Image
+ working-directory: ./utilities/project-factory/migration
+ env:
+ DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
+ DB_IMAGE_NAME: ${{ steps.docker_db_build.outputs.db_image_name }}
+ run: |
+ # Authenticate with Docker Hub
+ echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
+
+ # Push the image to Docker Hub
+ docker push $DB_IMAGE_NAME
+ echo "Docker image pushed: $DB_IMAGE_NAME"
diff --git a/.gitignore b/.gitignore
index 84763f33d2a..cdb588bba78 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@
accelerators/frontend/micro-ui-internals/node_modules/*
.idea
index.lock
-utilities/
\ No newline at end of file
+utilities/project-factory/node_modules/*
+utilities/egov-bff/node_modules/*
+utilities/
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 00000000000..65322fe9f51
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,17 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "node",
+ "request": "attach",
+ "name": "Attach to Remote",
+ "address": "localhost",
+ "port": 9229,
+ "localRoot": "${workspaceFolder}",
+ "remoteRoot": "/app"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000000..14f60307eb1
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "editor.inlineSuggest.showToolbar": "onHover"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index d758d985c9c..b0ad104ede6 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
+
# DIGIT UI
A React App built on top of DIGIT UI Core.
diff --git a/health/micro-ui/.gitignore b/health/micro-ui/.gitignore
new file mode 100644
index 00000000000..feb4cac5c94
--- /dev/null
+++ b/health/micro-ui/.gitignore
@@ -0,0 +1,32 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+.env
+.eslintcache
+
+# yarn $
+.yarn
+yarn.lock
+.yarnrc.yml
+
+# dependencies
+node_modules
+.yarn
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/web/build
+dist
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/health/micro-ui/Jenkinsfile b/health/micro-ui/Jenkinsfile
new file mode 100644
index 00000000000..1206b9c141d
--- /dev/null
+++ b/health/micro-ui/Jenkinsfile
@@ -0,0 +1,3 @@
+library 'ci-libs'
+
+buildPipeline(configFile: './build/build-config.yml')
diff --git a/health/micro-ui/README.md b/health/micro-ui/README.md
new file mode 100644
index 00000000000..9f559d81783
--- /dev/null
+++ b/health/micro-ui/README.md
@@ -0,0 +1,139 @@
+
+# DIGIT ui
+
+A React App built on top of DIGIT UI Core.
+
+# DIGIT
+
+DIGIT eGovernance Platform Services
+
+DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://core.digit.org/ for more details.
+
+DIGIT platform is microservices based API platform enabling quick rebundling of services as per specific needs. This is a repo that lays down the core platform on top of which other mission services depend.
+
+
+# DIGIT UI
+
+
+This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries.
+
+Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications
+
+It is also used to manage the Localisation data present in the system (Localisation service)
+
+
+## Run Locally
+
+Clone the project
+
+```bash
+ git clone https://github.com/egovernments/DIGIT-Frontend.git
+```
+
+Go to the Sub directory to run UI
+```bash
+ cd into micro-ui/web/micro-ui-internals
+```
+
+Install dependencies
+
+```bash
+ yarn install
+```
+
+Add .env file
+```bash
+ micro-ui/web/micro-ui-internals/example/.env
+```
+
+Start the server
+
+```bash
+ yarn start
+```
+
+
+## Environment Variables
+
+To run this project, you will need to add the following environment variables to your .env file
+
+`REACT_APP_PROXY_API` :: `{{server url}}`
+
+`REACT_APP_GLOBAL` :: `{{server url}}`
+
+`REACT_APP_PROXY_ASSETS` :: `{{server url}}`
+
+`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}`
+
+`SKIP_PREFLIGHT_CHECK` :: `true`
+
+[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev)
+
+## Tech Stack
+
+**Libraries:**
+
+[React](https://react.dev/)
+
+[React Hook Form](https://www.react-hook-form.com/)
+
+[React Query](https://tanstack.com/query/v3/)
+
+[Tailwind CSS](https://tailwindcss.com/)
+
+[Webpack](https://webpack.js.org/)
+
+## License
+
+[MIT](https://choosealicense.com/licenses/mit/)
+
+
+## Author
+
+- [@jagankumar-egov](https://www.github.com/jagankumar-egov)
+
+
+## Documentation
+
+[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui)
+
+
+## Support
+
+For support, add the issues in https://github.com/egovernments/DIGIT-core/issues.
+
+
+## Modules
+
+ 1. Core
+ 2. Workbench
+ 3. HRMS
+ 4. Dashboard
+ 5. Engagement
+ 6. Payment
+
+## Starting with Digit-UI App (Impelmentation Teams) - MICRO-UI
+
+
+Go to the Sub directory to run UI
+
+```bash
+ cd into micro-ui/web
+```
+
+```bash
+ yarn install
+```
+
+Add .env file
+```bash
+ micro-ui/web/.env
+```
+
+Start the server
+
+```bash
+ yarn start
+```
+
+![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png)
diff --git a/health/micro-ui/package.json b/health/micro-ui/package.json
new file mode 100644
index 00000000000..19a3c47d6ee
--- /dev/null
+++ b/health/micro-ui/package.json
@@ -0,0 +1,4 @@
+{
+ "name": "workbench-ui",
+ "version": "1.0.0"
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/.babelrc b/health/micro-ui/web/.babelrc
new file mode 100644
index 00000000000..5f90443d15e
--- /dev/null
+++ b/health/micro-ui/web/.babelrc
@@ -0,0 +1,5 @@
+{
+ "presets": [
+ "@babel/preset-env","@babel/preset-react"
+ ]
+ }
\ No newline at end of file
diff --git a/health/micro-ui/web/.env.sample b/health/micro-ui/web/.env.sample
new file mode 100644
index 00000000000..e87c7f586c4
--- /dev/null
+++ b/health/micro-ui/web/.env.sample
@@ -0,0 +1,3 @@
+SKIP_PREFLIGHT_CHECK=true
+REACT_APP_STATE_LEVEL_TENANT_ID=pb
+REACT_APP_PROXY_URL=https://works-dev.digit.org
diff --git a/health/micro-ui/web/CHANGELOG.md b/health/micro-ui/web/CHANGELOG.md
new file mode 100644
index 00000000000..826105084e8
--- /dev/null
+++ b/health/micro-ui/web/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Changelog
+All notable changes to this module will be documented in this file.
+
+## 0.1.0 - 2024-05-28
+#### Base Admin console web
+ 1. Helps in creating the Campaign and configure delivery rules
+ 2. Create Data: Validates and creates resource details of type facility,user and boundary.
diff --git a/health/micro-ui/web/docker/Dockerfile b/health/micro-ui/web/docker/Dockerfile
new file mode 100644
index 00000000000..8e9b173bb85
--- /dev/null
+++ b/health/micro-ui/web/docker/Dockerfile
@@ -0,0 +1,25 @@
+# FROM egovio/alpine-node-builder-14:yarn AS build
+FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build
+RUN apk update && apk upgrade
+RUN apk add --no-cache git>2.30.0
+ARG WORK_DIR
+WORKDIR /app
+ENV NODE_OPTIONS "--max-old-space-size=8168"
+
+COPY ${WORK_DIR} .
+RUN ls -lah
+
+#RUN node web/envs.js
+RUN cd web/ \
+ && ./install-deps.sh \
+ && yarn install \
+ && yarn build:webpack
+
+FROM nginx:mainline-alpine
+#FROM ghcr.io/egovernments/nginx:mainline-alpine
+ENV WORK_DIR=/var/web/digit-ui
+
+RUN mkdir -p ${WORK_DIR}
+
+COPY --from=build /app/web/build ${WORK_DIR}/
+COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf
diff --git a/health/micro-ui/web/docker/nginx.conf b/health/micro-ui/web/docker/nginx.conf
new file mode 100644
index 00000000000..4f532e4a6ed
--- /dev/null
+++ b/health/micro-ui/web/docker/nginx.conf
@@ -0,0 +1,12 @@
+server
+{
+ listen 80;
+ underscores_in_headers on;
+
+ location /digit-ui
+ {
+ root /var/web;
+ index index.html index.htm;
+ try_files $uri $uri/ /digit-ui/index.html;
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/envs.js b/health/micro-ui/web/envs.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/health/micro-ui/web/install-deps.sh b/health/micro-ui/web/install-deps.sh
new file mode 100755
index 00000000000..efaceaee20d
--- /dev/null
+++ b/health/micro-ui/web/install-deps.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+BRANCH="$(git branch --show-current)"
+
+echo "Main Branch: $BRANCH"
+
+INTERNALS="micro-ui-internals"
+
+cp $INTERNALS/example/src/UICustomizations.js src/Customisations
+
+cd $INTERNALS && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages"
+
+
+# yarn install
diff --git a/health/micro-ui/web/micro-ui-internals/.gitignore b/health/micro-ui/web/micro-ui-internals/.gitignore
new file mode 100644
index 00000000000..1747c795d6f
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/.gitignore
@@ -0,0 +1,143 @@
+# Created by https://www.toptal.com/developers/gitignore/api/node,react
+# Edit at https://www.toptal.com/developers/gitignore?templates=node,react
+
+### eGov ###
+packages/css/example/index.css
+package-lock.json
+locales/
+build/
+packages/**/dist/
+
+# yarn #
+.yarn
+.yarnrc.yml
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+.env*.local
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+dist-storybook
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+### react ###
+.DS_*
+**/*.backup.*
+**/*.back.*
+
+node_modules
+
+*.sublime*
+
+psd
+thumb
+sketch
+
+# vs code
+.vscode/
+
+# End of https://www.toptal.com/developers/gitignore/api/node,react
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/.prettierignore b/health/micro-ui/web/micro-ui-internals/.prettierignore
new file mode 100644
index 00000000000..d54de016ef0
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/.prettierignore
@@ -0,0 +1,23 @@
+
+# See https://help.github.com/ignore-files/ for more about ignoring files.
+# dependencies
+node_modules
+# builds
+build
+dist
+.rpt2_cache
+# dev
+dev.css
+index.css
+index.compat.css
+index.min.css
+# misc
+.DS_Store
+.env
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/health/micro-ui/web/micro-ui-internals/.prettierrc.json b/health/micro-ui/web/micro-ui-internals/.prettierrc.json
new file mode 100644
index 00000000000..b975008d6f8
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/.prettierrc.json
@@ -0,0 +1,3 @@
+{
+ "printWidth": 150
+}
diff --git a/health/micro-ui/web/micro-ui-internals/README.md b/health/micro-ui/web/micro-ui-internals/README.md
new file mode 100644
index 00000000000..f23a1fcfe9c
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/README.md
@@ -0,0 +1,100 @@
+
+# workbench ui
+
+A React App built on top of DIGIT UI Core.
+
+
+# DIGIT UI
+
+DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://www.digit.org for more details.
+
+This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries.
+
+Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications
+
+It is also used to manage the Localisation data present in the system (Localisation service)
+
+
+## Run Locally
+
+Clone the project
+
+```bash
+ git clone https://github.com/egovernments/Digit-Core.git
+```
+
+Go to the Sub directory to run UI
+```bash
+ cd into frontend/micro-ui/web/micro-ui-internals
+```
+
+Install dependencies
+
+```bash
+ yarn install
+```
+
+Add .env file
+```bash
+ frontend/micro-ui/web/micro-ui-internals/example/.env
+```
+
+Start the server
+
+```bash
+ yarn start
+```
+
+
+## Environment Variables
+
+To run this project, you will need to add the following environment variables to your .env file
+
+`REACT_APP_PROXY_API` :: `{{server url}}`
+
+`REACT_APP_GLOBAL` :: `{{server url}}`
+
+`REACT_APP_PROXY_ASSETS` :: `{{server url}}`
+
+`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}`
+
+`SKIP_PREFLIGHT_CHECK` :: `true`
+
+[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev)
+
+## Tech Stack
+
+**Libraries:**
+
+[React](https://react.dev/)
+
+[React Hook Form](https://www.react-hook-form.com/)
+
+[React Query](https://tanstack.com/query/v3/)
+
+[Tailwind CSS](https://tailwindcss.com/)
+
+[Webpack](https://webpack.js.org/)
+
+## License
+
+[MIT](https://choosealicense.com/licenses/mit/)
+
+
+## Author
+
+- [@jagankumar-egov](https://www.github.com/jagankumar-egov)
+
+
+## Documentation
+
+[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui)
+
+
+## Support
+
+For support, add the issues in https://github.com/egovernments/DIGIT-core/issues.
+
+
+![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png)
+
diff --git a/health/micro-ui/web/micro-ui-internals/clean.sh b/health/micro-ui/web/micro-ui-internals/clean.sh
new file mode 100644
index 00000000000..2235ef1c1d0
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/clean.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+BASEDIR="$( cd "$( dirname "$0" )" && pwd )"
+
+msg() {
+ echo -e "\n\n\033[32;32m$1\033[0m"
+}
+
+msg "Cleaning root"
+rm -rf node_modules
+
+msg "Cleaning css"
+cd "$BASEDIR/packages/css" && rm -rf node_modules
+
+msg "Cleaning libraries"
+cd "$BASEDIR/packages/libraries" && rm -rf node_modules
+
+msg "Cleaning react-components"
+cd "$BASEDIR/packages/react-components" && rm -rf node_modules
+
+msg "Cleaning PGR module"
+cd "$BASEDIR/packages/modules/pgr" && rm -rf node_modules
+
+msg "Cleaning FSM module"
+cd "$BASEDIR/packages/modules/fsm" && rm -rf node_modules
+
+msg "Cleaning Core module"
+cd "$BASEDIR/packages/modules/core" && rm -rf node_modules
diff --git a/health/micro-ui/web/micro-ui-internals/example/.env-health-qa b/health/micro-ui/web/micro-ui-internals/example/.env-health-qa
new file mode 100644
index 00000000000..73b42b7dfad
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/.env-health-qa
@@ -0,0 +1,7 @@
+SKIP_PREFLIGHT_CHECK=true
+REACT_APP_USER_TYPE=EMPLOYEE
+REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a
+REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c
+REACT_APP_PROXY_API=https://health-qa.digit.org
+REACT_APP_PROXY_ASSETS=https://health-qa.digit.org
+REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCM.js
diff --git a/health/micro-ui/web/micro-ui-internals/example/.env-mz-prod b/health/micro-ui/web/micro-ui-internals/example/.env-mz-prod
new file mode 100644
index 00000000000..2d02707d7eb
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/.env-mz-prod
@@ -0,0 +1,7 @@
+SKIP_PREFLIGHT_CHECK=true
+REACT_APP_USER_TYPE=EMPLOYEE
+REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a
+REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c
+REACT_APP_PROXY_API=https://salama.digit.org
+REACT_APP_PROXY_ASSETS=https://salama.digit.org
+REACT_APP_GLOBAL=https://moz-health-prd.s3.af-south-1.amazonaws.com/globalConfig.js
diff --git a/health/micro-ui/web/micro-ui-internals/example/.env-mz-uat b/health/micro-ui/web/micro-ui-internals/example/.env-mz-uat
new file mode 100644
index 00000000000..bedf28a95b1
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/.env-mz-uat
@@ -0,0 +1,7 @@
+SKIP_PREFLIGHT_CHECK=true
+REACT_APP_USER_TYPE=EMPLOYEE
+REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a
+REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c
+REACT_APP_PROXY_API=https://moz-health-uat.digit.org
+REACT_APP_PROXY_ASSETS=https://moz-health-uat.digit.org
+REACT_APP_GLOBAL=https://moz-health-uat.s3.ap-south-1.amazonaws.com/globalConfig.js
diff --git a/health/micro-ui/web/micro-ui-internals/example/.env-unifieddev b/health/micro-ui/web/micro-ui-internals/example/.env-unifieddev
new file mode 100644
index 00000000000..81fd56e040a
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/.env-unifieddev
@@ -0,0 +1,9 @@
+SKIP_PREFLIGHT_CHECK=true
+REACT_APP_USER_TYPE=EMPLOYEE
+REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a
+REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c
+REACT_APP_PROXY_API=https://unified-dev.digit.org
+REACT_APP_PROXY_ASSETS=https://unified-dev.digit.org
+REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsMicroplan.js
+REACT_APP_CONTEXT=works
+WORKBENCH=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCMMZ.js
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/example/package.json b/health/micro-ui/web/micro-ui-internals/example/package.json
new file mode 100644
index 00000000000..7c60f4a1d6c
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "@egovernments/digit-ui-example",
+ "version": "1.0.0",
+ "main": "index.js",
+ "license": "MIT",
+ "private": true,
+ "homepage": "digit-ui",
+ "scripts": {
+ "start": "react-scripts start"
+ },
+ "devDependencies": {
+ "@egovernments/digit-ui-libraries": "1.8.2-beta.1",
+ "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3",
+ "@egovernments/digit-ui-components": "0.0.2-beta.1",
+ "@egovernments/digit-ui-module-core": "1.8.2-beta.2",
+ "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
+ "@egovernments/digit-ui-module-campaign-manager": "0.0.1",
+ "http-proxy-middleware": "^1.0.5",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-i18next": "11.16.2",
+ "react-router-dom": "5.3.0",
+ "react-scripts": "^4.0.1"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/example/public/index.html b/health/micro-ui/web/micro-ui-internals/example/public/index.html
new file mode 100644
index 00000000000..d42798fc275
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/public/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+ DIGIT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js b/health/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js
new file mode 100644
index 00000000000..9bafce3dc89
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js
@@ -0,0 +1,11 @@
+class Registry {
+ constructor(registry = {}) {
+ this._registry = registry;
+ }
+
+ getComponent(id) {
+ return this._registry[id];
+ }
+}
+
+export default Registry;
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
new file mode 100644
index 00000000000..d21e82500b7
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
@@ -0,0 +1,663 @@
+import { Link } from "react-router-dom";
+import _ from "lodash";
+import { useLocation, useHistory } from "react-router-dom";
+import { useParams } from "react-router-dom";
+
+//create functions here based on module name set in mdms(eg->SearchProjectConfig)
+//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName]
+// these functions will act as middlewares
+var Digit = window.Digit || {};
+
+const businessServiceMap = {
+ "muster roll": "MR",
+};
+
+const inboxModuleNameMap = {
+ "muster-roll-approval": "muster-roll-service",
+};
+
+export const UICustomizations = {
+ businessServiceMap,
+ updatePayload: (applicationDetails, data, action, businessService) => {
+ if (businessService === businessServiceMap.estimate) {
+ const workflow = {
+ comment: data.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ estimate: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap.contract) {
+ const workflow = {
+ comment: data?.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ contract: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap?.["muster roll"]) {
+ const workflow = {
+ comment: data?.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ musterRoll: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap?.["works.purchase"]) {
+ const workflow = {
+ comment: data.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ const additionalFieldsToSet = {
+ projectId: applicationDetails.additionalDetails.projectId,
+ invoiceDate: applicationDetails.billDate,
+ invoiceNumber: applicationDetails.referenceId.split("_")?.[1],
+ contractNumber: applicationDetails.referenceId.split("_")?.[0],
+ documents: applicationDetails.additionalDetails.documents,
+ };
+ return {
+ bill: { ...applicationDetails, ...additionalFieldsToSet },
+ workflow,
+ };
+ }
+ },
+ enableModalSubmit: (businessService, action, setModalSubmit, data) => {
+ if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") {
+ setModalSubmit(data?.acceptTerms);
+ }
+ },
+ enableHrmsSearch: (businessService, action) => {
+ if (businessService === businessServiceMap.estimate) {
+ return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD");
+ }
+ if (businessService === businessServiceMap.contract) {
+ return action.action.includes("VERIFY_AND_FORWARD");
+ }
+ if (businessService === businessServiceMap?.["muster roll"]) {
+ return action.action.includes("VERIFY");
+ }
+ if (businessService === businessServiceMap?.["works.purchase"]) {
+ return action.action.includes("VERIFY_AND_FORWARD");
+ }
+ return false;
+ },
+ getBusinessService: (moduleCode) => {
+ if (moduleCode?.includes("estimate")) {
+ return businessServiceMap?.estimate;
+ } else if (moduleCode?.includes("contract")) {
+ return businessServiceMap?.contract;
+ } else if (moduleCode?.includes("muster roll")) {
+ return businessServiceMap?.["muster roll"];
+ } else if (moduleCode?.includes("works.purchase")) {
+ return businessServiceMap?.["works.purchase"];
+ } else if (moduleCode?.includes("works.wages")) {
+ return businessServiceMap?.["works.wages"];
+ } else if (moduleCode?.includes("works.supervision")) {
+ return businessServiceMap?.["works.supervision"];
+ } else {
+ return businessServiceMap;
+ }
+ },
+ getInboxModuleName: (moduleCode) => {
+ if (moduleCode?.includes("estimate")) {
+ return inboxModuleNameMap?.estimate;
+ } else if (moduleCode?.includes("contract")) {
+ return inboxModuleNameMap?.contracts;
+ } else if (moduleCode?.includes("attendence")) {
+ return inboxModuleNameMap?.attendencemgmt;
+ } else {
+ return inboxModuleNameMap;
+ }
+ },
+
+ AttendanceInboxConfig: {
+ preProcess: (data) => {
+ //set tenantId
+ data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId();
+
+ const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim();
+ if (musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber;
+
+ const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim();
+ if (attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName;
+
+ // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side)
+ const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee);
+ delete data.body.inbox.moduleSearchCriteria.assignee;
+ if (assignee?.code === "ASSIGNED_TO_ME") {
+ data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid;
+ }
+
+ //cloning locality and workflow states to format them
+ // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []);
+
+ let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null);
+ delete data.body.inbox.moduleSearchCriteria.orgId;
+ if (selectedOrg) {
+ data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber;
+ }
+
+ // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null);
+ // delete data.body.inbox.moduleSearchCriteria.ward;
+ // if(selectedWard) {
+ // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code;
+ // }
+
+ let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []);
+ let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []);
+ // delete data.body.inbox.moduleSearchCriteria.locality;
+ delete data.body.inbox.moduleSearchCriteria.state;
+ delete data.body.inbox.moduleSearchCriteria.ward;
+
+ // locality = locality?.map((row) => row?.code);
+ states = Object.keys(states)?.filter((key) => states[key]);
+ ward = ward?.map((row) => row?.code);
+
+ // //adding formatted data to these keys
+ // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality;
+ if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states;
+ if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward;
+ const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {});
+ if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code;
+
+ //adding tenantId to moduleSearchCriteria
+ data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId();
+
+ //setting limit and offset becoz somehow they are not getting set in muster inbox
+ data.body.inbox.limit = data.state.tableForm.limit;
+ data.body.inbox.offset = data.state.tableForm.offset;
+ delete data.state;
+ return data;
+ },
+ postProcess: (responseArray, uiConfig) => {
+ const statusOptions = responseArray?.statusMap
+ ?.filter((item) => item.applicationstatus)
+ ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` }));
+ if (uiConfig?.type === "filter") {
+ let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus");
+ if (fieldConfig.length) {
+ fieldConfig[0].populators.options = statusOptions;
+ }
+ }
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ if (key === "ATM_MUSTER_ROLL_ID") {
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+ }
+ if (key === "ATM_ATTENDANCE_WEEK") {
+ const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate(
+ value?.endDate,
+ "dd/MM/yyyy"
+ )}`;
+ return {week}
;
+ }
+ if (key === "ATM_NO_OF_INDIVIDUALS") {
+ return {value?.length}
;
+ }
+ if (key === "ATM_AMOUNT_IN_RS") {
+ return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")};
+ }
+ if (key === "ATM_SLA") {
+ return parseInt(value) > 0 ? (
+ {t(value) || ""}
+ ) : (
+ {t(value) || ""}
+ );
+ }
+ if (key === "COMMON_WORKFLOW_STATES") {
+ return {t(`WF_MUSTOR_${value}`)};
+ }
+ //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default
+ return {t(`CASE_NOT_HANDLED`)};
+ },
+ MobileDetailsOnClick: (row, tenantId) => {
+ let link;
+ Object.keys(row).map((key) => {
+ if (key === "ATM_MUSTER_ROLL_ID")
+ link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`;
+ });
+ return link;
+ },
+ populateReqCriteria: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ return {
+ url: "/org-services/organisation/v1/_search",
+ params: { limit: 50, offset: 0 },
+ body: {
+ SearchCriteria: {
+ tenantId: tenantId,
+ functions: {
+ type: "CBO",
+ },
+ },
+ },
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.organisations;
+ },
+ },
+ };
+ },
+ },
+ SearchWageSeekerConfig: {
+ customValidationCheck: (data) => {
+ //checking both to and from date are present
+ const { createdFrom, createdTo } = data;
+ if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === ""))
+ return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" };
+
+ return false;
+ },
+ preProcess: (data) => {
+ data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() };
+
+ let requestBody = { ...data.body.Individual };
+ const pathConfig = {
+ name: "name.givenName",
+ };
+ const dateConfig = {
+ createdFrom: "daystart",
+ createdTo: "dayend",
+ };
+ const selectConfig = {
+ wardCode: "wardCode[0].code",
+ socialCategory: "socialCategory.code",
+ };
+ const textConfig = ["name", "individualId"];
+ let Individual = Object.keys(requestBody)
+ .map((key) => {
+ if (selectConfig[key]) {
+ requestBody[key] = _.get(requestBody, selectConfig[key], null);
+ } else if (typeof requestBody[key] == "object") {
+ requestBody[key] = requestBody[key]?.code;
+ } else if (textConfig?.includes(key)) {
+ requestBody[key] = requestBody[key]?.trim();
+ }
+ return key;
+ })
+ .filter((key) => requestBody[key])
+ .reduce((acc, curr) => {
+ if (pathConfig[curr]) {
+ _.set(acc, pathConfig[curr], requestBody[curr]);
+ } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) {
+ _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr]));
+ } else {
+ _.set(acc, curr, requestBody[curr]);
+ }
+ return acc;
+ }, {});
+
+ data.body.Individual = { ...Individual };
+ return data;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ //here we can add multiple conditions
+ //like if a cell is link then we return link
+ //first we can identify which column it belongs to then we can return relevant result
+ switch (key) {
+ case "MASTERS_WAGESEEKER_ID":
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+
+ case "MASTERS_SOCIAL_CATEGORY":
+ return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA");
+
+ case "CORE_COMMON_PROFILE_CITY":
+ return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA");
+
+ case "MASTERS_WARD":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+
+ case "MASTERS_LOCALITY":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+ default:
+ return t("ES_COMMON_NA");
+ }
+ },
+ MobileDetailsOnClick: (row, tenantId) => {
+ let link;
+ Object.keys(row).map((key) => {
+ if (key === "MASTERS_WAGESEEKER_ID")
+ link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`;
+ });
+ return link;
+ },
+ additionalValidations: (type, data, keys) => {
+ if (type === "date") {
+ return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true;
+ }
+ },
+ },
+ SearchDefaultConfig: {
+ customValidationCheck: (data) => {
+ //checking both to and from date are present
+ const { createdFrom, createdTo } = data;
+ if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === ""))
+ return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" };
+
+ return false;
+ },
+ preProcess: (data) => {
+ const location = useLocation();
+ data.params = { ...data.params };
+ const { masterName } = useParams();
+
+ const searchParams = new URLSearchParams(location.search);
+ const paths = {
+ "SearchProjectConfig": {
+ basePath: "Projects",
+ pathConfig: {
+ // id: "id[0]",
+ tenantId: "tenantId",
+ },
+ dateConfig: {
+ endDate: "dayend",
+ startDate: "daystart"
+ },
+ selectConfig: {
+ },
+ textConfig :["id", "tenantId", "name", "projectNumber", "projectSubType" , "projectType"]
+ },
+ "SearchProductConfig": {
+ basePath: "Product",
+ pathConfig: {
+ id: "id[0]",
+ },
+ dateConfig: {
+ },
+ selectConfig: {
+ },
+ textConfig :["id", "manufacturer", "name", "type"]
+ },
+ "SearchHouseholdConfig": {
+ basePath: "Household",
+ pathConfig: {
+ id: "id[0]",
+ clientReferenceId: "clientReferenceId[0]",
+ },
+ dateConfig: {
+ },
+ selectConfig: {
+ },
+ textConfig :["boundaryCode", "clientReferenceId", "id"]
+ },
+ "SearchProductVariantConfig": {
+ basePath: "ProductVariant",
+ pathConfig: {
+ id: "id[0]",
+ },
+ dateConfig: {
+ },
+ selectConfig: {
+ },
+ textConfig :["productId", "sku", "variation"]
+ },
+ "SearchProjectBeneficiaryConfig": {
+ basePath: "ProjectBeneficiary",
+ pathConfig: {
+ id: "id[0]",
+ clientReferenceId: "clientReferenceId[0]",
+
+ },
+ dateConfig: {
+ dateOfRegistration: "daystart"
+ },
+ selectConfig: {
+ },
+ textConfig :["beneficiaryId", "projectId"]
+ },
+ "SearchProjectStaffConfig": {
+ basePath: "ProjectStaff",
+ pathConfig: {
+ id: "id[0]",
+ },
+ dateConfig: {
+ startDate: "daystart",
+ endDate: "dayend",
+ },
+ selectConfig: {
+ },
+ textConfig :["projectId", "userId"]
+ },
+ "SearchProjectResourceConfig": {
+ basePath: "ProjectResource",
+ pathConfig: {
+ id: "id[0]"
+ },
+ dateConfig: {
+ },
+ selectConfig: {
+ },
+ textConfig : []
+ },
+ "SearchProjectTaskConfig": {
+ basePath: "Task",
+ pathConfig: {
+ id: "id[0]",
+ clientReferenceId: "clientReferenceId[0]",
+ },
+ dateConfig: {
+ plannedEndDate: "dayend",
+ plannedStartDate: "daystart",
+ actualEndDate: "dayend",
+ actualStartDate: "daystart",
+ },
+ selectConfig: {
+ },
+ textConfig :["projectId","localityCode", "projectBeneficiaryId", "status"]
+ },
+ "SearchFacilityConfig": {
+ basePath: "Facility",
+ pathConfig: {
+ id: "id[0]"
+ },
+ dateConfig: {
+ },
+ selectConfig: {
+ },
+ textConfig :["faciltyUsage","localityCode", "storageCapacity","id"]
+ },
+ "SearchProjectFacilityConfig": {
+ basePath: "ProjectFacility",
+ pathConfig: {
+ id: "id[0]",
+ projectId: "projectId[0]",
+ facilityId: "facilityId[0]"
+ },
+ dateConfig: {
+ },
+ selectConfig: {
+ },
+ textConfig :[]
+ },
+ }
+
+ const id = searchParams.get("config")|| masterName;
+
+ if(!paths||!paths?.[id]){
+ return data;
+ }
+ let requestBody = { ...data.body[paths[id]?.basePath] };
+ const pathConfig = paths[id]?.pathConfig;
+ const dateConfig = paths[id]?.dateConfig;
+ const selectConfig = paths[id]?.selectConfig;
+ const textConfig = paths[id]?.textConfig
+
+ if(paths[id].basePath == "Projects"){
+ data.state.searchForm={...data.state.searchForm,tenantId:"mz"}
+ }
+ let Product = Object.keys(requestBody)
+ .map((key) => {
+ if (selectConfig[key]) {
+ requestBody[key] = _.get(requestBody, selectConfig[key], null);
+ } else if (typeof requestBody[key] == "object") {
+ requestBody[key] = requestBody[key]?.code;
+ } else if (textConfig?.includes(key)) {
+ requestBody[key] = requestBody[key]?.trim();
+ }
+ return key;
+ })
+ .filter((key) => requestBody[key])
+ .reduce((acc, curr) => {
+ if (pathConfig[curr]) {
+ _.set(acc, pathConfig[curr], requestBody[curr]);
+ } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) {
+ _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr]));
+ } else {
+ _.set(acc, curr, requestBody[curr]);
+ }
+ return acc;
+ }, {});
+
+ if(paths[id].basePath == "Projects"){
+
+ data.body[paths[id].basePath] = [{ ...Product}];
+ }
+ else data.body[paths[id].basePath] = { ...Product};
+ return data;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ //here we can add multiple conditions
+ //like if a cell is link then we return link
+ //first we can identify which column it belongs to then we can return relevant result
+ switch (key) {
+ case "ID":
+
+ return (
+
+
+
+
+ );
+
+ case "MASTERS_SOCIAL_CATEGORY":
+ return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA");
+
+ case "CORE_COMMON_PROFILE_CITY":
+ return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA");
+
+ case "MASTERS_WARD":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+
+ case "MASTERS_LOCALITY":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+ default:
+ return t("ES_COMMON_NA");
+ }
+ },
+ MobileDetailsOnClick: (row, tenantId) => {
+ let link;
+ Object.keys(row).map((key) => {
+ if (key === "MASTERS_WAGESEEKER_ID")
+ link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`;
+ });
+ return link;
+ },
+ additionalValidations: (type, data, keys) => {
+ if (type === "date") {
+ return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true;
+ }
+ },
+ }
+};
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js b/health/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js
new file mode 100644
index 00000000000..28c85515205
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js
@@ -0,0 +1,31 @@
+export const config = {
+ routes: {
+ "complaint-type": {
+ nextStep: "pincode",
+ },
+ landmark: {
+ nextStep: "apartment",
+ },
+ apartment: {
+ component: "SelectName",
+ texts: {
+ header: "Apartment or Society",
+ cardText: "CS_COMPLAINT_SUBTYPE_TEXT",
+ submitBarLabel: "PT_COMMONS_NEXT",
+ },
+ inputs: [
+ {
+ label: "Apartment",
+ type: "text",
+ name: "custom.additionalDetails.apartment",
+ validation: {
+ minLength: 6,
+ maxLength: 7,
+ },
+ error: "CORE_COMMON_PINCODE_INVALID",
+ },
+ ],
+ nextStep: "upload-photos",
+ },
+ },
+};
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js b/health/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js
new file mode 100644
index 00000000000..56d2a195c12
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js
@@ -0,0 +1,8 @@
+import React from "react";
+import { FormStep } from "@egovernments/digit-ui-react-components";
+
+const SelectName = ({ config, onSelect, onSkip, t }) => {
+ return ;
+};
+
+export default SelectName;
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/fsm.js b/health/micro-ui/web/micro-ui-internals/example/src/fsm.js
new file mode 100644
index 00000000000..271d3ddad56
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/fsm.js
@@ -0,0 +1,38 @@
+const fsmCustomizations = {
+ getEmployeeApplicationCustomization: (config, t) => {
+ const employeeConfig = [
+ {
+ name: "applicationDetails",
+ // fields: ["sanitationType", "applicationChannel"],
+ // fieldsOrder: {sanitationType: 0, applicationChannel: 1}, // TODO
+ allFields: true, // for example: If in applicationDetails you have 10 fields and in fieldsOrder you only enter 3 fields name then on browser you will only see 3 fields in that order but if you want to see rest of 7 fields at the bottom.
+ // removeFields: ["applicantName"], // type the name of the field in camelCase to remove it
+ addFields: [
+ // by default all the custom fields will add at the bottom, you can add "field name" to "fieldsOrder" if you want them in your custom order.
+ {
+ name: "example",
+ label: t("EXAMPLE"),
+ type: "text",
+ isMandatory: true,
+ populators: {
+ name: "example",
+ validation: {
+ required: true,
+ pattern: /[A-Za-z]/,
+ },
+ },
+ },
+ ],
+ },
+ ];
+
+ return {
+ config: employeeConfig,
+ defaultConfig: true, // You want to use defaultConfig and you only want to update one field section. The above employeeConfig is also an order for all the field section. So if defaultConfig is false then on browser you will only see those field section who are inside employeeConfig
+ };
+ },
+};
+
+const fsmComponents = {};
+
+export { fsmCustomizations, fsmComponents };
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/index.js b/health/micro-ui/web/micro-ui-internals/example/src/index.js
new file mode 100644
index 00000000000..2f01957d5b8
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/index.js
@@ -0,0 +1,84 @@
+import React from "react";
+import ReactDOM from "react-dom";
+
+import { initLibraries } from "@egovernments/digit-ui-libraries";
+// import { paymentConfigs, PaymentLinks, PaymentModule } from "@egovernments/digit-ui-module-common";
+import { DigitUI } from "@egovernments/digit-ui-module-core";
+import "@egovernments/digit-ui-css/example/index.css";
+
+import { pgrCustomizations } from "./pgr";
+import { UICustomizations } from "./UICustomizations";
+import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager"
+import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
+import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
+import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench";
+
+var Digit = window.Digit || {};
+
+const enabledModules = [
+ "DSS",
+ "HRMS",
+ "Workbench",
+ "HCMWORKBENCH",
+ "Campaign",
+ // "Engagement", "NDSS","QuickPayLinks", "Payment",
+ "Utilities",
+ "Microplanning"
+ //added to check fsm
+ // "FSM"
+];
+
+const initTokens = (stateCode) => {
+ const userType = window.sessionStorage.getItem("userType") || process.env.REACT_APP_USER_TYPE || "CITIZEN";
+ const token = window.localStorage.getItem("token") || process.env[`REACT_APP_${userType}_TOKEN`];
+
+ const citizenInfo = window.localStorage.getItem("Citizen.user-info");
+
+ const citizenTenantId = window.localStorage.getItem("Citizen.tenant-id") || stateCode;
+
+ const employeeInfo = window.localStorage.getItem("Employee.user-info");
+ const employeeTenantId = window.localStorage.getItem("Employee.tenant-id");
+
+ const userTypeInfo = userType === "CITIZEN" || userType === "QACT" ? "citizen" : "employee";
+ window.Digit.SessionStorage.set("user_type", userTypeInfo);
+ window.Digit.SessionStorage.set("userType", userTypeInfo);
+
+ if (userType !== "CITIZEN") {
+ window.Digit.SessionStorage.set("User", { access_token: token, info: userType !== "CITIZEN" ? JSON.parse(employeeInfo) : citizenInfo });
+ } else {
+ // if (!window.Digit.SessionStorage.get("User")?.extraRoleInfo) window.Digit.SessionStorage.set("User", { access_token: token, info: citizenInfo });
+ }
+
+ window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId);
+
+ if (employeeTenantId && employeeTenantId.length) window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId);
+};
+
+const initDigitUI = () => {
+ window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH") || "digit-ui";
+ window.Digit.Customizations = {
+ PGR: pgrCustomizations,
+ commonUiConfig: UICustomizations
+ };
+ window?.Digit.ComponentRegistryService.setupRegistry({
+ // PaymentModule,
+ // ...paymentConfigs,
+ // PaymentLinks,
+ });
+ initUtilitiesComponents();
+ initWorkbenchComponents();
+ initWorkbenchHCMComponents();
+ initCampaignComponents();
+
+ const moduleReducers = (initData) => initData;
+
+
+ const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb";
+ initTokens(stateCode);
+
+ ReactDOM.render(, document.getElementById("root"));
+};
+
+initLibraries().then(() => {
+ initDigitUI();
+});
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/pgr.js b/health/micro-ui/web/micro-ui-internals/example/src/pgr.js
new file mode 100644
index 00000000000..48a498e4582
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/pgr.js
@@ -0,0 +1,15 @@
+import SelectName from "./components/SelectName";
+
+// import { config as complaintConfig } from "./complaintConfig";
+
+const pgrCustomizations = {
+ // complaintConfig,
+ getComplaintDetailsTableRows: ({ id, service, role, t }) => {
+ return {};
+ },
+};
+
+const pgrComponents = {
+ SelectName: SelectName,
+};
+export { pgrCustomizations, pgrComponents };
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js b/health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
new file mode 100644
index 00000000000..fbc52c4a879
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
@@ -0,0 +1,100 @@
+const { createProxyMiddleware } = require("http-proxy-middleware");
+
+const createProxy = createProxyMiddleware({
+ //target: process.env.REACT_APP_PROXY_API || "https://uat.digit.org",
+ // target: process.env.REACT_APP_PROXY_API || "https://qa.digit.org",
+ target: process.env.REACT_APP_PROXY_API || "https://works-dev.digit.org",
+ changeOrigin: true,
+ secure: false,
+});
+const assetsProxy = createProxyMiddleware({
+ target: process.env.REACT_APP_PROXY_ASSETS || "https://works-dev.digit.org",
+ changeOrigin: true,
+ secure: false,
+});
+const mdmsProxy = createProxyMiddleware({
+ target: process.env.REACT_APP_PROXY_ASSETS || "http://localhost:8080",
+ changeOrigin: true,
+ secure: false,
+});
+module.exports = function (app) {
+ ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy));
+ [
+ "/access/v1/actions/mdms",
+ "/egov-mdms-service",
+ "/mdms-v2",
+ "/egov-idgen",
+ "/egov-location",
+ "/localization",
+ "/egov-workflow-v2",
+ "/pgr-services",
+ "/filestore",
+ "/egov-hrms",
+ "/user-otp",
+ "/user",
+ "/fsm",
+ "/billing-service",
+ "/collection-services",
+ "/pdf-service",
+ "/pg-service",
+ "/vehicle",
+ "/vendor",
+ "/property-services",
+ "/fsm-calculator/v1/billingSlab/_search",
+ "/pt-calculator-v2",
+ "/dashboard-analytics",
+ "/echallan-services",
+ "/egov-searcher/bill-genie/mcollectbills/_get",
+ "/egov-searcher/bill-genie/billswithaddranduser/_get",
+ "/egov-searcher/bill-genie/waterbills/_get",
+ "/egov-searcher/bill-genie/seweragebills/_get",
+ "/egov-pdf/download/UC/mcollect-challan",
+ "/egov-hrms/employees/_count",
+ "/tl-services/v1/_create",
+ "/tl-services/v1/_search",
+ "/egov-url-shortening/shortener",
+ "/inbox/v1/_search",
+ "/inbox/v2/_search",
+ "/tl-services",
+ "/tl-calculator",
+ "/org-services",
+ "/edcr",
+ "/bpa-services",
+ "/noc-services",
+ "/egov-user-event",
+ "/egov-document-uploader",
+ "/egov-pdf",
+ "/egov-survey-services",
+ "/ws-services",
+ "/sw-services",
+ "/ws-calculator",
+ "/sw-calculator/",
+ "/egov-searcher",
+ "/report",
+ "/inbox/v1/dss/_search",
+ "/loi-service",
+ "/project/v1/",
+ "/estimate-service",
+ "/loi-service",
+ "/works-inbox-service/v2/_search",
+ "/egov-pdf/download/WORKSESTIMATE/estimatepdf",
+ "/muster-roll",
+ "/individual",
+ "/mdms-v2",
+ "/hcm-moz-impl",
+ "/project",
+ "/project/staff/v1/_search",
+ "/project/v1/_search",
+ "/facility/v1/_search",
+ "/product/v1/_search",
+ "/product/variant/v1/_search",
+ "/hcm-bff/bulk/_transform",
+ "/hcm-bff/hcm/_processmicroplan",
+ "/health-hrms",
+ "/project-factory",
+ "/boundary-service",
+ "/product",
+ ].forEach((location) => app.use(location, createProxy));
+ ["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy));
+ ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy));
+};
diff --git a/health/micro-ui/web/micro-ui-internals/package.json b/health/micro-ui/web/micro-ui-internals/package.json
new file mode 100644
index 00000000000..92f1e334d77
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "egovernments",
+ "version": "1.0.0",
+ "main": "index.js",
+ "workspaces": [
+ "example",
+ "packages/css",
+ "packages/modules/*"
+ ],
+ "author": "JaganKumar ",
+ "license": "MIT",
+ "private": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "scripts": {
+ "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev",
+ "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script",
+ "start:dev": "run-p dev:**",
+ "start:script": "./scripts/create.sh",
+ "dev:css": "cd packages/css && yarn start",
+ "publish:css": "cd packages/css && yarn && npm publish --tag workbench-1.0",
+ "dev:example": "cd example && yarn start",
+ "dev:campaign": "cd packages/modules/campaign-manager && yarn start",
+ "build": "run-p build:**",
+ "build:campaign": "cd packages/modules/campaign-manager && yarn build",
+ "deploy:jenkins": "./scripts/jenkins.sh",
+ "clean": "rm -rf node_modules"
+ },
+ "resolutions": {
+ "**/@babel/runtime": "7.20.1",
+ "**/babel-preset-react-app": "10.0.0"
+ },
+ "devDependencies": {
+ "husky": "7.0.4",
+ "lint-staged": "12.3.7",
+ "npm-run-all": "4.1.5",
+ "prettier": "2.1.2"
+ },
+ "husky": {},
+ "lint-staged": {
+ "*.{js,css,md}": "prettier --write"
+ },
+ "dependencies": {
+ "ajv": "8.12.0",
+ "lodash": "4.17.21",
+ "microbundle-crl": "0.13.11",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-components": "0.0.2-beta.1",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0"
+ }
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/README.md b/health/micro-ui/web/micro-ui-internals/packages/css/README.md
new file mode 100644
index 00000000000..6efe08ae5c5
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/README.md
@@ -0,0 +1,62 @@
+
+
+# digit-ui-css
+
+## Install
+
+```bash
+npm install --save @egovernments/digit-ui-css
+```
+
+## Limitation
+
+```bash
+This Package is more specific to DIGIT-UI's can be used across mission's
+It is the base css for all Digit UI's
+```
+
+## Usage
+
+After adding the dependency make sure you have this dependency in
+
+```bash
+frontend/micro-ui/web/package.json
+```
+
+```json
+"@egovernments/digit-ui-css":"^1.5.0",
+```
+
+then navigate to App.js
+
+```bash
+frontend/micro-ui/web/public/index.html
+```
+
+```jsx
+/** add this import **/
+
+
+
+```
+### Changelog
+
+```bash
+1.0.7-campaign some css fixes in attribute
+1.0.5-campaign some css fixes in previous button
+1.0.4-campaign updated styling for create campaign screens
+1.0.2-campaign update Styling added for delivery rule screen
+1.0.1-campaign Styling added for delivery rule screen
+1.0.0-campaign Base version
+
+```
+## Contributors
+
+[jagankumar-egov] [nipunarora-eGov]
+
+### Published from DIGIT Frontend
+DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/develop)
+
+## License
+
+MIT © [jagankumar-egov](https://github.com/jagankumar-egov)
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js b/health/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js
new file mode 100644
index 00000000000..5d1a705494a
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js
@@ -0,0 +1,71 @@
+const fs = require("fs");
+const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync("package.json"));
+
+const headerString = `
+@charset "UTF-8";
+/*!
+ * ${name} - ${version}
+ *
+ * Copyright (c) ${new Date().getFullYear()} ${author}
+ *
+ */
+ `;
+const { series, src, dest, watch, task } = require("gulp");
+const header = require("postcss-header");
+
+const clean = require("gulp-clean");
+const postcss = require("gulp-postcss");
+const sass = require('gulp-sass');
+
+const postcssPresetEnv = require("postcss-preset-env");
+const cleanCSS = require("gulp-clean-css");
+const rename = require("gulp-rename");
+const livereload = require("gulp-livereload");
+
+let output = "./example";
+if (process.env.NODE_ENV === "production") {
+ output = "./dist";
+}
+
+function cleanStyles() {
+ return src(`${output}/*.css`, { read: false }).pipe(clean());
+}
+
+function styles() {
+ const plugins = [
+ require("postcss-import"),
+ require("tailwindcss"),
+ postcssPresetEnv({ stage: 2, autoprefixer: { cascade: false }, features: { "custom-properties": true } }),
+ require("autoprefixer"),
+ require("cssnano"),
+ header({ header: headerString }),
+ ];
+ return src("src/index.scss").pipe(postcss(plugins)).pipe(sass()).pipe(dest(output));
+}
+
+function minify() {
+ return src(`${output}/index.css`).pipe(cleanCSS()).pipe(rename(`index.min.css`)).pipe(dest(output));
+}
+
+function stylesLive() {
+ styles().pipe(livereload({ start: true }));
+}
+
+function livereloadStyles() {
+ livereload.listen();
+ watch("src/**/*.scss", series(stylesLive));
+}
+
+exports.styles = styles;
+exports.default = series(styles);
+exports.watch = livereloadStyles;
+if (process.env.NODE_ENV === "production") {
+ exports.build = series(cleanStyles, styles, minify);
+} else {
+ exports.build = series(styles, livereloadStyles);
+}
+
+// gulp.task("watch:styles", function () {
+// livereload.listen();
+// gulp.watch("**/*.scss", ["styles"]);
+// });
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/package.json b/health/micro-ui/web/micro-ui-internals/packages/css/package.json
new file mode 100644
index 00000000000..5f503a9ebf5
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/package.json
@@ -0,0 +1,65 @@
+{
+ "name": "@egovernments/digit-ui-css",
+ "version": "1.0.56-campaign",
+ "license": "MIT",
+ "main": "dist/index.css",
+ "author": "Jagankumar ",
+ "engines": {
+ "node": ">=14"
+ },
+ "cssConfig": {
+ "prefix": ""
+ },
+ "scripts": {
+ "start": "gulp build",
+ "build:prod": "NODE_ENV=production gulp build",
+ "prepublish": "yarn build:prod",
+ "deploy": "gulp && cp -R svg example && cp -R img example && gh-pages -d example"
+ },
+ "browserslist": [
+ "> 3%",
+ "last 2 versions"
+ ],
+ "style": "./dist/index.css",
+ "dependencies": {
+ "node-sass": "4.14.1",
+ "normalize.css": "8.0.1",
+ "postcss-scss": "3.0.5",
+ "tailwindcss": "1.9.6"
+ },
+ "devDependencies": {
+ "autoprefixer": "10.4.14",
+ "cssnano": "4.1.11",
+ "gh-pages": "3.2.3",
+ "gulp": "4.0.2",
+ "gulp-clean": "0.4.0",
+ "gulp-clean-css": "4.3.0",
+ "gulp-livereload": "4.0.2",
+ "gulp-postcss": "9.0.1",
+ "gulp-rename": "2.0.0",
+ "gulp-sass": "4.1.1",
+ "postcss": "8.4.26",
+ "postcss-cli": "8.3.1",
+ "postcss-header": "2.0.0",
+ "postcss-import": "12.0.1",
+ "postcss-prefixer": "2.1.3",
+ "postcss-preset-env": "6.7.1",
+ "postcss-scss": "3.0.5",
+ "sass": "^1.26.11"
+ },
+ "files": [
+ "dist/index.min.css",
+ "dist/index.css",
+ "svg/**/*.svg",
+ "img/**/*.png",
+ "src/**/*.scss",
+ "src/**/*.css"
+ ],
+ "keywords": [
+ "digit",
+ "egov",
+ "dpg",
+ "digit-ui",
+ "css"
+ ]
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js b/health/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js
new file mode 100644
index 00000000000..18485de221e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js
@@ -0,0 +1,55 @@
+const postcssPresetEnv = require("postcss-preset-env");
+
+module.exports = {
+ parser: require("postcss-scss"),
+ plugins: [
+ require("postcss-import"),
+ require("postcss-nested").default,
+ require("tailwindcss"),
+ require("postcss-preset-env"),
+ require("autoprefixer"),
+ // require("cssnano"),
+ ],
+};
+
+// const fs = require('fs');
+// const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync('package.json'));
+
+// const header = `
+// @charset "UTF-8";
+// /*!
+// * ${name} - ${version}
+// *
+// * Copyright (c) ${new Date().getFullYear()} ${author.name}
+// */
+// `;
+
+// module.exports = (ctx) => {
+// const prefix = ctx.env === 'compat' ? '' : cssConfig.prefix;
+// const devMessage = `🎉🎉🎉🎉 \n${name} ${ctx.env} build was compiled sucessfully! \n`;
+
+
+// return {
+// map: ctx.options.map,
+// parser: ctx.options.parser,
+// plugins: {
+// 'postcss-import': { root: ctx.file.dirname },
+// 'postcss-prefixer': {
+// prefix,
+// ignore: [/\[class\*=.*\]/],
+// },
+// 'postcss-preset-env': {
+// autoprefixer: {
+// cascade: false,
+// },
+// features: {
+// 'custom-properties': true,
+// },
+// },
+// cssnano: ctx.env === 'production' || ctx.env === 'compat' ? {} : false,
+// 'postcss-header': {
+// header,
+// },
+// },
+// };
+// };
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss b/health/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss
new file mode 100644
index 00000000000..f01756f1e7d
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss
@@ -0,0 +1,363 @@
+.microplanning {
+ .upload {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ margin-top: 1.25rem;
+ }
+
+ .upload-section-option {
+ width: 12.5rem;
+ min-height: 32rem;
+ background-color: #ffffff;
+ border-top-left-radius: 0.5rem;
+ border-bottom-left-radius: 0.5rem;
+ padding: 0.625rem;
+ box-shadow: 0px 1px 2px 0px #00000029;
+ }
+
+ .upload-section-options-active {
+ min-height: 3.7rem;
+ display: flex;
+ align-items: center;
+ border-bottom: 1px rgba(214, 213, 212, 1) solid;
+ cursor: pointer;
+ border-right: 0.3rem solid rgba(244, 119, 56, 1);
+ background-color: rgba(244, 119, 56, 0.12);
+
+ p {
+ color: rgba(80, 90, 95, 1);
+ font-weight: 400;
+ font-size: 16px;
+ }
+ }
+
+ .upload-section-options-inactive {
+ min-height: 3.7rem;
+ display: flex;
+ align-items: center;
+ border-bottom: 1px rgba(214, 213, 212, 1) solid;
+ cursor: pointer;
+ border-right: none;
+ background-color: rgba(255, 255, 255, 1);
+
+ p {
+ color: rgba(80, 90, 95, 1);
+ font-weight: 400;
+ font-size: 16px;
+ }
+ }
+
+ .upload-component {
+ width: 80%;
+ height: min-content;
+ border-radius: 0.25rem;
+ padding: 1.5rem;
+ background-color: rgba(255, 255, 255, 1);
+ margin: 0;
+ margin-right: 0.3rem;
+ padding-bottom: 0.625rem;
+ }
+
+ .upload-component-active {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 0;
+
+ .greyedout-name {
+ color: rgba(177, 180, 182, 1);
+ margin: 0 0.625rem;
+ font-size: 1.25rem;
+ padding-top: 0px;
+ font-weight: 500;
+ }
+
+ h2 {
+ margin-top: 0.625rem;
+ font-size: 2.5rem;
+ margin: 0.625rem 0;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 0.625rem 0;
+ padding-top: 0.625;
+ font-size: 1rem;
+ margin-top: 0.625rem;
+ font-weight: 400;
+ }
+ }
+
+ .upload-component-inactive {
+ display: none;
+ }
+
+ .upload-option-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1.25rem 0;
+ flex-wrap: wrap;
+
+ .upload-option-container-selected {
+ border: 2px rgba(244, 119, 56, 1) solid;
+ color: rgba(244, 119, 56, 1);
+ }
+ }
+
+ .upload-option {
+ border-radius: 0.25rem;
+ border: 0.0625rem rgba(214, 213, 212, 1) solid;
+ min-width: 12.5rem;
+ min-height: 8.75rem;
+ box-shadow: 0 0.0625rem rgba(0, 0, 0, 0.16);
+ padding: 0.625rem 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ justify-items: center;
+ margin: 0 1.25rem;
+ cursor: pointer;
+
+ &:hover {
+ border: 2px rgba(244, 119, 56, 1) solid;
+ }
+
+ p {
+ margin-top: 0.625rem;
+ }
+
+ .upload-option-selected {
+ border: 0.125rem rgba(244, 119, 56, 1) solid;
+ color: rgba(244, 119, 56, 1);
+ }
+
+ .select-button {
+ justify-self: end;
+ border: 1px solid rgba(244, 119, 56, 1);
+ background-color: rgba(255, 255, 255, 1);
+ width: 11rem;
+ height: 2.5rem;
+ padding: 0.6rem 0.5rem;
+ color: rgba(244, 119, 56, 1);
+ font-size: 1rem;
+ font-weight: 600;
+ }
+
+ .selected-button {
+ justify-self: end;
+ border: 1px solid rgba(244, 119, 56, 1);
+ background-color: rgba(244, 119, 56, 1);
+ width: 11rem;
+ height: 2.5rem;
+ padding: 0.6rem 0.5rem;
+ color: rgb(255, 255, 255);
+ font-size: 1rem;
+ font-weight: 600;
+ }
+ }
+
+ .modal-header {
+ width: 30rem;
+ font-weight: 700;
+ font-size: 1.5rem;
+ padding-left: 1rem;
+ margin-bottom: 0;
+ display: flex;
+ flex-wrap: wrap;
+ overflow: hidden;
+ }
+
+ .modal-body {
+ overflow: hidden;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ margin-bottom: 1rem;
+ margin-right: 1rem;
+
+ p {
+ font-weight: 400;
+ font-size: 1rem;
+ }
+ }
+
+ .upload-file {
+ min-width: 90%;
+ min-height: 10rem;
+ padding-top: 0.625;
+ border: 1px rgba(214, 213, 212, 1) dotted;
+ margin: 1rem 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(250, 250, 250, 255);
+ }
+
+ .uploaded-file {
+ border: 1px solid rgba(214, 213, 212, 1);
+ min-height: 4.75rem;
+ background-color: rgb(256, 252, 252);
+ display: flex !important;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 0.625rem;
+ padding: 0 0.625rem;
+ flex-wrap: wrap;
+
+ .uploaded-file-details {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ flex-wrap: wrap;
+ padding: 1rem 0;
+
+ p {
+ padding: 0;
+ margin: 0;
+ height: min-content;
+ font-weight: 700;
+ font-size: 1.5rem;
+ color: rgba(80, 90, 95, 1);
+ text-align: start;
+ }
+ }
+
+ .uploaded-file-operations {
+ display: flex !important;
+ flex-direction: row;
+ align-items: center;
+ justify-items: end;
+ flex-wrap: wrap;
+ .button {
+ display: flex !important;
+ flex-direction: row;
+ align-items: center !important;
+ justify-content: center;
+ margin-left: 1rem;
+ min-width: 9rem;
+ height: 2.5rem;
+ border: 1px rgba(244, 119, 56, 1) solid;
+ background-color: white;
+ cursor: pointer;
+ }
+
+ p {
+ padding: 0;
+ margin: 0;
+ color: rgba(244, 119, 56, 1);
+ font-weight: 600;
+ font-size: 1rem;
+ }
+
+ .deletebutton {
+ background-color: rgb(255, 255, 255, 0);
+ border: none;
+ }
+ }
+ }
+
+ .loader-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ background-color: rgba(0, 0, 0, 0.7);
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 99999;
+
+ .loader {
+ border: 0.5rem solid rgb(255, 255, 255);
+ border-top: 0.5rem solid rgba(80, 76, 76, 0);
+ border-radius: 50%;
+ width: 3.125rem;
+ height: 3.125rem;
+ animation: spin 2s linear infinite;
+ }
+
+ .loader-inner {
+ border: 1px solid rgb(255, 255, 255);
+ border-radius: 50%;
+ width: 100%;
+ height: 100%;
+ }
+
+ .loader-text {
+ color: whitesmoke;
+ padding-top: 1.25rem;
+ }
+ }
+
+ @keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+ }
+
+ .toast-container {
+ position: fixed;
+ width: 50%;
+ bottom: 1.25rem;
+ left: 50%;
+ transform: translateX(-50%);
+ color: #fff;
+ padding: 1rem;
+ z-index: 9999;
+ }
+
+ .success {
+ background-color: rgba(0, 112, 60, 1);
+ }
+
+ .toast-content {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ .message {
+ margin-right: 0.6px;
+ }
+
+ .close-button {
+ background: transparent;
+ border: none;
+ color: inherit;
+ cursor: pointer;
+ }
+
+ .altrady-have-template-button {
+ display: flex !important;
+ justify-content: center;
+ font-weight: 600;
+ font-size: 1rem;
+ }
+
+ .download-template-button {
+ display: flex !important;
+ justify-content: center;
+
+ .icon {
+ display: flex;
+ align-items: center;
+ margin: 0;
+ padding: 0;
+ }
+
+ p {
+ font-weight: 500;
+ font-size: 1rem;
+ }
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/src/index.scss b/health/micro-ui/web/micro-ui-internals/packages/css/src/index.scss
new file mode 100644
index 00000000000..ff5ace2af3e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/src/index.scss
@@ -0,0 +1,13 @@
+/*@import 'normalize.css';*/
+
+/*@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap");*/
+
+@import "tailwindcss/base";
+
+@import "tailwindcss/components";
+
+@import "tailwindcss/utilities";
+
+@import "./components/microplanning.scss";
+@import "./pages/employee/index.scss";
+@import "./pages/employee/campaign.scss";
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss
new file mode 100644
index 00000000000..5c6b56289d3
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss
@@ -0,0 +1,109 @@
+@import url("../../index.scss");
+@import "../../typography.scss";
+
+.summary-header {
+ @extend .typography.text-heading-l;
+ font-size: 2.25rem;
+}
+.date-field-container {
+ display: grid;
+ grid-template-columns: 20rem 20rem;
+ grid-gap: 1.5rem;
+ width: 70%;
+ padding-top: 0.3rem;
+ margin-top: 0rem;
+}
+.date-field {
+ display: grid;
+ grid-template-columns: 1fr 2fr;
+ align-items: start;
+}
+.campaign-type {
+ margin-right: 5rem;
+ padding-bottom: 1.2rem;
+ font-weight: bold;
+}
+.name-container {
+ margin-right: 4rem;
+ font-weight: bold;
+ text-wrap: nowrap;
+}
+.beneficiary-type {
+ margin-right: 5.4rem;
+ font-weight: bold;
+}
+.campaign-dates {
+ display: flex;
+ font-weight: bold;
+}
+.mandatory-date {
+ margin-top: 0.8rem;
+ margin-left: 0.5rem;
+ color: red !important;
+ font-size: 1rem;
+ font-weight: 700;
+}
+.description-type {
+ margin-top: 2rem;
+ margin-bottom: 2rem;
+}
+.name-description {
+ margin-top: 2rem;
+ margin-bottom: 2rem;
+}
+.dates-description {
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+ padding-bottom: 1.2rem;
+}
+.selecting-boundary-div {
+ padding-top: 0.5rem;
+ .label-field-pair {
+ margin-bottom: 1.5rem;
+ }
+}
+.campaign-table {
+ border-collapse: collapse;
+ border-color: transparent;
+ border-width: 0rem 1.5rem;
+ tbody {
+ tr:hover {
+ background: rgba(#f47738, 0.12);
+ }
+ }
+}
+.info-points {
+ display: flex;
+ gap: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+.infoClass{
+ margin-bottom: 1.5rem
+}
+.headerWrapperClassName{
+ display: none
+}
+.popup-close-svg{
+ display: none;
+}
+.whoLogo{
+ margin-top: -1rem;
+ margin-bottom: -1rem;
+}
+
+.digit-popup-wrapper{
+ &.popUpClass{
+ width:45rem;
+
+ .popUpFooter{
+ .digit-popup-footer-buttons{
+ margin-left: 0px;
+ width: 100%;
+
+ button{
+ flex:1;
+ }
+ }
+ }
+ }
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss
new file mode 100644
index 00000000000..74296abb568
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss
@@ -0,0 +1,331 @@
+@import "../../typography.scss";
+
+.campaign-cycle-container {
+ .campaign-tabs-container {
+ }
+ .sub-tab-container {
+ margin-top: 5px;
+ padding: 1.5rem;
+ .card-text {
+ margin-bottom: 0;
+ }
+ }
+ .add-resource-container {
+ background-color: #fafafa;
+ border: 1px solid #d6d5d4;
+ border-radius: 0.4rem;
+ padding: 1rem;
+ margin-right: 1.5rem;
+ margin-bottom: 1.5rem;
+ .card-text {
+ margin: 0;
+ font-weight: 700;
+ }
+ .header-container {
+ display: flex;
+ align-items: flex-end;
+ justify-content: space-between;
+ }
+ }
+ .delete-resource-icon {
+ cursor: pointer;
+ font-weight: 600;
+ font-size: 1rem;
+ color: theme(digitv2.lightTheme.primary);
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+ }
+ .add-resource-label-field-container {
+ display: grid;
+ grid-template-columns: 2fr 1fr;
+ grid-gap: 2rem;
+ .options-card {
+ max-height: 10rem !important;
+ }
+ }
+ .popup-wrap {
+ .popup-module-main {
+ max-height: 707px;
+ overflow-y: auto;
+ width: 99%;
+ &::-webkit-scrollbar {
+ width: 0.5rem;
+ background: transparent;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: #d6d5d4; /* Color of the scrollbar thumb */
+ border-radius: 5px; /* Adjust the border-radius for rounded corners */
+ height: 0.5rem;
+ }
+ }
+ .popup-module-action-bar {
+ .selector-button-primary {
+ padding: 0.6rem 2.5rem;
+ height: unset;
+ margin: 1.5rem;
+ background-color: theme(digitv2.lightTheme.primary);
+ }
+ }
+ }
+}
+.selector-button-primary {
+ background-color: theme(digitv2.lightTheme.primary);
+}
+.campaign-breadcrumb {
+ margin: 0;
+ margin-bottom: 1.5rem;
+ color: theme(digitv2.lightTheme.primary) !important;
+}
+.sc-jlZhew.dVtbRz {
+ overflow: hidden;
+}
+.campaign-popup-module {
+ margin: auto;
+ width: calc(100% - 5rem);
+}
+.campaign-bulk-upload {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 1.5rem;
+ .campaign-download-template-btn {
+ font-weight: 700;
+ }
+}
+.bulk-info-text {
+ margin-bottom: 1.5rem;
+}
+.delete-and-download-button {
+ display: flex;
+ gap: 1.5rem;
+}
+.bulk-upload-file {
+ .uploaded-file-container {
+ margin: 0;
+ margin-bottom: 1.5rem;
+ }
+}
+.uploaded-file-container {
+ margin-left: 0rem;
+}
+.upload-drag-drop-container {
+ background-color: #fafafa;
+ border: 1.5px dashed #d6d5d4;
+ border-radius: 5px;
+ padding: 1rem 1rem 1rem 1rem;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+
+ .drag-drop-text {
+ text-decoration: none;
+
+ .browse-text {
+ text-decoration: none;
+ color: theme(digitv2.lightTheme.primary);
+ transition: color 0.3s;
+ }
+
+ .browse-text:hover {
+ color: theme(digitv2.lightTheme.primary);
+ text-decoration: underline;
+ cursor: pointer;
+ }
+ }
+}
+
+.upload-drag-drop-container {
+ margin-left: 0rem;
+ .drag-drop {
+ color: #b1b4b6;
+ }
+ .browse-text {
+ text-decoration: underline;
+ color: theme(digitv2.lightTheme.primary);
+ transition: color 0.3s;
+ }
+}
+
+.campaign-counter-container {
+ padding: 1.5rem;
+ padding-bottom: 0.5rem;
+ .card-text {
+ margin-top: 0;
+ }
+ .label-field-pair {
+ margin-bottom: 1rem;
+ .card-label {
+ font-weight: 700;
+ }
+ }
+ .date-field-container {
+ display: grid;
+ grid-template-columns: 18.75rem 18.75rem;
+ grid-gap: 1.5rem;
+ width: 100%;
+ }
+ .PlusMinus {
+ width: 30%;
+ input {
+ width: 100%;
+ }
+ }
+}
+
+.campaign-tab-head {
+ padding: 1rem;
+ width: 12.5rem;
+ height: 3rem;
+ border-radius: 10px 10px 0px 0px;
+ background-color: #ffffff;
+ outline: none;
+ box-sizing: border-box;
+ font-weight: 700;
+ font-size: 1rem;
+ font-family: "Roboto";
+ color: #505a5f;
+ margin-bottom: -6px;
+ border: 1px solid #d6d5d4;
+ background-color: #fafafa;
+ &.active {
+ height: 3.375rem;
+ background-color: #ffffff;
+ outline: none;
+ font-weight: bold;
+ color: theme(digitv2.lightTheme.primary);
+ border: 1px solid theme(digitv2.lightTheme.primary);
+ border-bottom: 4px solid theme(digitv2.lightTheme.primary);
+ box-sizing: border-box;
+ font-size: 1.5rem;
+ }
+ :focus {
+ outline: none;
+ }
+}
+.campaign-sub-tab-head {
+ outline: none;
+ background-color: #ffffff;
+ color: theme(digitv2.lightTheme.primary);
+ border: 1px solid theme(digitv2.lightTheme.primary);
+ height: 2rem;
+ width: 9.188rem;
+ font-size: 1rem;
+ font-weight: 400;
+ &.active {
+ background-color: theme(digitv2.lightTheme.primary);
+ color: #ffffff;
+ font-weight: bold;
+ outline: none;
+ height: 2rem;
+ width: 9.188rem;
+ font-family: "Roboto";
+ font-weight: 700;
+ font-size: 1rem;
+ }
+}
+.tab-content-header {
+ margin-top: 1.5rem;
+ margin-bottom: 1.5rem !important;
+}
+
+.delivery-rule-container {
+ padding-top: 0;
+ .card-header {
+ .title {
+ margin: 0 !important;
+ }
+ font-size: 1.5rem !important;
+ margin: 0;
+ display: flex;
+ align-content: center;
+ justify-content: space-between;
+ }
+ .attribute-container {
+ border: 1px solid #d6d5d4;
+ background-color: #fafafa;
+ padding: 1rem;
+ padding-top: 0;
+ .add-attribute {
+ width: 74.5%;
+ justify-content: center;
+ h2 {
+ font-size: 1rem;
+ font-family: Roboto;
+ width: unset !important;
+ font-weight: 600;
+ }
+ }
+ }
+}
+.attribute-field-wrapper {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+ align-items: center;
+ gap: 2.5rem;
+ .label-field-pair {
+ flex-direction: column;
+ align-items: flex-start !important;
+ .card-label.card-label-smaller {
+ font-weight: 700;
+ }
+ .employee-select-wrap.form-field {
+ width: 100%;
+ }
+ .digit-employee-card-input {
+ margin-bottom: 0;
+ }
+ }
+ .options-card {
+ max-height: 10rem !important;
+ }
+ .card-label {
+ margin-bottom: 0.5rem;
+ }
+}
+.add-rule-btn {
+ margin: auto;
+ h2 {
+ font-family: Roboto;
+ font-size: 1rem;
+ font-weight: 600;
+ }
+}
+.add-product-btn {
+ h2 {
+ font-family: Roboto;
+ font-size: 1rem;
+ font-weight: 600;
+ }
+}
+.popup-wrap.campaign-product-wrapper {
+ .popup-module {
+ width: 70%;
+ padding-left: 1.5rem;
+ padding-bottom: 1.5rem;
+ .header-wrap {
+ font-size: 1.5rem;
+ font-weight: 700;
+ .header-content.popup-header-fix {
+ margin-top: 1.5rem;
+ }
+ }
+ }
+ .popup-module-action-bar {
+ margin-top: 1.5rem;
+ margin-right: 1.5rem;
+ }
+}
+.search-button-wrapper {
+ grid-column-end: -1 !important;
+ flex-direction: row !important;
+}
+.add-resource-modal {
+}
+.add-resource-wrapper {
+ .link {
+ color: theme(digitv2.lightTheme.primary);
+ }
+}
+.digit-toast-success {
+ margin-bottom: -0.5rem;
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss
new file mode 100644
index 00000000000..295d90c1264
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss
@@ -0,0 +1,173 @@
+@import "../../typography.scss";
+
+/* language selection issue*/
+.customBtn-selected {
+ background-color: theme(digitv2.lightTheme.primary);
+}
+
+/* login screen issue*/
+
+.primary-label-btn {
+ color: theme(digitv2.lightTheme.primary);
+}
+
+/* landing screen issue*/
+
+.employeeCard {
+ .complaint-links-container .header .logo {
+ background-color: theme(digitv2.lightTheme.primary);
+ }
+
+ .complaint-links-container .body {
+ &.link {
+ color: theme(digitv2.lightTheme.primary);
+ }
+ .inbox-total {
+ background-color: theme(digitv2.lightTheme.primary);
+ }
+ }
+}
+
+.employee .topbar .right .user-img-txt {
+ background-color: theme(digitv2.lightTheme.primary);
+}
+/* button component issue*/
+
+.action-bar-wrap {
+ .submit-bar {
+ background-color: theme(digitv2.lightTheme.primary);
+ }
+}
+
+.jk-digit-secondary-btn {
+ color: theme(digitv2.lightTheme.primary);
+ border-color: theme(digitv2.lightTheme.primary);
+
+ svg {
+ fill: theme(digitv2.lightTheme.primary);
+
+ path {
+ fill: theme(digitv2.lightTheme.primary);
+ }
+ }
+}
+.error-boundary .error-container button {
+ background-color: theme(digitv2.lightTheme.primary);
+}
+
+/* inbox screen issue*/
+
+.inbox-search-wrapper {
+ .search-tabs-container .search-tab-head-selected {
+ color: theme(digitv2.lightTheme.primary);
+ border-color: theme(digitv2.lightTheme.primary);
+ }
+ .submit-bar {
+ background-color: theme(digitv2.lightTheme.primary);
+ }
+ .search-component-table .link {
+ color: theme(digitv2.lightTheme.primary);
+ }
+ .link-label {
+ color: theme(digitv2.lightTheme.primary) !important;
+ }
+}
+.drag-drop-container .drag-drop-text .browse-text {
+ color: theme(digitv2.lightTheme.primary);
+}
+/* toast new componnet css added */
+
+.toast-success {
+ gap: 0.5rem;
+ height: 3rem;
+ padding: 0.75rem 0.5rem 0.75rem 0.75rem !important;
+ background-color: theme(digitv2.alert.success);
+ transition: bottom 0.5s ease;
+ grid-gap: 0.5rem;
+ &.error {
+ background-color: theme(digitv2.alert.error) !important;
+ }
+
+ &.warning {
+ background-color: #f19100;
+
+ &.warning-buttons {
+ @apply block;
+ }
+ }
+
+ h2 {
+ @apply text-left overflow-hidden whitespace-no-wrap flex-grow flex items-center h-6;
+ letter-spacing: 0rem;
+ color: theme(digitv2.lightTheme.paper);
+ margin: 0rem;
+ text-overflow: ellipsis;
+ font-family: Roboto;
+ font-weight: 500;
+ font-size: 1.25rem;
+ font-style: normal;
+ }
+ svg {
+ @apply flex-shrink-0;
+ }
+}
+
+@keyframes slideInFromBottom {
+ from {
+ bottom: -3rem;
+ }
+ to {
+ bottom: 4rem;
+ }
+}
+
+.toast-success.animate {
+ animation: slideInFromBottom 0.5s ease forwards;
+}
+
+@media screen and (max-width: 768px) {
+ .topbar {
+ background: #0b4b66 !important;
+ color: #fff;
+ }
+}
+header {
+ @extend .typography.text-heading-xl;
+}
+.digit-button-primary{
+ background-color: theme(digitv2.lightTheme.primary) !important;
+}
+.digit-button-secondary{
+ .icon-label-container{
+ h2{
+ color: theme(digitv2.lightTheme.primary) !important;
+ }
+ }
+}
+
+/*.digit-popup-wrap {
+ background: rgba(0, 0, 0, 0.7);
+ @apply flex fixed w-full h-full overflow-auto top-0 left-0 min-h-screen;
+ z-index: 10000;
+ max-width: 100% !important;
+ max-height: 100% !important;
+}
+
+@screen dt {
+ .digit-popup-wrap {
+ background: rgba(0, 0, 0, 0.7);
+ @apply min-h-screen;
+ }
+}
+
+.digit-popup-close-icon {
+ @apply flex justify-end;
+}*/
+
+.employee{
+ .digit-employeeSidebar{
+ .sidebar{
+ z-index:999
+ }
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss
new file mode 100644
index 00000000000..2b989e87305
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss
@@ -0,0 +1,481 @@
+@import "./campaignCycle.scss";
+@import "./coreOverride.scss";
+@import "../../typography.scss";
+
+.wbh-header-container {
+ margin-top: 1.5rem;
+}
+.main.digit-home-main {
+ margin-left: 92px;
+ .employee-app-wrapper.digit-home-app-wrapper {
+ margin-left: 0;
+ margin-right: 2rem;
+ .ground-container.digit-home-ground {
+ padding: 0;
+ .employee-app-container.digit-home-employee-app {
+ .ground-container.moduleCardWrapper.gridModuleWrapper.digit-home-moduleCardWrapper {
+ gap: 2.5rem;
+ margin-top: 2rem;
+ padding: 0;
+ display: grid !important;
+ grid-template-columns: repeat(auto-fill, minmax(263px, 1fr));
+ .employeeCard.customEmployeeCard.card-home.home-action-cards {
+ margin: 0 !important;
+ min-width: 263px !important;
+ width: auto !important;
+ }
+ }
+ }
+ }
+ }
+}
+.campaign-cycle-container {
+ .popup-header-fix {
+ margin-top: 1.5rem !important;
+ }
+}
+
+.tag.inbox-tag {
+ max-width: fit-content;
+ background-color: #d6d5d4;
+ border-radius: 2rem;
+ padding: 0.5rem;
+ display: flex;
+ align-items: center;
+ height: 2rem;
+ margin-bottom: 0.7rem;
+ grid-gap: 0.2rem;
+ gap: 0.2rem;
+}
+.mandatory-span {
+ margin-left: 0.5rem;
+ color: red !important;
+ font-size: 1rem;
+ font-weight: 700;
+}
+
+.digit-employee-card-input.numeric {
+ margin-bottom: unset;
+}
+
+.actionBarClass {
+ display: flex;
+ justify-content: space-between;
+ flex-direction: row-reverse;
+ z-index: 0;
+}
+.previous-button {
+ margin-left: 4rem;
+ min-width: 12.5rem;
+}
+.info-text {
+ padding-bottom: 1.5rem;
+}
+
+.view-composer-header-section {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+}
+.card-with-background {
+ margin-top: 1rem;
+ .card-head {
+ margin-bottom: 1rem;
+ color: #505a5f;
+ }
+}
+.no-data-found {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ .error-msg {
+ margin-top: 1rem;
+ }
+}
+.search-tab-head {
+ color: #505a5f;
+}
+.search-tabs-container {
+ border-bottom: none;
+ margin-bottom: 0;
+}
+.delivery-preview-card {
+ margin-bottom: 1.5rem !important;
+ background-color: #fafafa;
+ border: 1px solid #d6d5d4;
+ width: 70%;
+ .custom-table-label {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: #505a5f;
+ margin-bottom: 1rem;
+ }
+ .campaign-attribute-table {
+ margin-bottom: 1rem;
+ border: 1px solid #d6d5d4;
+ overflow: hidden;
+ border-radius: 4px;
+ table {
+ border-width: 0px !important;
+ background-color: #fafafa;
+ border: 1px solid #d6d5d4;
+ border-collapse: collapse;
+ border-radius: 1rem;
+ tbody {
+ tr:nth-child(odd) {
+ background-color: white;
+ }
+ }
+ th {
+ border-right: 1px solid #d6d5d4;
+ }
+ th:last-child {
+ border-right: none;
+ }
+ td {
+ padding: 1rem;
+ border-right: 1px solid #d6d5d4;
+ }
+ td:last-child {
+ padding: 1rem;
+ border-right: none;
+ }
+ }
+ }
+ .campaign-product-table {
+ margin-bottom: 1rem;
+ border: 1px solid #d6d5d4;
+ overflow: hidden;
+ border-radius: 4px;
+ table {
+ background-color: #fafafa;
+ border: 1px solid #d6d5d4;
+ border-collapse: collapse;
+ border-radius: 1rem;
+ border-width: 0px !important;
+ tbody {
+ background-color: #fff;
+ tr:nth-child(odd) {
+ background-color: white;
+ }
+ }
+ th {
+ border-right: 1px solid #d6d5d4;
+ }
+ th:last-child {
+ border-right: none;
+ }
+ td {
+ padding: 1rem;
+ border-right: 1px solid #d6d5d4;
+ }
+ td:last-child {
+ border-right: none;
+ }
+ }
+ }
+}
+.cycle-paragraph {
+ font-weight: 700;
+ font-size: 24px;
+ color: #505a5f;
+ margin-top: 0.5rem;
+}
+.header-end {
+ margin-right: 1rem;
+}
+.digit-stepper-container {
+ margin-bottom: 1.5rem;
+}
+.employee-app-wrapper {
+ margin: 0rem 1rem;
+}
+input[type="date"]::-webkit-calendar-picker-indicator {
+ position: absolute;
+ right: 5px;
+ top: 20%;
+ transform: translateY(-10%);
+}
+.campaign-preview-edit-container {
+ display: flex;
+ gap: 1rem;
+ span {
+ color: theme(digitv2.lightTheme.primary);
+ }
+}
+.campaign-attribute-table {
+ border: 1px solid #d6d5d4;
+ overflow: hidden;
+ border-radius: 4px;
+ tbody {
+ tr:nth-child(odd) {
+ background-color: white;
+ }
+ }
+}
+tbody {
+ tr:nth-child(odd) {
+ background-color: white;
+ }
+}
+.popup-wrap.campaign-data-preview {
+ flex-direction: column;
+}
+
+.digit-employee-card-input.numeric {
+ pointer-events: none;
+}
+.product-tag-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1.5rem;
+ margin-bottom: 1rem;
+}
+
+.workbench-download-template-btn {
+ font-weight: 700;
+}
+.digit-employee-card-input.numeric {
+ text-align: center;
+}
+.in-between {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ @media screen and (min-width: 1024px) {
+ grid-gap: 10rem;
+ }
+}
+.setup-campaign {
+ .setup-campaign-card {
+ padding-bottom: 1.5rem;
+ }
+ .digit-dropdown-options-card {
+ max-height: 10rem !important;
+ }
+ .digit-field {
+ margin-bottom: 0 !important;
+ }
+}
+.campaign-summary-container {
+ .setup-campaign-card {
+ .employeeCard.employeeCard-override {
+ padding: 1.5rem;
+ margin-bottom: 1.5rem !important;
+ }
+ }
+ .row {
+ justify-content: flex-start;
+ gap: 5rem;
+ h2 {
+ margin: 0;
+ width: 272px;
+ }
+ .value {
+ width: unset;
+ p {
+ margin: 0;
+ }
+ }
+ }
+ .digit-infobanner-wrap.error {
+ margin-left: 0;
+ margin-bottom: 1.5rem;
+ min-width: 100%;
+ .digit-button-primary {
+ height: 1.5rem;
+ background-color: #d4351c !important;
+ .icon-label-container.primary.large {
+ font-size: 14px;
+ .digit-button-label {
+ font-size: 14px;
+ color: #ffffff;
+ }
+ }
+ }
+ }
+}
+.view-composer-header-section {
+ .employee-card-sub-header {
+ @extend .typography.text-heading-m;
+ margin-bottom: 1.5rem;
+ }
+ .employee-card-sub-header.error {
+ color: #d4351c;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ }
+}
+.add-new-product-container {
+ border: 1px solid #d6d5d4;
+ background-color: #fafafa;
+ width: 70%;
+ padding-top: 0;
+ .heading-bar {
+ font-weight: 700;
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ .card-text {
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+ }
+ }
+ .label-field-pair {
+ gap: 5rem;
+ align-items: baseline;
+ .product-label-field {
+ width: 12rem;
+ text-wrap: nowrap;
+ font-weight: 700;
+ }
+ }
+}
+.page-padding-fix {
+ margin-top: 1.5rem;
+}
+.addProductActionClass {
+ display: flex;
+ flex-direction: row-reverse;
+ justify-content: space-between;
+ .submit-bar {
+ width: max-content;
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+ }
+}
+.loginFormStyleEmployee {
+ .loginCardClassName {
+ .digit-header-content {
+ &:not(label) {
+ display: flex;
+ justify-content: center;
+ }
+ }
+ }
+}
+.selecting-boundaries-dropdown {
+ .digit-multiselectdropdown-server {
+ max-height: 15rem;
+ }
+}
+.hover {
+ cursor: pointer;
+}
+.digit-dropdown-employee-select-wrap {
+ .digit-dropdown-employee-select-wrap--elipses {
+ font-size: 1rem !important;
+ }
+}
+.digit-dropdown-employee-select-wrap.language-dropdown {
+ .digit-dropdown-options-card {
+ min-width: fit-content;
+ }
+}
+.digit-popup-wrapper.boundaries-pop-module.default {
+ width: 36rem;
+ .digit-popup-footer {
+ .digit-popup-footer-buttons {
+ width: 100% !important;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ .digit-button-secondary {
+ width: 100%;
+ }
+ .digit-button-primary {
+ width: 100%;
+ }
+ }
+ }
+}
+.campaign-type-alert-button {
+ .digit-button-label {
+ width: 100% !important;
+ }
+}
+.campaign-pop-module {
+ padding: 1.5rem;
+ border-radius: 4px;
+ width: 36rem;
+}
+.campaign-modal-heading {
+ font-size: 2rem;
+ font-weight: 700;
+ margin: 0 !important;
+}
+.campaign-pop-main {
+ font-size: 1.25rem;
+ padding: 0 !important;
+ font-size: 400;
+ .card-text {
+ margin-bottom: 1.5rem !important;
+ }
+ .popup-module-action-bar.campaign-pop-action {
+ .selector-button-border {
+ background-color: #ffffff;
+ border: 1px solid #c84c0e;
+ h2 {
+ color: #c84c0e !important;
+ }
+ }
+ }
+}
+
+.digit-toast-success {
+ max-width: 90%;
+ margin-left: auto;
+ margin-right: auto;
+ height: auto;
+ .toast-label {
+ line-height: 1.5;
+ word-break: break-word;
+ height: auto;
+ white-space: unset;
+ }
+}
+
+.digit-dropdown-select.error {
+ border: 1px solid #d4351c;
+}
+.campaign-type-wrapper {
+ .digit-error-icon-message-wrap {
+ margin-top: 4px;
+ font-size: 14px;
+ }
+}
+.individualElement {
+ h2 {
+ color: theme(digitv2.lightTheme.text-primary);
+ }
+}
+.link {
+ color: #c84c0e !important;
+}
+.employeeCard.employeeCard-override.card-error {
+ border: 1px solid #d4351c;
+}
+.label-field-pair.delivery-type-radio {
+ gap: 5rem;
+ .digit-radio-options-wrap {
+ gap: 2rem;
+ margin-bottom: 0 !important;
+ .radio-option-container {
+ margin-bottom: 0;
+ align-items: center;
+ }
+ }
+}
+.bold {
+ font-weight: 700;
+}
+.summary-doc-error {
+ p {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+ .digit-infobanner-wrap.error {
+ margin-bottom: 0.5rem;
+ margin-top: 1.5rem;
+ }
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss b/health/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss
new file mode 100644
index 00000000000..4a50014cf88
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss
@@ -0,0 +1,512 @@
+.typography {
+ &.text-heading-xl {
+ font-family: theme(digitv2.fontFamily.rc);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.heading-xl.desktop);
+ }
+
+ @media (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.heading-xl.tablet);
+ }
+
+ @media (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.heading-xl.mobile);
+ }
+ }
+
+ &.text-heading-l {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.heading-l.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.heading-l.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.heading-l.mobile);
+ }
+ }
+
+ &.text-heading-m {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.heading-m.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.heading-m.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.heading-m.desktop);
+ }
+ }
+
+ &.text-heading-s {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.heading-s.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.heading-s.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.heading-s.mobile);
+ }
+ }
+
+ &.text-heading-xs {
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.heading-xs.mobile);
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+ }
+ }
+
+ &.text-caption-l {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.medium);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.caption-l.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.caption-l.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.caption-l.mobile);
+ }
+ }
+
+ &.text-caption-m {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.medium);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.caption-m.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.caption-m.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.caption-m.mobile);
+ }
+ }
+
+ &.text-caption-s {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.medium);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.caption-s.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.caption-s.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.caption-s.desktop);
+ }
+ }
+
+ &.text-body-l {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.regular);
+ color: theme(digitv2.lightTheme.text-primary);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.body-l.desktop);
+ line-height: theme(digitv2.lineHeight.line-height-body-l.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.body-l.tablet);
+ line-height: theme(digitv2.lineHeight.line-height-body-l.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.body-l.mobile);
+ line-height: theme(digitv2.lineHeight.line-height-body-l.mobile);
+ }
+ }
+
+ &.text-body-s {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.regular);
+ color: theme(digitv2.lightTheme.text-primary);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.body-s.desktop);
+ line-height: theme(digitv2.lineHeight.line-height-body-s.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.body-s.tablet);
+ line-height: theme(digitv2.lineHeight.line-height-body-s.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.body-s.mobile);
+ line-height: theme(digitv2.lineHeight.line-height-body-s.mobile);
+ }
+ }
+
+ &.text-body-xs {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.regular);
+ color: theme(digitv2.lightTheme.text-primary);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.body-xs.desktop);
+ line-height: theme(digitv2.lineHeight.line-height-body-xs.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.body-xs.tablet);
+ line-height: theme(digitv2.lineHeight.line-height-body-xs.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.body-xs.mobile);
+ line-height: theme(digitv2.lineHeight.line-height-body-xs.mobile);
+ }
+ }
+
+ &.text-label {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.regular);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.label.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.label.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.label.mobile);
+ }
+ }
+
+ &.text-link {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.regular);
+ color: theme(digitv2.lightTheme.text-primary);
+ line-height: theme(digitv2.lineHeight.normal);
+ text-decoration: theme(digitv2.textDecorationLine.underline);
+
+ @media screen and (min-width: theme(digitv2.screens.desktop)) {
+ font-size: theme(digitv2.fontSize.link.desktop);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.tablet)) {
+ font-size: theme(digitv2.fontSize.link.tablet);
+ }
+
+ @media screen and (min-width: theme(digitv2.screens.mobile)) {
+ font-size: theme(digitv2.fontSize.link.mobile);
+ }
+ }
+
+ &.heading-xl {
+ font-family: theme(digitv2.fontFamily.rc);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.heading-xl.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.heading-xl.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.heading-xl.desktop);
+ }
+ }
+
+ &.heading-l {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.heading-l.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.heading-l.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.heading-l.desktop);
+ }
+ }
+
+ &.heading-m {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.heading-m.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.heading-m.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.heading-m.desktop);
+ }
+ }
+
+ &.heading-s {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.heading-s.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.heading-s.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.heading-s.desktop);
+ }
+ }
+
+ &.heading-xs {
+ font-size: theme(digitv2.fontSize.heading-xs.mobile);
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.bold);
+ }
+
+ &.caption-l {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.medium);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.caption-l.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.caption-l.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.caption-l.desktop);
+ }
+ }
+
+ &.caption-m {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.medium);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.caption-m.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.caption-m.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.caption-m.desktop);
+ }
+ }
+
+ &.caption-s {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.italic);
+ font-weight: theme(digitv2.fontWeight.medium);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.caption-s.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.caption-s.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.caption-s.desktop);
+ }
+ }
+
+ &.body-l {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.regular);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.body-l.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.body-l.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.body-l.desktop);
+ }
+ }
+
+ &.body-s {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.regular);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.body-s.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.body-s.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.body-s.desktop);
+ }
+ }
+
+ &.body-xs {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.regular);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.body-xs.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.body-xs.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.body-xs.desktop);
+ }
+ }
+
+ &.label {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.regular);
+
+ @media (max-width: 30rem) {
+ /* Media query for mobile */
+ font-size: theme(digitv2.fontSize.label.mobile);
+ }
+
+ @media (min-width: 30.063rem) and (max-width: 47.938rem) {
+ /* Media query for tablets */
+ font-size: theme(digitv2.fontSize.label.tablet);
+ }
+
+ @media (min-width: 48rem) {
+ /* Media query for desktop */
+ font-size: theme(digitv2.fontSize.label.desktop);
+ }
+ }
+
+ &.link {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.regular);
+ text-decoration: theme(digitv2.textDecorationLine.underline);
+ font-size: theme(digitv2.fontSize.link.desktop);
+ }
+
+ &.button {
+ font-family: theme(digitv2.fontFamily.sans);
+ font-style: theme(digitv2.fontStyle.normal);
+ font-weight: theme(digitv2.fontWeight.medium);
+ font-size: theme(digitv2.fontSize.button.desktop);
+ }
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/health/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js
new file mode 100644
index 00000000000..c9b2a06dedf
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js
@@ -0,0 +1,233 @@
+module.exports = {
+ future: {
+ removeDeprecatedGapUtilities: true,
+ purgeLayersByDefault: true,
+ },
+ purge: { enabled: true, content: ["./example/index.html"] },
+ theme: {
+ screens: {
+ dt: "780px",
+ sm: { max: "425px" },
+ },
+ colors: {
+ primary: {
+ light: "#F18F5E",
+ main: "#F47738",
+ dark: "#C8602B",
+ },
+ secondary: "#22394D",
+ text: {
+ primary: "#0B0C0C",
+ secondary: "#505A5F",
+ },
+ link: {
+ normal: "#1D70B8",
+ hover: "#003078",
+ },
+ border: "#D6D5D4",
+ inputBorder: "#464646",
+ "input-border": "#464646",
+ focus: "#F47738",
+ error: "#D4351C",
+ success: "#00703C",
+ black: "#000000",
+ grey: {
+ dark: "#9E9E9E",
+ mid: "#EEEEEE",
+ light: "#FAFAFA",
+ bg: "#E3E3E3",
+ },
+ white: "#FFFFFF",
+ },
+ fontFamily: {
+ sans: ["Roboto", "sans-serif"],
+ rc: ['"Roboto Condensed"', "sans-serif"],
+ },
+ fontSize: {
+ "heading-xl-dt": ["48px", "56px"],
+ "heading-xl": ["32px", "40px"],
+ "heading-l-dt": ["36px", "40px"],
+ "heading-l": ["24px", "32px"],
+ "heading-m-dt": ["24px", "32px"],
+ "heading-m": ["18px", "28px"],
+ "heading-s": ["16px", "24px"],
+ "caption-xl-dt": ["27px", "32px"],
+ "caption-xl": ["18px", "26px"],
+ "caption-l-dt": ["24px", "28px"],
+ "caption-l": ["18px", "21px"],
+ "caption-m-dt": ["19px", "23px"],
+ "caption-m": ["16px", "19px"],
+ "form-field": ["16px", "20px"],
+ "body-l-dt": ["19px", "28px"],
+ "body-l": ["16px", "24px"],
+ "body-s-dt": ["16px", "24px"],
+ "body-s": ["14px", "16px"],
+ legend: ["19px", "23px"],
+ link: ["16px", "24px"],
+ "text-btn": ["16px", "24px"],
+ },
+ fontWeight: {
+ regular: 400,
+ medium: 500,
+ bold: 700,
+ },
+ padding: {
+ sm: "8px",
+ md: "16px",
+ lg: "24px",
+ xl: "36px",
+ },
+ margin: {
+ xs: "4px",
+ sm: "8px",
+ md: "16px",
+ lg: "24px",
+ xl: "64px",
+ },
+ borderWidth: {
+ default: "1px",
+ 0: "0",
+ 2: "1px",
+ 4: "4px",
+ 10: "10px",
+ },
+ boxShadow: {
+ card: "0 1px 2px 0 rgba(0, 0, 0, 0.16)",
+ radiobtn: "0 0 0 5px #F47738",
+ },
+ inset: {
+ 0: 0,
+ 6: "6px",
+ 10: "10px",
+ },
+ extend: {},
+ digitv2: {
+ lightTheme: {
+ primary: "#C84C0E",
+ "text-color-primary": "#0B0C0C",
+ "text-color-secondary": "#505A5F",
+ "text-color-disabled": "#B1B4B6",
+ background: "#EEEEEE",
+ paper: "#FFFFFF",
+ "paper-secondary": "#FAFAFA",
+ divider: "#D6D5D4",
+ "header-sidenav": "#0B4B66",
+ "input-border": "#505A5F",
+ "primary-bg": "#FEEFE7",
+ "text-primary": "#363636",
+ "error-v2": "#D4351C",
+ },
+ alert: {
+ error: "#b91900",
+ "error-bg": "#EFC7C1",
+ success: "#00703C",
+ "success-bg": "#BAD6C9",
+ info: "#3498DB",
+ "info-bg": "#C7E0F1",
+ },
+ chart: {
+ "chart-1": "#048BD0",
+ "chart-1-gradient": "#048BD0",
+ "chart-2": "#FBC02D",
+ "chart-2-gradient": "#FBC02D",
+ "chart-3": "#8E29BF",
+ "chart-4": "#EA8A3B",
+ "chart-5": "#0BABDE",
+ },
+ fontSize: {
+ "heading-xl": {
+ mobile: "2rem",
+ tablet: "2.25rem",
+ desktop: "2.5rem",
+ },
+ "heading-l": {
+ mobile: "1.5rem",
+ tablet: "1.75rem",
+ desktop: "2rem",
+ },
+ "heading-m": {
+ mobile: "1.25rem",
+ tablet: "1.375rem",
+ desktop: "1.5rem",
+ },
+ "heading-s": {
+ mobile: "1rem",
+ tablet: "1rem",
+ desktop: "1rem",
+ },
+ "heading-xs": {
+ mobile: "0.75rem",
+ },
+ "caption-l": {
+ mobile: "1.5rem",
+ tablet: "1.75rem",
+ desktop: "1.75rem",
+ },
+ "caption-m": {
+ mobile: "1.25rem",
+ tablet: "1.5rem",
+ desktop: "1.5rem",
+ },
+ "caption-s": {
+ mobile: "1rem",
+ tablet: "1.25rem",
+ desktop: "1.25rem",
+ },
+ "body-l": {
+ mobile: "1rem",
+ tablet: "1.25rem",
+ desktop: "1.25rem",
+ },
+ "body-s": {
+ mobile: "0.875rem",
+ tablet: "1rem",
+ desktop: "1rem",
+ },
+ "body-xs": {
+ mobile: "0.75rem",
+ tablet: "0.875rem",
+ desktop: "0.875rem",
+ },
+ label: {
+ mobile: "1rem",
+ tablet: "1rem",
+ desktop: "1rem",
+ },
+ link: {
+ mobile: "1rem",
+ tablet: "1rem",
+ desktop: "1rem",
+ },
+ },
+ fontFamily: {
+ sans: ["Roboto"],
+ rc: ['"Roboto Condensed"'],
+ },
+ fontStyle: {
+ normal: "normal",
+ italic: "italic",
+ },
+ textDecorationLine: {
+ underline: "underline",
+ },
+ fontWeight: {
+ regular: 400,
+ medium: 500,
+ bold: 700,
+ },
+ lineHeight: {
+ "line-height-body-l": { mobile: "1.5rem", tablet: "1.75rem", desktop: "1.75rem" },
+ "line-height-body-s": { mobile: "1.0938rem", tablet: "1.5rem", desktop: "1.5rem" },
+ "line-height-body-xs": { mobile: "1.125rem", tablet: "1.5rem", desktop: "1.5rem" },
+ normal: "normal",
+ },
+ screens: {
+ mobile: "400px",
+ tablet: "768px",
+ desktop: "1024px",
+ },
+ },
+ },
+ variants: {},
+ plugins: [],
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md
new file mode 100644
index 00000000000..0d206b3021e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md
@@ -0,0 +1,159 @@
+# digit-ui-module-workbench
+
+## Install
+
+```bash
+npm install --save digit-ui-module-workbench
+```
+
+## Limitation
+
+```bash
+This Package is more specific to DIGIT-UI's can be used across mission's
+```
+
+## Usage
+
+After adding the dependency make sure you have this dependency in
+
+```bash
+frontend/micro-ui/web/package.json
+```
+
+```json
+"@egovernments/digit-ui-module-workbench":"1.0.0",
+```
+
+then navigate to App.js
+
+```bash
+ frontend/micro-ui/web/src/App.js
+```
+
+```jsx
+/** add this import **/
+
+import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
+
+/** inside enabledModules add this new module key **/
+
+const enabledModules = ["workbench"];
+
+/** inside init Function call this function **/
+
+const initDigitUI = () => {
+ initWorkbenchComponents();
+};
+
+```
+
+In MDMS
+
+_Add this configuration to enable this module [MDMS Enabling Workbench Module](https://github.com/egovernments/works-mdms-data/blob/588d241ba3a9ab30f4d4c2c387a513da811620ca/data/pg/tenant/citymodule.json#L227)_
+
+## List of Screens available in this versions were as follows
+
+1 . Search Master Data
+ > -Provides a screen based on Schema and renders the search result if data is present
+ > -It also provides a dynamic filter based on which data can be filtered
+
+
+2 . Add Master Data based on selected schema
+ > -Provides a screen to add new master data according to the schema
+ > -Provides a Dropdown if it has any referenced master
+
+3 . Update Master data for selected data.
+ > -View the master data from search screen
+ > -Disable/Enable the master data if required
+ > -Update the master data value except the unique-identifier field mentioned in the schema
+
+
+
+4 . Localisation screens
+ > -Provides a screen to search the localisation present in the environment
+ > -Add new localisation
+ > -Update existing localisation
+ > -Bulk Upload of Localisation data
+
+5 . MDMS UI Schema
+
+6 . Data push for any API based on schema
+
+### Mandatory changes to use Workbench module
+
+1 . Assuming core module is already updated with 1.5.38+ and related changes were taken
+
+2 . add the following hook method in micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js
+
+reference::
+https://github.com/egovernments/DIGIT-Dev/blob/6e711bdc005c226c7debd533209681fc77078a3e/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js
+
+3 . add the following utility method in micro-ui-internals/packages/libraries/src/utils/index.js
+```jsx
+didEmployeeHasAtleastOneRole
+
+const didEmployeeHasAtleastOneRole = (roles = []) => {
+ return roles.some((role) => didEmployeeHasRole(role));
+};
+
+```
+
+4 . stylesheet link has to be added
+```jsx
+
+```
+Reference commit for the enabling workbench
+https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd533209681fc77078a3e
+
+
+
+### Changelog
+
+```bash
+1.0.1-beta.1 Republished after merging with Master due to version issues.
+1.0.0-beta.14 Added info message in localisation search
+1.0.0-beta.13 Added new role to support hcm localisation create
+1.0.0-beta.13 Added customisable label for custom dropdown through workbench ui schema
+1.0.0-beta.11 Added customisable label for custom dropdown through workbench ui schema
+1.0.0-beta.10 fixed the dropdown undefined issue
+1.0.0-beta.9 Added new role to support hcm manage masters
+1.0.0-beta.8 minor fixes
+1.0.0-beta.7 Added Bulk Upload Ui for MDMS Add
+1.0.0-beta.6 Added Bulk Upload Ui for MDMS Add
+1.0.0-beta.5 Fixed some loading issue
+1.0.0-beta.2 custom api support added
+1.0.0-beta.1 republished due to some version issues
+1.0.1 Fixes related to the limits
+1.0.0 Workbench v1.0 release
+1.0.0-beta workbench base version beta release
+0.0.3 readme updated
+0.0.2 readme updated
+0.0.1 base version
+```
+
+### Contributors
+
+- [jagankumar-egov](https://github.com/jagankumar-egov)
+- [nipun-egov](https://github.com/nipun-egov)
+
+
+## License
+
+[MIT](https://choosealicense.com/licenses/mit/)
+
+## Documentation
+
+Documentation Site (https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui)
+Workbench Documentation(https://workbench.digit.org/platform/functional-specifications/workbench-ui)
+
+## Maintainer
+
+- [jagankumar-egov](https://www.github.com/jagankumar-egov)
+
+
+### Published from DIGIT Frontend
+DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/master)
+
+
+![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png)
+
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json
new file mode 100644
index 00000000000..41e43fdb6fd
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "@egovernments/digit-ui-module-campaign-manager",
+ "version": "0.0.1",
+ "description": "Campaign",
+ "main": "dist/index.js",
+ "module": "dist/index.modern.js",
+ "source": "src/Module.js",
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "start": "microbundle-crl watch --no-compress --format modern,cjs",
+ "build": "microbundle-crl --compress --no-sourcemap --format cjs",
+ "prepublish": "yarn build"
+ },
+ "peerDependencies": {
+ "react": "17.0.2",
+ "react-router-dom": "5.3.0"
+ },
+ "dependencies": {
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-components": "0.0.2-beta.1",
+ "@rjsf/core": "5.10.0",
+ "@rjsf/utils": "5.10.0",
+ "@rjsf/validator-ajv8": "5.10.0",
+ "ajv": "8.12.0",
+ "react": "17.0.2",
+ "react-date-range": "1.4.0",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0",
+ "react-select": "5.7.4",
+ "react-table": "7.7.0",
+ "xlsx": "0.17.5",
+ "react-drag-drop-files": "^2.3.10",
+ "@cyntler/react-doc-viewer": "1.10.3"
+ },
+ "author": "JaganKumar ",
+ "license": "MIT",
+ "keywords": [
+ "digit",
+ "egov",
+ "dpg",
+ "digit-ui",
+ "workbench",
+ "campaign",
+ "Campaign"
+ ]
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js
new file mode 100644
index 00000000000..cc2f33443d4
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js
@@ -0,0 +1,141 @@
+import { Loader, TourProvider } from "@egovernments/digit-ui-react-components";
+import React from "react";
+import { useRouteMatch } from "react-router-dom";
+import EmployeeApp from "./pages/employee";
+import { CustomisedHooks } from "./hooks";
+import { UICustomizations } from "./configs/UICustomizations";
+import CampaignCard from "./components/CampaignCard";
+import CycleConfiguration from "./pages/employee/CycleConfiguration";
+import DeliverySetup from "./pages/employee/deliveryRule";
+import TimelineCampaign from "./components/TimelineCampaign";
+import CampaignDates from "./components/CampaignDates";
+import CampaignType from "./components/CampaignType";
+import CampaignName from "./components/CampaignName";
+import MyCampaign from "./pages/employee/MyCampaign";
+import CampaignSummary from "./components/CampaignSummary";
+import CycleDetaisPreview from "./components/CycleDetaisPreview";
+import Response from "./pages/employee/Response";
+import SelectingBoundaries from "./components/SelectingBoundaries";
+import UploadData from "./components/UploadData";
+import CampaignSelection from "./components/CampaignType";
+import CampaignDocumentsPreview from "./components/CampaignDocumentsPreview";
+import AddProduct from "./pages/employee/AddProduct";
+import AddProductField from "./components/AddProductField";
+import CycleDataPreview from "./components/CycleDataPreview";
+import { ErrorBoundary } from "@egovernments/digit-ui-components";
+import CampaignResourceDocuments from "./components/CampaignResourceDocuments";
+
+/**
+ * The CampaignModule function fetches store data based on state code, module code, and language, and
+ * renders the EmployeeApp component within a TourProvider component if the data is not loading.
+ * @returns The CampaignModule component returns either a Loader component if data is still loading, or
+ * a TourProvider component wrapping an EmployeeApp component with specific props passed to it.
+ */
+const CampaignModule = ({ stateCode, userType, tenants }) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], {
+ select: (data) => {
+ return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy;
+ },
+ });
+
+ const moduleCode = ["campaignmanager", "workbench", "mdms", "schema", "hcm-admin-schemas", `boundary-${BOUNDARY_HIERARCHY_TYPE}`];
+ const { path, url } = useRouteMatch();
+ const language = Digit.StoreData.getCurrentLanguage();
+ const { isLoading, data: store } = Digit.Services.useStore({
+ stateCode,
+ moduleCode,
+ language,
+ });
+
+ if (isLoading) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+ );
+};
+
+const componentsToRegister = {
+ CampaignModule: CampaignModule,
+ CampaignCard: CampaignCard,
+ UploadData,
+ DeliveryRule: DeliverySetup,
+ CycleConfiguration: CycleConfiguration,
+ TimelineCampaign,
+ CampaignDates,
+ CampaignType,
+ CampaignName,
+ MyCampaign,
+ CampaignSummary,
+ CycleDetaisPreview,
+ Response,
+ SelectingBoundaries,
+ CampaignSelection,
+ CampaignDocumentsPreview: CampaignDocumentsPreview,
+ AddProduct,
+ AddProductField,
+ CycleDataPreview,
+ CampaignResourceDocuments,
+};
+
+const overrideHooks = () => {
+ Object.keys(CustomisedHooks).map((ele) => {
+ if (ele === "Hooks") {
+ Object.keys(CustomisedHooks[ele]).map((hook) => {
+ Object.keys(CustomisedHooks[ele][hook]).map((method) => {
+ setupHooks(hook, method, CustomisedHooks[ele][hook][method]);
+ });
+ });
+ } else if (ele === "Utils") {
+ Object.keys(CustomisedHooks[ele]).map((hook) => {
+ Object.keys(CustomisedHooks[ele][hook]).map((method) => {
+ setupHooks(hook, method, CustomisedHooks[ele][hook][method], false);
+ });
+ });
+ } else {
+ Object.keys(CustomisedHooks[ele]).map((method) => {
+ setupLibraries(ele, method, CustomisedHooks[ele][method]);
+ });
+ }
+ });
+};
+
+/* To Overide any existing hook we need to use similar method */
+const setupHooks = (HookName, HookFunction, method, isHook = true) => {
+ window.Digit = window.Digit || {};
+ window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {};
+ window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {};
+ window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method;
+};
+/* To Overide any existing libraries we need to use similar method */
+const setupLibraries = (Library, service, method) => {
+ window.Digit = window.Digit || {};
+ window.Digit[Library] = window.Digit[Library] || {};
+ window.Digit[Library][service] = method;
+};
+
+/* To Overide any existing config/middlewares we need to use similar method */
+const updateCustomConfigs = () => {
+ setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations });
+ // setupLibraries("Utils", "parsingUtils", { ...window?.Digit?.Utils?.parsingUtils, ...parsingUtils });
+};
+
+/**
+ * The `initCampaignComponents` function initializes campaign components by overriding hooks, updating
+ * custom configurations, and registering components.
+ */
+const initCampaignComponents = () => {
+ overrideHooks();
+ updateCustomConfigs();
+ Object.entries(componentsToRegister).forEach(([key, value]) => {
+ Digit.ComponentRegistryService.setComponent(key, value);
+ });
+};
+
+export { initCampaignComponents };
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js
new file mode 100644
index 00000000000..94a73fd6b24
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js
@@ -0,0 +1,144 @@
+import React, { useState, useEffect } from "react";
+import { AddIcon, Button, Card, CardText, Header, TextInput, Dropdown } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import { LabelFieldPair } from "@egovernments/digit-ui-react-components";
+import { DustbinIcon } from "./icons/DustbinIcon";
+// import { productType } from "../configs/productType";
+import { PRIMARY_COLOR } from "../utils";
+
+const AddProductField = ({ onSelect }) => {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const { isLoading: productTypeLoading, data: productType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "productType" }], {
+ select: (data) => {
+ return data?.["HCM-ADMIN-CONSOLE"]?.productType;
+ },
+ });
+ const [productFieldData, setProductFieldData] = useState([{ key: 1, name: null, type: null, variant: null }]);
+
+ useEffect(() => {
+ onSelect("addProduct", productFieldData);
+ }, [productFieldData]);
+
+ const addMoreField = () => {
+ setProductFieldData((prev) => [
+ ...prev,
+ {
+ key: prev.length + 1,
+ name: null,
+ type: null,
+ variant: null,
+ },
+ ]);
+ };
+
+ const deleteProductField = (index) => {
+ setProductFieldData((prev) => {
+ const temp = prev.filter((i) => i.key !== index);
+ return temp.map((i, n) => ({ ...i, key: n + 1 }));
+ });
+ };
+
+ const handleUpdateField = (data, target, index) => {
+ setProductFieldData((prev) => {
+ return prev.map((i) => {
+ if (i.key === index) {
+ return {
+ ...i,
+ [target]: data,
+ };
+ }
+ return {
+ ...i,
+ };
+ });
+ });
+ };
+
+ return (
+
+ {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_HEADER`)}
+
+ {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_PRE_TEXT`)} {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_BOLD_TEXT`)}
+ {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_POST_TEXT`)}
+
+ {productFieldData?.map((field, index) => {
+ return (
+
+
+
Product {field?.key}
+ {productFieldData?.length > 1 && (
+
deleteProductField(field.key)}
+ style={{
+ cursor: "pointer",
+ fontWeight: "600",
+ marginLeft: "1rem",
+ fontSize: "1rem",
+ color: PRIMARY_COLOR,
+ display: "flex",
+ gap: "0.5rem",
+ alignItems: "center",
+ marginTop: "1rem",
+ }}
+ >
+
+ {t(`CAMPAIGN_DELETE_ROW_TEXT`)}
+
+ )}
+
+
+
+ {`${t("HCM_PRODUCT_NAME")}`}
+ *
+
+ handleUpdateField(event.target.value, "name", field.key)}
+ />
+
+
+
+ {`${t("HCM_PRODUCT_TYPE")}`}
+ *
+
+ {
+ handleUpdateField(value, "type", field.key);
+ }}
+ />
+
+
+
+ {`${t("HCM_PRODUCT_VARIANT")}`}
+ *
+
+ handleUpdateField(event.target.value, "variant", field?.key)}
+ />
+
+
+ );
+ })}
+ }
+ onButtonClick={addMoreField}
+ />
+
+ );
+};
+
+export default AddProductField;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js
new file mode 100644
index 00000000000..5f854cfac79
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js
@@ -0,0 +1,202 @@
+import React, { useState, useMemo, useEffect } from "react";
+import { UploadIcon, FileIcon, DeleteIconv2, Button, DownloadIcon, PopUp, SVG } from "@egovernments/digit-ui-react-components";
+import { FileUploader } from "react-drag-drop-files";
+import { useTranslation } from "react-i18next";
+import XLSX from "xlsx";
+import XlsPreview from "./XlsPreview";
+import { PRIMARY_COLOR } from "../utils";
+import { Toast } from "@egovernments/digit-ui-components";
+
+/**
+ * The BulkUpload component in JavaScript allows users to upload, validate, preview, download, and
+ * delete files in bulk with support for Excel file validation.
+ * @returns The `BulkUpload` component is returning a JSX structure that includes conditional rendering
+ * based on the presence of `fileData`. If `fileData` is empty or null, it renders a `FileUploader`
+ * component with drag and drop functionality. If `fileData` contains files, it renders file cards for
+ * each file with options to download and delete. Additionally, it includes a preview component for
+ * Excel files
+ */
+const BulkUpload = ({ multiple = true, onSubmit, fileData, onFileDelete, onFileDownload }) => {
+ const { t } = useTranslation();
+ const [files, setFiles] = useState([]);
+ const fileTypes = ["XLS", "XLSX", "csv", "CSV"];
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const [showPreview, setShowPreview] = useState(false);
+ const [fileUrl, setFileUrl] = useState(fileData?.[0]);
+ const [fileName, setFileName] = useState(null);
+ const [showToast, setShowToast] = useState(false);
+
+ useEffect(() => {
+ const fetch = async () => {
+ const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch([fileData?.[0]?.filestoreId], tenantId);
+ const temp = fileData?.map((i) => ({
+ ...i,
+ url: fileUrl?.[0]?.url,
+ }));
+ setFileUrl(temp?.[0]);
+ };
+ fetch();
+ }, [fileData]);
+
+ const closeToast = () => {
+ setTimeout(() => {
+ setShowToast(null);
+ }, 5000);
+ };
+
+ const dragDropJSX = (
+
+
+
+ {t("WBH_DRAG_DROP")} {t("WBH_BULK_BROWSE_FILES")}
+
+
+ );
+
+ const handleFileDelete = (file, index) => {
+ onFileDelete(file, index);
+ };
+
+ const validateExcel = (selectedFile) => {
+ return new Promise((resolve, reject) => {
+ // Check if a file is selected
+ if (!selectedFile) {
+ reject(t("HCM_FILE_UPLOAD_ERROR"));
+ return;
+ }
+
+ // Read the Excel file
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ try {
+ const data = new Uint8Array(e.target.result);
+ const workbook = XLSX.read(data, { type: "array" });
+
+ // Assuming your columns are in the first sheet
+ const sheet = workbook.Sheets[workbook.SheetNames[0]];
+
+ const columnsToValidate = XLSX.utils.sheet_to_json(sheet, {
+ header: 1,
+ })[0];
+
+ // Check if all columns have non-empty values in every row
+ const isValid = XLSX.utils
+ .sheet_to_json(sheet)
+ .every((row) => columnsToValidate.every((column) => row[column] !== undefined && row[column] !== null && row[column] !== ""));
+
+ if (isValid) {
+ // All columns in all rows have non-empty values, it is valid
+ resolve(true);
+ } else {
+ // const label = "HCM_FILE_VALIDATION_ERROR";
+ // setShowToast({ isError: true, label });
+ reject(t("HCM_FILE_VALIDATION_ERROR"));
+ }
+ } catch (error) {
+ reject("HCM_FILE_UNAVAILABLE");
+ }
+ };
+
+ reader.readAsArrayBuffer(selectedFile);
+ });
+ };
+
+ const handleFileDownload = async (e, file) => {
+ if (e?.stopPropagation) {
+ e.stopPropagation();
+ }
+ onFileDownload(file);
+ };
+
+ const handleChange = async (newFiles) => {
+ try {
+ // await validateExcel(newFiles[0]);
+ onSubmit([...newFiles]);
+ } catch (error) {
+ // Handle the validation error, you can display a message or take appropriate actions.
+ setShowToast({ key: "error", label: error });
+ closeToast();
+ }
+ };
+
+ const fileTypeError = (err) => {
+ setShowToast({ key: "error", label: t("HCM_ERROR_INVALID_FILE_TYPE") });
+ };
+
+ const renderFileCards = useMemo(() => {
+ return fileData?.map((file, index) => (
+ {
+ e.stopPropagation();
+ setShowPreview(true);
+ }}
+ >
+
{
+ // setShowPreview(true);
+ // }}
+ >
+
+
{file.filename}
+
+
+ }
+ type="button"
+ className="workbench-download-template-btn hover"
+ onButtonClick={(e) => {
+ e.stopPropagation();
+ handleFileDownload(e, fileUrl);
+ }}
+ />
+ }
+ type="button"
+ className="workbench-download-template-btn hover"
+ onButtonClick={(e) => {
+ e.stopPropagation();
+ handleFileDelete(file, index);
+ setShowPreview(false);
+ }}
+ />
+
+
+ ));
+ }, [fileData, fileUrl]);
+
+ return (
+
+ {(!fileData || fileData?.length === 0) && (
+
+ )}
+ {fileData?.length > 0 && renderFileCards}
+ {showPreview && handleFileDownload(null, fileUrl)} onBack={() => setShowPreview(false)} />}
+ {showToast && (
+ setShowToast(null)}
+ >
+ )}
+
+ );
+};
+
+export default BulkUpload;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js
new file mode 100644
index 00000000000..e5b5b7419b7
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js
@@ -0,0 +1,71 @@
+import { EmployeeModuleCard, SVG } from "@egovernments/digit-ui-react-components";
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+const ROLES = {
+ CAMPAIGN_MANAGER:["CAMPAIGN_MANAGER"]
+};
+
+/**
+ * The CampaignCard component renders a card with links related to campaign management, filtering out
+ * links based on employee roles.
+ * @returns The CampaignCard component is being returned. It contains a list of links related to
+ * campaign actions, such as setting up a campaign and viewing personal campaigns. The links are
+ * filtered based on employee roles before being displayed in the EmployeeModuleCard component.
+ */
+const CampaignCard = () => {
+ if (!Digit.Utils.didEmployeeHasAtleastOneRole(Object.values(ROLES).flatMap((e) => e))) {
+ return null;
+ }
+
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ // const reqCriteria = {
+ // url: "/project-factory/v1/project-type/search",
+ // params: {},
+ // body: { CampaignDetails:{
+ // tenantId,
+ // createdBy: Digit.UserService.getUser().info.uuid,
+ // pagination: {
+ // "sortBy": "createdTime",
+ // "sortOrder": "desc",
+ // "limit": 1,
+ // "offset": 0
+ // }
+ // } },
+ // config: {
+ // select: (data) => {
+ // return data?.totalCount;
+ // },
+ // },
+ // };
+ // const { isLoading, data } = Digit.Hooks.useCustomAPIHook(
+ // reqCriteria
+ // );
+ let links = [
+
+ {
+ label: t("ACTION_TEST_SETUP_CAMPAIGN"),
+ link: `/${window?.contextPath}/employee/campaign/setup-campaign`,
+ roles: ROLES.CAMPAIGN_MANAGER
+ },
+ {
+ label: t("ACTION_TEST_MY_CAMPAIGN"),
+ link: `/${window?.contextPath}/employee/campaign/my-campaign`,
+ roles: ROLES.CAMPAIGN_MANAGER,
+ // count: isLoading?"-":data
+ },
+ ];
+
+ links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true));
+
+ const propsForModuleCard = {
+ Icon: ,
+ moduleName: t("ACTION_TEST_CAMPAIGN"),
+ kpis: [],
+ links: links,
+ };
+ return ;
+};
+
+export default CampaignCard;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js
new file mode 100644
index 00000000000..71bcfa4e447
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js
@@ -0,0 +1,122 @@
+import React, { useState, useEffect } from "react";
+import { DatePicker, LabelFieldPair, Header } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import { ErrorMessage, FieldV1, TextInput } from "@egovernments/digit-ui-components";
+
+const CampaignDates = ({ onSelect, formData, ...props }) => {
+ const { t } = useTranslation();
+ const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;
+ const today = Digit.Utils.date.getDate(Date.now() + ONE_DAY_IN_MS);
+ const [dates, setDates] = useState({
+ startDate: props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate || today,
+ endDate: props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate || today,
+ });
+ const [startDate, setStartDate] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate); // Set default start date to today
+ const [endDate, setEndDate] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate); // Default end date
+ const [executionCount, setExecutionCount] = useState(0);
+ const [error, setError] = useState(null);
+ const [startValidation, setStartValidation] = useState(null);
+
+ useEffect(() => {
+ setDates({
+ startDate: props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate,
+ endDate: props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate,
+ });
+ setStartDate(props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate);
+ setEndDate(props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate);
+ }, [props?.props?.sessionData?.HCM_CAMPAIGN_DATE?.campaignDates]);
+
+ useEffect(() => {
+ if (props?.props?.isSubmitting && !endDate && !startDate) {
+ setError({ startDate: "CAMPAIGN_FIELD_MANDATORY", endDate: "CAMPAIGN_FIELD_MANDATORY" });
+ } else if (props?.props?.isSubmitting && !startDate) {
+ setError({ startDate: "CAMPAIGN_FIELD_MANDATORY" });
+ } else if (props?.props?.isSubmitting && !endDate) {
+ setError({ endDate: "CAMPAIGN_FIELD_MANDATORY" });
+ } else if (!props?.props?.isSubmitting) {
+ setError(null);
+ }
+ }, [props?.props?.isSubmitting]);
+ useEffect(() => {
+ if (!startDate && startValidation) {
+ setError({ startDate: "CAMPAIGN_START_DATE_ERROR" });
+ } else if (!endDate && startValidation) {
+ setError({ endDate: "CAMPAIGN_END_DATE_ERROR" });
+ } else if (new Date(endDate).getTime() < new Date(startDate).getTime() && startValidation) {
+ setError({ endDate: "CAMPAIGN_END_DATE_BEFORE_ERROR" });
+ onSelect("campaignDates", { startDate: startDate, endDate: endDate });
+ } else if (startValidation && new Date(endDate).getTime() === new Date(startDate).getTime()) {
+ setError({ endDate: "CAMPAIGN_END_DATE_SAME_ERROR" });
+ onSelect("campaignDates", { startDate: startDate, endDate: endDate });
+ } else if (startDate || endDate) {
+ setError(null);
+ onSelect("campaignDates", { startDate: startDate, endDate: endDate });
+ }
+ }, [startDate, endDate]);
+
+ useEffect(() => {
+ if (executionCount < 5) {
+ onSelect("campaignDates", { startDate: startDate, endDate: endDate });
+ setExecutionCount((prevCount) => prevCount + 1);
+ }
+ });
+
+ function setStart(value) {
+ setStartDate(value);
+ }
+
+ function setEnd(date) {
+ setEndDate(date);
+ }
+
+ return (
+
+ {t(`HCM_CAMPAIGN_DATES_HEADER`)}
+ {t(`HCM_CAMPAIGN_DATES_DESCRIPTION`)}
+
+
+
{t(`HCM_CAMPAIGN_DATES`)}
+
*
+
+
+ {
+ // setStartValidation(true);
+ setStart(d);
+ }}
+ />
+ {
+ setStartValidation(true);
+ setEnd(d);
+ }}
+ />
+
+
+
+ );
+};
+
+export default CampaignDates;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js
new file mode 100644
index 00000000000..2c8bbf77eaf
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js
@@ -0,0 +1,92 @@
+import React, { useState, useEffect, Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import { DocumentIcon } from "./DocumentIcon";
+import XlsPreview from "./XlsPreview";
+import { XlsxFile } from "./icons/XlsxFile";
+import { downloadExcelWithCustomName } from "../utils";
+import { InfoCard } from "@egovernments/digit-ui-components";
+
+function CampaignDocumentsPreview({ documents = [], svgStyles = {}, isUserGenerate = false, cardErrors }) {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const [filesArray, setFilesArray] = useState(null);
+ const [pdfFiles, setPdfFiles] = useState({});
+ const [showPreview, setShowPreview] = useState(false);
+
+ useEffect(() => {
+ let acc = documents?.map((i) => (i?.id ? i?.id : i?.filestoreId));
+ setFilesArray(acc);
+ }, [documents]);
+
+ useEffect(() => {
+ if (filesArray?.length > 0) {
+ Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getCurrentTenantId()).then((res) => {
+ setPdfFiles(res?.data);
+ });
+ }
+ }, [filesArray]);
+
+ const handleFileDownload = ({ id, name }) => {
+ const fileNameWithoutExtension = name?.split(/\.(xlsx|xls)/)?.[0];
+ downloadExcelWithCustomName({ fileStoreId: id, customName: fileNameWithoutExtension });
+ };
+ return (
+
+
+ {documents?.length > 0 ? (
+ documents?.map(
+ (document, index) =>
+ (document?.id || document?.filestoreId) && (
+
+
setShowPreview(true)}>
+
+
+
+
+ {isUserGenerate
+ ? document?.type
+ : document?.filename
+ ? t(document?.filename)
+ : t("CAMPAIGN_DOCUMENT_TITLE", { INDEX: index + 1 })}
+
+
+ {showPreview && (
+
+ handleFileDownload({
+ id: document?.id ? document?.id : document?.filestoreId,
+ name: isUserGenerate ? document?.type : document?.filename,
+ })
+ }
+ onBack={() => setShowPreview(false)}
+ />
+ )}
+
+ )
+ )
+ ) : (
+
+
{t("ES_CAMPAIGN_NO_DOCUMENTS_AVAILABLE")}
+ {cardErrors?.map((i) => (
+
]}
+ />
+ ))}
+
+ )}
+
+
+ );
+}
+
+export default CampaignDocumentsPreview;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js
new file mode 100644
index 00000000000..5a4f7f546f2
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js
@@ -0,0 +1,32 @@
+import { BackButton, Tutorial, useTourState, Help } from "@egovernments/digit-ui-react-components";
+import React, { useEffect, useContext, Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import { useLocation } from "react-router-dom";
+import { TourSteps } from "../utils/TourSteps";
+
+const CampaignHeader = () => {
+ const { tourState, setTourState } = useTourState();
+ // const { tutorial, updateTutorial } = useContext(TutorialContext);
+ const { t } = useTranslation();
+ //using location.pathname we can update the stepIndex accordingly when help is clicked from any other screen(other than home screen)
+ const { pathname } = useLocation();
+
+ const startTour = () => {
+ setTourState({
+ run: TourSteps[pathname]?.length > 0 ? true : false,
+ steps: TourSteps[pathname] || [],
+ tourActive: TourSteps[pathname]?.length > 0 ? true : false,
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
+
+export default CampaignHeader;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js
new file mode 100644
index 00000000000..4540e3f46f4
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js
@@ -0,0 +1,66 @@
+import React, { useState, useEffect ,Fragment} from "react";
+import { Header } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import { LabelFieldPair } from "@egovernments/digit-ui-react-components";
+import { ErrorMessage, FieldV1 } from "@egovernments/digit-ui-components";
+
+const CampaignName = ({ onSelect, formData, control, formState, ...props }) => {
+ const { t } = useTranslation();
+ const [name, setName] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_NAME?.campaignName || "");
+ const [executionCount, setExecutionCount] = useState(0);
+ const [startValidation, setStartValidation] = useState(null);
+ const [error, setError] = useState(null);
+ useEffect(() => {
+ setName(props?.props?.sessionData?.HCM_CAMPAIGN_NAME?.campaignName);
+ }, [props?.props?.sessionData?.HCM_CAMPAIGN_NAME]);
+
+ useEffect(() => {
+ if (props?.props?.isSubmitting && !name) {
+ setError({ message: "CAMPAIGN_FIELD_ERROR_MANDATORY" });
+ } else {
+ setError(null);
+ }
+ }, [props?.props?.isSubmitting]);
+ useEffect(() => {
+ if (startValidation && !name) {
+ setError({ message: "CAMPAIGN_NAME_FIELD_ERROR" });
+ } else if (name) {
+ setError(null);
+ onSelect("campaignName", name);
+ }
+ }, [name, props?.props?.sessionData?.HCM_CAMPAIGN_NAME?.campaignName]);
+
+ useEffect(() => {
+ if (executionCount < 5) {
+ onSelect("campaignName", name);
+ setExecutionCount((prevCount) => prevCount + 1);
+ }
+ });
+
+ return (
+
+ {t(`HCM_CAMPAIGN_NAME_HEADER`)}
+ {t(`HCM_CAMPAIGN_NAME_DESCRIPTION`)}
+
+
+ {`${t("HCM_CAMPAIGN_NAME")}`}
+ *
+
+ {
+ setStartValidation(true);
+ setName(event.target.value);
+ }}
+ />
+
+
+ );
+};
+
+export default CampaignName;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js
new file mode 100644
index 00000000000..827ff5062eb
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js
@@ -0,0 +1,50 @@
+import React, { useState, useEffect, Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import CampaignDocumentsPreview from "./CampaignDocumentsPreview";
+import { CardText } from "@egovernments/digit-ui-components";
+
+function CampaignResourceDocuments({ resources = [], svgStyles = {}, isUserGenerate = false }) {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const [processData, setProcessData] = useState([]);
+ const reqCriteriaResource = {
+ url: `/project-factory/v1/data/_search`,
+ body: {
+ SearchCriteria: {
+ tenantId: tenantId,
+ id: resources,
+ },
+ },
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.ResourceDetails;
+ },
+ },
+ };
+
+ const { isLoading, data: resourceData, isFetching } = Digit.Hooks.useCustomAPIHook(reqCriteriaResource);
+
+ useEffect(() => {
+ if (!isLoading) {
+ const temp = resourceData.map((i) => {
+ return {
+ id: i?.processedFilestoreId,
+ type: "User Credential",
+ };
+ });
+ setProcessData(temp);
+ }
+ }, [isLoading, resourceData]);
+
+ if (!processData?.[0]?.id) {
+ return {t("NO_DOCUMENTS_AVAILABLE")};
+ }
+ return (
+
+
+
+ );
+}
+
+export default CampaignResourceDocuments;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js
new file mode 100644
index 00000000000..6f37dfb6ae2
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js
@@ -0,0 +1,484 @@
+import React, { Fragment, useEffect, useRef, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { useHistory } from "react-router-dom";
+import { Button, EditIcon, Header, Loader, ViewComposer } from "@egovernments/digit-ui-react-components";
+import { InfoBannerIcon, Toast } from "@egovernments/digit-ui-components";
+import { DownloadIcon } from "@egovernments/digit-ui-react-components";
+import { PRIMARY_COLOR, downloadExcelWithCustomName } from "../utils";
+
+function mergeObjects(item) {
+ const arr = item;
+ const mergedArr = [];
+ const mergedAttributes = new Set();
+
+ arr.forEach((obj) => {
+ if (!mergedAttributes.has(obj.attribute)) {
+ const sameAttrObjs = arr.filter((o) => o.attribute === obj.attribute);
+
+ if (sameAttrObjs.length > 1) {
+ const fromValue = Math.min(...sameAttrObjs.map((o) => o.value));
+ const toValue = Math.max(...sameAttrObjs.map((o) => o.value));
+
+ mergedArr.push({
+ fromValue,
+ toValue,
+ value: fromValue > 0 && toValue > 0 ? `${fromValue} to ${toValue}` : null,
+ operator: "IN_BETWEEN",
+ attribute: obj.attribute,
+ });
+
+ mergedAttributes.add(obj.attribute);
+ } else {
+ mergedArr.push(obj);
+ }
+ }
+ });
+
+ return mergedArr;
+}
+
+function loopAndReturn(dataa, t) {
+ let newArray = [];
+ const data = dataa?.map((i) => ({ ...i, operator: i?.operator, attribute: i?.attribute }));
+
+ data.forEach((item) => {
+ // Check if an object with the same attribute already exists in the newArray
+ const existingIndex = newArray.findIndex((element) => element.attribute === item.attribute);
+ if (existingIndex !== -1) {
+ // If an existing item is found, replace it with the new object
+ const existingItem = newArray[existingIndex];
+ newArray[existingIndex] = {
+ attribute: existingItem.attribute,
+ operator: "IN_BETWEEN",
+ toValue: existingItem.value && item.value ? Math.min(existingItem.value, item.value) : null,
+ fromValue: existingItem.value && item.value ? Math.max(existingItem.value, item.value) : null,
+ };
+ } else if (item?.operator === "EQUAL_TO") {
+ newArray.push({
+ ...item,
+ value: item?.value ? t(item?.value) : null,
+ });
+ } else {
+ newArray.push(item);
+ }
+ });
+
+ const withKey = newArray.map((i, c) => ({ key: c + 1, ...i }));
+ const format = withKey.map((i) => {
+ if (i.operator === "IN_BETWEEN") {
+ return {
+ ...i,
+ value: `${i?.toValue ? i?.toValue : "N/A"} to ${i?.fromValue ? i?.fromValue : "N/A"}`,
+ };
+ }
+ return {
+ ...i,
+ };
+ });
+ return format;
+}
+
+function reverseDeliveryRemap(data, t) {
+ if (!data) return null;
+ const reversedData = [];
+ let currentCycleIndex = null;
+ let currentCycle = null;
+
+ data.forEach((item, index) => {
+ if (currentCycleIndex !== item.cycleNumber) {
+ currentCycleIndex = item.cycleNumber;
+ currentCycle = {
+ cycleIndex: currentCycleIndex.toString(),
+ startDate: item?.startDate ? Digit.Utils.date.convertEpochToDate(item?.startDate) : null,
+ endDate: item?.endDate ? Digit.Utils.date.convertEpochToDate(item?.endDate) : null,
+ active: index === 0, // Initialize active to false
+ deliveries: [],
+ };
+ reversedData.push(currentCycle);
+ }
+
+ const deliveryIndex = item.deliveryNumber.toString();
+
+ let delivery = currentCycle.deliveries.find((delivery) => delivery.deliveryIndex === deliveryIndex);
+
+ if (!delivery) {
+ delivery = {
+ deliveryIndex: deliveryIndex,
+ active: item.deliveryNumber === 1, // Set active to true only for the first delivery
+ deliveryRules: [],
+ };
+ currentCycle.deliveries.push(delivery);
+ }
+
+ delivery.deliveryRules.push({
+ ruleKey: item.deliveryRuleNumber,
+ delivery: {},
+ attributes: loopAndReturn(item.conditions, t),
+ products: [...item.products],
+ });
+ });
+
+ return reversedData;
+}
+
+const fetchResourceFile = async (tenantId, resourceIdArr) => {
+ const res = await Digit.CustomService.getResponse({
+ url: `/project-factory/v1/data/_search`,
+ body: {
+ SearchCriteria: {
+ tenantId: tenantId,
+ id: resourceIdArr,
+ },
+ },
+ });
+ return res?.ResourceDetails;
+};
+
+const CampaignSummary = (props) => {
+ const { t } = useTranslation();
+ const history = useHistory();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const searchParams = new URLSearchParams(location.search);
+ const id = searchParams.get("id");
+ const noAction = searchParams.get("action");
+ const [showToast, setShowToast] = useState(null);
+ const [userCredential, setUserCredential] = useState(null);
+ const [deliveryErrors, setDeliveryErrors] = useState(null);
+ const [targetErrors, setTargetErrors] = useState(null);
+ const [facilityErrors, setFacilityErrors] = useState(null);
+ const [userErrors, setUserErrors] = useState(null);
+ const [cycleDatesError, setCycleDatesError] = useState(null);
+ const [summaryErrors, setSummaryErrors] = useState(null);
+ const handleRedirect = (step, activeCycle) => {
+ const urlParams = new URLSearchParams(window.location.search);
+ const id = urlParams.get("id");
+ urlParams.set("key", step);
+ urlParams.set("preview", false);
+ if (activeCycle) {
+ urlParams.set("activeCycle", activeCycle);
+ }
+ const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
+ history.push(newUrl);
+ };
+
+ useEffect(() => {
+ if (props?.props?.summaryErrors) {
+ if (props?.props?.summaryErrors?.deliveryErrors) {
+ const temp = props?.props?.summaryErrors?.deliveryErrors?.map((i) => {
+ return {
+ ...i,
+ onClick: i?.dateError ? () => handleRedirect(5) : () => handleRedirect(6, i?.cycle),
+ };
+ });
+ setSummaryErrors({ ...props?.props?.summaryErrors, deliveryErrors: temp });
+ } else {
+ setSummaryErrors(props?.props?.summaryErrors);
+ }
+ }
+ // if (props?.props?.summaryErrors?.deliveryErrors) {
+ // const temp = props?.props?.summaryErrors?.deliveryErrors?.map((i) => {
+ // return {
+ // ...i,
+ // onClick: () => handleRedirect(6, i?.cycle),
+ // };
+ // });
+ // setDeliveryErrors(temp);
+ // }
+ // if (props?.props?.summaryErrors?.targetErrors) {
+ // setTargetErrors(props?.props?.summaryErrors?.targetErrors);
+ // }
+ // if (props?.props?.summaryErrors?.facilityErrors) {
+ // setFacilityErrors(props?.props?.summaryErrors?.facilityErrors);
+ // }
+ // if (props?.props?.summaryErrors?.userErrors) {
+ // setUserErrors(props?.props?.summaryErrors?.userErrors);
+ // }
+ }, [props?.props?.summaryErrors]);
+
+ const { isLoading, data, error, refetch } = Digit.Hooks.campaign.useSearchCampaign({
+ tenantId: tenantId,
+ filter: {
+ ids: [id],
+ },
+ config: {
+ select: (data) => {
+ const resourceIdArr = [];
+ data?.[0]?.resources?.map((i) => {
+ if (i?.createResourceId && i?.type === "user") {
+ resourceIdArr.push(i?.createResourceId);
+ }
+ });
+ let processid;
+
+ const ss = async () => {
+ let temp = await fetchResourceFile(tenantId, resourceIdArr);
+ processid = temp;
+ return;
+ };
+ ss();
+ const target = data?.[0]?.deliveryRules;
+ const cycleData = reverseDeliveryRemap(target, t);
+ return {
+ cards: [
+ {
+ sections: [
+ {
+ type: "DATA",
+ cardHeader: { value: t("CAMPAIGN_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } },
+ cardSecondaryAction: noAction !== "false" && (
+ handleRedirect(1)}>
+ {t(`CAMPAIGN_EDIT`)}
+
+
+ ),
+ values: [
+ {
+ key: "CAMPAIGN_TYPE",
+ value: data?.[0]?.projectType ? t(`CAMPAIGN_PROJECT_${data?.[0]?.projectType?.toUpperCase()}`) : t("CAMPAIGN_SUMMARY_NA"),
+ },
+ {
+ key: "CAMPAIGN_NAME",
+ value: data?.[0]?.campaignName || t("CAMPAIGN_SUMMARY_NA"),
+ },
+ {
+ key: "CAMPAIGN_START_DATE",
+ value: Digit.Utils.date.convertEpochToDate(data?.[0]?.startDate) || t("CAMPAIGN_SUMMARY_NA"),
+ },
+ {
+ key: "CAMPAIGN_END_DATE",
+ value: Digit.Utils.date.convertEpochToDate(data?.[0]?.endDate) || t("CAMPAIGN_SUMMARY_NA"),
+ },
+ ],
+ },
+ ],
+ },
+ // data?.[0]?.resources?.find((i) => i?.type === "boundaryWithTarget") ?
+ {
+ name: "target",
+ errorName: "target",
+ sections: [
+ {
+ name: "target",
+ type: "COMPONENT",
+ component: "CampaignDocumentsPreview",
+ props: {
+ documents: data?.[0]?.resources?.filter((i) => i?.type === "boundaryWithTarget"),
+ },
+ cardHeader: { value: t("TARGET_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } },
+ cardSecondaryAction: noAction !== "false" && (
+ handleRedirect(7)}>
+ {t(`CAMPAIGN_EDIT`)}
+
+
+ ),
+ },
+ ],
+ },
+ // : {}
+ // data?.[0]?.resources?.find((i) => i?.type === "facility") ?
+ {
+ name: "facility",
+ errorName: "facility",
+ sections: [
+ {
+ name: "facility",
+ type: "COMPONENT",
+ component: "CampaignDocumentsPreview",
+ props: {
+ documents: data?.[0]?.resources?.filter((i) => i.type === "facility"),
+ },
+ cardHeader: { value: t("FACILITY_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } },
+ cardSecondaryAction: noAction !== "false" && (
+ handleRedirect(8)}>
+ {t(`CAMPAIGN_EDIT`)}
+
+
+ ),
+ },
+ ],
+ },
+ // : {}
+ // data?.[0]?.resources?.find((i) => i?.type === "user") ?
+ {
+ name: "user",
+ errorName: "user",
+ sections: [
+ {
+ name: "user",
+ type: "COMPONENT",
+ component: "CampaignDocumentsPreview",
+ props: {
+ documents: data?.[0]?.resources?.filter((i) => i.type === "user"),
+ },
+ cardHeader: { value: t("USER_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } },
+ cardSecondaryAction: noAction !== "false" && (
+ handleRedirect(9)}>
+ {t(`CAMPAIGN_EDIT`)}
+
+
+ ),
+ },
+ ],
+ },
+ // : {}
+ resourceIdArr?.length > 0
+ ? {
+ sections: [
+ {
+ type: "COMPONENT",
+ component: "CampaignResourceDocuments",
+ props: {
+ isUserGenerate: true,
+ // resources: processid,
+ resources: resourceIdArr,
+ },
+ cardHeader: { value: t("USER_GENERATE_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } },
+ },
+ ],
+ }
+ : {},
+ {
+ sections: [
+ {
+ type: "DATA",
+ cardHeader: { value: t("CAMPAIGN_DELIVERY_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } },
+ cardSecondaryAction: noAction !== "false" && (
+ handleRedirect(5)}>
+ {t(`CAMPAIGN_EDIT`)}
+
+
+ ),
+ values: [
+ {
+ key: "CAMPAIGN_NO_OF_CYCLES",
+ value:
+ data?.[0]?.deliveryRules && data?.[0]?.deliveryRules.map((item) => item.cycleNumber)?.length > 0
+ ? Math.max(...data?.[0]?.deliveryRules.map((item) => item.cycleNumber))
+ : t("CAMPAIGN_SUMMARY_NA"),
+ },
+ {
+ key: "CAMPAIGN_NO_OF_DELIVERIES",
+ value:
+ data?.[0]?.deliveryRules && data?.[0]?.deliveryRules.map((item) => item.deliveryNumber)?.length > 0
+ ? Math.max(...data?.[0]?.deliveryRules.map((item) => item.deliveryNumber))
+ : t("CAMPAIGN_SUMMARY_NA"),
+ },
+ ],
+ },
+ ],
+ },
+ ...cycleData?.map((item, index) => {
+ return {
+ name: `CYCLE_${index + 1}`,
+ errorName: "deliveryErrors",
+ sections: [
+ {
+ name: `CYCLE_${index + 1}`,
+ type: "COMPONENT",
+ cardHeader: { value: `${t("CYCLE")} ${item?.cycleIndex}`, inlineStyles: { marginTop: 0, fontSize: "1.5rem" } },
+ cardSecondaryAction: noAction !== "false" && (
+ handleRedirect(5)}>
+ {t(`CAMPAIGN_EDIT`)}
+
+
+ ),
+ component: "CycleDataPreview",
+ props: {
+ data: item,
+ },
+ },
+ ],
+ };
+ }),
+ ],
+ error: data?.[0]?.additionalDetails?.error,
+ data: data?.[0],
+ status: data?.[0]?.status,
+ userGenerationSuccess: resourceIdArr,
+ };
+ },
+ enabled: id ? true : false,
+ staleTime: 0,
+ cacheTime: 0,
+ },
+ });
+
+ if (isLoading) {
+ return ;
+ }
+ const closeToast = () => {
+ setShowToast(null);
+ };
+ useEffect(() => {
+ if (showToast) {
+ setTimeout(closeToast, 5000);
+ }
+ }, [showToast]);
+ useEffect(() => {
+ if (data?.status === "failed" && data?.error) {
+ setShowToast({ label: data?.error, key: "error" });
+ }
+ if (data?.status === "creating") {
+ setShowToast({ label: "CAMPAIGN_STATUS_CREATING_MESSAGE", key: "info" });
+ }
+ if (data?.status === "created" && data?.userGenerationSuccess?.length > 0) {
+ setShowToast({ label: "CAMPAIGN_USER_GENERATION_SUCCESS", key: "success" });
+ }
+ }, [data]);
+
+ const downloadUserCred = async () => {
+ downloadExcelWithCustomName(userCredential);
+ };
+
+ useEffect(() => {
+ if (data?.userGenerationSuccess?.length > 0) {
+ const fetchUser = async () => {
+ const responseTemp = await Digit.CustomService.getResponse({
+ url: `/project-factory/v1/data/_search`,
+ body: {
+ SearchCriteria: {
+ tenantId: tenantId,
+ id: data?.userGenerationSuccess,
+ },
+ },
+ });
+
+ const response = responseTemp?.ResourceDetails?.map((i) => i?.processedFilestoreId);
+
+ if (response?.[0]) {
+ setUserCredential({ fileStoreId: response?.[0], customName: "userCredential" });
+ }
+ };
+ fetchUser();
+ }
+ }, [data]);
+ return (
+ <>
+
+ {t("ES_TQM_SUMMARY_HEADING")}
+ {userCredential && (
+ }
+ type="button"
+ className="campaign-download-template-btn hover"
+ onButtonClick={downloadUserCred}
+ />
+ )}
+
+
+
+ {showToast && (
+
+ )}
+
+ >
+ );
+};
+
+export default CampaignSummary;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js
new file mode 100644
index 00000000000..a57ceb7008f
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js
@@ -0,0 +1,143 @@
+import React, { useState, useMemo, useRef, useEffect } from "react";
+import { UploadIcon, FileIcon, DeleteIconv2, Toast, Card, Header } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import { LabelFieldPair } from "@egovernments/digit-ui-react-components";
+import { Button, CardText, Dropdown, ErrorMessage, PopUp } from "@egovernments/digit-ui-components";
+
+const CampaignSelection = ({ onSelect, formData, formState, ...props }) => {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getStateId();
+ const { isLoading, data: projectType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-PROJECT-TYPES", [{ name: "projectTypes" }]);
+ const [type, setType] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType || {});
+ const [beneficiaryType, setBeneficiaryType] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType || "");
+ const [showBeneficiary, setShowBeneficiaryType] = useState(Boolean(props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType));
+ const [executionCount, setExecutionCount] = useState(0);
+ const [error, setError] = useState(null);
+ const [startValidation, setStartValidation] = useState(null);
+ const [showPopUp, setShowPopUp] = useState(null);
+ const [canUpdate, setCanUpdate] = useState(null);
+
+ useEffect(() => {
+ if (props?.props?.isSubmitting && !type) {
+ setError({ message: "CAMPAIGN_FIELD_MANDATORY" });
+ }
+ }, [props?.props?.isSubmitting]);
+ useEffect(() => {
+ setType(props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType);
+ setBeneficiaryType(props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType);
+ setShowBeneficiaryType(Boolean(props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType));
+ }, [props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType]);
+
+ const handleChange = (data) => {
+ setType(data);
+ setBeneficiaryType(data?.beneficiaryType);
+ setShowBeneficiaryType(true);
+ };
+
+ useEffect(() => {
+ if (!type && startValidation) {
+ setError({ message: "CAMPAIGN_FIELD_MANDATORY" });
+ } else {
+ setError(null);
+ onSelect("projectType", type);
+ }
+ }, [type]);
+
+ useEffect(() => {
+ if (executionCount < 5) {
+ onSelect("projectType", type);
+ setExecutionCount((prevCount) => prevCount + 1);
+ }
+ });
+ return (
+
+ {t(`HCM_CAMPAIGN_TYPE_HEADER`)}
+ {t(`HCM_CAMPAIGN_TYPE_DESCRIPTION`)}
+
+
+ {`${t("HCM_CAMPAIGN_TYPE")}`}
+ *
+
+ {
+ if (props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType && !canUpdate) {
+ setShowPopUp(true);
+ return;
+ }
+ return;
+ }}
+ onFocus={(e) => {
+ if (props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType && !canUpdate) {
+ setShowPopUp(true);
+ return;
+ }
+ return;
+ }}
+ >
+ {
+ setStartValidation(true);
+ handleChange(value);
+ }}
+ />
+ {error?.message && }
+
+
+ {showBeneficiary && (
+
+ {`${t("HCM_BENEFICIARY_TYPE")}`}
+ {t(`CAMPAIGN_TYPE_${beneficiaryType}`)}
+
+ )}
+ {showPopUp && (
+
+ {t("ES_CAMPAIGN_UPDATE_TYPE_MODAL_TEXT") + " "}
+ ,
+ ]}
+ onOverlayClick={() => {
+ setShowPopUp(false);
+ }}
+ footerChildren={[
+
+ )}
+
+ );
+};
+
+export default CampaignSelection;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js
new file mode 100644
index 00000000000..9faad7c4c2a
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js
@@ -0,0 +1,186 @@
+import { Card, LabelFieldPair, Row } from "@egovernments/digit-ui-react-components";
+import React, { Fragment, useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import DetailsTable from "./DetailsTable";
+import { Button, InfoCard } from "@egovernments/digit-ui-components";
+
+const Tabs = ({ deliveryData, onTabChange }) => {
+ // const { campaignData, dispatchCampaignData } = useContext(CycleContext);
+ const { t } = useTranslation();
+
+ return (
+
+ {deliveryData?.map((_, index) => (
+ onTabChange(_.deliveryIndex, index)}
+ >
+ {t(`CAMPAIGN_DELIVERY`)} {index + 1}
+
+ ))}
+
+ );
+};
+
+const CycleDataPreview = ({ data, items, index, errors, onErrorClick, cardErrors }) => {
+ const { t } = useTranslation();
+ const [deliveryData, setDeliveryData] = useState(data?.deliveries);
+ const [activeTab, setActiveTab] = useState(1);
+
+ useEffect(() => {
+ setDeliveryData(data?.deliveries);
+ }, [data?.deliveries]);
+
+ const handleTabChange = (tabIndex, index) => {
+ setDeliveryData((prev) => {
+ return prev.map((i) => {
+ if (i.deliveryIndex == tabIndex) {
+ return {
+ ...i,
+ active: true,
+ };
+ } else {
+ return {
+ ...i,
+ active: false,
+ };
+ }
+ });
+ });
+ };
+ // return null;
+ return (
+ <>
+ {cardErrors?.map((i) => (
+ ]}
+ />
+ ))}
+ {/* {i.error ? i.error : i.message)} */}
+
+ {data?.startDate && (
+
+ )}
+ {data?.endDate && (
+
+ )}
+
+
+
+
+
+
+ {deliveryData
+ .find((i) => i.active === true)
+ ?.deliveryRules?.map((rules, ruleIndex) => {
+ return (
+
+ {rules?.attributes?.length > 0 && (
+
+ )}
+ {rules?.products?.length > 0 && (
+
+ )}
+
+ );
+ })}
+
+ {/*
+ {item?.conditions?.length > 0 && (
+
+ )}
+ {item?.products?.length > 0 && (
+
+ )}
+ */}
+ >
+ );
+};
+
+export default CycleDataPreview;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js
new file mode 100644
index 00000000000..515b25191d9
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js
@@ -0,0 +1,143 @@
+import { Card, LabelFieldPair, Row } from "@egovernments/digit-ui-react-components";
+import React, { Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import DetailsTable from "./DetailsTable";
+
+function mergeObjects(item) {
+ const arr = item?.conditions;
+ const mergedArr = [];
+ const mergedAttributes = new Set();
+
+ arr.forEach((obj) => {
+ if (!mergedAttributes.has(obj.attribute)) {
+ const sameAttrObjs = arr.filter((o) => o.attribute === obj.attribute);
+
+ if (sameAttrObjs.length > 1) {
+ const fromValue = Math.min(...sameAttrObjs.map((o) => o.value));
+ const toValue = Math.max(...sameAttrObjs.map((o) => o.value));
+
+ mergedArr.push({
+ fromValue,
+ toValue,
+ value: fromValue > 0 && toValue > 0 ? `${fromValue} to ${toValue}` : null,
+ operator: "IN_BETWEEN",
+ attribute: obj.attribute,
+ });
+
+ mergedAttributes.add(obj.attribute);
+ } else {
+ mergedArr.push(obj);
+ }
+ }
+ });
+
+ return { ...item, conditions: mergedArr };
+}
+
+const CycleDetaisPreview = ({ data, items, index }) => {
+ const { t } = useTranslation();
+ const item = mergeObjects(items);
+
+ return (
+ <>
+
+
+ {/*
+ {`${t("CYCLE_NUMBER")}`}
+ {item?.cycleNumber}
+
+
+ {`${t("DELIVERY_NUMBER")}`}
+ {item?.deliveryNumber}
+ */}
+ {item?.startDate || item?.endDate ? (
+
+
+
+ {t(`CYCLE`)} {item?.cycleNumber}
+
+
+ {item?.startDate && (
+
+ )}
+ {item?.endDate && (
+
+ )}
+
+ ) : null}
+
+
+ {item?.conditions?.length > 0 && (
+
+ )}
+ {item?.products?.length > 0 && (
+
+ )}
+
+ >
+ );
+};
+
+export default CycleDetaisPreview;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js
new file mode 100644
index 00000000000..5c6e01fcc22
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js
@@ -0,0 +1,76 @@
+import React, { Fragment } from "react";
+import { useTable } from "react-table";
+import { useTranslation } from "react-i18next";
+import { CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components";
+
+const DetailsTable = ({ className = "", columnsData, rowsData, summaryRows, cardHeader }) => {
+ const { t } = useTranslation();
+
+ const columns = React.useMemo(() => columnsData, [t]);
+
+ const data = React.useMemo(() => {
+ const temp = rowsData.map((i) => ({
+ ...i,
+ operator: t(i?.operator),
+ attribute: i?.attribute ? t(`CAMPAIGN_ATTRIBUTE_${i?.attribute?.toUpperCase()}`) : "",
+ }));
+ return temp;
+ }, [rowsData]);
+
+ const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({
+ columns,
+ data,
+ });
+
+ return (
+ <>
+ {cardHeader && (
+
+ {cardHeader?.value}
+
+ )}
+
+
+
+ {headerGroups.map((headerGroup) => (
+
+ {headerGroup.headers.map((column) => (
+
+ {column.render("Header")}
+ |
+ ))}
+
+ ))}
+
+
+
+ {rows.map((row) => {
+ prepareRow(row);
+ return (
+
+ {row.cells.map((cell) => (
+
+ {cell.render("Cell")}
+ |
+ ))}
+
+ );
+ })}
+
+ {summaryRows && (
+
+ {summaryRows.map((cell, index) => (
+
+ {index === 4 ? {cell} : cell}
+ |
+ ))}
+
+ )}
+
+
+
+ >
+ );
+};
+
+export default DetailsTable;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js
new file mode 100644
index 00000000000..9b61bf67136
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js
@@ -0,0 +1,29 @@
+import React from "react";
+export const DocumentIcon = ({ styles = {}, className, fill = "#D4351C" }) => (
+
+);
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js
new file mode 100644
index 00000000000..89d7b574032
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js
@@ -0,0 +1,47 @@
+import React, { useState } from "react";
+
+const PlusMinusInput = (props, customProps) => {
+ let count = props?.defaultValues || 1;
+
+ function incrementCount() {
+ if (count >= 1) {
+ count = count + 1;
+ props.onSelect(count);
+ } else {
+ count = 1;
+ props.onSelect(count);
+ }
+ }
+ function decrementCount() {
+ if (count > 1) {
+ count = count - 1;
+ props.onSelect(count);
+ } else {
+ count = 1;
+ props.onSelect(count);
+ }
+ }
+
+ return (
+
+
+ decrementCount(count)} className="PlusMinusbutton">
+ -
+
+
+ incrementCount(count)} className="PlusMinusbutton">
+ +
+
+
+
+ );
+};
+
+export default PlusMinusInput;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js
new file mode 100644
index 00000000000..b04159181a6
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js
@@ -0,0 +1,16 @@
+import React from "react";
+import { Close } from "@egovernments/digit-ui-react-components";
+
+const RemoveableTagNew = ({ text = {}, onClick, extraStyles, disabled = false }) => (
+
+ {text?.label && {`${text?.label} :`}}
+
+ {text?.value}
+
+
+
+
+
+);
+
+export default RemoveableTagNew;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js
new file mode 100644
index 00000000000..239cf948ee0
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js
@@ -0,0 +1,542 @@
+import React, { useEffect, useState, Fragment, useMemo } from "react";
+import { CardText, LabelFieldPair, Card, Header, CardLabel, LoaderWithGap } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import { InfoCard, MultiSelectDropdown, PopUp, Button, Toast } from "@egovernments/digit-ui-components";
+import { mailConfig } from "../configs/mailConfig";
+/**
+ * The function `SelectingBoundaries` in JavaScript handles the selection of boundaries based on
+ * hierarchy data and allows users to choose specific boundaries within the hierarchy.
+ * @returns The `SelectingBoundaries` component is being returned. It consists of JSX elements
+ * including Cards, Headers, Dropdowns, MultiSelectDropdowns, and InfoCard. The component allows users
+ * to select hierarchy types and boundaries based on the data fetched from API calls. It also handles
+ * the selection of boundaries and updates the state accordingly. The component is designed to be
+ * interactive and user-friendly for selecting boundaries within
+ */
+function SelectingBoundaries({ onSelect, formData, ...props }) {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const [params, setParams] = useState(props?.props?.dataParams);
+ const [hierarchy, setHierarchy] = useState(params?.hierarchyType);
+ const [boundaryType, setBoundaryType] = useState(
+ props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData ? undefined : null
+ );
+ const [targetedData, setTargetedData] = useState();
+ const [boundaryData, setBoundaryData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || {});
+ // const [parentArray, setParentArray] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData.filter(item => item.includeAllChildren).map(item => item.code) || null);
+ const [parentArray, setParentArray] = useState(null);
+ const [boundaryTypeDataresult, setBoundaryTypeDataresult] = useState(null);
+ const [selectedData, setSelectedData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData || []);
+ const [parentBoundaryTypeRoot, setParentBoundaryTypeRoot] = useState(
+ (props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData?.find((item) => item?.isRoot === true) || {})
+ ?.boundaryType || null
+ );
+ const [showToast, setShowToast] = useState(null);
+ const [updatedHierarchy, setUpdatedHierarchy] = useState({});
+ const [hierarchyTypeDataresult, setHierarchyTypeDataresult] = useState(params?.hierarchy);
+ const [executionCount, setExecutionCount] = useState(0);
+ // State variable to store the lowest hierarchy level
+ // const [lowestHierarchy, setLowestHierarchy] = useState(null);
+ const [showPopUp, setShowPopUp] = useState(null);
+ const [restrictSelection, setRestrictSelection] = useState(null);
+ const [updateBoundary, setUpdateBoundary] = useState(null);
+ const [loaderEnabled, setLoaderEnabled] = useState(false);
+ const { isLoading, data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]);
+
+ // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy;
+ const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]);
+ const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item) => item.parentBoundaryType === lowestHierarchy)?.[0]?.boundaryType;
+ const searchParams = new URLSearchParams(location.search);
+ const isDraft = searchParams.get("draft");
+
+ useEffect(() => {
+ if (!updateBoundary) {
+ if (
+ props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 ||
+ props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 ||
+ props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0
+ ) {
+ setRestrictSelection(true);
+ }
+ }
+ }, [props?.props?.sessionData, updateBoundary]);
+
+ useEffect(() => {
+ if (props?.props?.dataParams) {
+ setParams(props?.props?.dataParams);
+ }
+ }, [props?.props?.dataParams]);
+
+ useEffect(() => {
+ onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary });
+ }, [boundaryData, selectedData]);
+
+ useEffect(() => {
+ setHierarchy(params?.hierarchyType);
+ }, [params?.hierarchyType]);
+
+ useEffect(() => {
+ if (params?.hierarchy) {
+ const sortHierarchy = (hierarchy) => {
+ const boundaryMap = new Map();
+ hierarchy.forEach(item => {
+ boundaryMap.set(item.boundaryType, item);
+ });
+
+ const sortedHierarchy = [];
+ let currentType = null;
+
+ while (sortedHierarchy.length < hierarchy.length) {
+ for (let i = 0; i < hierarchy.length; i++) {
+ if (hierarchy[i].parentBoundaryType === currentType) {
+ sortedHierarchy.push(hierarchy[i]);
+ currentType = hierarchy[i].boundaryType;
+ break;
+ }
+ }
+ }
+
+ return sortedHierarchy;
+ };
+
+ const sortedHierarchy = sortHierarchy(params.hierarchy.boundaryHierarchy);
+ setHierarchyTypeDataresult({
+ ...params.hierarchy,
+ boundaryHierarchy: sortedHierarchy
+ });
+ }
+ }, [params?.hierarchy]);
+
+ useEffect(() => {
+ if (executionCount < 5) {
+ onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary });
+ setExecutionCount((prevCount) => prevCount + 1);
+ }
+ });
+
+ useEffect(() => {
+ setBoundaryData(
+ props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData
+ ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData
+ : {}
+ );
+ setSelectedData(
+ props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData
+ ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData
+ : []
+ );
+ }, [props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType]);
+
+ const closeToast = () => {
+ setShowToast(null);
+ };
+
+ useEffect(() => {
+ if (hierarchyTypeDataresult) {
+ const boundaryDataObj = {};
+ hierarchyTypeDataresult?.boundaryHierarchy?.forEach((boundary) => {
+ boundaryDataObj[boundary?.boundaryType] = [];
+ });
+ if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) {
+ setBoundaryData(boundaryDataObj);
+ }
+ const boundaryWithTypeNullParent = hierarchyTypeDataresult?.boundaryHierarchy?.find((boundary) => boundary?.parentBoundaryType === null);
+ // Set the boundary type with null parentBoundaryType
+ if (boundaryWithTypeNullParent) {
+ if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) {
+ setBoundaryType(boundaryWithTypeNullParent?.boundaryType);
+ }
+ setParentBoundaryTypeRoot(boundaryWithTypeNullParent?.boundaryType);
+ }
+ createHierarchyStructure(hierarchyTypeDataresult);
+ }
+ }, [hierarchyTypeDataresult]);
+
+ function createHierarchyStructure(hierarchyTypeDataresult) {
+ const hierarchyStructure = {};
+
+ // Recursive function to gather all descendants for a given boundary type
+ function gatherDescendants(boundaryType) {
+ const descendants = [];
+ hierarchyTypeDataresult;
+
+ // Find all children for the current boundary type
+ const children = hierarchyTypeDataresult?.boundaryHierarchy?.filter((item) => item?.parentBoundaryType === boundaryType);
+
+ // Recursively gather descendants for each child
+ children.forEach((child) => {
+ const childBoundaryType = child?.boundaryType;
+ const childDescendants = gatherDescendants(childBoundaryType);
+ descendants.push(childBoundaryType, ...childDescendants);
+ });
+
+ return descendants;
+ }
+
+ // Iterate through the boundaryHierarchy array to populate hierarchyStructure
+ hierarchyTypeDataresult?.boundaryHierarchy?.forEach((item) => {
+ const boundaryType = item?.boundaryType;
+ const descendants = gatherDescendants(boundaryType);
+
+ hierarchyStructure[boundaryType] = descendants;
+ });
+
+ setUpdatedHierarchy(hierarchyStructure);
+ }
+
+ const newData = [];
+ const fetchBoundaryTypeData = async () => {
+ if (boundaryType === undefined || boundaryType === lowestChild) {
+ // Do nothing if boundaryType is undefined
+ return;
+ }
+ if (parentArray === null) {
+ const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({
+ url: "/boundary-service/boundary-relationships/_search",
+ params: {
+ tenantId: tenantId,
+ hierarchyType: hierarchy,
+ boundaryType: boundaryType,
+ parent: null,
+ },
+ body: {},
+ });
+ // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") });
+ const boundaryTypeData = await reqCriteriaBoundaryTypeSearch;
+ setBoundaryTypeDataresult([{ parentCode: null, boundaryTypeData: boundaryTypeData }]);
+ // closeToast();
+ } else {
+ // for (const parentCode of parentArray) {
+ // const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({
+ // url: "/boundary-service/boundary-relationships/_search",
+ // params: {
+ // tenantId: tenantId,
+ // hierarchyType: hierarchy,
+ // boundaryType: boundaryType,
+ // parent: parentCode,
+ // },
+ // body: {},
+ // });
+ // // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") });
+ // setLoaderEnabled(true);
+ // const boundaryTypeData = await reqCriteriaBoundaryTypeSearch;
+ // newData.push({ parentCode, boundaryTypeData });
+ // }
+ setLoaderEnabled(true);
+ const temp = await Digit.Hooks.campaign.useParallelSearch({
+ parentArray: parentArray,
+ tenantId: tenantId,
+ boundaryType: boundaryType,
+ hierarchy: hierarchy,
+ targetedData: targetedData,
+ });
+ const newDataArray = [...newData, ...temp];
+ setBoundaryTypeDataresult(newDataArray);
+ setTimeout(() => {
+ setLoaderEnabled(false);
+ }, 100);
+ // closeToast();
+ }
+ };
+
+ useEffect(() => {
+ fetchBoundaryTypeData();
+ }, [boundaryType, parentArray, selectedData]);
+
+ useEffect(() => {
+ if (boundaryTypeDataresult) {
+ if (boundaryType !== undefined) {
+ const updatedBoundaryData = {
+ ...boundaryData,
+ [boundaryType]: boundaryTypeDataresult,
+ };
+ setBoundaryData(updatedBoundaryData);
+ } else {
+ const updatedBoundaryData = {
+ ...boundaryData,
+ [boundaryTypeDataresult?.[0]?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.[0]?.boundaryType]: boundaryTypeDataresult,
+ };
+ setBoundaryData(updatedBoundaryData);
+ }
+ }
+ }, [boundaryTypeDataresult]);
+
+ const checkDataPresent = ({ action }) => {
+ if (action === false) {
+ setShowPopUp(false);
+ setUpdateBoundary(true);
+ setRestrictSelection(false);
+ return;
+ }
+ if (action === true) {
+ setShowPopUp(false);
+ setUpdateBoundary(false);
+ return;
+ }
+ };
+
+ const handleBoundaryChange = (data, boundary) => {
+ setTargetedData(boundary?.boundaryType);
+ if (
+ !updateBoundary &&
+ restrictSelection &&
+ (props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 ||
+ props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 ||
+ props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0)
+ ) {
+ setShowPopUp(true);
+ return;
+ }
+ if (!data || data.length === 0) {
+ const check = updatedHierarchy[boundary?.boundaryType];
+
+ if (check) {
+ const typesToRemove = [boundary?.boundaryType, ...check];
+ const updatedSelectedData = selectedData?.filter((item) => !typesToRemove?.includes(item?.type));
+ const updatedBoundaryData = { ...boundaryData };
+
+ typesToRemove.forEach((type) => {
+ if (type !== boundary?.boundaryType && updatedBoundaryData?.hasOwnProperty(type)) {
+ updatedBoundaryData[type] = [];
+ }
+ });
+ if (!_.isEqual(selectedData, updatedSelectedData)) {
+ setSelectedData(updatedSelectedData);
+ }
+ setBoundaryData(updatedBoundaryData);
+ }
+ return;
+ }
+
+ let res = [];
+ data &&
+ data?.map((ob) => {
+ res.push(ob?.[1]);
+ });
+
+ // const transformedRes = res?.map((item) => ({
+ // code: item.code,
+ // type: item.type || item.boundaryType,
+ // isRoot: item.boundaryType === parentBoundaryTypeRoot,
+ // includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy,
+ // parent: item?.parent,
+ // }));
+
+ let transformedRes = [];
+ if (!isDraft) {
+ transformedRes = res?.map((item) => ({
+ code: item.code,
+ type: item.type || item.boundaryType,
+ isRoot: item.boundaryType === parentBoundaryTypeRoot,
+ includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy,
+ parent: item?.parent,
+ }));
+ } else {
+ // transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType)
+ const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType);
+ if (filteredData.length === 0) {
+ // If no selected data for the particular boundary type, run the transformation logic
+ transformedRes = res?.map((item) => ({
+ code: item.code,
+ type: item.type || item.boundaryType,
+ isRoot: item.boundaryType === parentBoundaryTypeRoot,
+ includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy,
+ parent: item?.parent,
+ }));
+ } else {
+ transformedRes = filteredData;
+ }
+ }
+
+ const newBoundaryType = transformedRes?.[0]?.type;
+ const existingBoundaryType = selectedData?.length > 0 ? selectedData?.[0]?.type : null;
+ if (existingBoundaryType === newBoundaryType) {
+ // Update only the data for the specific boundaryType
+ const flattenedRes = transformedRes.flat();
+ const updatedSelectedData = selectedData
+ ?.map((item) => {
+ if (item.type === newBoundaryType) {
+ return transformedRes?.flat();
+ } else {
+ return item;
+ }
+ })
+ .flat();
+ if (!_.isEqual(selectedData, updatedSelectedData)) {
+ setSelectedData(updatedSelectedData);
+ }
+ } else {
+ // Update only the data for the new boundaryType
+ const mergedData = [...selectedData?.filter((item) => item?.type !== newBoundaryType), ...transformedRes];
+
+ // Filter out items with undefined type
+ const filteredData = mergedData?.filter(
+ (item, index, self) => item?.type !== undefined && index === self?.findIndex((t) => t?.code === item?.code)
+ );
+
+ // Filter out items whose parent is not present in the array
+
+ const updatedSelectedData = [];
+ const addChildren = (item) => {
+ updatedSelectedData.push(item);
+ const children = filteredData.filter((child) => child.parent === item.code);
+ children.forEach((child) => addChildren(child));
+ };
+ filteredData.filter((item) => item.isRoot).forEach((rootItem) => addChildren(rootItem));
+ if (!_.isEqual(selectedData, updatedSelectedData)) {
+ setSelectedData(updatedSelectedData);
+ }
+ }
+ const parentBoundaryEntry = hierarchyTypeDataresult
+ ? hierarchyTypeDataresult?.boundaryHierarchy?.find(
+ (e) => e?.parentBoundaryType === res?.[0]?.boundaryType || e?.parentBoundaryType === res?.[0]?.type
+ )
+ : null;
+ setBoundaryType(parentBoundaryEntry?.boundaryType);
+ const codes = res?.map((item) => item?.code);
+ if (JSON.stringify(codes) !== JSON.stringify(parentArray)) {
+ setParentArray(codes);
+ }
+ };
+
+ return (
+ <>
+ {loaderEnabled && }
+
+
+
{t(`CAMPAIGN_SELECT_BOUNDARY`)}
+
{t(`CAMPAIGN_SELECT_BOUNDARIES_DESCRIPTION`)}
+ {hierarchyTypeDataresult?.boundaryHierarchy
+ .filter((boundary, index, array) => {
+ // Find the index of the lowest hierarchy
+ const lowestIndex = array.findIndex((b) => b.boundaryType === lowestHierarchy);
+ // Include only those boundaries that are above or equal to the lowest hierarchy
+ return index <= lowestIndex;
+ })
+ .map((boundary, index) =>
+ boundary?.parentBoundaryType == null ? (
+
+
+ {/* {t(`${hierarchy}_${boundary?.boundaryType}`?.toUpperCase())} */}
+ {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())}
+
+ *
+
+
+ item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary)?.flat() || []
+ }
+ optionsKey={"code"}
+ selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []}
+ onSelect={(value) => {
+ handleBoundaryChange(value, boundary);
+ }}
+ />
+
+
+ ) : (
+
+
+ {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())}
+ *
+
+
+ ({
+ code: item?.parentCode,
+ options:
+ item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.map((child) => ({
+ code: child?.code,
+ type: child?.boundaryType,
+ parent: item?.parentCode,
+ })) || [],
+ })) || []
+ }
+ optionsKey={"code"}
+ onSelect={(value) => {
+ handleBoundaryChange(value, boundary);
+ }}
+ selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []}
+ addCategorySelectAllCheck={true}
+ addSelectAllCheck={true}
+ variant="nestedmultiselect"
+ />
+
+
+ )
+ )}
+
+
+
+ {t("HCM_BOUNDARY_INFO ")}
+
+ {mailConfig?.mailId}
+
+ ,
+ ]}
+ label={"Info"}
+ />
+ {showPopUp && (
+
+ {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_TEXT") + " "}
+ ,
+ ]}
+ onOverlayClick={() => {
+ setShowPopUp(false);
+ }}
+ footerChildren={[
+ {
+ checkDataPresent({ action: false });
+ }}
+ />,
+ {
+ checkDataPresent({ action: true });
+ }}
+ />,
+ ]}
+ sortFooterChildren={true}
+ >
+ )}
+ {showToast && (
+
+ )}
+ >
+ );
+}
+export default SelectingBoundaries;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js
new file mode 100644
index 00000000000..8e4f6062d86
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js
@@ -0,0 +1,46 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { TickMark } from "@egovernments/digit-ui-react-components";
+
+let actions = [];
+
+const getAction = (flow) => {
+ switch (flow) {
+ case "STAKEHOLDER":
+ actions = ["BPA_LICENSE_DETAILS_LABEL", "BPA_NEW_ADDRESS_HEADER_DETAILS", "BPA_DOC_DETAILS_SUMMARY", "BPA_STEPPER_SUMMARY_HEADER"];
+ break;
+ case "OCBPA":
+ actions = ["BPA_BASIC_AND_PLOT_DETAILS_LABEL", "BPA_SCRUTINY_DETAILS", "BPA_DOCUMENT_AND_NOC_DETAILS_LABEL", "BPA_STEPPER_SUMMARY_HEADER"];
+ break;
+ default:
+ actions = [
+ "HCM_CAMPAIGN_SETUP_DETAILS",
+ "HCM_DELIVERY_DETAILS",
+ "HCM_BOUNDARY_DETAILS",
+ "HCM_TARGETS",
+ "HCM_FACILITY_DETAILS",
+ "HCM_USER_DETAILS",
+ "HCM_REVIEW_DETAILS",
+ ];
+ }
+};
+const TimelineCampaign = ({ currentStep = 1, flow = "" , onStepClick }) => {
+ const { t } = useTranslation();
+ const isMobile = window.Digit.Utils.browser.isMobile();
+ getAction(flow);
+ return (
+
+ {actions.map((action, index, arr) => (
+
onStepClick(index)}>
+
+ {index < currentStep - 1 ? : index + 1}
+ {t(action)}
+
+ {index < arr.length - 1 &&
}
+
+ ))}
+
+ );
+};
+
+export default TimelineCampaign;
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js
new file mode 100644
index 00000000000..09cb1a0f9c0
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js
@@ -0,0 +1,1163 @@
+import { Header, LoaderWithGap } from "@egovernments/digit-ui-react-components";
+import React, { useRef, useState, useEffect, Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import { Card, Modal, CardText } from "@egovernments/digit-ui-react-components";
+import BulkUpload from "./BulkUpload";
+import Ajv from "ajv";
+import XLSX from "xlsx";
+import { InfoCard, PopUp, Toast, Button, DownloadIcon } from "@egovernments/digit-ui-components";
+import { schemaConfig } from "../configs/schemaConfig";
+import { headerConfig } from "../configs/headerConfig";
+import { PRIMARY_COLOR } from "../utils";
+import { downloadExcelWithCustomName } from "../utils";
+
+/**
+ * The `UploadData` function in JavaScript handles the uploading, validation, and management of files
+ * for different types of data in a web application.
+ * @returns The `UploadData` component is returning a JSX structure that includes a div with class
+ * names, a Header component, a Button component for downloading a template, an info-text div, a
+ * BulkUpload component for handling file uploads, and an InfoCard component for displaying error
+ * messages if any validation errors occur during file upload.
+ */
+const UploadData = ({ formData, onSelect, ...props }) => {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const [uploadedFile, setUploadedFile] = useState([]);
+ const params = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_UPLOAD_ID");
+ const [showInfoCard, setShowInfoCard] = useState(false);
+ const [errorsType, setErrorsType] = useState({});
+ const [schema, setSchema] = useState(null);
+ const [showToast, setShowToast] = useState(null);
+ const type = props?.props?.type;
+ const [executionCount, setExecutionCount] = useState(0);
+ const [isError, setIsError] = useState(false);
+ const [isSuccess, setIsSuccess] = useState(false);
+ const [apiError, setApiError] = useState(null);
+ const [isValidation, setIsValidation] = useState(false);
+ const [fileName, setFileName] = useState(null);
+ const [downloadError, setDownloadError] = useState(false);
+ const [resourceId, setResourceId] = useState(null);
+ const searchParams = new URLSearchParams(location.search);
+ const id = searchParams.get("id");
+ // const { isLoading, data: Schemas } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [
+ // { name: "facilitySchema" },
+ // { name: "userSchema" },
+ // { name: "Boundary" },
+ // ]);
+
+ const { data: Schemas, isLoading: isThisLoading } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "adminSchema" }]);
+
+ const { data: readMe } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "ReadMeConfig" }]);
+ const { data: baseTimeOut } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "baseTimeout" }]);
+ const [sheetHeaders, setSheetHeaders] = useState({});
+ const [translatedSchema, setTranslatedSchema] = useState({});
+ const [readMeInfo, setReadMeInfo] = useState({});
+ const [enabled, setEnabled] = useState(false);
+ const [showPopUp, setShowPopUp] = useState(true);
+ const currentKey = searchParams.get("key");
+ const totalData = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ const [convertedSchema, setConvertedSchema] = useState({});
+ const [loader, setLoader] = useState(false);
+
+
+ useEffect(() => {
+ if (type === "facilityWithBoundary") {
+ onSelect("uploadFacility", { uploadedFile, isError, isValidation, apiError, isSuccess });
+ } else if (type === "boundary") {
+ onSelect("uploadBoundary", { uploadedFile, isError, isValidation, apiError, isSuccess });
+ } else {
+ onSelect("uploadUser", { uploadedFile, isError, isValidation, apiError, isSuccess });
+ }
+ }, [uploadedFile, isError, isValidation, apiError, isSuccess]);
+
+ useEffect(() => {
+ if (resourceId) {
+ setUploadedFile((prev) =>
+ prev.map((i) => ({
+ ...i,
+ resourceId: resourceId,
+ }))
+ );
+ }
+ }, [resourceId]);
+ var translateSchema = (schema) => {
+ var newSchema = { ...schema };
+ var newProp = {};
+
+ // Object.keys(schema?.properties)
+ // .map((e) => ({ key: e, value: t(e) }))
+ // .map((e) => {
+ // newProp[e.value] = schema?.properties[e.key];
+ // });
+
+ // Translate properties keys and their 'name' fields
+ Object.keys(schema?.properties).forEach((key) => {
+ const translatedKey = t(key);
+ const translatedProperty = { ...schema.properties[key], name: t(schema.properties[key].name) };
+ newProp[translatedKey] = translatedProperty;
+ });
+ const newRequired = schema?.required.map((e) => t(e));
+
+ newSchema.properties = newProp;
+ newSchema.required = newRequired;
+ delete newSchema.unique;
+ return { ...newSchema };
+ };
+
+ var translateReadMeInfo = (schema) => {
+ const translatedSchema = schema.map((item) => {
+ return {
+ header: t(item.header),
+ isHeaderBold: item.isHeaderBold,
+ inSheet: item.inSheet,
+ inUiInfo: item.inUiInfo,
+ descriptions: item.descriptions.map((desc) => {
+ return {
+ text: t(desc.text),
+ isStepRequired: desc.isStepRequired,
+ };
+ }),
+ };
+ });
+ return translatedSchema;
+ };
+
+ function enrichSchema(data, properties, required, columns) {
+ // Sort columns based on orderNumber, using name as tie-breaker if orderNumbers are equal
+ columns.sort((a, b) => {
+ if (a?.orderNumber === b?.orderNumber) {
+ return a.name.localeCompare(b.name);
+ }
+ return a.orderNumber - b.orderNumber;
+ });
+
+ // Extract sorted property names
+ const sortedPropertyNames = columns.map((column) => column.name);
+
+ // Update data with new properties and required fields
+ data.properties = properties;
+ data.required = required;
+ // delete data.campaignType;
+ // data.columns = sortedPropertyNames;
+ }
+
+ function convertIntoSchema(data) {
+ var convertData = { ...data };
+ var properties = {};
+ var required = [];
+ var columns = [];
+
+ for (const propType of ["enumProperties", "numberProperties", "stringProperties"]) {
+ if (convertData?.properties[propType] && Array.isArray(convertData?.properties[propType]) && convertData?.properties[propType]?.length > 0) {
+ for (const property of convertData?.properties[propType]) {
+ properties[property?.name] = {
+ ...property,
+ type: propType === "stringProperties" ? "string" : propType === "numberProperties" ? "number" : undefined,
+ };
+
+ if (property?.isRequired && required.indexOf(property?.name) === -1) {
+ required.push(property?.name);
+ }
+
+ // If orderNumber is missing, default to a very high number
+ columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 });
+ }
+ }
+ }
+ enrichSchema(convertData, properties, required, columns);
+ const newData = JSON.parse(JSON.stringify(convertData));
+ delete newData.campaignType;
+ return newData;
+ }
+
+ useEffect(() => {
+ if (uploadedFile.length == 0) {
+ setErrorsType({});
+ }
+ }, [uploadedFile]);
+
+ useEffect(async () => {
+ if (Schemas?.["HCM-ADMIN-CONSOLE"]?.adminSchema) {
+ const facility = await convertIntoSchema(Schemas?.["HCM-ADMIN-CONSOLE"]?.adminSchema?.filter((item) => item.title === "facility")?.[0]);
+ const boundary = await convertIntoSchema(
+ Schemas?.["HCM-ADMIN-CONSOLE"]?.adminSchema?.filter(
+ (item) => item.title === "boundaryWithTarget" && item.campaignType === totalData?.HCM_CAMPAIGN_TYPE?.projectType?.code
+ )?.[0]
+ );
+ const user = await convertIntoSchema(Schemas?.["HCM-ADMIN-CONSOLE"]?.adminSchema?.filter((item) => item.title === "user")?.[0]);
+ const schema = {
+ boundary: boundary,
+ facilityWithBoundary: facility,
+ userWithBoundary: user,
+ };
+
+ setConvertedSchema(schema);
+ }
+ }, [Schemas?.["HCM-ADMIN-CONSOLE"]?.adminSchema, type]);
+
+ useEffect(async () => {
+ if (convertedSchema && Object.keys(convertedSchema).length > 0) {
+ const newFacilitySchema = await translateSchema(convertedSchema?.facilityWithBoundary);
+ const newBoundarySchema = await translateSchema(convertedSchema?.boundary);
+ const newUserSchema = await translateSchema(convertedSchema?.userWithBoundary);
+ const headers = {
+ boundary: Object?.keys(newBoundarySchema?.properties),
+ facilityWithBoundary: Object?.keys(newFacilitySchema?.properties),
+ userWithBoundary: Object?.keys(newUserSchema?.properties),
+ };
+
+ const schema = {
+ boundary: newBoundarySchema,
+ facilityWithBoundary: newFacilitySchema,
+ userWithBoundary: newUserSchema,
+ };
+
+ setSheetHeaders(headers);
+ setTranslatedSchema(schema);
+ }
+ }, [convertedSchema]);
+
+ useEffect(async () => {
+ if (readMe?.["HCM-ADMIN-CONSOLE"]) {
+ const newReadMeFacility = await translateReadMeInfo(
+ readMe?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig?.filter((item) => item.type === type)?.[0]?.texts
+ );
+ const newReadMeUser = await translateReadMeInfo(readMe?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig?.filter((item) => item.type === type)?.[0]?.texts);
+ const newReadMeboundary = await translateReadMeInfo(
+ readMe?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig?.filter((item) => item.type === type)?.[0]?.texts
+ );
+
+ const readMeText = {
+ boundary: newReadMeboundary,
+ facilityWithBoundary: newReadMeFacility,
+ userWithBoundary: newReadMeUser,
+ };
+
+ setReadMeInfo(readMeText);
+ }
+ }, [readMe?.["HCM-ADMIN-CONSOLE"], type]);
+
+ useEffect(() => {
+ if (executionCount < 5) {
+ let uploadType = "uploadUser";
+ if (type === "boundary") {
+ uploadType = "uploadBoundary";
+ } else if (type === "facilityWithBoundary") {
+ uploadType = "uploadFacility";
+ }
+ onSelect(uploadType, { uploadedFile, isError, isValidation: false, apiError: false, isSuccess: uploadedFile?.length > 0 });
+ setExecutionCount((prevCount) => prevCount + 1);
+ }
+ });
+
+ useEffect(() => {
+ switch (type) {
+ case "boundary":
+ setUploadedFile(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile || []);
+ setApiError(null);
+ setIsValidation(false);
+ setDownloadError(false);
+ setIsError(false);
+ setIsSuccess(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.isSuccess || null);
+ setShowPopUp(!props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile.length);
+ break;
+ case "facilityWithBoundary":
+ setUploadedFile(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile || []);
+ setApiError(null);
+ setIsValidation(false);
+ setDownloadError(false);
+ setIsError(false);
+ setIsSuccess(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.isSuccess || null);
+ setShowPopUp(!props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile.length);
+ break;
+ default:
+ setUploadedFile(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile || []);
+ setApiError(null);
+ setIsValidation(false);
+ setDownloadError(false);
+ setIsError(false);
+ setIsSuccess(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.isSuccess || null);
+ setShowPopUp(!props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile.length);
+ break;
+ }
+ }, [type, props?.props?.sessionData]);
+
+ useEffect(() => {
+ if (errorsType[type]) {
+ setShowInfoCard(true);
+ } else {
+ setShowInfoCard(false);
+ }
+ }, [type, errorsType]);
+
+ const validateData = (data) => {
+ const ajv = new Ajv({ strict: false }); // Initialize Ajv
+ let validate = ajv.compile(translatedSchema[type]);
+ const errors = []; // Array to hold validation errors
+
+ data.forEach((item, index) => {
+ if (!validate(item)) {
+ errors.push({ index: (item?.["!row#number!"] || item?.["__rowNum__"]) + 1, errors: validate.errors });
+ }
+ });
+
+ if (errors.length > 0) {
+ const errorMessage = errors
+ .map(({ index, errors }) => {
+ const formattedErrors = errors
+ .map((error) => {
+ let instancePath = error.instancePath || ""; // Assign an empty string if dataPath is not available
+ if (instancePath.startsWith("/")) {
+ instancePath = instancePath.slice(1);
+ }
+ if (error.keyword === "required") {
+ const missingProperty = error.params?.missingProperty || "";
+ return `${t("HCM_DATA_AT_ROW")} ${index} ${t("HCM_IN_COLUMN")} '${missingProperty}' ${t("HCM_DATA_SHOULD_NOT_BE_EMPTY")}`;
+ }
+ if(error.keyword === "type" && error.message === "must be string"){
+ return `${t("HCM_DATA_AT_ROW")} ${index} ${t("HCM_IN_COLUMN")} ${instancePath} ${t("HCM_IS_INVALID")}`
+ }
+ let formattedError = `${t("HCM_IN_COLUMN")} '${instancePath}' ${error.message}`;
+ if (error.keyword === "enum" && error.params && error.params.allowedValues) {
+ formattedError += `${t("HCM_DATA_ALLOWED_VALUES_ARE")} ${error.params.allowedValues.join("/ ")}`;
+ }
+ return `${t("HCM_DATA_AT_ROW")} ${index} ${formattedError}`;
+ })
+ .join(", ");
+ return formattedErrors;
+ })
+ .join(", ");
+
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return false;
+ } else {
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: "", // Clear the error message
+ }));
+ setShowInfoCard(false);
+ return true;
+ }
+ };
+
+ const validateTarget = (jsonData, headersToValidate) => {
+ const boundaryCodeIndex = headersToValidate.indexOf(t("HCM_ADMIN_CONSOLE_BOUNDARY_CODE"));
+ const headersBeforeBoundaryCode = headersToValidate.slice(0, boundaryCodeIndex);
+
+ const filteredData = jsonData
+ .filter((e) => {
+ if (e[headersBeforeBoundaryCode[headersBeforeBoundaryCode.length - 1]]) {
+ return true;
+ }
+ })
+ .filter((e) => e[t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")]);
+
+ if (filteredData.length == 0) {
+ const errorMessage = t("HCM_MISSING_TARGET");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return false;
+ }
+
+ const targetValue = filteredData?.[0][t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")];
+
+ if (targetValue <= 0 || targetValue >= 100000000) {
+ const errorMessage = t("HCM_TARGET_VALIDATION_ERROR");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return false;
+ }
+ return true;
+ };
+
+ const validateTargetData = (data, sheetName, targetError) => {
+ const ajv = new Ajv({ strict: false }); // Initialize Ajv
+ let validate = ajv.compile(translatedSchema[type]);
+ const errors = []; // Array to hold validation errors
+
+
+ data.forEach((item, index) => {
+ if (!validate(item)) {
+ errors.push({ index: (item?.["!row#number!"] || item?.["__rowNum__"]) + 1, errors: validate.errors });
+ }
+ });
+
+ // if (errors.length > 0) {
+ // const errorMessage = errors
+ // .map(({ index, errors }) => {
+ // const formattedErrors = errors.map((error) => {
+
+ // let formattedError = `${error.instancePath}: ${error.message}`;
+ // if (error.keyword === "enum" && error.params && error.params.allowedValues) {
+ // formattedError += `. Allowed values are: ${error.params.allowedValues.join("/ ")}`;
+ // }
+ // return formattedError;
+ // })
+ // .join(", ");
+ // return `Data at row ${index}: ${formattedErrors} at ${sheetName}`;
+ // })
+ // .join(" , ");
+ // setIsError(true);
+ // targetError.push(errorMessage);
+ // return false;
+ // } else {
+ // return true;
+ // }
+
+ if (errors.length > 0) {
+ const errorMessage = errors
+ .map(({ index, errors }) => {
+ const formattedErrors = errors
+ .map((error) => {
+ let instancePath = error.instancePath || ""; // Assign an empty string if dataPath is not available
+ if (instancePath.startsWith("/")) {
+ instancePath = instancePath.slice(1);
+ }
+ if (error.keyword === "required") {
+ const missingProperty = error.params?.missingProperty || "";
+ return `${t("HCM_DATA_AT_ROW")} ${index} ${t("HCM_IN_COLUMN")} '${missingProperty}' ${t("HCM_DATA_SHOULD_NOT_BE_EMPTY")} at ${sheetName}`;
+ }
+ if(error.keyword === "type" && error.message === "must be string"){
+ return `${t("HCM_DATA_AT_ROW")} ${index} ${t("HCM_IN_COLUMN")} ${instancePath} ${t("HCM_IS_INVALID")} at ${sheetName}`
+ }
+ let formattedError = `${t("HCM_IN_COLUMN")} '${instancePath}' ${error.message}`;
+ if (error.keyword === "enum" && error.params && error.params.allowedValues) {
+ formattedError += `${t("HCM_DATA_ALLOWED_VALUES_ARE")} ${error.params.allowedValues.join("/ ")}`;
+ }
+ return `${t("HCM_DATA_AT_ROW")} ${index} ${formattedError} at ${sheetName}`;
+ })
+ .join(", ");
+ return formattedErrors;
+ })
+ .join(", ");
+
+
+ setIsError(true);
+ targetError.push(errorMessage);
+ return false;
+ }else{
+ return true;
+ }
+ };
+ // Function to compare arrays for equality
+ const arraysEqual = (arr1, arr2) => {
+ if (arr1.length !== arr2.length) return false;
+ for (let i = 0; i < arr1.length; i++) {
+ if (arr1[i] !== arr2[i]) return false;
+ }
+ return true;
+ };
+
+ const validateMultipleTargets = (workbook) => {
+ let isValid = true;
+ const sheet = workbook.Sheets[workbook.SheetNames[2]];
+ const mdmsHeaders = sheetHeaders[type];
+ const expectedHeaders = XLSX.utils.sheet_to_json(sheet, {
+ header: 1,
+ })[0];
+
+
+ for (const header of mdmsHeaders) {
+ if (!expectedHeaders.includes(t(header))) {
+ const errorMessage = t("HCM_MISSING_HEADERS");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ isValid = false;
+ break;
+ }
+ }
+
+ if (!isValid) return isValid;
+
+ for (let i = 2; i < workbook.SheetNames.length; i++) {
+ const sheetName = workbook?.SheetNames[i];
+
+ const sheet = workbook?.Sheets[sheetName];
+
+ // Convert the sheet to JSON to extract headers
+ const headersToValidate = XLSX.utils.sheet_to_json(sheet, {
+ header: 1,
+ })[0];
+
+ // Check if headers match the expected headers
+ if (!arraysEqual(headersToValidate, expectedHeaders)) {
+ const errorMessage = t("HCM_MISSING_HEADERS");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ isValid = false;
+ break;
+ }
+ }
+
+ if (!isValid) return isValid;
+ const targetError = [];
+
+ // Iterate over each sheet in the workbook, starting from the second sheet
+ for (let i = 2; i < workbook.SheetNames.length; i++) {
+ const sheetName = workbook?.SheetNames[i];
+
+ const sheet = workbook?.Sheets[sheetName];
+
+ // Convert the sheet to JSON to extract headers
+ const headersToValidate = XLSX.utils.sheet_to_json(sheet, {
+ header: 1,
+ })[0];
+
+ const jsonData = XLSX.utils.sheet_to_json(sheet, { blankrows: true });
+
+ // const boundaryCodeIndex = headersToValidate.indexOf(t("HCM_ADMIN_CONSOLE_BOUNDARY_CODE"));
+ // const headersBeforeBoundaryCode = headersToValidate.slice(0, boundaryCodeIndex);
+
+ // const columnBeforeBoundaryCode = jsonData.map((row) => row[headersBeforeBoundaryCode[headersBeforeBoundaryCode.length - 1]]);
+
+ // // Getting the length of data in the column before the boundary code
+ // const lengthOfColumnBeforeBoundaryCode = columnBeforeBoundaryCode.filter((value) => value !== undefined && value !== "").length;
+
+ // const filteredData = jsonData
+ // .filter((e) => e[headersBeforeBoundaryCode[headersBeforeBoundaryCode?.length - 1]])
+ // .filter((e) => e[t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")]);
+ // if (filteredData?.length == 0 || filteredData?.length != lengthOfColumnBeforeBoundaryCode) {
+ // const errorMessage = t("HCM_MISSING_TARGET");
+ // setErrorsType((prevErrors) => ({
+ // ...prevErrors,
+ // [type]: errorMessage,
+ // }));
+ // setIsError(true);
+ // isValid = false;
+ // break;
+ // }
+
+ // const targetValue = filteredData?.[0][t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")];
+
+ // if (targetValue <= 0 || targetValue >= 100000000) {
+ // const errorMessage = t("HCM_TARGET_VALIDATION_ERROR");
+ // setErrorsType((prevErrors) => ({
+ // ...prevErrors,
+ // [type]: errorMessage,
+ // }));
+ // setIsError(true);
+ // isValid = false;
+ // break;
+ // }
+ // }
+
+ if (!validateTargetData(jsonData, sheetName, targetError)) {
+ // setShowInfoCard(true);
+ // isValid = false;
+ // break;
+ }
+ }
+ if (targetError.length > 0) {
+ const errorMessage = targetError.join(", ");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setShowInfoCard(true);
+ isValid = false;
+ } else {
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: "", // Clear the error message
+ }));
+ setShowInfoCard(false);
+ isValid = true;
+ }
+ return isValid;
+ };
+
+ const validateExcel = (selectedFile) => {
+ return new Promise((resolve, reject) => {
+ // Check if a file is selected
+ if (!selectedFile) {
+ reject(t("HCM_FILE_UPLOAD_ERROR"));
+ return;
+ }
+
+ // Read the Excel file
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ try {
+ const data = new Uint8Array(e.target.result);
+ const workbook = XLSX.read(data, { type: "array" });
+ const sheet = workbook.Sheets[workbook.SheetNames[1]];
+ const headersToValidate = XLSX.utils.sheet_to_json(sheet, {
+ header: 1,
+ })[0];
+
+ const SheetNames = workbook.SheetNames[1];
+ const expectedHeaders = sheetHeaders[type];
+
+ const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[1]], { blankrows: true });
+ var jsonData = sheetData.map((row, index) => {
+ const rowData = {};
+ if (Object.keys(row).length > 0) {
+ Object.keys(row).forEach((key) => {
+ rowData[key] = row[key] === undefined || row[key] === "" ? "" : row[key];
+ });
+ rowData["!row#number!"] = index + 1; // Adding row number
+ return rowData;
+ }
+ });
+
+ jsonData = jsonData.filter((element) => element !== undefined);
+ if (type === "boundary") {
+ if (SheetNames !== t("HCM_ADMIN_CONSOLE_BOUNDARY_DATA")) {
+ const errorMessage = t("HCM_INVALID_BOUNDARY_SHEET");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return;
+ }
+ } else if (type === "facilityWithBoundary") {
+ if (type === "facilityWithBoundary") {
+ const activeColumnName = t("HCM_ADMIN_CONSOLE_FACILITY_USAGE");
+ const uniqueIdentifierColumnName = t("HCM_ADMIN_CONSOLE_FACILITY_CODE");
+ if (activeColumnName && uniqueIdentifierColumnName) {
+ jsonData = jsonData.filter((item) => item[activeColumnName] !== "Inactive" || !item[uniqueIdentifierColumnName]);
+ }
+ if (jsonData.length == 0) {
+ const errorMessage = t("HCM_FACILITY_USAGE_VALIDATION");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return;
+ }
+ }
+ if (SheetNames !== t("HCM_ADMIN_CONSOLE_AVAILABLE_FACILITIES")) {
+ const errorMessage = t("HCM_INVALID_FACILITY_SHEET");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return;
+ }
+ } else {
+ if (SheetNames !== t("HCM_ADMIN_CONSOLE_USER_LIST")) {
+ const errorMessage = t("HCM_INVALID_USER_SHEET");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return;
+ }
+ }
+ if (type === "boundary" && workbook?.SheetNames?.length >= 3) {
+ if (!validateMultipleTargets(workbook)) {
+ return;
+ }
+ } else if (type !== "boundary") {
+ for (const header of expectedHeaders) {
+ if (!headersToValidate.includes(header)) {
+ const errorMessage = t("HCM_MISSING_HEADERS");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return;
+ }
+ }
+ }
+
+ if (type === "boundary" && workbook?.SheetNames.length == 1) {
+ if (!validateTarget(jsonData, headersToValidate)) {
+ return;
+ }
+ }
+
+ if (jsonData.length == 0) {
+ const errorMessage = t("HCM_EMPTY_SHEET");
+ setErrorsType((prevErrors) => ({
+ ...prevErrors,
+ [type]: errorMessage,
+ }));
+ setIsError(true);
+ return;
+ }
+ if (type !== "boundary") {
+ if (validateData(jsonData, SheetNames)) {
+ resolve(true);
+ } else {
+ setShowInfoCard(true);
+ }
+ }
+ } catch (error) {
+ console.log("error", error);
+ reject("HCM_FILE_UNAVAILABLE");
+ }
+ };
+
+ reader.readAsArrayBuffer(selectedFile);
+ });
+ };
+
+ const onBulkUploadSubmit = async (file) => {
+ if (file.length > 1) {
+ setShowToast({ key: "error", label: t("HCM_ERROR_MORE_THAN_ONE_FILE") });
+ return;
+ }
+ setFileName(file?.[0]?.name);
+ const module = "HCM-ADMIN-CONSOLE-CLIENT";
+ const { data: { files: fileStoreIds } = {} } = await Digit.UploadServices.MultipleFilesStorage(module, file, tenantId);
+ const filesArray = [fileStoreIds?.[0]?.fileStoreId];
+ const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch(filesArray, tenantId);
+ const fileData = fileUrl
+ .map((i) => {
+ const urlParts = i?.url?.split("/");
+ const fileName = file?.[0]?.name;
+ const id = fileUrl?.[0]?.id;
+ // const fileType = type === "facilityWithBoundary" ? "facility" : type === "userWithBoundary" ? "user" : type;
+ const fileType =
+ type === "facilityWithBoundary" ? "facility" : type === "userWithBoundary" ? "user" : type === "boundary" ? "boundaryWithTarget" : type;
+ return {
+ // ...i,
+ filestoreId: id,
+ resourceId: resourceId,
+ filename: fileName,
+ type: fileType,
+ };
+ })
+ .map(({ id, ...rest }) => rest);
+ setUploadedFile(fileData);
+ const validate = await validateExcel(file[0]);
+ };
+
+ const onFileDelete = (file, index) => {
+ setUploadedFile((prev) => prev.filter((i) => i.id !== file.id));
+ setIsError(false);
+ setIsSuccess(false);
+ setIsValidation(false);
+ setApiError(null);
+ setErrorsType({});
+ setShowToast(null);
+ };
+
+ const onFileDownload = (file) => {
+ if (file && file?.url) {
+ // Splitting filename before .xlsx or .xls
+ const fileNameWithoutExtension = file?.filename.split(/\.(xlsx|xls)/)[0];
+ downloadExcelWithCustomName({ fileStoreId: file?.filestoreId, customName: fileNameWithoutExtension });
+ }
+ };
+ useEffect(() => {
+ const fetchData = async () => {
+ if (!errorsType[type] && uploadedFile?.length > 0 && !isSuccess) {
+ // setShowToast({ key: "info", label: t("HCM_VALIDATION_IN_PROGRESS") });
+ setIsValidation(true);
+ setIsError(true);
+ setLoader(true);
+
+ try {
+ const temp = await Digit.Hooks.campaign.useResourceData(
+ uploadedFile,
+ params?.hierarchyType,
+ type,
+ tenantId,
+ id,
+ baseTimeOut?.["HCM-ADMIN-CONSOLE"]
+ );
+ if (temp?.isError) {
+ setLoader(false);
+ setIsValidation(false);
+ const errorMessage = temp?.error.replaceAll(":", "-");
+ setShowToast({ key: "error", label: errorMessage, transitionTime: 5000000 });
+ setIsError(true);
+ setApiError(errorMessage);
+
+ return;
+ }
+ if (temp?.status === "completed") {
+ setLoader(false);
+ setIsValidation(false);
+ if (temp?.additionalDetails?.sheetErrors.length === 0) {
+ setShowToast({ key: "success", label: t("HCM_VALIDATION_COMPLETED") });
+ if (temp?.id) {
+ setResourceId(temp?.id);
+ }
+ if (!errorsType[type]) {
+ setIsError(false);
+ setIsSuccess(true);
+ return;
+ // setIsValidation(false);
+ }
+ return;
+ } else {
+ const processedFileStore = temp?.processedFilestoreId;
+ if (!processedFileStore) {
+ setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED") });
+ // setIsValidation(true);
+ return;
+ } else {
+ const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch([processedFileStore], tenantId);
+ const fileData = fileUrl
+ .map((i) => {
+ const urlParts = i?.url?.split("/");
+ const id = fileUrl?.[0]?.id;
+ // const fileName = fileName;
+ const fileType =
+ type === "facilityWithBoundary"
+ ? "facility"
+ : type === "userWithBoundary"
+ ? "user"
+ : type === "boundary"
+ ? "boundaryWithTarget"
+ : type;
+ return {
+ ...i,
+ filestoreId: id,
+ filename: fileName,
+ type: fileType,
+ resourceId: temp?.id,
+ };
+ })
+ .map(({ id, ...rest }) => rest);
+ // onFileDelete(uploadedFile);
+ setUploadedFile(fileData);
+ setShowToast({ key: "warning", label: t("HCM_CHECK_FILE_AGAIN") });
+ setIsError(true);
+ }
+ }
+ } else {
+ setLoader(false);
+ setIsValidation(false);
+ // setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED"), transitionTime: 5000000 });
+ const processedFileStore = temp?.processedFilestoreId;
+ if (!processedFileStore) {
+ setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED"), transitionTime: 5000000 });
+ return;
+ } else {
+ setIsError(true);
+ const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch([processedFileStore], tenantId);
+ const fileData = fileUrl
+ .map((i) => {
+ const urlParts = i?.url?.split("/");
+ const id = fileUrl?.[0]?.id;
+ // const fileName = file?.[0]?.name;
+ const fileType =
+ type === "facilityWithBoundary"
+ ? "facility"
+ : type === "userWithBoundary"
+ ? "user"
+ : type === "boundary"
+ ? "boundaryWithTarget"
+ : type;
+ return {
+ ...i,
+ filestoreId: id,
+ filename: fileName,
+ type: fileType,
+ };
+ })
+ .map(({ id, ...rest }) => rest);
+ // onFileDelete(uploadedFile);
+ setUploadedFile(fileData);
+ setShowToast({ key: "warning", label: t("HCM_CHECK_FILE_AGAIN"), transitionTime: 5000000 });
+ setIsError(true);
+ }
+ }
+ } catch (error) {}
+ }
+ };
+
+ fetchData();
+ }, [errorsType]);
+
+ const { data: facilityId, isLoading: isFacilityLoading, refetch: refetchFacility } = Digit.Hooks.campaign.useGenerateIdCampaign({
+ type: "facilityWithBoundary",
+ hierarchyType: params?.hierarchyType,
+ campaignId: id,
+ // config: {
+ // enabled: setTimeout(fetchUpload || (fetchBoundary && currentKey > 6)),
+ // },
+ config: {
+ enabled: enabled,
+ },
+ });
+
+ const { data: boundaryId, isLoading: isBoundaryLoading, refetch: refetchBoundary } = Digit.Hooks.campaign.useGenerateIdCampaign({
+ type: "boundary",
+ hierarchyType: params?.hierarchyType,
+ campaignId: id,
+ // config: {
+ // enabled: fetchUpload || (fetchBoundary && currentKey > 6),
+ // },
+ config: {
+ enabled: enabled,
+ },
+ });
+
+ const { data: userId, isLoading: isUserLoading, refetch: refetchUser } = Digit.Hooks.campaign.useGenerateIdCampaign({
+ type: "userWithBoundary",
+ hierarchyType: params?.hierarchyType,
+ campaignId: id,
+ // config: {
+ // enabled: fetchUpload || (fetchBoundary && currentKey > 6),
+ // },
+ config: {
+ enabled: enabled,
+ },
+ });
+
+ const Template = {
+ url: "/project-factory/v1/data/_download",
+ params: {
+ tenantId: tenantId,
+ type: type,
+ hierarchyType: params?.hierarchyType,
+ id: type === "boundary" ? params?.boundaryId : type === "facilityWithBoundary" ? params?.facilityId : params?.userId,
+ },
+ };
+ const mutation = Digit.Hooks.useCustomAPIMutationHook(Template);
+
+ const downloadTemplate = async () => {
+ if (type === "boundary" && params?.isBoundaryLoading) {
+ setDownloadError(true);
+ setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") });
+ return;
+ }
+ if (type === "facilityWithBoundary" && params?.isFacilityLoading) {
+ setDownloadError(true);
+ setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") });
+ return;
+ }
+ if (type === "userWithBoundary" && params?.isUserLoading) {
+ setDownloadError(true);
+ setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") });
+ return;
+ }
+ if (!params?.boundaryId || !params?.facilityId || !params?.userId) {
+ setEnabled(true);
+
+ setDownloadError(true);
+ setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") });
+ return;
+ }
+ await mutation.mutate(
+ {
+ params: {
+ tenantId: tenantId,
+ type: type,
+ hierarchyType: params?.hierarchyType,
+ id: type === "boundary" ? params?.boundaryId : type === "facilityWithBoundary" ? params?.facilityId : params?.userId,
+ },
+ },
+ {
+ onSuccess: async (result) => {
+ if (result?.GeneratedResource?.[0]?.status === "failed") {
+ setDownloadError(true);
+ setShowToast({ key: "error", label: t("ERROR_WHILE_DOWNLOADING") });
+ return;
+ }
+ if (!result?.GeneratedResource?.[0]?.fileStoreid || result?.GeneratedResource?.length == 0) {
+ setDownloadError(true);
+ setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") });
+ return;
+ }
+ const filesArray = [result?.GeneratedResource?.[0]?.fileStoreid];
+ const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch(filesArray, tenantId);
+ const fileData = fileUrl?.map((i) => {
+ const urlParts = i?.url?.split("/");
+ // const fileName = urlParts[urlParts?.length - 1]?.split("?")?.[0];
+ const fileName = type === "boundary" ? "Target Template" : type === "facilityWithBoundary" ? "Facility Template" : "User Template";
+ return {
+ ...i,
+ filename: fileName,
+ };
+ });
+
+ if (fileData && fileData?.[0]?.url) {
+ setDownloadError(false);
+ if (fileData?.[0]?.id) {
+ downloadExcelWithCustomName({ fileStoreId: fileData?.[0]?.id, customName: fileData?.[0]?.filename });
+ }
+ } else {
+ setDownloadError(true);
+ setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT") });
+ }
+ },
+ onError: (result) => {
+ setDownloadError(true);
+ setShowToast({ key: "error", label: t("ERROR_WHILE_DOWNLOADING") });
+ },
+ }
+ );
+ };
+
+ // useEffect(() => {
+ // if (showToast) {
+ // setTimeout(closeToast, 5000);
+ // }
+ // }, [showToast]);
+ const closeToast = () => {
+ setShowToast(null);
+ };
+ useEffect(() => {
+ if (showToast) {
+ const t = setTimeout(closeToast, 50000);
+ return () => clearTimeout(t);
+ }
+ }, [showToast]);
+
+ useEffect(() => {
+ setShowToast(null);
+ }, [currentKey]);
+
+ return (
+ <>
+ {loader && }
+
+
+
+ {type === "boundary" ? t("WBH_UPLOAD_TARGET") : type === "facilityWithBoundary" ? t("WBH_UPLOAD_FACILITY") : t("WBH_UPLOAD_USER")}
+
+
+
+ {uploadedFile.length === 0 && (
+
+ {type === "boundary" ? t("HCM_BOUNDARY_MESSAGE") : type === "facilityWithBoundary" ? t("HCM_FACILITY_MESSAGE") : t("HCM_USER_MESSAGE")}
+
+ )}
+
+ {showInfoCard && (
+
+ {errorsType[type] && (
+
+ {errorsType[type].split(",").slice(0,50).map((error, index) => (
+
+ {index > 0 &&
}
+ {error.trim()}
+
+ ))}
+
+ )}
+ ,
+ ]}
+ />
+ )}
+
+ (
+
+
{info?.header}
+
+ {info?.descriptions.map((desc, i) => (
+ -
+
{i + 1}.
+ {desc.text}
+
+ ))}
+
+
+ ))}
+ label={"Info"}
+ />
+ {showPopUp && (
+
+ {type === "boundary"
+ ? t("ES_CAMPAIGN_UPLOAD_BOUNDARY_DATA_MODAL_TEXT")
+ : type === "facilityWithBoundary"
+ ? t("ES_CAMPAIGN_UPLOAD_FACILITY_DATA_MODAL_TEXT")
+ : t("ES_CAMPAIGN_UPLOAD_USER_DATA_MODAL_TEXT ")}
+ ,
+ ]}
+ onOverlayClick={() => {
+ setShowPopUp(false);
+ }}
+ footerChildren={[
+ {
+ setShowPopUp(false);
+ }}
+ />,
+ {
+ downloadTemplate(), setShowPopUp(false);
+ }}
+ />,
+ ]}
+ sortFooterChildren={true}
+ onClose={() => {
+ setShowPopUp(false);
+ }}
+ >
+ )}
+ {showToast && (uploadedFile?.length > 0 || downloadError) && (
+
+ )}
+ >
+ );
+};
+
+export default UploadData;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js
new file mode 100644
index 00000000000..a3a10a43830
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js
@@ -0,0 +1,69 @@
+import { PopUp, SVG, DownloadIcon, Button } from "@egovernments/digit-ui-react-components";
+import React from "react";
+import DocViewer, { DocViewerRenderers } from "@cyntler/react-doc-viewer";
+import { useTranslation } from "react-i18next";
+import { PRIMARY_COLOR } from "../utils";
+
+const ArrowBack = ({ className = "", height = "15", width = "15", styles = {} }) => {
+ return (
+
+ );
+};
+function XlsPreview({ file, ...props }) {
+ const { t } = useTranslation();
+ const documents = file
+ ? [
+ {
+ fileType: "xlsx",
+ fileName: file?.filename,
+ uri: file?.url,
+ },
+ ]
+ : null;
+
+ return (
+
+
+ }
+ type="button"
+ className="workbench-download-template-btn"
+ onButtonClick={() => props?.onBack()}
+ />
+ }
+ type="button"
+ className="workbench-download-template-btn"
+ onButtonClick={() => props?.onDownload()}
+ />
+
+
+
+
+
+ );
+}
+
+export default XlsPreview;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js
new file mode 100644
index 00000000000..b9191f6db26
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js
@@ -0,0 +1,10 @@
+import React from "react";
+import { PRIMARY_COLOR } from "../../utils";
+export const DustbinIcon = () => (
+
+);
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js
new file mode 100644
index 00000000000..82ecfa8f625
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js
@@ -0,0 +1,32 @@
+import React from "react";
+
+export const XlsxFile = ({ className = "", fill = "none", style = {} }) => (
+
+);
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js
new file mode 100644
index 00000000000..91195b2376f
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js
@@ -0,0 +1,267 @@
+export const CampaignConfig = (totalFormData, dataParams, isSubmitting, summaryErrors) => {
+ return [
+ {
+ form: [
+ {
+ stepCount: "1",
+ key: "1",
+ name: "HCM_CAMPAIGN_TYPE",
+ body: [
+ {
+ isMandatory: false,
+ key: "projectType",
+ type: "component",
+ skipAPICall: true,
+ component: "CampaignSelection",
+ withoutLabel: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ isSubmitting: isSubmitting,
+ },
+ populators: {
+ name: "projectType",
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "1",
+ key: "2",
+ name: "HCM_CAMPAIGN_NAME",
+ body: [
+ {
+ isMandatory: false,
+ key: "campaignName",
+ type: "component",
+ component: "CampaignName",
+ mandatoryOnAPI: true,
+ withoutLabel: true,
+ withoutLabelFieldPair: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ isSubmitting: isSubmitting,
+ },
+ populators: {
+ name: "campaignName",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "2",
+ key: "3",
+ name: "HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA",
+ body: [
+ {
+ isMandatory: false,
+ key: "boundaryType",
+ type: "component",
+ component: "SelectingBoundaries",
+ withoutLabelFieldPair: true,
+ withoutLabel: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ dataParams: dataParams,
+ },
+ populators: {
+ name: "boundaryType",
+ // optionsKey: "code",
+ error: "ES__REQUIRED",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "3",
+ key: "4",
+ name: "HCM_CAMPAIGN_DATE",
+ body: [
+ {
+ isMandatory: false,
+ key: "campaignDates",
+ type: "component",
+ component: "CampaignDates",
+ withoutLabel: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ isSubmitting: isSubmitting,
+ },
+ populators: {
+ name: "campaignDates",
+ // optionsKey: "code",
+ // error: "ES__REQUIRED",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "3",
+ key: "5",
+ name: "HCM_CAMPAIGN_CYCLE_CONFIGURE",
+ body: [
+ {
+ isMandatory: false,
+ key: "cycleConfigure",
+ type: "component",
+ component: "CycleConfiguration",
+ withoutLabelFieldPair: true,
+ withoutLabel: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ },
+ populators: {
+ name: "cycleConfiguration",
+ sessionData: totalFormData,
+ // optionsKey: "code",
+ error: "ES__REQUIRED",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "3",
+ key: "6",
+ name: "HCM_CAMPAIGN_DELIVERY_DATA",
+ body: [
+ {
+ isMandatory: false,
+ key: "deliveryRule",
+ type: "component",
+ component: "DeliveryRule",
+ withoutLabelFieldPair: true,
+ withoutLabel: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ },
+ populators: {
+ name: "deliveryRule",
+ // optionsKey: "code",
+ error: "ES__REQUIRED",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "4",
+ key: "7",
+ name: "HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA",
+ body: [
+ {
+ isMandatory: false,
+ key: "uploadBoundary",
+ type: "component",
+ component: "UploadData",
+ withoutLabel: true,
+ withoutLabelFieldPair: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ type: "boundary",
+ },
+ populators: {
+ name: "uploadBoundary",
+ // optionsKey: "code",
+ // error: "ES__REQUIRED",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "5",
+ key: "8",
+ name: "HCM_CAMPAIGN_UPLOAD_FACILITY_DATA",
+ body: [
+ {
+ isMandatory: false,
+ key: "uploadFacility",
+ type: "component",
+ component: "UploadData",
+ withoutLabel: true,
+ withoutLabelFieldPair: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ type: "facilityWithBoundary",
+ },
+ populators: {
+ name: "uploadFacility",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "6",
+ key: "9",
+ name: "HCM_CAMPAIGN_UPLOAD_USER_DATA",
+ body: [
+ {
+ isMandatory: false,
+ key: "uploadUser",
+ type: "component",
+ component: "UploadData",
+ withoutLabel: true,
+ withoutLabelFieldPair: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ type: "userWithBoundary",
+ },
+ populators: {
+ name: "uploadUser",
+ required: true,
+ },
+ },
+ ],
+ },
+ {
+ stepCount: "7",
+ key: "10",
+ isLast: true,
+ body: [
+ {
+ isMandatory: false,
+ key: "summary",
+ type: "component",
+ component: "CampaignSummary",
+ withoutLabel: true,
+ withoutLabelFieldPair: true,
+ disable: false,
+ customProps: {
+ module: "HCM",
+ sessionData: totalFormData,
+ summaryErrors: summaryErrors
+ },
+ populators: {
+ name: "summary",
+ // optionsKey: "code",
+ // error: "ES__REQUIRED",
+ required: true,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ ];
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js
new file mode 100644
index 00000000000..63954b2a810
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js
@@ -0,0 +1,472 @@
+import { Link, useHistory } from "react-router-dom";
+import _ from "lodash";
+import React from "react";
+
+//create functions here based on module name set in mdms(eg->SearchProjectConfig)
+//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName]
+// these functions will act as middlewares
+// var Digit = window.Digit || {};
+
+const businessServiceMap = {};
+
+const inboxModuleNameMap = {};
+
+export const UICustomizations = {
+ MyCampaignConfigOngoing: {
+ preProcess: (data, additionalDetails) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body = { RequestInfo: data.body.RequestInfo };
+ const { limit, offset } = data?.state?.tableForm || {};
+ const { campaignName, campaignType } = data?.state?.searchForm || {};
+ data.body.CampaignDetails = {
+ tenantId: tenantId,
+ status: ["creating", "created"],
+ createdBy: Digit.UserService.getUser().info.uuid,
+ campaignsIncludeDates: true,
+ startDate: Date.now(),
+ endDate: Date.now(),
+ pagination: {
+ sortBy: "createdTime",
+ sortOrder: "desc",
+ limit: limit,
+ offset: offset,
+ },
+ };
+ if (campaignName) {
+ data.body.CampaignDetails.campaignName = campaignName;
+ }
+ if (campaignType) {
+ data.body.CampaignDetails.projectType = campaignType?.[0]?.code;
+ }
+ delete data.body.custom;
+ delete data.body.inbox;
+ delete data.params;
+ return data;
+ },
+ populateCampaignTypeReqCriteria: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ return {
+ url: "/egov-mdms-service/v1/_search",
+ params: { tenantId },
+ body: {
+ MdmsCriteria: {
+ tenantId: tenantId,
+ moduleDetails: [
+ {
+ moduleName: "HCM-PROJECT-TYPES",
+ masterDetails: [
+ {
+ name: "projectTypes",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ changeQueryName: "setWorkflowStatus",
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes;
+ },
+ },
+ };
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "";
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ switch (key) {
+ case "CAMPAIGN_NAME":
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+
+ case "CAMPAIGN_START_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ case "CAMPAIGN_END_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ default:
+ return "case_not_found";
+ }
+ },
+ onCardClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ onCardActionClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "TQM_VIEW_TEST_DETAILS";
+ },
+ },
+ MyCampaignConfigCompleted: {
+ preProcess: (data, additionalDetails) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body = { RequestInfo: data.body.RequestInfo };
+ const { limit, offset } = data?.state?.tableForm || {};
+ const { campaignName, campaignType } = data?.state?.searchForm || {};
+ data.body.CampaignDetails = {
+ tenantId: tenantId,
+ status: ["creating", "created"],
+ endDate: Date.now() - 24 * 60 * 60 * 1000,
+ createdBy: Digit.UserService.getUser().info.uuid,
+ pagination: {
+ sortBy: "createdTime",
+ sortOrder: "desc",
+ limit: limit,
+ offset: offset,
+ },
+ };
+ if (campaignName) {
+ data.body.CampaignDetails.campaignName = campaignName;
+ }
+ if (campaignType) {
+ data.body.CampaignDetails.projectType = campaignType?.[0]?.code;
+ }
+ delete data.body.custom;
+ delete data.body.inbox;
+ delete data.params;
+ return data;
+ },
+ populateCampaignTypeReqCriteria: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ return {
+ url: "/egov-mdms-service/v1/_search",
+ params: { tenantId },
+ body: {
+ MdmsCriteria: {
+ tenantId: tenantId,
+ moduleDetails: [
+ {
+ moduleName: "HCM-PROJECT-TYPES",
+ masterDetails: [
+ {
+ name: "projectTypes",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ changeQueryName: "setWorkflowStatus",
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes;
+ },
+ },
+ };
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "";
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ switch (key) {
+ case "CAMPAIGN_NAME":
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+
+ case "CAMPAIGN_START_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ case "CAMPAIGN_END_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ default:
+ return "case_not_found";
+ }
+ },
+ onCardClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ onCardActionClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "TQM_VIEW_TEST_DETAILS";
+ },
+ },
+ MyCampaignConfigUpcoming: {
+ preProcess: (data, additionalDetails) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body = { RequestInfo: data.body.RequestInfo };
+ const { limit, offset } = data?.state?.tableForm || {};
+ const { campaignName, campaignType } = data?.state?.searchForm || {};
+ data.body.CampaignDetails = {
+ tenantId: tenantId,
+ status: ["creating", "created"],
+ createdBy: Digit.UserService.getUser().info.uuid,
+ campaignsIncludeDates: false,
+ startDate: Date.now() + 24 * 60 * 60 * 1000,
+ pagination: {
+ sortBy: "createdTime",
+ sortOrder: "desc",
+ limit: limit,
+ offset: offset,
+ },
+ };
+ if (campaignName) {
+ data.body.CampaignDetails.campaignName = campaignName;
+ }
+ if (campaignType) {
+ data.body.CampaignDetails.projectType = campaignType?.[0]?.code;
+ }
+ delete data.body.custom;
+ delete data.body.inbox;
+ delete data.params;
+ return data;
+ },
+ populateCampaignTypeReqCriteria: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ return {
+ url: "/egov-mdms-service/v1/_search",
+ params: { tenantId },
+ body: {
+ MdmsCriteria: {
+ tenantId: tenantId,
+ moduleDetails: [
+ {
+ moduleName: "HCM-PROJECT-TYPES",
+ masterDetails: [
+ {
+ name: "projectTypes",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ changeQueryName: "setWorkflowStatus",
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes;
+ },
+ },
+ };
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "";
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ switch (key) {
+ case "CAMPAIGN_NAME":
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+
+ case "CAMPAIGN_START_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ case "CAMPAIGN_END_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ default:
+ return "case_not_found";
+ }
+ },
+ onCardClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ onCardActionClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "TQM_VIEW_TEST_DETAILS";
+ },
+ },
+ MyCampaignConfigDrafts: {
+ preProcess: (data, additionalDetails) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body = { RequestInfo: data.body.RequestInfo };
+ const { limit, offset } = data?.state?.tableForm || {};
+ const { campaignName, campaignType } = data?.state?.searchForm || {};
+ data.body.CampaignDetails = {
+ tenantId: tenantId,
+ status: ["drafted"],
+ createdBy: Digit.UserService.getUser().info.uuid,
+ pagination: {
+ sortBy: "createdTime",
+ sortOrder: "desc",
+ limit: limit,
+ offset: offset,
+ },
+ };
+ if (campaignName) {
+ data.body.CampaignDetails.campaignName = campaignName;
+ }
+ if (campaignType) {
+ data.body.CampaignDetails.projectType = campaignType?.[0]?.code;
+ }
+ delete data.body.custom;
+ delete data.body.custom;
+ delete data.body.inbox;
+ delete data.params;
+ return data;
+ },
+ populateCampaignTypeReqCriteria: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ return {
+ url: "/egov-mdms-service/v1/_search",
+ params: { tenantId },
+ body: {
+ MdmsCriteria: {
+ tenantId: tenantId,
+ moduleDetails: [
+ {
+ moduleName: "HCM-PROJECT-TYPES",
+ masterDetails: [
+ {
+ name: "projectTypes",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ changeQueryName: "setWorkflowStatus",
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes;
+ },
+ },
+ };
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "";
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ switch (key) {
+ case "CAMPAIGN_NAME":
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+
+ case "CAMPAIGN_START_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ case "CAMPAIGN_END_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ default:
+ return "case_not_found";
+ }
+ },
+ onCardClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ onCardActionClick: (obj) => {
+ return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "TQM_VIEW_TEST_DETAILS";
+ },
+ },
+ MyCampaignConfigFailed: {
+ preProcess: (data, additionalDetails) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body = { RequestInfo: data.body.RequestInfo };
+ const { limit, offset } = data?.state?.tableForm || {};
+ const { campaignName, campaignType } = data?.state?.searchForm || {};
+ data.body.CampaignDetails = {
+ tenantId: tenantId,
+ status: ["failed"],
+ createdBy: Digit.UserService.getUser().info.uuid,
+ pagination: {
+ sortBy: "createdTime",
+ sortOrder: "desc",
+ limit: limit,
+ offset: offset,
+ },
+ };
+ if (campaignName) {
+ data.body.CampaignDetails.campaignName = campaignName;
+ }
+ if (campaignType) {
+ data.body.CampaignDetails.projectType = campaignType?.[0]?.code;
+ }
+ delete data.body.custom;
+ delete data.body.inbox;
+ delete data.params;
+ return data;
+ },
+ populateCampaignTypeReqCriteria: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ return {
+ url: "/egov-mdms-service/v1/_search",
+ params: { tenantId },
+ body: {
+ MdmsCriteria: {
+ tenantId: tenantId,
+ moduleDetails: [
+ {
+ moduleName: "HCM-PROJECT-TYPES",
+ masterDetails: [
+ {
+ name: "projectTypes",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ changeQueryName: "setWorkflowStatus",
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes;
+ },
+ },
+ };
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "";
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ switch (key) {
+ case "CAMPAIGN_NAME":
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+
+ case "CAMPAIGN_START_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ case "CAMPAIGN_END_DATE":
+ return Digit.DateUtils.ConvertEpochToDate(value);
+ default:
+ return "case_not_found";
+ }
+ },
+ onCardClick: (obj) => {
+ // return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ onCardActionClick: (obj) => {
+ // return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`;
+ },
+ getCustomActionLabel: (obj, row) => {
+ return "TQM_VIEW_TEST_DETAILS";
+ },
+ },
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js
new file mode 100644
index 00000000000..a13b5bc9c0e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js
@@ -0,0 +1,19 @@
+export const addProductConfig = [
+ {
+ body: [
+ {
+ type: "component",
+ component: "AddProductField",
+ withoutLabel: true,
+ key: "addProduct",
+ validation: {},
+ populators: {
+ validation: {},
+ },
+ customProps: {
+ module: "Campaign",
+ },
+ },
+ ],
+ },
+];
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js
new file mode 100644
index 00000000000..75864d62ab5
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js
@@ -0,0 +1,23 @@
+//migrated to mdms
+export const attributeConfig = [
+ {
+ key: 1,
+ code: "Age",
+ i18nKey: "CAMPAIGN_ATTRIBUTE_AGE",
+ },
+ {
+ key: 2,
+ code: "Height",
+ i18nKey: "CAMPAIGN_ATTRIBUTE_HEIGHT",
+ },
+ {
+ key: 3,
+ code: "Weight",
+ i18nKey: "CAMPAIGN_ATTRIBUTE_WEIGHT",
+ },
+ {
+ key: 4,
+ code: "Gender",
+ i18nKey: "CAMPAIGN_ATTRIBUTE_GENDER",
+ },
+];
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js
new file mode 100644
index 00000000000..97047c1596e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js
@@ -0,0 +1,6 @@
+export const baseTimeOut =
+ {
+ baseTimeOut: 100,
+ maxTime: 5000
+ };
+
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js
new file mode 100644
index 00000000000..3d67d30818f
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js
@@ -0,0 +1,206 @@
+//migrated to mdms
+export const deliveryConfig = [
+ {
+ projectType: "LLIN-mz",
+ attrAddDisable: true,
+ deliveryAddDisable: true,
+ customAttribute: true,
+ cycleConfig: {
+ cycle: 1,
+ deliveries: 1,
+ },
+ deliveryConfig: [
+ {
+ attributeConfig: [
+ {
+ key: 1,
+ label: "Custom",
+ attrType: "text",
+ attrValue: "CAMPAIGN_BEDNET_INDIVIDUAL_LABEL",
+ },
+ {
+ key: 2,
+ label: "Custom",
+ attrType: "text",
+ attrValue: "CAMPAIGN_BEDNET_HOUSEHOLD_LABEL",
+ },
+ ],
+ productConfig: [
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-05-03-000305",
+ name: "SP - 250mg",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ projectType: "MR-DN",
+ attrAddDisable: false,
+ deliveryAddDisable: false,
+ customAttribute: true,
+ cycleConfig: {
+ cycle: 3,
+ deliveries: 3,
+ },
+ deliveryConfig: [
+ {
+ delivery: 1,
+ conditionConfig: [
+ {
+ deliveryType: "DIRECT",
+ disableDeliveryType: true,
+ attributeConfig: [
+ {
+ key: 1,
+ label: "Custom",
+ attrType: "dropdown",
+ attrValue: "Age",
+ operatorValue: "IN_BETWEEN",
+ fromValue: 3,
+ toValue: 11,
+ },
+ ],
+ productConfig: [
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-01-24-000079",
+ name: "AQ - 75mg",
+ },
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-05-03-000305",
+ name: "SP - 250mg",
+ },
+ ],
+ },
+ {
+ disableDeliveryType: true,
+ deliveryType: "DIRECT",
+ attributeConfig: [
+ {
+ key: 1,
+ label: "Custom",
+ attrType: "dropdown",
+ attrValue: "Age",
+ operatorValue: "IN_BETWEEN",
+ fromValue: 12,
+ toValue: 59,
+ },
+ ],
+ productConfig: [
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-01-24-000078",
+ name: "AQ - 150mg",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ delivery: 2,
+ conditionConfig: [
+ {
+ deliveryType: "INDIRECT",
+ attributeConfig: [
+ {
+ key: 1,
+ label: "Custom",
+ attrType: "dropdown",
+ attrValue: "Age",
+ operatorValue: "IN_BETWEEN",
+ fromValue: 3,
+ toValue: 11,
+ },
+ ],
+ productConfig: [
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-01-24-000079",
+ name: "AQ - 75mg",
+ },
+ ],
+ },
+ {
+ deliveryType: "INDIRECT",
+ attributeConfig: [
+ {
+ key: 1,
+ label: "Custom",
+ attrType: "dropdown",
+ attrValue: "Age",
+ operatorValue: "IN_BETWEEN",
+ fromValue: 12,
+ toValue: 59,
+ },
+ ],
+ productConfig: [
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-01-24-000078",
+ name: "AQ - 150mg",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ delivery: 3,
+ conditionConfig: [
+ {
+ deliveryType: "INDIRECT",
+ attributeConfig: [
+ {
+ key: 1,
+ label: "Custom",
+ attrType: "dropdown",
+ attrValue: "Age",
+ operatorValue: "IN_BETWEEN",
+ fromValue: 3,
+ toValue: 11,
+ },
+ ],
+ productConfig: [
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-01-24-000079",
+ name: "AQ - 75mg",
+ },
+ ],
+ },
+ {
+ deliveryType: "INDIRECT",
+ attributeConfig: [
+ {
+ key: 1,
+ label: "Custom",
+ attrType: "dropdown",
+ attrValue: "Age",
+ operatorValue: "IN_BETWEEN",
+ fromValue: 12,
+ toValue: 59,
+ },
+ ],
+ productConfig: [
+ {
+ key: 1,
+ count: 1,
+ value: "PVAR-2024-01-24-000078",
+ name: "AQ - 150mg",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+];
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js
new file mode 100644
index 00000000000..66ef03113f1
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js
@@ -0,0 +1,20 @@
+export const headerConfig = {
+ boundary: [
+ "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", "HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL"
+ ],
+ facilityWithBoundary: [
+ "HCM_ADMIN_CONSOLE_FACILITY_CODE",
+ "HCM_ADMIN_CONSOLE_FACILITY_NAME",
+ "HCM_ADMIN_CONSOLE_FACILITY_TYPE",
+ "HCM_ADMIN_CONSOLE_FACILITY_STATUS",
+ "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY",
+ "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY"
+ ],
+ User: [
+ "HCM_ADMIN_CONSOLE_USER_NAME",
+ "HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER",
+ "HCM_ADMIN_CONSOLE_USER_ROLE",
+ "HCM_ADMIN_CONSOLE_USER_EMPLOYMENT_TYPE",
+ "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY"
+ ]
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js
new file mode 100644
index 00000000000..7bd788d976c
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js
@@ -0,0 +1,5 @@
+export const mailConfig =
+ {
+ mailId: "L1team@email.com"
+ };
+
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js
new file mode 100644
index 00000000000..4152a57759e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js
@@ -0,0 +1,667 @@
+/* The above code defines a JavaScript object `myCampaignConfig` which contains configurations for
+different types of campaigns - ongoing, completed, and drafts. Each campaign type has its own search
+configuration with fields like campaign name, type, start date, end date, etc. The configurations
+also include API details for fetching data, UI styles, search result columns, pagination settings,
+and more. The object is exported for use in other parts of the codebase. */
+export const myCampaignConfig = {
+ tenantId: "mz",
+ moduleName: "commonCampaignUiConfig",
+ showTab: true,
+ myCampaignConfig: [
+ {
+ label: "CAMPAIGN_ONGOING",
+ type: "search",
+ apiDetails: {
+ serviceName: "/project-factory/v1/project-type/search",
+ requestParam: {},
+ requestBody: {},
+ minParametersForSearchForm: 0,
+ minParametersForFilterForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigOngoing",
+ tableFormJsonPath: "requestBody.inbox",
+ filterFormJsonPath: "requestBody.custom",
+ searchFormJsonPath: "requestBody.custom",
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ headerLabel: "ES_COMMON_SEARCH",
+ type: "search",
+ typeMobile: "filter",
+ searchWrapperStyles: {
+ flexDirection: "column-reverse",
+ marginTop: "1.4rem",
+ alignItems: "center",
+ justifyContent: "end",
+ gridColumn: "3",
+ },
+ headerStyle: null,
+ primaryLabel: "Search",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 0,
+ defaultValues: {
+ name: "",
+ type: "",
+ },
+ fields: [
+ {
+ label: "CAMPAIGN_SEARCH_NAME",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "campaignName",
+ error: "TQM_ERR_VALID_CAMPAIGN_NAME",
+ style: {
+ marginBottom: "0px",
+ },
+ },
+ },
+ {
+ label: "CAMPAIGN_SEARCH_TYPE",
+ type: "apidropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ optionsCustomStyle: {
+ top: "2.3rem",
+ },
+ name: "campaignType",
+ optionsKey: "code",
+ allowMultiSelect: false,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigOngoing",
+ customfn: "populateCampaignTypeReqCriteria",
+ },
+ },
+ ],
+ },
+ label: "",
+ labelMobile: "ES_COMMON_SEARCH",
+ children: {},
+ show: true,
+ },
+ searchResult: {
+ uiConfig: {
+ columns: [
+ {
+ label: "CAMPAIGN_NAME",
+ jsonPath: "campaignName",
+ additionalCustomization: true,
+ },
+ {
+ label: "CAMPAIGN_TYPE",
+ jsonPath: "projectType",
+ prefix: "CAMPAIGN_PROJECT_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_BENEFICIARY_TYPE",
+ jsonPath: "additionalDetails.beneficiaryType",
+ prefix: "",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_START_DATE",
+ jsonPath: "startDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ {
+ label: "CAMPAIGN_END_DATE",
+ jsonPath: "endDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ ],
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "CampaignDetails",
+ // customDefaultPagination: {
+ // limit: 5,
+ // offset: 0,
+ // },
+ // customPageSizesArray: [5, 10, 15, 20],
+ tableClassName: "table campaign-table",
+ },
+ children: {},
+ show: true,
+ },
+ links: {
+ show: false,
+ },
+ filter: {
+ show: false,
+ },
+ },
+ additionalSections: {},
+ persistFormData: true,
+ showAsRemovableTagsInMobile: true,
+ },
+ {
+ label: "CAMPAIGN_COMPLETED",
+ type: "search",
+ apiDetails: {
+ serviceName: "/project-factory/v1/project-type/search",
+ requestParam: {},
+ requestBody: {},
+ minParametersForSearchForm: 0,
+ minParametersForFilterForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigCompleted",
+ tableFormJsonPath: "requestBody.inbox",
+ filterFormJsonPath: "requestBody.custom",
+ searchFormJsonPath: "requestBody.custom",
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ headerLabel: "ES_COMMON_SEARCH",
+ type: "search",
+ typeMobile: "filter",
+ searchWrapperStyles: {
+ flexDirection: "column-reverse",
+ marginTop: "1.4rem",
+ alignItems: "center",
+ justifyContent: "end",
+ gridColumn: "3",
+ },
+ headerStyle: null,
+ primaryLabel: "Search",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 0,
+ defaultValues: {
+ name: "",
+ type: "",
+ },
+ fields: [
+ {
+ label: "CAMPAIGN_SEARCH_NAME",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "campaignName",
+ error: "TQM_ERR_VALID_CAMPAIGN_NAME",
+ style: {
+ marginBottom: "0px",
+ },
+ },
+ },
+ {
+ label: "CAMPAIGN_SEARCH_TYPE",
+ type: "apidropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ optionsCustomStyle: {
+ top: "2.3rem",
+ },
+ name: "campaignType",
+ optionsKey: "code",
+ allowMultiSelect: false,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigCompleted",
+ customfn: "populateCampaignTypeReqCriteria",
+ },
+ },
+ ],
+ },
+ label: "",
+ labelMobile: "ES_COMMON_SEARCH",
+ children: {},
+ show: true,
+ },
+ searchResult: {
+ uiConfig: {
+ columns: [
+ {
+ label: "CAMPAIGN_NAME",
+ jsonPath: "campaignName",
+ additionalCustomization: true,
+ },
+ {
+ label: "CAMPAIGN_TYPE",
+ jsonPath: "projectType",
+ prefix: "CAMPAIGN_PROJECT_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_BENEFICIARY_TYPE",
+ jsonPath: "additionalDetails.beneficiaryType",
+ prefix: "",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_START_DATE",
+ jsonPath: "startDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ {
+ label: "CAMPAIGN_END_DATE",
+ jsonPath: "endDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ ],
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "CampaignDetails",
+ // customDefaultPagination: {
+ // limit: 5,
+ // offset: 0,
+ // },
+ // customPageSizesArray: [5, 10, 15, 20],
+ tableClassName: "table campaign-table",
+ },
+ children: {},
+ show: true,
+ },
+ links: {
+ show: false,
+ },
+ filter: {
+ show: false,
+ },
+ },
+ additionalSections: {},
+ persistFormData: true,
+ showAsRemovableTagsInMobile: true,
+ },
+ {
+ label: "CAMPAIGN_UPCOMING",
+ type: "search",
+ apiDetails: {
+ serviceName: "/project-factory/v1/project-type/search",
+ requestParam: {},
+ requestBody: {},
+ minParametersForSearchForm: 0,
+ minParametersForFilterForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigUpcoming",
+ tableFormJsonPath: "requestBody.inbox",
+ filterFormJsonPath: "requestBody.custom",
+ searchFormJsonPath: "requestBody.custom",
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ headerLabel: "ES_COMMON_SEARCH",
+ type: "search",
+ typeMobile: "filter",
+ searchWrapperStyles: {
+ flexDirection: "column-reverse",
+ marginTop: "1.4rem",
+ alignItems: "center",
+ justifyContent: "end",
+ gridColumn: "3",
+ },
+ headerStyle: null,
+ primaryLabel: "Search",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 0,
+ defaultValues: {
+ name: "",
+ type: "",
+ },
+ fields: [
+ {
+ label: "CAMPAIGN_SEARCH_NAME",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "campaignName",
+ error: "TQM_ERR_VALID_CAMPAIGN_NAME",
+ style: {
+ marginBottom: "0px",
+ },
+ },
+ },
+ {
+ label: "CAMPAIGN_SEARCH_TYPE",
+ type: "apidropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ optionsCustomStyle: {
+ top: "2.3rem",
+ },
+ name: "campaignType",
+ optionsKey: "code",
+ allowMultiSelect: false,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigUpcoming",
+ customfn: "populateCampaignTypeReqCriteria",
+ },
+ },
+ ],
+ },
+ label: "",
+ labelMobile: "ES_COMMON_SEARCH",
+ children: {},
+ show: true,
+ },
+ searchResult: {
+ uiConfig: {
+ columns: [
+ {
+ label: "CAMPAIGN_NAME",
+ jsonPath: "campaignName",
+ additionalCustomization: true,
+ },
+ {
+ label: "CAMPAIGN_TYPE",
+ jsonPath: "projectType",
+ prefix: "CAMPAIGN_PROJECT_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_BENEFICIARY_TYPE",
+ jsonPath: "additionalDetails.beneficiaryType",
+ prefix: "",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_START_DATE",
+ jsonPath: "startDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ {
+ label: "CAMPAIGN_END_DATE",
+ jsonPath: "endDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ ],
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "CampaignDetails",
+ // customDefaultPagination: {
+ // limit: 5,
+ // offset: 0,
+ // },
+ // customPageSizesArray: [5, 10, 15, 20],
+ tableClassName: "table campaign-table",
+ },
+ children: {},
+ show: true,
+ },
+ links: {
+ show: false,
+ },
+ filter: {
+ show: false,
+ },
+ },
+ additionalSections: {},
+ persistFormData: true,
+ showAsRemovableTagsInMobile: true,
+ },
+ {
+ label: "CAMPAIGN_DRAFTS",
+ type: "search",
+ apiDetails: {
+ serviceName: "/project-factory/v1/project-type/search",
+ requestParam: {},
+ requestBody: {},
+ minParametersForSearchForm: 0,
+ minParametersForFilterForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigDrafts",
+ tableFormJsonPath: "requestBody.inbox",
+ filterFormJsonPath: "requestBody.custom",
+ searchFormJsonPath: "requestBody.custom",
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ headerLabel: "ES_COMMON_SEARCH",
+ type: "search",
+ typeMobile: "filter",
+ searchWrapperStyles: {
+ flexDirection: "column-reverse",
+ marginTop: "1.4rem",
+ alignItems: "center",
+ justifyContent: "end",
+ gridColumn: "3",
+ },
+ headerStyle: null,
+ primaryLabel: "Search",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 0,
+ defaultValues: {
+ campaignName: "",
+ campaignType: "",
+ },
+ fields: [
+ {
+ label: "CAMPAIGN_SEARCH_NAME",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "campaignName",
+ error: "TQM_ERR_VALID_CAMPAIGN_NAME",
+ style: {
+ marginBottom: "0px",
+ },
+ },
+ },
+ {
+ label: "CAMPAIGN_SEARCH_TYPE",
+ type: "apidropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ optionsCustomStyle: {
+ top: "2.3rem",
+ },
+ name: "campaignType",
+ optionsKey: "code",
+ allowMultiSelect: false,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigDrafts",
+ customfn: "populateCampaignTypeReqCriteria",
+ },
+ },
+ ],
+ },
+ label: "",
+ labelMobile: "ES_COMMON_SEARCH",
+ children: {},
+ show: true,
+ },
+ searchResult: {
+ uiConfig: {
+ columns: [
+ {
+ label: "CAMPAIGN_NAME",
+ jsonPath: "campaignName",
+ additionalCustomization: true,
+ },
+ {
+ label: "CAMPAIGN_TYPE",
+ jsonPath: "projectType",
+ prefix: "CAMPAIGN_PROJECT_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_BENEFICIARY_TYPE",
+ jsonPath: "additionalDetails.beneficiaryType",
+ prefix: "",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_START_DATE",
+ jsonPath: "startDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ {
+ label: "CAMPAIGN_END_DATE",
+ jsonPath: "endDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ ],
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "CampaignDetails",
+ // customDefaultPagination: {
+ // limit: 5,
+ // offset: 0,
+ // },
+ // customPageSizesArray: [5, 10, 15, 20],
+ tableClassName: "table campaign-table",
+ },
+ children: {},
+ show: true,
+ },
+ links: {
+ show: false,
+ },
+ filter: {
+ show: false,
+ },
+ },
+ additionalSections: {},
+ persistFormData: true,
+ showAsRemovableTagsInMobile: true,
+ },
+ {
+ label: "CAMPAIGN_FAILED",
+ type: "search",
+ apiDetails: {
+ serviceName: "/project-factory/v1/project-type/search",
+ requestParam: {},
+ requestBody: {},
+ minParametersForSearchForm: 0,
+ minParametersForFilterForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigFailed",
+ tableFormJsonPath: "requestBody.inbox",
+ filterFormJsonPath: "requestBody.custom",
+ searchFormJsonPath: "requestBody.custom",
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ headerLabel: "ES_COMMON_SEARCH",
+ type: "search",
+ typeMobile: "filter",
+ searchWrapperStyles: {
+ flexDirection: "column-reverse",
+ marginTop: "1.4rem",
+ alignItems: "center",
+ justifyContent: "end",
+ gridColumn: "3",
+ },
+ headerStyle: null,
+ primaryLabel: "Search",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 0,
+ defaultValues: {
+ name: "",
+ type: "",
+ },
+ fields: [
+ {
+ label: "CAMPAIGN_SEARCH_NAME",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "campaignName",
+ error: "TQM_ERR_VALID_CAMPAIGN_NAME",
+ style: {
+ marginBottom: "0px",
+ },
+ },
+ },
+ {
+ label: "CAMPAIGN_SEARCH_TYPE",
+ type: "apidropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ optionsCustomStyle: {
+ top: "2.3rem",
+ },
+ name: "campaignType",
+ optionsKey: "code",
+ allowMultiSelect: false,
+ masterName: "commonUiConfig",
+ moduleName: "MyCampaignConfigCompleted",
+ customfn: "populateCampaignTypeReqCriteria",
+ },
+ },
+ ],
+ },
+ label: "",
+ labelMobile: "ES_COMMON_SEARCH",
+ children: {},
+ show: true,
+ },
+ searchResult: {
+ uiConfig: {
+ columns: [
+ {
+ label: "CAMPAIGN_NAME",
+ jsonPath: "campaignName",
+ additionalCustomization: true,
+ },
+ {
+ label: "CAMPAIGN_TYPE",
+ jsonPath: "projectType",
+ prefix: "CAMPAIGN_PROJECT_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_BENEFICIARY_TYPE",
+ jsonPath: "additionalDetails.beneficiaryType",
+ prefix: "",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_START_DATE",
+ jsonPath: "startDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ {
+ label: "CAMPAIGN_END_DATE",
+ jsonPath: "endDate",
+ additionalCustomization: true,
+ // disableSortBy: true,
+ },
+ ],
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "CampaignDetails",
+ // customDefaultPagination: {
+ // limit: 5,
+ // offset: 0,
+ // },
+ // customPageSizesArray: [5, 10, 15, 20],
+ tableClassName: "table campaign-table",
+ },
+ children: {},
+ show: true,
+ },
+ links: {
+ show: false,
+ },
+ filter: {
+ show: false,
+ },
+ },
+ additionalSections: {},
+ persistFormData: true,
+ showAsRemovableTagsInMobile: true,
+ },
+ ],
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js
new file mode 100644
index 00000000000..94ffd6c4e56
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js
@@ -0,0 +1,27 @@
+//migrated to mdms
+export const operatorConfig = [
+ {
+ key: 1,
+ code: "LESS_THAN",
+ },
+ {
+ key: 2,
+ code: "GREATER_THAN",
+ },
+ {
+ key: 3,
+ code: "IN_BETWEEN",
+ },
+ {
+ key: 4,
+ code: "EQUAL_TO",
+ },
+ {
+ key: 5,
+ code: "GREATER_THAN_EQUAL_TO",
+ },
+ {
+ key: 6,
+ code: "LESSER_THAN_EQUAL_TO",
+ },
+];
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js
new file mode 100644
index 00000000000..1e33ecd8e41
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js
@@ -0,0 +1,124 @@
+export const previewConfig = {
+ HCM_CAMPAIGN_DATE: {
+ campaignDates: {
+ startDate: "2024-04-01",
+ endDate: "2024-04-26",
+ },
+ },
+ HCM_CAMPAIGN_TYPE: {
+ projectType: {
+ id: "84e28a7b-8c6d-4505-a7ef-5d714e0361f6",
+ name: "mz project type configuration for LLIN Campaigns",
+ code: "LLIN-mz",
+ group: "MALARIA",
+ beneficiaryType: "HOUSEHOLD",
+ eligibilityCriteria: ["All households are eligible.", "Prison inmates are eligible."],
+ dashboardUrls: {
+ NATIONAL_SUPERVISOR: "/digit-ui/employee/dss/landing/national-health-dashboard",
+ PROVINCIAL_SUPERVISOR: "/digit-ui/employee/dss/dashboard/provincial-health-dashboard",
+ DISTRICT_SUPERVISOR: "/digit-ui/employee/dss/dashboard/district-health-dashboard",
+ },
+ taskProcedure: [
+ "1 bednet is to be distributed per 2 household members.",
+ "If there are 4 household members, 2 bednets should be distributed.",
+ "If there are 5 household members, 3 bednets should be distributed.",
+ ],
+ resources: [
+ {
+ productVariantId: "PVAR-2024-02-13-000211",
+ isBaseUnitVariant: false,
+ },
+ ],
+ },
+ },
+ HCM_CAMPAIGN_NAME: {
+ campaignName: "sdkfkdhsdjkhkjsdh",
+ },
+ HCM_CAMPAIGN_CYCLE_CONFIGURE: {
+ cycleConfigure: {
+ cycleConfgureDate: {
+ cycle: 2,
+ deliveries: 1,
+ },
+ cycleData: [
+ {
+ key: 1,
+ fromDate: "2001-12-12",
+ toDate: "2002-11-11",
+ },
+ {
+ key: 2,
+ fromDate: "2002-01-12",
+ toDate: "2011-11-11",
+ },
+ ],
+ },
+ },
+ HCM_CAMPAIGN_DELIVERY_DATA: {
+ deliveryRule: [
+ {
+ cycleIndex: "1",
+ active: false,
+ deliveries: [
+ {
+ deliveryIndex: "1",
+ active: true,
+ deliveryRules: [
+ {
+ ruleKey: 1,
+ delivery: {},
+ attributes: [
+ {
+ key: 1,
+ attribute: {
+ key: 1,
+ code: "Age",
+ },
+ operator: {
+ key: 1,
+ code: "LESS_THAN",
+ },
+ value: "576",
+ },
+ ],
+ products: [],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ cycleIndex: "2",
+ active: true,
+ deliveries: [
+ {
+ deliveryIndex: "1",
+ active: true,
+ deliveryRules: [
+ {
+ ruleKey: 1,
+ delivery: {},
+ attributes: [
+ {
+ key: 1,
+ attribute: {
+ key: 1,
+ code: "Age",
+ },
+ operator: {
+ key: 2,
+ code: "GREATER_THAN",
+ },
+ value: "65",
+ },
+ ],
+ products: [],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ undefined: {},
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js
new file mode 100644
index 00000000000..449b55450b1
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js
@@ -0,0 +1,15 @@
+//migrated to mdms
+export const productType = [
+ {
+ key: 1,
+ code: "BEDNET",
+ },
+ {
+ key: 2,
+ code: "TABLET",
+ },
+ {
+ key: 3,
+ code: "DRUG",
+ },
+];
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js
new file mode 100644
index 00000000000..48611ca7a41
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js
@@ -0,0 +1,80 @@
+export const schemaConfig = {
+ Boundary: {
+ $schema: "http://json-schema.org/draft-07/schema#",
+ title: "BoundaryTemplateSchema",
+ type: "object",
+ properties: {
+ "Boundary Code": {
+ type: "string",
+ minLength: 1,
+ },
+ "Target at the Selected Boundary level": {
+ type: "integer",
+ minimum: 1,
+ maximum: 100000000,
+ },
+ },
+ required: ["Boundary Code"],
+ },
+ facilityWithBoundary: {
+ $schema: "http://json-schema.org/draft-07/schema#",
+ title: "FacilityTemplateSchema",
+ type: "object",
+ properties: {
+ "Facility Name": {
+ type: "string",
+ maxLength: 2000,
+ minLength: 1,
+ },
+ "Facility Type": {
+ type: "string",
+ enum: ["Warehouse", "Health Facility"],
+ },
+ "Facility Status": {
+ type: "string",
+ enum: ["Temporary", "Permanent"],
+ },
+ Capacity: {
+ type: "integer",
+ minimum: 1,
+ maximum: 100000000,
+ multipleOf: 1,
+ },
+ "Boundary Code": {
+ type: "string",
+ minLength: 1,
+ },
+ },
+ required: ["Facility Name", "Facility Type", "Facility Status", "Capacity", "Boundary Code"],
+ },
+ User: {
+ $schema: "http://json-schema.org/draft-07/schema#",
+ title: "UserTemplateSchema",
+ type: "object",
+ properties: {
+ "Name of the Person (Mandatory)": {
+ type: "string",
+ maxLength: 128,
+ minLength: 1,
+ },
+ "Phone Number": {
+ type: "integer",
+ minimum: 100000000,
+ maximum: 9999999999,
+ },
+ "Role (Mandatory)": {
+ type: "string",
+ },
+ "Employment Type (Mandatory)": {
+ type: "string",
+ enum: ["Temporary", "Permanent"],
+ },
+ "Capacity": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 100000000
+ }
+ },
+ required: ["Name of the Person (Mandatory)", "Phone Number (Mandatory)", "Role (Mandatory)", "Employment Type (Mandatory)"],
+ },
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js
new file mode 100644
index 00000000000..feb20e7a340
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js
@@ -0,0 +1,47 @@
+import utils from "../utils";
+import { useSearchCampaign } from "./services/useSearchCampaign";
+import useCreateCampaign from "./useCreateCampaign";
+import { useProductList } from "./useProductList";
+import useUpdateCampaign from "./useUpdateCampaign";
+import { useGenerateIdCampaign } from "./useGenerateIdCampaign";
+import { useResourceData } from "./useResourceData";
+import useCreateProductVariant from "./useCreateProductVariant";
+import useCreateProduct from "./useCreateProduct";
+import useParallelSearch from "./useParallelSearch";
+
+const UserService = {};
+
+const workbench = {};
+
+const contracts = {};
+
+const campaign = {
+ useProductList,
+ useCreateCampaign,
+ useSearchCampaign,
+ useUpdateCampaign,
+ useGenerateIdCampaign,
+ useResourceData,
+ useCreateProduct,
+ useCreateProductVariant,
+ useParallelSearch,
+};
+
+const Hooks = {
+ campaign,
+};
+
+const Utils = {
+ browser: {
+ sample: () => {},
+ },
+ workbench: {
+ ...utils,
+ },
+};
+
+export const CustomisedHooks = {
+ Hooks,
+ UserService,
+ Utils,
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js
new file mode 100644
index 00000000000..d78f2255133
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js
@@ -0,0 +1,19 @@
+const createCampaignService = async (req, tenantId) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/project-factory/v1/project-type/create",
+ body: {
+ CampaignDetails: req,
+ },
+ });
+ return response;
+ } catch (error) {
+ if (!error?.response?.data?.Errors[0].description) {
+ throw new Error(error?.response?.data?.Errors[0].code);
+ } else {
+ throw new Error(error?.response?.data?.Errors[0].description);
+ }
+ }
+};
+
+export default createCampaignService;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js
new file mode 100644
index 00000000000..3fae8e281ac
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js
@@ -0,0 +1,20 @@
+const updateCampaignService = async (req, tenantId) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/project-factory/v1/project-type/update",
+ body: {
+ CampaignDetails: req,
+ },
+ });
+ return response;
+ } catch (error) {
+ // throw new Error(error?.response?.data?.Errors[0].message);
+ if (!error?.response?.data?.Errors[0].description) {
+ throw new Error(error?.response?.data?.Errors[0].code);
+ } else {
+ throw new Error(error?.response?.data?.Errors[0].description);
+ }
+ }
+};
+
+export default updateCampaignService;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js
new file mode 100644
index 00000000000..dbc5fc52040
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js
@@ -0,0 +1,21 @@
+import { useQuery } from "react-query";
+
+const searchCampaignService = async ({ tenantId, filter, pagination }) => {
+ const response = await Digit.CustomService.getResponse({
+ url: "/project-factory/v1/project-type/search",
+ body: {
+ CampaignDetails: {
+ tenantId: tenantId,
+ ...filter,
+ pagination: {
+ ...pagination,
+ },
+ },
+ },
+ });
+ return response?.CampaignDetails;
+};
+
+export const useSearchCampaign = ({ tenantId, filter, pagination, config = {} }) => {
+ return useQuery(["SEARCH_CAMPAIGN", tenantId, filter, pagination], () => searchCampaignService({ tenantId, filter, pagination }), config);
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js
new file mode 100644
index 00000000000..cf01fe94ef4
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js
@@ -0,0 +1,10 @@
+import { useMutation } from "react-query";
+import createCampaignService from "./services/createCampaignService";
+
+const useCreateCampaign = (tenantId) => {
+ return useMutation((reqData) => {
+ return createCampaignService(reqData, tenantId);
+ });
+};
+
+export default useCreateCampaign;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js
new file mode 100644
index 00000000000..70954c9802d
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js
@@ -0,0 +1,24 @@
+import { useMutation } from "react-query";
+
+const createProductService = async (req, tenantId) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/product/v1/_create",
+ body: {
+ Product: req,
+ apiOperation: "CREATE",
+ },
+ });
+ return response;
+ } catch (error) {
+ throw new Error(error?.response?.data?.Errors?.[0].description);
+ }
+};
+
+const useCreateProduct = (tenantId) => {
+ return useMutation((reqData) => {
+ return createProductService(reqData, tenantId);
+ });
+};
+
+export default useCreateProduct;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js
new file mode 100644
index 00000000000..4063f6dc24c
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js
@@ -0,0 +1,24 @@
+import { useMutation } from "react-query";
+
+const createProductVariantService = async (req, tenantId) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/product/variant/v1/_create",
+ body: {
+ ProductVariant: req,
+ apiOperation: "CREATE",
+ },
+ });
+ return response;
+ } catch (error) {
+ throw new Error(error?.response?.data?.Errors?.[0].description);
+ }
+};
+
+const useCreateProductVariant = (tenantId) => {
+ return useMutation((reqData) => {
+ return createProductVariantService(reqData, tenantId);
+ });
+};
+
+export default useCreateProductVariant;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js
new file mode 100644
index 00000000000..af75746abdd
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js
@@ -0,0 +1,26 @@
+export const useGenerateIdCampaign = ({ type, hierarchyType, filters, campaignId, config = {}, forceUpdate = "true" }) => {
+ const updatedFilters = filters?.map(({ type, ...rest }) => ({
+ ...rest,
+ boundaryType: type,
+ }));
+ const reqCriteria = {
+ url: `/project-factory/v1/data/_generate`,
+ changeQueryName: `${type}${hierarchyType}${filters}`,
+ params: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ type: type,
+ forceUpdate: forceUpdate,
+ hierarchyType: hierarchyType,
+ campaignId: campaignId,
+ },
+ body: type === "boundary" ? (updatedFilters === undefined ? { Filters: null } : { Filters: { boundaries: updatedFilters } }) : {},
+ config: {
+ ...config,
+ cacheTime: 0,
+ staleTime: 0,
+ },
+ };
+ const { data: Data, refetch, isLoading } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+
+ return { isLoading: isLoading, data: Data?.GeneratedResource?.[0]?.id, refetch };
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js
new file mode 100644
index 00000000000..6a2adb07f10
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js
@@ -0,0 +1,88 @@
+const useParallelSearch = async ({ parentArray, tenantId, boundaryType, hierarchy, targetedData }) => {
+ let cacheData = window.Digit.SessionStorage.get("HCM_CAMPAIGN_BOUNDARY_DATA") ? window.Digit.SessionStorage.get("HCM_CAMPAIGN_BOUNDARY_DATA") : {};
+ let missingParent = null;
+ let removeData = null;
+
+ function findMissingCodes(d, c) {
+ let missingCodes = [];
+
+ for (let i = 0; i < d?.length; i++) {
+ let found = false;
+ for (let j = 0; j < c?.length; j++) {
+ if (d?.[i] === c?.[j]?.parentCode) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ missingCodes?.push(d[i]);
+ }
+ }
+
+ return missingCodes;
+ }
+
+ function removeMissingParentCodes(cacheData, parentArray) {
+ const validParentCodes = new Set(parentArray);
+
+ return cacheData?.filter((obj) => validParentCodes?.has(obj?.parentCode));
+ }
+
+ function checkremoveMissingParentCodes(cacheData, parentArray) {
+ const validParentCodes = new Set(parentArray);
+ return cacheData?.filter((obj) => !validParentCodes?.has(obj?.parentCode));
+ }
+
+ function checkParentCodePresence(data, array) {
+ return array.every((item) => data.some((entry) => entry.parentCode === item));
+ }
+ if (parentArray?.length > cacheData?.[targetedData]?.length) {
+ missingParent = findMissingCodes(parentArray, cacheData?.[targetedData]);
+ const requests = missingParent.map((parentCode) => {
+ return Digit.CustomService.getResponse({
+ url: "/boundary-service/boundary-relationships/_search",
+ params: {
+ tenantId: tenantId,
+ hierarchyType: hierarchy,
+ boundaryType: boundaryType,
+ parent: parentCode,
+ },
+ body: {},
+ }).then((boundaryTypeData) => ({ parentCode, boundaryTypeData }));
+ });
+ const newData = await Promise.all(requests);
+ const setcacheData = { ...cacheData, [targetedData]: cacheData?.[targetedData] ? [...cacheData?.[targetedData], ...newData] : [...newData] };
+ window.Digit.SessionStorage.set("HCM_CAMPAIGN_BOUNDARY_DATA", setcacheData);
+ return setcacheData?.[targetedData];
+ } else if (cacheData?.[targetedData]?.length > parentArray?.length && checkParentCodePresence(cacheData?.[targetedData], parentArray)) {
+ removeData = removeMissingParentCodes(cacheData?.[targetedData], parentArray);
+ const setcacheData = { ...cacheData, [targetedData]: [...removeData] };
+ // window.Digit.SessionStorage.set("HCM_CAMPAIGN_BOUNDARY_DATA", setcacheData);
+ return setcacheData?.[targetedData];
+ } else if (
+ parentArray?.length === cacheData?.[targetedData]?.length &&
+ !checkremoveMissingParentCodes(cacheData?.[targetedData], parentArray)?.length &&
+ findMissingCodes(parentArray, cacheData?.[targetedData])?.length === 0
+ ) {
+ return cacheData?.[targetedData];
+ } else {
+ const requests = parentArray.map((parentCode) => {
+ return Digit.CustomService.getResponse({
+ url: "/boundary-service/boundary-relationships/_search",
+ params: {
+ tenantId: tenantId,
+ hierarchyType: hierarchy,
+ boundaryType: boundaryType,
+ parent: parentCode,
+ },
+ body: {},
+ }).then((boundaryTypeData) => ({ parentCode, boundaryTypeData }));
+ });
+ const newData = await Promise.all(requests);
+ const setcacheData = { ...cacheData, [targetedData]: cacheData?.targetedData ? [...cacheData?.targetedData, ...newData] : [...newData] };
+ window.Digit.SessionStorage.set("HCM_CAMPAIGN_BOUNDARY_DATA", setcacheData);
+ return setcacheData?.[targetedData];
+ }
+};
+
+export default useParallelSearch;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js
new file mode 100644
index 00000000000..cb102a128e7
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js
@@ -0,0 +1,53 @@
+export const useProductList = (tenantId) => {
+ const reqCriteriaVariant = {
+ url: `/product/variant/v1/_search`,
+ params: { tenantId: tenantId, limit: 1000, offset: 0 },
+ body: {
+ ProductVariant: {},
+ },
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.ProductVariant;
+ },
+ },
+ };
+
+ const { isLoading, data: productVariant, isFetching } = Digit.Hooks.useCustomAPIHook(reqCriteriaVariant);
+
+ const reqCriteriaProduct = {
+ url: `/product/v1/_search`,
+ params: { tenantId: tenantId, limit: 1000, offset: 0 },
+ body: {
+ Product: {
+ id: productVariant?.map((i) => i?.productId),
+ },
+ },
+ config: {
+ enabled: productVariant && !isLoading ? true : false,
+ select: (data) => {
+ return data?.Product;
+ },
+ },
+ };
+
+ const { isLoading: isProductLoading, data: product } = Digit.Hooks.useCustomAPIHook(reqCriteriaProduct);
+
+ let productList;
+ if (productVariant && product) {
+ productList = productVariant
+ ?.map((item) => {
+ const target = product?.find((j) => j.id === item.productId);
+ if (!target?.name || !item?.variation) {
+ return null;
+ }
+ return {
+ ...item,
+ displayName: `${target?.name} - ${item?.variation}`,
+ };
+ })
+ ?.filter((i) => i !== null);
+ }
+
+ return productList;
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js
new file mode 100644
index 00000000000..0c8f41f8288
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js
@@ -0,0 +1,107 @@
+import axios from 'axios';
+import * as XLSX from 'xlsx';
+import { baseTimeOut } from '../configs/baseTimeOut';
+export const useResourceData = async (data, hierarchyType, type, tenantId, id , baseTimeOut) => {
+
+
+ let Type;
+ let jsonDataLength;
+ let Error = {
+ isError: false,
+ error: {},
+ };
+ let response;
+ if (type === "facilityWithBoundary") {
+ Type = "facility";
+ } else if (type === "userWithBoundary") {
+ Type = "user";
+ } else {
+ Type = "boundaryWithTarget";
+ }
+ try {
+ if(data){
+ axios
+ .get("/filestore/v1/files/id", {
+ responseType: "arraybuffer",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ "auth-token": Digit.UserService.getUser()?.["access_token"],
+ },
+ params: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ fileStoreId: data?.[0]?.filestoreId,
+ },
+ })
+ .then(async (res) => {
+ const fileData = res.data;
+ const workbook = XLSX.read(fileData, { type: 'buffer' });
+ const sheetName = workbook.SheetNames[1];
+ const worksheet = workbook.Sheets[sheetName];
+ const jsonData = XLSX.utils.sheet_to_json(worksheet);
+ jsonDataLength = jsonData.length;
+ });
+ }
+ const responseTemp = await Digit.CustomService.getResponse({
+ url: "/project-factory/v1/data/_create",
+ body: {
+ ResourceDetails: {
+ type: Type,
+ hierarchyType: hierarchyType,
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ fileStoreId: data?.[0]?.filestoreId,
+ action: "validate",
+ campaignId: id,
+ additionalDetails: {},
+ },
+ },
+ });
+
+ response = responseTemp;
+
+ } catch (error) {
+ if (error?.response && error?.response?.data) {
+ const errorMessage = error?.response?.data?.Errors?.[0]?.message;
+ const errorDescription = error?.response?.data?.Errors?.[0]?.description;
+ if (errorDescription) {
+ Error.error = `${errorMessage} : ${errorDescription}`;
+ Error.isError = true;
+ return Error;
+ } else {
+ Error = errorMessage;
+ Error.isError = true;
+ return Error;
+ }
+ }
+ }
+
+ let searchResponse;
+ let status = "validation-started";
+ const baseDelay = baseTimeOut?.baseTimeout?.[0]?.baseTimeOut;
+ const maxTime = baseTimeOut?.baseTimeout?.[0]?.maxTime;
+ let retryInterval = Math.min(baseDelay * jsonDataLength , maxTime);
+
+ await new Promise((resolve) => setTimeout(resolve, retryInterval));
+
+ // Retry until a response is received
+ while (status !== "failed" && status !== "invalid" && status !== "completed") {
+ searchResponse = await Digit.CustomService.getResponse({
+ url: "/project-factory/v1/data/_search",
+ body: {
+ SearchCriteria: {
+ id: [response?.ResourceDetails?.id],
+ tenantId: tenantId,
+ type: Type,
+ },
+ },
+ });
+ status = searchResponse?.ResourceDetails?.[0]?.status;
+ if (status !== "failed" && status !== "invalid" && status !== "completed") {
+ await new Promise((resolve) => setTimeout(resolve, retryInterval));
+ }
+ }
+ if (Error.isError) {
+ return Error;
+ }
+ return searchResponse?.ResourceDetails?.[0];
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js
new file mode 100644
index 00000000000..7123ace38c8
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js
@@ -0,0 +1,10 @@
+import { useMutation } from "react-query";
+import updateCampaignService from "./services/updateCampaignService";
+
+const useUpdateCampaign = (tenantId) => {
+ return useMutation((reqData) => {
+ return updateCampaignService(reqData, tenantId);
+ });
+};
+
+export default useUpdateCampaign;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js
new file mode 100644
index 00000000000..1ce059dbbef
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js
@@ -0,0 +1,161 @@
+import { Loader, FormComposerV2, Header } from "@egovernments/digit-ui-react-components";
+import React, { useState, useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { useHistory, useLocation } from "react-router-dom";
+import { addProductConfig } from "../../configs/addProductConfig";
+import { Toast } from "@egovernments/digit-ui-components";
+
+function AddProduct() {
+ const { t } = useTranslation();
+ const history = useHistory();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const [showToast, setShowToast] = useState(null);
+ const { state } = useLocation();
+ const { mutate: createProduct } = Digit.Hooks.campaign.useCreateProduct(tenantId);
+ const { mutate: createProductVariant } = Digit.Hooks.campaign.useCreateProductVariant(tenantId);
+
+ const checkValid = (formData) => {
+ const target = formData?.["addProduct"];
+ let isValid = false;
+ if (target) {
+ isValid = target?.some((i) => !i.name || !i.type || !i.variant);
+ return !isValid;
+ } else {
+ return isValid;
+ }
+ };
+ const closeToast = () => {
+ setShowToast(null);
+ };
+
+ useEffect(() => {
+ if (showToast) {
+ setTimeout(closeToast, 5000);
+ }
+ }, [showToast]);
+
+ const onSubmit = async (formData) => {
+ const isValid = checkValid(formData);
+ const invalidName = formData?.addProduct
+ ?.map((i) => {
+ if (i?.name?.length > 2 && i?.name?.length < 101) {
+ return true;
+ } else {
+ return false;
+ }
+ })
+ ?.includes(false);
+
+ const invalidVariant = formData?.addProduct
+ ?.map((i) => {
+ if (i?.variant?.length > 2 && i?.variant?.length < 101) {
+ return true;
+ } else {
+ return false;
+ }
+ })
+ ?.includes(false);
+
+ if (!isValid) {
+ setShowToast({ key: "error", label: "CAMPAIGN_ADD_PRODUCT_MANDATORY_ERROR", isError: true });
+ return;
+ }
+
+ if (invalidName) {
+ setShowToast({ key: "error", label: "CAMPAIGN_PRODUCT_NAME_ERROR", isError: true });
+ return;
+ }
+
+ if (invalidVariant) {
+ setShowToast({ key: "error", label: "CAMPAIGN_PRODUCT_VARIANT_ERROR", isError: true });
+ return;
+ }
+
+ const payloadData = formData?.["addProduct"]?.map((i) => ({
+ tenantId: tenantId,
+ type: i?.type?.code,
+ name: i?.name,
+ }));
+
+ await createProduct(payloadData, {
+ onError: (error, variables) => {
+ console.log(error);
+ setShowToast({ key: "error", label: error, isError: true });
+ },
+ onSuccess: async (data) => {
+ const resData = data?.Product;
+ const variantPayload = resData.map((i) => {
+ const target = formData?.["addProduct"]?.find((f) => f.name === i.name);
+ if (target) {
+ return {
+ tenantId: tenantId,
+ productId: i?.id,
+ variation: target?.variant,
+ sku: `${target?.name} - ${target?.variant}`,
+ };
+ }
+ return;
+ });
+ await createProductVariant(variantPayload, {
+ onError: (error, variables) => {
+ console.log(error);
+ setShowToast({ key: "error", label: error, isError: true });
+ },
+ onSuccess: async (data) => {
+ history.push(`/${window.contextPath}/employee/campaign/response?isSuccess=${true}`, {
+ message: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE",
+ preText: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE_PRE_TEXT",
+ boldText: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE_BOLD_TEXT",
+ postText: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE_POST_TEXT",
+ actionLabel: "ES_PRODUCT_RESPONSE_ACTION",
+ actionLink: `/${window.contextPath}/employee/campaign/setup-campaign${state?.urlParams}`,
+ });
+ },
+ });
+ },
+ });
+ return;
+ };
+ const onFormValueChange = (setValue, formData, formState, reset, setError, clearErrors, trigger, getValues) => {
+ return;
+ };
+
+ const onSecondayActionClick = () => {
+ history.push(`/${window.contextPath}/employee/campaign/setup-campaign${state?.urlParams}`);
+ };
+
+ return (
+
+ {
+ return {
+ ...config,
+ };
+ })}
+ onSubmit={onSubmit}
+ fieldStyle={{ marginRight: 0 }}
+ noBreakLine={true}
+ cardClassName={"page-padding-fix"}
+ onFormValueChange={onFormValueChange}
+ actionClassName={"addProductActionClass"}
+ showSecondaryLabel={true}
+ secondaryLabel={t("HCM_BACK")}
+ onSecondayActionClick={onSecondayActionClick}
+ />
+
+ {showToast && (
+ setShowToast(false)}
+ />
+ )}
+
+ );
+}
+
+export default AddProduct;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js
new file mode 100644
index 00000000000..78691266b13
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js
@@ -0,0 +1,248 @@
+import React, { useReducer, Fragment, useEffect, useState } from "react";
+import { CardText, LabelFieldPair, Card, CardLabel, CardSubHeader, Paragraph, Header } from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import { TextInput, InfoCard } from "@egovernments/digit-ui-components";
+// import { deliveryConfig } from "../../configs/deliveryConfig";
+
+const initialState = (saved, filteredDeliveryConfig, refetch) => {
+ const data = {
+ cycleConfgureDate: {
+ cycle:
+ saved?.cycleConfgureDate?.cycle && !refetch
+ ? saved?.cycleConfgureDate?.cycle
+ : filteredDeliveryConfig?.cycleConfig
+ ? filteredDeliveryConfig?.cycleConfig?.cycle
+ : 1,
+ deliveries:
+ saved?.cycleConfgureDate?.deliveries && !refetch
+ ? saved?.cycleConfgureDate?.deliveries
+ : filteredDeliveryConfig?.cycleConfig
+ ? filteredDeliveryConfig?.cycleConfig?.deliveries
+ : 1,
+ },
+ cycleData: saved?.cycleData ? [...saved?.cycleData] : [],
+ };
+ // onSelect("cycleConfigure", state);
+ return data;
+};
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case "RELOAD":
+ return initialState(action.saved, action.filteredDeliveryConfig, action.refetch);
+ case "UPDATE_CYCLE":
+ return { ...state, cycleConfgureDate: { ...state.cycleConfgureDate, cycle: action.payload } };
+ case "UPDATE_DELIVERY":
+ return { ...state, cycleConfgureDate: { ...state.cycleConfgureDate, deliveries: action.payload } };
+ case "SELECT_TO_DATE":
+ return {
+ ...state,
+ cycleData: updateCycleData(state.cycleData, action.index, { toDate: action.payload }),
+ // cycleData: state.cycleData.map((item) => (item.key === action.index ? { ...item, toDate: action.payload } : item)),
+ };
+ case "SELECT_FROM_DATE":
+ return {
+ ...state,
+ cycleData: updateCycleData(state.cycleData, action.index, { fromDate: action.payload }),
+ // cycleData: state.cycleData.map((item) => (item.key === action.index ? { ...item, fromDate: action.payload } : item)),
+ };
+ default:
+ return state;
+ }
+};
+
+const updateCycleData = (cycleData, index, update) => {
+ const existingItem = cycleData.find((item) => item.key === index);
+
+ if (!existingItem) {
+ // If the item with the specified key doesn't exist, add a new item
+ return [...cycleData, { key: index, ...update }];
+ }
+
+ // If the item exists, update it
+ return cycleData.map((item) => (item.key === index ? { ...item, ...update } : item));
+};
+
+function CycleConfiguration({ onSelect, formData, control, ...props }) {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const selectedProjectType = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_TYPE?.projectType?.code;
+ const { isLoading: deliveryConfigLoading, data: filteredDeliveryConfig } = Digit.Hooks.useCustomMDMS(
+ tenantId,
+ "HCM-ADMIN-CONSOLE",
+ [{ name: "deliveryConfig" }],
+ {
+ select: (data) => {
+ const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig;
+ return temp?.find((i) => i?.projectType === selectedProjectType);
+ // return deliveryConfig?.find((i) => i?.projectType === selectedProjectType);
+ },
+ }
+ );
+ const saved = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure;
+ const refetch = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure?.cycleConfgureDate
+ ?.refetch;
+ const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ const [state, dispatch] = useReducer(reducer, initialState(saved, filteredDeliveryConfig, refetch));
+ const { cycleConfgureDate, cycleData } = state;
+ const { t } = useTranslation();
+ const [dateRange, setDateRange] = useState({
+ startDate: tempSession?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate,
+ endDate: tempSession?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate,
+ });
+ const [executionCount, setExecutionCount] = useState(0);
+
+ useEffect(() => {
+ if (!deliveryConfigLoading) {
+ dispatch({
+ type: "RELOAD",
+ saved: saved,
+ filteredDeliveryConfig: filteredDeliveryConfig,
+ refetch: refetch,
+ });
+ }
+ }, [filteredDeliveryConfig, deliveryConfigLoading]);
+ useEffect(() => {
+ onSelect("cycleConfigure", state);
+ }, [state]);
+
+ useEffect(() => {
+ if (executionCount < 5) {
+ onSelect("cycleConfigure", state);
+ setExecutionCount((prevCount) => prevCount + 1);
+ }
+ });
+
+ const updateCycle = (d) => {
+ if (d === 0 || d > 5) return;
+ if (Number(d?.target?.value) === 0 || Number(d?.target?.value) > 5) return;
+ // if (d?.target?.value.trim() === "") return;
+ dispatch({ type: "UPDATE_CYCLE", payload: d?.target?.value ? Number(d?.target?.value) : d?.target?.value === "" ? d.target.value : d });
+ };
+
+ const updateDelivery = (d) => {
+ if (d === 0 || d > 5) return;
+ if (Number(d?.target?.value) === 0 || Number(d?.target?.value) > 5) return;
+ // if (d?.target?.value.trim() === "") return;
+ dispatch({ type: "UPDATE_DELIVERY", payload: d?.target?.value ? Number(d?.target?.value) : d });
+ };
+
+ const selectToDate = (index, d) => {
+ dispatch({ type: "SELECT_TO_DATE", index, payload: d });
+ };
+
+ const selectFromDate = (index, d) => {
+ dispatch({ type: "SELECT_FROM_DATE", index, payload: d });
+ };
+
+ return (
+ <>
+
+ {t(
+ `CAMPAIGN_PROJECT_${
+ tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code
+ ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase()
+ : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase()
+ }`
+ )}
+
+
+ ,
+ {t(
+ `CAMPAIGN_CYCLE_INFO_${
+ tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code
+ ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase()
+ : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase()
+ }`
+ )},
+ ]}
+ label={"Info"}
+ headerClassName={"headerClassName"}
+ />
+
+
+ {t(
+ `CAMPAIGN_CYCLE_CONFIGURE_HEADING_${
+ tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code
+ ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase()
+ : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase()
+ }`
+ )}
+
+
+
+ {t(`CAMPAIGN_NO_OF_CYCLE`)}
+ *
+
+ updateCycle(d)} />
+ {/* updateCycle(d)} /> */}
+
+
+
+ {t(`CAMPAIGN_NO_OF_DELIVERY`)}
+ *
+
+ updateDelivery(d)} />
+ {/* updateDelivery(d)} /> */}
+
+
+
+ {t(`CAMPAIGN_ADD_START_END_DATE_TEXT`)}
+ {[...Array(cycleConfgureDate.cycle)].map((_, index) => (
+
+
+ {t(`CAMPAIGN_CYCLE`)} {index + 1}
+
+
+ j.key === index + 1)?.fromDate}
+ min={
+ index > 0 && cycleData?.find((j) => j.key === index)?.toDate
+ ? new Date(new Date(cycleData?.find((j) => j.key === index)?.toDate)?.getTime() + 86400000)?.toISOString()?.split("T")?.[0]
+ : dateRange?.startDate
+ }
+ max={dateRange?.endDate}
+ onChange={(d) => selectFromDate(index + 1, d)}
+ />
+ j.key === index + 1)?.toDate}
+ min={
+ cycleData?.find((j) => j.key === index + 1)?.fromDate
+ ? new Date(new Date(cycleData?.find((j) => j.key === index + 1)?.fromDate)?.getTime() + 86400000)?.toISOString()?.split("T")?.[0]
+ : null
+ }
+ max={dateRange?.endDate}
+ onChange={(d) => selectToDate(index + 1, d)}
+ />
+
+
+ ))}
+
+ >
+ );
+}
+
+export default CycleConfiguration;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js
new file mode 100644
index 00000000000..4e72d9f98e1
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js
@@ -0,0 +1,80 @@
+import React, { useMemo, useState, useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { Button, Header, InboxSearchComposer, Loader } from "@egovernments/digit-ui-react-components";
+import { useHistory, useLocation } from "react-router-dom";
+import { myCampaignConfig } from "../../configs/myCampaignConfig";
+
+/**
+ * The `MyCampaign` function is a React component that displays a header with a campaign search title
+ * and an inbox search composer with tabs for different configurations.
+ * @returns The `MyCampaign` component is returning a React fragment containing a Header component with
+ * a title fetched using the `useTranslation` hook, and a div with a className of
+ * "inbox-search-wrapper" that contains an `InboxSearchComposer` component. The `InboxSearchComposer`
+ * component is being passed props such as `configs`, `showTab`, `tabData`, and `onTabChange
+ */
+const MyCampaign = () => {
+ const { t } = useTranslation();
+ const location = useLocation();
+ const history = useHistory();
+ const moduleName = Digit?.Utils?.getConfigModuleName() || "commonCampaignUiConfig";
+ const tenant = Digit.ULBService.getStateId();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const [config, setConfig] = useState(myCampaignConfig?.myCampaignConfig?.[0]);
+ const [tabData, setTabData] = useState(
+ myCampaignConfig?.myCampaignConfig?.map((configItem, index) => ({ key: index, label: configItem.label, active: index === 0 ? true : false }))
+ );
+
+ const onTabChange = (n) => {
+ setTabData((prev) => prev.map((i, c) => ({ ...i, active: c === n ? true : false })));
+ setConfig(myCampaignConfig?.myCampaignConfig?.[n]);
+ };
+
+ useEffect(() => {
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID");
+ }, []);
+
+ const onClickRow = ({ original: row }) => {
+ const currentTab = tabData?.find((i) => i?.active === true)?.label;
+ switch (currentTab) {
+ case "CAMPAIGN_ONGOING":
+ history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`);
+ break;
+ case "CAMPAIGN_COMPLETED":
+ history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`);
+ break;
+ case "CAMPAIGN_UPCOMING":
+ history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`);
+ break;
+ case "CAMPAIGN_DRAFTS":
+ history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&draft=${true}&fetchBoundary=${true}`);
+ break;
+ case "CAMPAIGN_FAILED":
+ history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`);
+ break;
+ default:
+ break;
+ }
+ };
+
+ return (
+
+ {t("CAMPAIGN_SEARCH_TITLE")}
+
+
+
+
+ );
+};
+
+export default MyCampaign;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js
new file mode 100644
index 00000000000..8e981b17965
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js
@@ -0,0 +1,65 @@
+import React, { useState, Fragment } from "react";
+import { Link, useHistory, useLocation } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import { ActionBar, SubmitBar } from "@egovernments/digit-ui-react-components";
+import { PanelCard } from "@egovernments/digit-ui-components";
+
+const Response = () => {
+ const { t } = useTranslation();
+ const history = useHistory();
+ const queryStrings = Digit.Hooks.useQueryParams();
+ const [campaignId, setCampaignId] = useState(queryStrings?.campaignId);
+ const [isResponseSuccess, setIsResponseSuccess] = useState(
+ queryStrings?.isSuccess === "true" ? true : queryStrings?.isSuccess === "false" ? false : true
+ );
+ const { state } = useLocation();
+ const isMobile = window.Digit.Utils.browser.isMobile();
+
+ const navigate = (page) => {
+ switch (page) {
+ case "contracts-inbox": {
+ history.push(`/${window.contextPath}/employee/tqm/summary`);
+ }
+ }
+ };
+
+ const children = [
+
+ {state?.boldText ? (
+
+ {t(state?.preText)}
+ {t(state?.boldText)}
+ {t(state?.postText)}
+
+ ) : (
+ t(state?.text, { CAMPAIGN_ID: campaignId })
+ )}
+
,
+ ];
+
+ return (
+ <>
+
+ {isMobile ? (
+
+
+
+ ) : (
+
+
+
+
+
+ )}
+ >
+ );
+};
+
+export default Response;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js
new file mode 100644
index 00000000000..0dc19dab4d7
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js
@@ -0,0 +1,1491 @@
+import { Loader, FormComposerV2, Header, MultiUploadWrapper, Button, Close, LogoutIcon } from "@egovernments/digit-ui-react-components";
+import React, { useState, useEffect, useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import { useHistory, useParams } from "react-router-dom";
+import { CampaignConfig } from "../../configs/CampaignConfig";
+import { QueryClient, useQueryClient } from "react-query";
+import { Stepper, Toast } from "@egovernments/digit-ui-components";
+import _ from "lodash";
+
+/**
+ * The `SetupCampaign` function in JavaScript handles the setup and management of campaign details,
+ * including form data handling, validation, and submission.
+ * @returns The `SetupCampaign` component is being returned. It consists of a form setup for creating
+ * or updating a campaign with multiple steps like campaign details, delivery details, boundary
+ * details, targets, facility details, user details, and review details. The form data is validated at
+ * each step, and the user can navigate between steps using a stepper component. The form submission
+ * triggers API calls to create or update the campaign
+ */
+
+function loopAndReturn(dataa) {
+ let newArray = [];
+ const data = dataa?.map((i) => ({ ...i, operator: { code: i?.operator }, attribute: { code: i?.attribute } }));
+
+ data.forEach((item) => {
+ // Check if an object with the same attribute already exists in the newArray
+ const existingIndex = newArray.findIndex((element) => element.attribute.code === item.attribute.code);
+ if (existingIndex !== -1) {
+ // If an existing item is found, replace it with the new object
+ const existingItem = newArray[existingIndex];
+ newArray[existingIndex] = {
+ attribute: existingItem.attribute,
+ operator: { code: "IN_BETWEEN" },
+ toValue: existingItem.value && item.value ? Math.min(existingItem.value, item.value) : null,
+ fromValue: existingItem.value && item.value ? Math.max(existingItem.value, item.value) : null,
+ };
+ }
+ // else if (item?.operator?.code === "EQUAL_TO" && item?.attribute?.code === "Gender") {
+ // newArray.push({
+ // ...item,
+ // value: item?.value
+ // ? {
+ // code: item?.value,
+ // }
+ // : null,
+ // });
+ // }
+ else {
+ // If no existing item with the same attribute is found, push the current item
+ // if (item?.operator?.code === "EQUAL_TO" && item?.attribute?.code === "Gender") {
+ // newArray.push({
+ // ...item,
+ // value: {
+ // code: item?.value,
+ // },
+ // });
+ // } else {
+ newArray.push(item);
+ // }
+ }
+ });
+
+ const withKey = newArray.map((i, c) => ({ key: c + 1, ...i }));
+ return withKey;
+}
+
+function cycleDataRemap(data) {
+ if (!data) return null;
+ const uniqueCycleObjects = Object.values(
+ data?.reduce((acc, obj) => {
+ acc[obj?.cycleNumber] = acc[obj?.cycleNumber] || obj;
+ return acc;
+ }, {})
+ );
+ return uniqueCycleObjects.map((i, n) => {
+ return {
+ key: i.cycleNumber,
+ fromDate: i?.startDate ? new Date(i?.startDate)?.toISOString()?.split("T")?.[0] : null,
+ toDate: i?.endDate ? new Date(i?.endDate)?.toISOString()?.split("T")?.[0] : null,
+ };
+ });
+}
+
+// function reverseDeliveryRemap(data) {
+// if (!data) return null;
+// const reversedData = [];
+// let currentCycleIndex = null;
+// let currentDeliveryIndex = null;
+// let currentCycle = null;
+// let currentDelivery = null;
+
+// data.forEach((item, index) => {
+// if (currentCycleIndex !== item.cycleNumber) {
+// currentCycleIndex = item.cycleNumber;
+// currentCycle = {
+// cycleIndex: currentCycleIndex.toString(),
+// active: index === 0, // Set active to true only for the first index
+// deliveries: [],
+// };
+// reversedData.push(currentCycle);
+// }
+
+// if (currentDeliveryIndex !== item.deliveryNumber) {
+// currentDeliveryIndex = item.deliveryNumber;
+// currentDelivery = {
+// deliveryIndex: currentDeliveryIndex.toString(),
+// active: item?.deliveryNumber === 1, // Set active to true only for the first index
+// deliveryRules: [],
+// };
+// currentCycle.deliveries.push(currentDelivery);
+// }
+
+// currentDelivery.deliveryRules.push({
+// ruleKey: currentDelivery.deliveryRules.length + 1,
+// delivery: {},
+// attributes: loopAndReturn(item.conditions),
+// products: [...item.products],
+// });
+// });
+
+// return reversedData;
+// }
+
+function reverseDeliveryRemap(data) {
+ if (!data) return null;
+ const reversedData = [];
+ let currentCycleIndex = null;
+ let currentCycle = null;
+
+ data.forEach((item, index) => {
+ if (currentCycleIndex !== item.cycleNumber) {
+ currentCycleIndex = item.cycleNumber;
+ currentCycle = {
+ cycleIndex: currentCycleIndex.toString(),
+ active: index === 0, // Initialize active to false
+ deliveries: [],
+ };
+ reversedData.push(currentCycle);
+ }
+
+ const deliveryIndex = item.deliveryNumber.toString();
+
+ let delivery = currentCycle.deliveries.find((delivery) => delivery.deliveryIndex === deliveryIndex);
+
+ if (!delivery) {
+ delivery = {
+ deliveryIndex: deliveryIndex,
+ active: item.deliveryNumber === 1, // Set active to true only for the first delivery
+ deliveryRules: [],
+ };
+ currentCycle.deliveries.push(delivery);
+ }
+
+ delivery.deliveryRules.push({
+ ruleKey: item.deliveryRuleNumber,
+ delivery: {},
+ deliveryType: item?.deliveryType,
+ attributes: loopAndReturn(item.conditions),
+ products: [...item.products],
+ });
+ });
+
+ return reversedData;
+}
+
+function groupByType(data) {
+ if (!data) return null;
+ const result = {};
+
+ data.forEach((item) => {
+ if (result[item.type]) {
+ result[item.type].push(item);
+ } else {
+ result[item.type] = [item];
+ }
+ });
+
+ return {
+ TenantBoundary: {
+ boundary: result,
+ },
+ };
+}
+
+function groupByTypeRemap(data) {
+ if (!data) return null;
+
+ const result = {};
+
+ data.forEach((item) => {
+ const type = item?.type;
+ const boundaryType = item?.type;
+ const parentCode = item?.parent;
+ const obj = {
+ parentCode,
+ boundaryTypeData: {
+ TenantBoundary: [
+ {
+ boundary: [{ ...item, boundaryType }],
+ },
+ ],
+ },
+ };
+
+ if (result[type]) {
+ result[type][0].boundaryTypeData.TenantBoundary[0].boundary.push(item);
+ } else {
+ result[type] = [obj];
+ }
+ });
+
+ return result;
+}
+
+// Example usage:
+// updateUrlParams({ id: 'sdjkhsdjkhdshfsdjkh', anotherParam: 'value' });
+function updateUrlParams(params) {
+ const url = new URL(window.location.href);
+ Object.entries(params).forEach(([key, value]) => {
+ url.searchParams.set(key, value);
+ });
+ window.history.replaceState({}, "", url);
+}
+
+const SetupCampaign = ({ hierarchyType }) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const { t } = useTranslation();
+ const history = useHistory();
+ const [currentStep, setCurrentStep] = useState(0);
+ const [totalFormData, setTotalFormData] = useState({});
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [campaignConfig, setCampaignConfig] = useState(CampaignConfig(totalFormData, null, isSubmitting));
+ const [shouldUpdate, setShouldUpdate] = useState(false);
+ const [params, setParams, clearParams] = Digit.Hooks.useSessionStorage("HCM_CAMPAIGN_MANAGER_FORM_DATA", {});
+ const [dataParams, setDataParams] = Digit.Hooks.useSessionStorage("HCM_CAMPAIGN_MANAGER_UPLOAD_ID", {});
+ const [showToast, setShowToast] = useState(null);
+ const [summaryErrors, setSummaryErrors] = useState({});
+ const { mutate } = Digit.Hooks.campaign.useCreateCampaign(tenantId);
+ const { mutate: updateCampaign } = Digit.Hooks.campaign.useUpdateCampaign(tenantId);
+ const searchParams = new URLSearchParams(location.search);
+ const id = searchParams.get("id");
+ const isPreview = searchParams.get("preview");
+ const isSummary = searchParams.get("summary");
+ const noAction = searchParams.get("action");
+ const isDraft = searchParams.get("draft");
+ const isSkip = searchParams.get("skip");
+ const keyParam = searchParams.get("key");
+ const [isDraftCreated, setIsDraftCreated] = useState(false);
+ const filteredBoundaryData = params?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData;
+ const client = useQueryClient();
+ // const hierarchyType2 = params?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.hierarchy?.hierarchyType
+ const [currentKey, setCurrentKey] = useState(() => {
+ const keyParam = searchParams.get("key");
+ return keyParam ? parseInt(keyParam) : 1;
+ });
+
+ // const [lowest, setLowest] = useState(null);
+ const [fetchBoundary, setFetchBoundary] = useState(() => Boolean(searchParams.get("fetchBoundary")));
+ const [fetchUpload, setFetchUpload] = useState(false);
+ const [enabled, setEnabled] = useState(false);
+ const [targetEnabled, setTargetEnabled] = useState(false);
+ const [facilityEnabled, setFacilityEnabled] = useState(false);
+ const [userEnabled, setUserEnabled] = useState(false);
+ const [active, setActive] = useState(0);
+ const { data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]);
+ const [refetchGenerate, setRefetchGenerate] = useState(null);
+ // const hierarchyType = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy;
+
+ // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy;
+ const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]);
+
+ const reqCriteria = {
+ url: `/boundary-service/boundary-hierarchy-definition/_search`,
+ changeQueryName: `${hierarchyType}`,
+ body: {
+ BoundaryTypeHierarchySearchCriteria: {
+ tenantId: tenantId,
+ limit: 2,
+ offset: 0,
+ hierarchyType: hierarchyType,
+ },
+ },
+ };
+
+ const { data: hierarchyDefinition } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+
+ // useEffect(() => {
+ // if (hierarchyDefinition) {
+ // setLowest(
+ // hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.filter(
+ // (e) => !hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.find((e1) => e1?.parentBoundaryType == e?.boundaryType)
+ // )
+ // );
+ // }
+ // }, [hierarchyDefinition]);
+ const { isLoading: draftLoading, data: draftData, error: draftError, refetch: draftRefetch } = Digit.Hooks.campaign.useSearchCampaign({
+ tenantId: tenantId,
+ filter: {
+ ids: [id],
+ },
+ config: {
+ enabled: id ? true : false,
+ select: (data) => {
+ return data?.[0];
+ },
+ },
+ });
+
+ const { isLoading, data: projectType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-PROJECT-TYPES", [{ name: "projectTypes" }]);
+
+ useEffect(() => {
+ if (fetchUpload) {
+ setFetchUpload(false);
+ }
+ if (fetchBoundary && currentKey > 5) {
+ setFetchBoundary(false);
+ }
+ }, [fetchUpload, fetchBoundary]);
+
+ useEffect(() => {
+ if (isPreview === "true") {
+ setIsDraftCreated(true);
+ setCurrentKey(10);
+ return;
+ }
+ if (isDraft === "true") {
+ setIsDraftCreated(true);
+ if (isSkip === "false") {
+ currentKey !== 1 ? null : setCurrentKey(1);
+ } else {
+ setCurrentKey(draftData?.additionalDetails?.key);
+ }
+ return;
+ }
+ }, [isPreview, isDraft, draftData]);
+
+ useEffect(() => {
+ setTotalFormData(params);
+ }, [params]);
+
+ //DATA STRUCTURE
+ useEffect(() => {
+ if (isLoading) return;
+ if (Object.keys(params).length !== 0) return;
+ if (!draftData) return;
+ const delivery = Array.isArray(draftData?.deliveryRules) ? draftData?.deliveryRules : [];
+ const filteredProjectType = projectType?.["HCM-PROJECT-TYPES"]?.projectTypes?.filter((i) => i?.code === draftData?.projectType);
+ const restructureFormData = {
+ HCM_CAMPAIGN_TYPE: { projectType: filteredProjectType?.[0] },
+ HCM_CAMPAIGN_NAME: {
+ campaignName: draftData?.campaignName,
+ },
+ HCM_CAMPAIGN_DATE: {
+ campaignDates: {
+ startDate: draftData?.startDate ? new Date(draftData?.startDate)?.toISOString()?.split("T")?.[0] : "",
+ endDate: draftData?.endDate ? new Date(draftData?.endDate)?.toISOString()?.split("T")?.[0] : "",
+ },
+ },
+ HCM_CAMPAIGN_CYCLE_CONFIGURE: {
+ cycleConfigure: {
+ cycleConfgureDate: draftData?.additionalDetails?.cycleData?.cycleConfgureDate
+ ? draftData?.additionalDetails?.cycleData?.cycleConfgureDate
+ : {
+ cycle: delivery?.map((obj) => obj?.cycleNumber)?.length > 0 ? Math.max(...delivery?.map((obj) => obj?.cycleNumber)) : 1,
+ deliveries: delivery?.map((obj) => obj?.deliveryNumber)?.length > 0 ? Math.max(...delivery?.map((obj) => obj?.deliveryNumber)) : 1,
+ refetch: true,
+ },
+ cycleData: draftData?.additionalDetails?.cycleData?.cycleData
+ ? draftData?.additionalDetails?.cycleData?.cycleData
+ : cycleDataRemap(delivery),
+ },
+ },
+ HCM_CAMPAIGN_DELIVERY_DATA: {
+ deliveryRule: reverseDeliveryRemap(delivery),
+ },
+ HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA: {
+ boundaryType: {
+ boundaryData: groupByTypeRemap(draftData?.boundaries),
+ selectedData: draftData?.boundaries,
+ },
+ },
+ HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA: {
+ uploadBoundary: { uploadedFile: draftData?.resources?.filter((i) => i?.type === "boundaryWithTarget"),
+ isSuccess : draftData?.resources?.filter((i) => i?.type === "boundaryWithTarget").length>0
+ },
+ },
+ HCM_CAMPAIGN_UPLOAD_FACILITY_DATA: {
+ uploadFacility: { uploadedFile: draftData?.resources?.filter((i) => i?.type === "facility") ,
+ isSuccess : draftData?.resources?.filter((i) => i?.type === "facility").length>0
+ }
+ },
+ HCM_CAMPAIGN_UPLOAD_USER_DATA: {
+ uploadUser: { uploadedFile: draftData?.resources?.filter((i) => i?.type === "user") ,
+ isSuccess : draftData?.resources?.filter((i) => i?.type === "user").length>0
+ },
+ },
+ };
+ setParams({ ...restructureFormData });
+ }, [params, draftData, isLoading, projectType]);
+
+ useEffect(() => {
+ setTimeout(() => {
+ setEnabled(fetchUpload || (fetchBoundary && currentKey > 3));
+ setFacilityEnabled(refetchGenerate || (!dataParams?.boundaryId && (fetchUpload || (fetchBoundary && currentKey > 3))));
+ setTargetEnabled(refetchGenerate || (!dataParams?.facilityId && (fetchUpload || (fetchBoundary && currentKey > 3))));
+ setUserEnabled(refetchGenerate || (!dataParams?.userId && (fetchUpload || (fetchBoundary && currentKey > 3))));
+ }, 3000);
+ if (refetchGenerate === true) {
+ setRefetchGenerate(false);
+ }
+ }, [fetchUpload, fetchBoundary, currentKey, dataParams, refetchGenerate]);
+
+ const { data: facilityId, isLoading: isFacilityLoading, refetch: refetchFacility } = Digit.Hooks.campaign.useGenerateIdCampaign({
+ type: "facilityWithBoundary",
+ hierarchyType: hierarchyType,
+ campaignId: id,
+ // config: {
+ // enabled: setTimeout(fetchUpload || (fetchBoundary && currentKey > 6)),
+ // },
+ config: {
+ enabled: facilityEnabled,
+ },
+ });
+
+ const { data: boundaryId, isLoading: isBoundaryLoading, refetch: refetchBoundary } = Digit.Hooks.campaign.useGenerateIdCampaign({
+ type: "boundary",
+ hierarchyType: hierarchyType,
+ campaignId: id,
+ // config: {
+ // enabled: fetchUpload || (fetchBoundary && currentKey > 6),
+ // },
+ config: {
+ enabled: targetEnabled,
+ },
+ });
+
+ const { data: userId, isLoading: isUserLoading, refetch: refetchUser } = Digit.Hooks.campaign.useGenerateIdCampaign({
+ type: "userWithBoundary",
+ hierarchyType: hierarchyType,
+ campaignId: id,
+ // config: {
+ // enabled: fetchUpload || (fetchBoundary && currentKey > 6),
+ // },
+ config: {
+ enabled: userEnabled,
+ },
+ });
+
+ useEffect(() => {
+ if (draftData?.additionalDetails?.facilityId && draftData?.additionalDetails?.targetId && draftData?.additionalDetails?.userId) {
+ setDataParams({
+ ...dataParams,
+ boundaryId: draftData?.additionalDetails?.targetId,
+ facilityId: draftData?.additionalDetails?.facilityId,
+ userId: draftData?.additionalDetails?.userId,
+ hierarchyType: hierarchyType,
+ hierarchy: hierarchyDefinition?.BoundaryHierarchy?.[0],
+ });
+ }
+ }, [isBoundaryLoading, isFacilityLoading, isUserLoading, facilityId, boundaryId, userId, hierarchyDefinition?.BoundaryHierarchy?.[0], draftData]); // Only run if dataParams changes
+
+
+ useEffect(() => {
+ if (hierarchyDefinition?.BoundaryHierarchy?.[0]) {
+ setDataParams({
+ ...dataParams,
+ facilityId: facilityId,
+ boundaryId: boundaryId,
+ userId: userId,
+ hierarchyType: hierarchyType,
+ hierarchy: hierarchyDefinition?.BoundaryHierarchy?.[0],
+ isBoundaryLoading,
+ isFacilityLoading,
+ isUserLoading,
+ });
+ }
+ }, [isBoundaryLoading, isFacilityLoading, isUserLoading, facilityId, boundaryId, userId, hierarchyDefinition?.BoundaryHierarchy?.[0], draftData]);
+ useEffect(() => {
+ setCampaignConfig(CampaignConfig(totalFormData, dataParams, isSubmitting, summaryErrors));
+ }, [totalFormData, dataParams, isSubmitting, summaryErrors]);
+
+ useEffect(() => {
+ setIsSubmitting(false);
+ if (currentKey === 10 && isSummary !== "true") {
+ updateUrlParams({ key: currentKey, summary: true });
+ } else {
+ updateUrlParams({ key: currentKey, summary: false });
+ setSummaryErrors(null);
+ }
+ }, [currentKey]);
+
+ function restructureData(data) {
+ const dateData = totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure?.cycleData;
+ const restructuredData = [];
+
+ data.forEach((cycle) => {
+ cycle.deliveries.forEach((delivery, index) => {
+ delivery.deliveryRules.forEach((rule) => {
+ const restructuredRule = {
+ startDate: Digit.Utils.date.convertDateToEpoch(dateData?.find((i) => i.key == cycle.cycleIndex)?.fromDate), // Hardcoded for now
+ endDate: Digit.Utils.date.convertDateToEpoch(dateData?.find((i) => i?.key == cycle?.cycleIndex)?.toDate), // Hardcoded for now
+ cycleNumber: parseInt(cycle.cycleIndex),
+ deliveryNumber: parseInt(delivery.deliveryIndex),
+ deliveryType: rule?.deliveryType,
+ deliveryRuleNumber: parseInt(rule.ruleKey), // New key added
+ products: [],
+ conditions: [],
+ };
+
+ rule.attributes.forEach((attribute) => {
+ if (attribute?.operator?.code === "IN_BETWEEN") {
+ restructuredRule.conditions.push({
+ attribute: attribute?.attribute?.code
+ ? attribute?.attribute?.code
+ : typeof attribute?.attribute === "string"
+ ? attribute?.attribute
+ : null,
+ operator: "LESS_THAN_EQUAL_TO",
+ value: attribute.fromValue ? Number(attribute.fromValue) : null,
+ });
+
+ restructuredRule.conditions.push({
+ attribute: attribute?.attribute?.code
+ ? attribute?.attribute?.code
+ : typeof attribute?.attribute === "string"
+ ? attribute?.attribute
+ : null,
+ operator: "GREATER_THAN_EQUAL_TO",
+ value: attribute.toValue ? Number(attribute.toValue) : null,
+ });
+ } else {
+ restructuredRule.conditions.push({
+ attribute: attribute?.attribute?.code
+ ? attribute?.attribute?.code
+ : typeof attribute?.attribute === "string"
+ ? attribute?.attribute
+ : null,
+ operator: attribute.operator ? attribute.operator.code : null,
+ value:
+ attribute?.attribute?.code === "Gender" && attribute?.value?.length > 0
+ ? attribute?.value
+ : attribute?.value
+ ? Number(attribute?.value)
+ : null,
+ });
+ }
+ });
+
+ rule.products.forEach((prod) => {
+ restructuredRule.products.push({
+ value: prod?.value,
+ name: prod?.name,
+ count: prod?.count,
+ });
+ });
+
+ restructuredData.push(restructuredRule);
+ });
+ });
+ });
+
+ return restructuredData;
+ }
+
+ function resourceData(facilityData, boundaryData, userData) {
+ const resources = [facilityData, boundaryData, userData].filter((data) => data !== null && data !== undefined);
+ return resources;
+ }
+
+ useEffect(async () => {
+ if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) {
+ const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule);
+ }
+ }, [shouldUpdate]);
+
+ const compareIdentical = (draftData, payload) => {
+ return _.isEqual(draftData, payload);
+ };
+ //API CALL
+ useEffect(async () => {
+ if (shouldUpdate === true) {
+ if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.skipAPICall && !id) {
+ return;
+ } else if (filteredConfig?.[0]?.form?.[0]?.isLast) {
+ const reqCreate = async () => {
+ let payloadData = { ...draftData };
+ payloadData.hierarchyType = hierarchyType;
+ payloadData.startDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate
+ ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate)
+ : null;
+ payloadData.endDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate
+ ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate)
+ : null;
+ payloadData.tenantId = tenantId;
+ payloadData.action = "create";
+ payloadData.campaignName = totalFormData?.HCM_CAMPAIGN_NAME?.campaignName;
+ if (totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData) {
+ payloadData.boundaries = totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData;
+ }
+ const temp = resourceData(
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0],
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0],
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0]
+ );
+ payloadData.resources = temp;
+ payloadData.projectType = totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.code;
+ payloadData.additionalDetails = {
+ beneficiaryType: totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType,
+ key: currentKey,
+ targetId: dataParams?.boundaryId,
+ facilityId: dataParams?.facilityId,
+ userId: dataParams?.userId,
+ };
+ if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) {
+ const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule);
+ payloadData.deliveryRules = temp;
+ }
+
+ // await mutate(payloadData, {
+ // onError: (error, variables) => {},
+ // onSuccess: async (data) => {
+ // draftRefetch();
+ // history.push(
+ // `/${window.contextPath}/employee/campaign/response?campaignId=${data?.CampaignDetails?.campaignNumber}&isSuccess=${true}`,
+ // {
+ // message: "ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE",
+ // text: "ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE_TEXT",
+ // }
+ // );
+ // Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ // },
+ // });
+ if (compareIdentical(draftData, payloadData) === false) {
+ await updateCampaign(payloadData, {
+ onError: (error, variables) => {
+ console.log(error);
+ setShowToast({ key: "error", label: error?.message ? error?.message : error });
+ },
+ onSuccess: async (data) => {
+ draftRefetch();
+ history.push(
+ `/${window.contextPath}/employee/campaign/response?campaignId=${data?.CampaignDetails?.campaignNumber}&isSuccess=${true}`,
+ {
+ message: t("ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE"),
+ text: t("ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE_TEXT"),
+ info: t("ES_CAMPAIGN_SUCCESS_INFO_TEXT"),
+ actionLabel: t("HCM_CAMPAIGN_SUCCESS_RESPONSE_ACTION"),
+ actionLink: `/${window.contextPath}/employee/campaign/my-campaign`,
+ }
+ );
+ Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ },
+ });
+ }
+ };
+
+ reqCreate();
+ } else if (!isDraftCreated && !id) {
+ const reqCreate = async () => {
+ let payloadData = {};
+ payloadData.hierarchyType = hierarchyType;
+ if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate) {
+ payloadData.startDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate
+ ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate)
+ : null;
+ }
+ if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate) {
+ payloadData.endDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate
+ ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate)
+ : null;
+ }
+ payloadData.tenantId = tenantId;
+ payloadData.action = "draft";
+ payloadData.campaignName = totalFormData?.HCM_CAMPAIGN_NAME?.campaignName;
+ if (totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData) {
+ payloadData.boundaries = totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData;
+ }
+ const temp = resourceData(
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0],
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0],
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0]
+ );
+ payloadData.resources = temp;
+ payloadData.projectType = totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.code;
+ payloadData.additionalDetails = {
+ beneficiaryType: totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType,
+ key: currentKey,
+ targetId: dataParams?.boundaryId,
+ facilityId: dataParams?.facilityId,
+ userId: dataParams?.userId,
+ };
+ if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) {
+ const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule);
+ payloadData.deliveryRules = temp;
+ }
+
+ await mutate(payloadData, {
+ onError: (error, variables) => {
+ if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) {
+ setShowToast({ key: "error", label: error?.message ? error?.message : error });
+ }
+ },
+ onSuccess: async (data) => {
+ updateUrlParams({ id: data?.CampaignDetails?.id });
+ setIsDraftCreated(true);
+ draftRefetch();
+ if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) {
+ setCurrentKey(currentKey + 1);
+ }
+ },
+ });
+ };
+
+ reqCreate();
+ } else {
+ const reqCreate = async () => {
+ let payloadData = { ...draftData };
+ payloadData.hierarchyType = hierarchyType;
+ if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate) {
+ payloadData.startDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate
+ ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate)
+ : null;
+ }
+ if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate) {
+ payloadData.endDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate
+ ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate)
+ : null;
+ }
+ payloadData.tenantId = tenantId;
+ payloadData.action = "draft";
+ payloadData.campaignName = totalFormData?.HCM_CAMPAIGN_NAME?.campaignName;
+ if (totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData) {
+ payloadData.boundaries = totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData;
+ }
+ const temp = resourceData(
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0],
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0],
+ totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0]
+ );
+ payloadData.resources = temp;
+ payloadData.projectType = totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.code;
+ payloadData.additionalDetails = {
+ beneficiaryType: totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType,
+ key: currentKey,
+ targetId: dataParams?.boundaryId,
+ facilityId: dataParams?.facilityId,
+ userId: dataParams?.userId,
+ };
+ if (totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure) {
+ payloadData.additionalDetails.cycleData = totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure;
+ } else {
+ payloadData.additionalDetails.cycleData = {};
+ }
+ if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) {
+ const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule);
+ payloadData.deliveryRules = temp;
+ } else {
+ payloadData.deliveryRules = [];
+ }
+ if (!payloadData?.startDate && !payloadData?.endDate) {
+ delete payloadData?.startDate;
+ delete payloadData?.endDate;
+ }
+ if (compareIdentical(draftData, payloadData) === false) {
+ await updateCampaign(payloadData, {
+ onError: (error, variables) => {
+ console.log(error);
+ if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) {
+ setShowToast({ key: "error", label: error?.message ? error?.message : error });
+ }
+ },
+ onSuccess: async (data) => {
+ updateUrlParams({ id: data?.CampaignDetails?.id });
+ draftRefetch();
+ if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) {
+ setCurrentKey(currentKey + 1);
+ }
+ },
+ });
+ } else {
+ setCurrentKey(currentKey + 1);
+ }
+ };
+
+ reqCreate();
+ }
+ setShouldUpdate(false);
+ }
+ }, [shouldUpdate]);
+
+ function validateCycleData(data) {
+ const { cycle, deliveries } = data?.cycleConfigure?.cycleConfgureDate;
+ const cycleData = data.cycleConfigure.cycleData;
+ let dateError = [];
+ // Validate cycle and deliveries
+ // if (cycle <= 0 || deliveries <= 0) {
+ // return { error: true, message: "DELIVERY_CYCLE_EMPTY_ERROR" };
+ // }
+
+ [...Array(cycle)].forEach((item, index) => {
+ const check = cycleData?.find((i) => i?.key === index + 1);
+ if (!check?.fromDate || !check?.toDate) {
+ dateError.push({
+ name: `CYCLE_${index + 1}`,
+ cycle: index + 1,
+ dateError: true,
+ // error: `Dates are missing in Cycle {CYCLE_NO}${index + 1}`,
+ error: t(`CAMPAIGN_SUMMARY_DATE_MISSING_ERROR`, { CYCLE_NO: index + 1 }),
+ button: t(`CAMPAIGN_SUMMARY_ADD_DATE_ACTION`),
+ });
+ }
+ });
+ // setSummaryErrors((prev) => {
+ // return {
+ // ...prev,
+ // deliveryErrors: prev?.deliveryErrors ? [...prev.deliveryErrors, ...dateError] : [...dateError],
+ // };
+ // });
+ // Validate cycleData length
+ // if (cycleData.length !== cycle) {
+ // return { error: true, message: "DELIVERY_CYCLE_MISMATCH_LENGTH_ERROR" };
+ // }
+
+ // Validate fromDate and startDate in cycleData
+ // for (const item of cycleData) {
+ // if (!item.fromDate || !item.toDate) {
+ // return { error: true, message: "DELIVERY_CYCLE_DATE_ERROR" };
+ // }
+ // }
+
+ return dateError;
+ }
+
+ function validateDeliveryRules(data, projectType, cycleConfigureData) {
+ let isValid = true;
+ let deliveryRulesError = [];
+ let dateError = validateCycleData(cycleConfigureData);
+
+ // Iterate over deliveryRule array
+ data.deliveryRule.forEach((cycle) => {
+ cycle.deliveries.forEach((delivery) => {
+ delivery.deliveryRules.forEach((rule) => {
+ // Validate attributes and products length
+ if (projectType !== "LLIN-MZ" && !rule?.deliveryType) {
+ isValid = false;
+ deliveryRulesError?.push({
+ name: `CYCLE_${cycle?.cycleIndex}`,
+ cycle: cycle?.cycleIndex,
+ // error: `Delivery Type missing in delivery condition ${rule?.ruleKey} delivery ${delivery?.deliveryIndex}`,
+ error: t(`CAMPAIGN_SUMMARY_DELIVERY_TYPE_MISSING_ERROR`, {
+ CONDITION_NO: rule?.ruleKey,
+ DELIVERY_NO: delivery?.deliveryIndex,
+ CYCLE_NO: cycle?.cycleIndex,
+ }),
+ button: t(`CAMPAIGN_SUMMARY_ADD_DELIVERY_TYPE_ACTION`),
+ });
+ // return;
+ }
+ if (rule.attributes.length === 0) {
+ isValid = false;
+ deliveryRulesError?.push({
+ name: `CYCLE_${cycle?.cycleIndex}`,
+ cycle: cycle?.cycleIndex,
+ // error: `Values missing in delivery condition ${rule?.ruleKey} delivery ${delivery?.deliveryIndex}`,
+ error: t(`CAMPAIGN_SUMMARY_VALUES_MISSING_ERROR`, {
+ CONDITION_NO: rule?.ruleKey,
+ DELIVERY_NO: delivery?.deliveryIndex,
+ CYCLE_NO: cycle?.cycleIndex,
+ }),
+ button: t(`CAMPAIGN_SUMMARY_ADD_VALUES_ACTION`),
+ });
+ // return;
+ }
+ if (rule.products.length === 0) {
+ isValid = false;
+ deliveryRulesError?.push({
+ name: `CYCLE_${cycle?.cycleIndex}`,
+ cycle: cycle?.cycleIndex,
+ // error: `Product missing in delivery condition ${rule?.ruleKey} delivery ${delivery?.deliveryIndex}`,
+ error: t(`CAMPAIGN_SUMMARY_PRODUCT_MISSING_ERROR`, {
+ CONDITION_NO: rule?.ruleKey,
+ DELIVERY_NO: delivery?.deliveryIndex,
+ CYCLE_NO: cycle?.cycleIndex,
+ }),
+ button: t(`CAMPAIGN_SUMMARY_ADD_PRODUCT_ACTION`),
+ });
+ // return;
+ }
+
+ rule.attributes.forEach((attribute) => {
+ // Check if attribute, operator, and value are empty
+ if (attribute.attribute === "" || attribute.operator === null || attribute.value === "") {
+ if (attribute?.operator?.code === "IN_BETWEEN" && attribute?.toValue !== "" && attribute?.fromValue !== "") {
+ isValid = true;
+ } else {
+ deliveryRulesError?.push({
+ name: `CYCLE_${cycle?.cycleIndex}`,
+ cycle: cycle?.cycleIndex,
+ error: t(`CAMPAIGN_SUMMARY_ATTRIBUTES_MISSING_ERROR`, {
+ CONDITION_NO: rule?.ruleKey,
+ DELIVERY_NO: delivery?.deliveryIndex,
+ CYCLE_NO: cycle?.cycleIndex,
+ }),
+ // error: `Attributes missing in delivery condition ${rule?.ruleKey} delivery ${delivery?.deliveryIndex}`,
+ button: t(`CAMPAIGN_SUMMARY_ADD_ATTRIBUTES_ACTION`),
+ });
+ isValid = false;
+ }
+ }
+ });
+
+ rule.products.forEach((product) => {
+ // Check if count and value are empty
+ if (product.count === null || product.value === null) {
+ isValid = false;
+ }
+ });
+ });
+ });
+ });
+
+ setSummaryErrors((prev) => {
+ return {
+ ...prev,
+ deliveryErrors: [...deliveryRulesError, ...dateError],
+ };
+ });
+ return isValid;
+ // ? "Delivery rules are valid"
+ // : "Attributes, operators, values, count, or value are not empty in delivery rules or attributes/products length is 0";
+ }
+
+ function checkAttributeValidity(data) {
+ for (const rule of data?.deliveryRule) {
+ for (const delivery of rule?.deliveries) {
+ for (const rule of delivery?.deliveryRules) {
+ for (const attribute of rule?.attributes) {
+ if (
+ attribute?.operator &&
+ attribute?.operator?.code === "IN_BETWEEN" &&
+ attribute?.fromValue &&
+ attribute?.toValue &&
+ attribute?.fromValue !== "" &&
+ attribute?.toValue !== "" &&
+ Number(attribute?.toValue) >= Number(attribute?.fromValue)
+ ) {
+ // return `Error: Attribute "${attribute?.attribute?.code ? attribute?.attribute?.code : attribute?.attribute}" has invalid range (${
+ // attribute.toValue
+ // } to ${attribute.fromValue})`;
+ return "CAMPAIGN_IN_BETWEEN_ERROR";
+ } else if (attribute?.value === 0 || attribute?.value === "0") {
+ return "CAMPAIGN_VALUE_ZERO_ERROR";
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ // function validateBoundaryLevel(data) {
+ // // Extracting boundary types from hierarchy response
+ // const boundaryTypes = new Set(hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy.map((item) => item?.boundaryType));
+
+ // // Extracting unique boundary types from data
+ // const uniqueDataBoundaryTypes = new Set(data?.map((item) => item.type));
+
+ // // Checking if all unique boundary types from hierarchy response are present in data
+ // const allBoundaryTypesPresent = [...boundaryTypes].every((type) => uniqueDataBoundaryTypes.has(type));
+
+ // return allBoundaryTypesPresent;
+ // }
+
+ function validateBoundaryLevel(data) {
+ // Extracting boundary hierarchy from hierarchy definition
+ const boundaryHierarchy = hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy || [];
+
+ // Find the index of the lowest hierarchy
+ const lowestIndex = boundaryHierarchy.findIndex((item) => item?.boundaryType === lowestHierarchy);
+
+ // Create a set of boundary types including only up to the lowest hierarchy
+ const boundaryTypes = new Set(boundaryHierarchy.filter((_, index) => index <= lowestIndex).map((item) => item?.boundaryType));
+
+ // Extracting unique boundary types from data
+ const uniqueDataBoundaryTypes = new Set(data?.map((item) => item.type));
+
+ // Checking if all boundary types from the filtered hierarchy are present in data
+ const allBoundaryTypesPresent = [...boundaryTypes].every((type) => uniqueDataBoundaryTypes.has(type));
+
+ return allBoundaryTypesPresent;
+ }
+
+ // function recursiveParentFind(filteredData) {
+ // const parentChildrenMap = {};
+
+ // // Build the parent-children map
+ // filteredData?.forEach((item) => {
+ // if (item?.parent) {
+ // if (!parentChildrenMap[item?.parent]) {
+ // parentChildrenMap[item?.parent] = [];
+ // }
+ // parentChildrenMap[item?.parent].push(item.code);
+ // }
+ // });
+
+ // // Check for missing children
+ // const missingParents = filteredData?.filter((item) => item?.parent && !parentChildrenMap[item.code]);
+ // const extraParent = missingParents?.filter((i) => i?.type !== lowest?.[0]?.boundaryType);
+
+ // return extraParent;
+ // }
+
+ function recursiveParentFind(filteredData) {
+ const parentChildrenMap = {};
+
+ // Build the parent-children map
+ filteredData?.forEach((item) => {
+ if (item?.parent) {
+ if (!parentChildrenMap[item?.parent]) {
+ parentChildrenMap[item?.parent] = [];
+ }
+ parentChildrenMap[item?.parent].push(item.code);
+ }
+ });
+
+ // Check for missing children
+ const missingParents = filteredData?.filter((item) => item?.parent && !parentChildrenMap[item.code]);
+ const extraParent = missingParents?.filter((i) => i?.type !== lowestHierarchy);
+
+ return extraParent;
+ }
+
+ // validating the screen data on clicking next button
+ const handleValidate = (formData) => {
+ const key = Object.keys(formData)?.[0];
+ switch (key) {
+ case "campaignName":
+ if (typeof formData?.campaignName !== "string" || !formData?.campaignName.trim()) {
+ setShowToast({ key: "error", label: "CAMPAIGN_NAME_MISSING_TYPE_ERROR" });
+ return false;
+ } else if (formData.campaignName.length > 250) {
+ setShowToast({ key: "error", label: "CAMPAIGN_NAME_TOO_LONG_ERROR" });
+ return false;
+ } else {
+ setShowToast(null);
+ return true;
+ }
+ case "projectType":
+ if (!formData?.projectType) {
+ setShowToast({ key: "error", label: "PROJECT_TYPE_UNDEFINED_ERROR" });
+ return false;
+ } else {
+ setShowToast(null);
+ return true;
+ }
+ case "campaignDates":
+ const startDateObj = new Date(formData?.campaignDates?.startDate);
+ const endDateObj = new Date(formData?.campaignDates?.endDate);
+ if (!formData?.campaignDates?.startDate || !formData?.campaignDates?.endDate) {
+ setShowToast({ key: "error", label: `${t("HCM_CAMPAIGN_DATE_MISSING")}` });
+ return false;
+ } else if (endDateObj.getTime() === startDateObj.getTime()) {
+ setShowToast({ key: "error", label: `${t("HCM_CAMPAIGN_END_DATE_EQUAL_START_DATE")}` });
+ return false;
+ } else if (endDateObj.getTime() < startDateObj) {
+ setShowToast({ key: "error", label: `${t("HCM_CAMPAIGN_END_DATE_BEFORE_START_DATE")}` });
+ return false;
+ } else {
+ setShowToast(null);
+ return true;
+ }
+ case "boundaryType":
+ if (formData?.boundaryType?.selectedData) {
+ const validateBoundary = validateBoundaryLevel(formData?.boundaryType?.selectedData);
+ const missedType = recursiveParentFind(formData?.boundaryType?.selectedData);
+ if (!validateBoundary) {
+ setShowToast({ key: "error", label: t("HCM_CAMPAIGN_ALL_THE_LEVELS_ARE_MANDATORY") });
+ return false;
+ } else if (recursiveParentFind(formData?.boundaryType?.selectedData).length > 0) {
+ setShowToast({
+ key: "error",
+ label: `${t(`HCM_CAMPAIGN_FOR`)} ${t(`${hierarchyType}_${missedType?.[0]?.type}`?.toUpperCase())} ${t(missedType?.[0]?.code)} ${t(
+ `HCM_CAMPAIGN_CHILD_NOT_PRESENT`
+ )}`,
+ });
+ return false;
+ }
+ setShowToast(null);
+ const checkEqual = _.isEqual(
+ formData?.boundaryType?.selectedData,
+ totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData
+ );
+ console.log("HSHSHS", checkEqual);
+ setFetchUpload(true);
+ setRefetchGenerate(checkEqual === false ? true : false);
+ return true;
+ } else {
+ setShowToast({ key: "error", label: `${t("HCM_SELECT_BOUNDARY")}` });
+ return false;
+ }
+
+ case "uploadBoundary":
+ if (formData?.uploadBoundary?.isValidation) {
+ setShowToast({ key: "info", label: `${t("HCM_FILE_VALIDATION_PROGRESS")}`, transitionTime: 6000000000 });
+ return false;
+ } else if (formData?.uploadBoundary?.isError) {
+ if (formData?.uploadBoundary?.apiError) {
+ setShowToast({ key: "error", label: formData?.uploadBoundary?.apiError, transitionTime: 6000000000 });
+ } else setShowToast({ key: "error", label: `${t("HCM_FILE_VALIDATION")}` });
+ return false;
+ } else {
+ setShowToast(null);
+ return true;
+ }
+
+ case "uploadFacility":
+ if (formData?.uploadFacility?.isValidation) {
+ setShowToast({ key: "info", label: `${t("HCM_FILE_VALIDATION_PROGRESS")}`, transitionTime: 6000000000 });
+ return false;
+ } else if (formData?.uploadFacility?.isError) {
+ if (formData?.uploadFacility?.apiError) {
+ setShowToast({ key: "error", label: formData?.uploadFacility?.apiError, transitionTime: 6000000000 });
+ } else setShowToast({ key: "error", label: `${t("HCM_FILE_VALIDATION")}` });
+ return false;
+ } else {
+ setShowToast(null);
+ return true;
+ }
+ case "uploadUser":
+ if (formData?.uploadUser?.isValidation) {
+ setShowToast({ key: "info", label: `${t("HCM_FILE_VALIDATION_PROGRESS")}`, transitionTime: 6000000000 });
+ return false;
+ } else if (formData?.uploadUser?.isError) {
+ if (formData?.uploadUser?.apiError) {
+ setShowToast({ key: "error", label: formData?.uploadUser?.apiError, transitionTime: 6000000000 });
+ } else setShowToast({ key: "error", label: `${t("HCM_FILE_VALIDATION")}` });
+ return false;
+ } else {
+ setShowToast(null);
+ return true;
+ }
+
+ case "cycleConfigure":
+ const cycleNumber = formData?.cycleConfigure?.cycleConfgureDate?.cycle;
+ const deliveryNumber = formData?.cycleConfigure?.cycleConfgureDate?.deliveries;
+ if (cycleNumber === "" || cycleNumber === 0 || deliveryNumber === "" || deliveryNumber === 0) {
+ setShowToast({ key: "error", label: "DELIVERY_CYCLE_ERROR" });
+ return false;
+ } else {
+ setShowToast(null);
+ return true;
+ }
+ case "deliveryRule":
+ const isAttributeValid = checkAttributeValidity(formData);
+ if (isAttributeValid) {
+ setShowToast({ key: "error", label: isAttributeValid });
+ return false;
+ }
+ setShowToast(null);
+ return;
+ case "summary":
+ const cycleConfigureData = totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE;
+ const isCycleError = validateCycleData(cycleConfigureData);
+ const deliveryCycleData = totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA;
+ const isDeliveryError = validateDeliveryRules(
+ deliveryCycleData,
+ totalFormData?.["HCM_CAMPAIGN_TYPE"]?.projectType?.code?.toUpperCase(),
+ cycleConfigureData
+ );
+ const isTargetError = totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0]?.filestoreId
+ ? false
+ : (setSummaryErrors((prev) => {
+ return {
+ ...prev,
+ target: [
+ {
+ name: `target`,
+ error: t(`TARGET_FILE_MISSING`),
+ },
+ ],
+ };
+ }),
+ true);
+ const isFacilityError = totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0]?.filestoreId
+ ? false
+ : (setSummaryErrors((prev) => {
+ return {
+ ...prev,
+ facility: [
+ {
+ name: `facility`,
+ error: t(`FACILITY_FILE_MISSING`),
+ },
+ ],
+ };
+ }),
+ true);
+ const isUserError = totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0]?.filestoreId
+ ? false
+ : (setSummaryErrors((prev) => {
+ return {
+ ...prev,
+ user: [
+ {
+ name: `user`,
+ error: t(`USER_FILE_MISSING`),
+ },
+ ],
+ };
+ }),
+ true);
+ if (isCycleError?.length > 0) {
+ setShowToast({ key: "error", label: "DELIVERY_CYCLE_MISMATCH_LENGTH_ERROR" });
+ return false;
+ }
+ if (isDeliveryError === false) {
+ setShowToast({ key: "error", label: "DELIVERY_RULES_ERROR" });
+ return false;
+ }
+ if (isTargetError) {
+ setShowToast({ key: "error", label: "TARGET_DETAILS_ERROR" });
+ return false;
+ }
+ if (isFacilityError) {
+ setShowToast({ key: "error", label: "FACILITY_DETAILS_ERROR" });
+ return false;
+ }
+ if (isUserError) {
+ setShowToast({ key: "error", label: "USER_DETAILS_ERROR" });
+ return false;
+ }
+ setShowToast(null);
+ return true;
+ default:
+ break;
+ }
+ };
+
+ useEffect(() => {
+ if (showToast) {
+ setTimeout(closeToast, 10000);
+ }
+ }, [showToast]);
+
+ const onSubmit = (formData, cc) => {
+ setIsSubmitting(true);
+ const checkValid = handleValidate(formData);
+ if (checkValid === false) {
+ return;
+ }
+
+ const name = filteredConfig?.[0]?.form?.[0]?.name;
+
+ if (name === "HCM_CAMPAIGN_TYPE" && totalFormData?.["HCM_CAMPAIGN_TYPE"]?.projectType?.code !== formData?.projectType?.code) {
+ setTotalFormData((prevData) => ({
+ [name]: formData,
+ }));
+ //to set the data in the local storage
+ setParams({
+ [name]: { ...formData },
+ });
+ } else if (name === "HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA" && formData?.boundaryType?.updateBoundary === true) {
+ setTotalFormData((prevData) => ({
+ ...prevData,
+ [name]: formData,
+ ["HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA"]: {},
+ ["HCM_CAMPAIGN_UPLOAD_FACILITY_DATA"]: {},
+ ["HCM_CAMPAIGN_UPLOAD_USER_DATA"]: {},
+ }));
+ //to set the data in the local storage
+ setParams({
+ ...params,
+ [name]: { ...formData },
+ ["HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA"]: {},
+ ["HCM_CAMPAIGN_UPLOAD_FACILITY_DATA"]: {},
+ ["HCM_CAMPAIGN_UPLOAD_USER_DATA"]: {},
+ });
+ } else {
+ setTotalFormData((prevData) => ({
+ ...prevData,
+ [name]: formData,
+ }));
+ //to set the data in the local storage
+ setParams({
+ ...params,
+ [name]: { ...formData },
+ });
+ }
+
+ if (
+ filteredConfig?.[0]?.form?.[0]?.isLast ||
+ !filteredConfig[0].form[0].body[0].skipAPICall ||
+ (filteredConfig[0].form[0].body[0].skipAPICall && id)
+ ) {
+ setShouldUpdate(true);
+ }
+
+ if (!filteredConfig?.[0]?.form?.[0]?.isLast && !filteredConfig[0].form[0].body[0].mandatoryOnAPI) {
+ setCurrentKey(currentKey + 1);
+ }
+ if (isDraft === "true" && isSkip !== "false") {
+ updateUrlParams({ skip: "false" });
+ }
+ return;
+ };
+
+ const onStepClick = (step) => {
+ if ((currentKey === 5 || currentKey === 6) && step > 1) {
+ return;
+ }
+ const filteredSteps = campaignConfig[0].form.filter((item) => item.stepCount === String(step + 1));
+
+ const key = parseInt(filteredSteps[0].key);
+ const name = filteredSteps[0].name;
+
+ if (step === 6 && Object.keys(totalFormData).includes("HCM_CAMPAIGN_UPLOAD_USER_DATA")) {
+ setCurrentKey(10);
+ setCurrentStep(7);
+ } else if (step === 1 && totalFormData["HCM_CAMPAIGN_NAME"] && totalFormData["HCM_CAMPAIGN_NAME"]) {
+ setCurrentKey(3);
+ setCurrentStep(1);
+ } else if (!totalFormData["HCM_CAMPAIGN_NAME"] || !totalFormData["HCM_CAMPAIGN_NAME"]) {
+ // Do not set stepper and key
+ } else if (Object.keys(totalFormData).includes(name)) {
+ setCurrentKey(key);
+ setCurrentStep(step);
+ // Do not set stepper and key
+ }
+ };
+
+ const filterNonEmptyValues = (obj) => {
+ const keys = [];
+ for (const key in obj) {
+ if (typeof obj[key] === "object" && obj[key] !== null) {
+ // Check if any nested value is non-null and non-empty
+ if (hasNonEmptyValue(obj[key])) {
+ keys.push(key);
+ }
+ } else if (obj[key] !== null && obj[key] !== "") {
+ keys.push(key);
+ }
+ }
+ return keys;
+ };
+
+ const hasNonEmptyValue = (obj) => {
+ for (const key in obj) {
+ if (obj[key] !== null && obj[key] !== "") {
+ if (typeof obj[key] === "object") {
+ if (hasNonEmptyValue(obj[key])) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ const findHighestStepCount = () => {
+ const totalFormDataKeys = Object.keys(totalFormData);
+
+ const nonNullFormDataKeys = filterNonEmptyValues(totalFormData);
+
+ const relatedSteps = campaignConfig?.[0]?.form.filter((step) => nonNullFormDataKeys.includes(step.name));
+
+ const highestStep = relatedSteps.reduce((max, step) => Math.max(max, parseInt(step.stepCount)), 0);
+ if(isDraft == "true"){
+ const filteredSteps = campaignConfig?.[0]?.form.find((item) => item.key === keyParam)?.stepCount;
+ setActive(filteredSteps);
+ }
+ else{
+ setActive(highestStep);
+ }
+
+ // setActive(highestStep);
+ };
+
+ useEffect(() => {
+ findHighestStepCount();
+ }, [totalFormData, campaignConfig]);
+
+ const onSecondayActionClick = () => {
+ if (currentKey > 1) {
+ setShouldUpdate(false);
+ setCurrentKey(currentKey - 1);
+ }
+ };
+
+ // filtering the config on the basis of the screen or key
+ // const filteredConfig = campaignConfig
+ // .map((config) => {
+ // return {
+ // ...config,
+ // form: config?.form.filter((step) => parseInt(step.key) == currentKey),
+ // };
+ // })
+ // .filter((config) => config.form.length > 0);
+
+ const filterCampaignConfig = (campaignConfig, currentKey) => {
+ return campaignConfig
+ .map((config) => {
+ return {
+ ...config,
+ form: config?.form.filter((step) => parseInt(step.key) === currentKey),
+ };
+ })
+ .filter((config) => config.form.length > 0);
+ };
+
+ const [filteredConfig, setFilteredConfig] = useState(filterCampaignConfig(campaignConfig, currentKey));
+
+ useEffect(() => {
+ setFilteredConfig(filterCampaignConfig(campaignConfig, currentKey));
+ }, [campaignConfig, currentKey]);
+
+ const config = filteredConfig?.[0];
+
+ // setting the current step when the key is changed on the basis of the config
+ useEffect(() => {
+ setCurrentStep(Number(filteredConfig?.[0]?.form?.[0]?.stepCount - 1));
+ // setShowToast(null);
+ }, [currentKey, filteredConfig]);
+
+ useEffect(() => {
+ // setCurrentStep(Number(filteredConfig?.[0]?.form?.[0]?.stepCount - 1));
+ setShowToast(null);
+ }, [currentKey]);
+
+ const closeToast = () => {
+ setShowToast(null);
+ };
+
+ if (isPreview === "true" && !draftData) {
+ return ;
+ }
+
+ if (isDraft === "true" && !draftData) {
+ return ;
+ }
+
+ return (
+
+ {noAction !== "false" && (
+
+ )}
+ {
+ return {
+ ...config,
+ body: config?.body.filter((a) => !a.hideInEmployee),
+ };
+ })}
+ onSubmit={onSubmit}
+ showSecondaryLabel={currentKey > 1 ? true : false}
+ secondaryLabel={noAction === "false" ? null : t("HCM_BACK")}
+ actionClassName={"actionBarClass"}
+ className="setup-campaign"
+ cardClassName="setup-campaign-card"
+ noCardStyle={currentKey === 4 || currentStep === 7 || currentStep === 0 ? false : true}
+ onSecondayActionClick={onSecondayActionClick}
+ label={noAction === "false" ? null : filteredConfig?.[0]?.form?.[0]?.isLast === true ? t("HCM_SUBMIT") : t("HCM_NEXT")}
+ />
+ {showToast && (
+
+ )}
+
+ );
+};
+
+export default SetupCampaign;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js
new file mode 100644
index 00000000000..3630f7aba53
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js
@@ -0,0 +1,813 @@
+import {
+ LabelFieldPair,
+ AddIcon,
+ CardLabel,
+ Dropdown,
+ // TextInput,
+ Button,
+ Card,
+ CardHeader,
+ Modal,
+ CloseSvg,
+} from "@egovernments/digit-ui-react-components";
+import { SVG } from "@egovernments/digit-ui-react-components";
+import React, { Fragment, useContext, useEffect, useRef, useState } from "react";
+import { useTranslation } from "react-i18next";
+// import { attributeConfig } from "../../../configs/attributeConfig";
+// import { operatorConfig } from "../../../configs/operatorConfig";
+import RemoveableTagNew from "../../../components/RemovableTagNew";
+import AddProducts from "./AddProductscontext";
+import { CycleContext } from ".";
+import { RadioButtons, TextInput } from "@egovernments/digit-ui-components";
+import { PRIMARY_COLOR } from "../../../utils";
+
+const DustbinIcon = () => (
+
+);
+
+const makeSequential = (jsonArray, keyName) => {
+ return jsonArray.map((item, index) => ({
+ ...item,
+ [keyName]: index + 1,
+ }));
+};
+
+const AddAttributeField = ({
+ config,
+ deliveryRuleIndex,
+ delivery,
+ deliveryRules,
+ setDeliveryRules,
+ attribute,
+ setAttributes,
+ index,
+ onDelete,
+ attributeConfig,
+ operatorConfig,
+ genderConfig,
+}) => {
+ const [val, setVal] = useState("");
+ const [showAttribute, setShowAttribute] = useState(null);
+ const [showOperator, setShowOperator] = useState(null);
+ const [addedOption, setAddedOption] = useState(null);
+ const { t } = useTranslation();
+
+ useEffect(() => {
+ setAddedOption(delivery?.attributes?.map((i) => i?.attribute?.code)?.filter((i) => i));
+ }, [delivery, deliveryRules]);
+
+ const selectValue = (e) => {
+ let val = e.target.value;
+ val = val.replace(/[^\d.]/g, "");
+ val = val.match(/^\d*\.?\d{0,2}/)[0] || "";
+ // if (val.startsWith("-")) {
+ // val = val.slice(1); // Remove the negative sign
+ // }
+ if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) {
+ val = val.slice(0, -1);
+ return;
+ }
+ // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item)));
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).value = val;
+ }
+ return item;
+ });
+ setDeliveryRules(updatedData);
+ };
+
+ const selectGender = (value) => {
+ // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item)));
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).value = value?.code;
+ }
+ return item;
+ });
+ setDeliveryRules(updatedData);
+ };
+
+ const selectToFromValue = (e, range) => {
+ let val = e.target.value;
+ val = val.replace(/[^\d.]/g, "");
+ val = val.match(/^\d*\.?\d{0,2}/)[0] || "";
+ // if (val.startsWith("-")) {
+ // val = val.slice(1); // Remove the negative sign
+ // }
+
+ if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) {
+ val = val.slice(0, -1);
+ return;
+ }
+ if (range === "to") {
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).toValue = val;
+ }
+ return item;
+ });
+ setDeliveryRules(updatedData);
+ } else {
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).fromValue = val;
+ }
+ return item;
+ });
+ setDeliveryRules(updatedData);
+ }
+ };
+
+ const selectAttribute = (value) => {
+ // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item)));
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).attribute = value;
+ item.attributes.find((i) => i.key === attribute.key).value = "";
+ item.attributes.find((i) => i.key === attribute.key).toValue = "";
+ item.attributes.find((i) => i.key === attribute.key).fromValue = "";
+ if (value.code === "Gender") {
+ item.attributes.find((i) => i.key === attribute.key).operator = {
+ code: "EQUAL_TO",
+ };
+ }
+ }
+ return item;
+ });
+ setShowAttribute(value);
+ setDeliveryRules(updatedData);
+ };
+
+ const selectOperator = (value) => {
+ // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item)));
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).operator = value;
+ delete item.attributes.find((i) => i.key === attribute.key).toValue;
+ delete item.attributes.find((i) => i.key === attribute.key).fromValue;
+ }
+ return item;
+ });
+ setShowOperator(value);
+ setDeliveryRules(updatedData);
+ };
+
+ return (
+
+
+
+ {t(`CAMPAIGN_ATTRIBUTE_LABEL`)}
+
+ item?.code === attribute?.attribute?.code)}
+ disable={false}
+ isMandatory={true}
+ option={addedOption ? attributeConfig?.filter((item) => !addedOption.includes(item.code)) : attributeConfig}
+ select={(value) => selectAttribute(value)}
+ optionKey="i18nKey"
+ t={t}
+ />
+
+
+
+ {t(`CAMPAIGN_OPERATOR_LABEL`)}
+
+ selectOperator(value)}
+ optionKey="code"
+ t={t}
+ />
+
+
+ {attribute?.operator?.code === "IN_BETWEEN" ? (
+
+
+ {t(`CAMPAIGN_FROM_LABEL`)}
+
+
+ selectToFromValue(e, "to")}
+ disable={false}
+ />
+
+
+
+
+ {t(`CAMPAIGN_TO_LABEL`)}
+
+
+ selectToFromValue(e, "from")}
+ disable={false}
+ />
+
+
+
+
+ ) : (
+
+ {t(`CAMPAIGN_VALUE_LABEL`)}
+
+ {attribute?.attribute?.code === "Gender" ? (
+ selectGender(value)}
+ optionKey="code"
+ t={t}
+ />
+ ) : (
+
+ )}
+
+
+ )}
+ {delivery.attributes.length !== 1 && (
+
onDelete()}
+ style={{
+ cursor: "pointer",
+ fontWeight: "600",
+ marginLeft: "1rem",
+ fontSize: "1rem",
+ color: PRIMARY_COLOR,
+ display: "flex",
+ gap: "0.5rem",
+ alignItems: "center",
+ marginTop: "1rem",
+ }}
+ >
+
+ {t(`CAMPAIGN_DELETE_ROW_TEXT`)}
+
+ )}
+
+ );
+};
+
+const AddCustomAttributeField = ({
+ config,
+ deliveryRuleIndex,
+ delivery,
+ deliveryRules,
+ setDeliveryRules,
+ attribute,
+ setAttributes,
+ index,
+ onDelete,
+ operatorConfig,
+ genderConfig,
+}) => {
+ const [val, setVal] = useState("");
+ const [showAttribute, setShowAttribute] = useState(null);
+ const [showOperator, setShowOperator] = useState(null);
+ const [addedOption, setAddedOption] = useState(null);
+ const { t } = useTranslation();
+ const { attrConfig } = useContext(CycleContext);
+
+ useEffect(() => {
+ setAddedOption(delivery?.attributes?.map((i) => i?.attribute?.code)?.filter((i) => i));
+ }, [delivery]);
+
+ const selectValue = (e) => {
+ let val = e.target.value;
+ val = val.replace(/[^\d.]/g, "");
+ val = val.match(/^\d*\.?\d{0,2}/)[0] || "";
+ // if (val.startsWith("-")) {
+ // val = val.slice(1); // Remove the negative sign
+ // }
+ if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) {
+ val = val.slice(0, -1);
+ }
+ // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item)));
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).value = val;
+ }
+ return item;
+ });
+ setDeliveryRules(updatedData);
+ };
+
+ const selectOperator = (value) => {
+ // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item)));
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).operator = value;
+ }
+ return item;
+ });
+ setShowOperator(value);
+ setDeliveryRules(updatedData);
+ };
+
+ const selectToFromValue = (e, range) => {
+ let val = e.target.value;
+ val = val.replace(/[^\d.]/g, "");
+ val = val.match(/^\d*\.?\d{0,2}/)[0] || "";
+ // if (val.startsWith("-")) {
+ // val = val.slice(1); // Remove the negative sign
+ // }
+ if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) {
+ val = val.slice(0, -1);
+ return;
+ }
+ if (range === "to") {
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).toValue = val;
+ }
+ return item;
+ });
+ setDeliveryRules(updatedData);
+ } else {
+ const updatedData = deliveryRules.map((item, index) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ item.attributes.find((i) => i.key === attribute.key).fromValue = val;
+ }
+ return item;
+ });
+ setDeliveryRules(updatedData);
+ }
+ };
+
+ return (
+
+
+
+ {t(`CAMPAIGN_ATTRIBUTE_LABEL`)}
+
+
+
+
+ {/* !addedOption.includes(item.code)) : attributeConfig}
+ select={(value) => selectAttribute(value)}
+ optionKey="code"
+ t={t}
+ /> */}
+
+
+
+ {t(`CAMPAIGN_OPERATOR_LABEL`)}
+
+ selectOperator(value)}
+ optionKey="code"
+ t={t}
+ />
+
+ {attribute?.operator?.code === "IN_BETWEEN" ? (
+
+
+ {t(`CAMPAIGN_FROM_LABEL`)}
+
+
+ selectToFromValue(e, "to")}
+ disable={false}
+ />
+
+
+
+
+ {t(`CAMPAIGN_TO_LABEL`)}
+
+
+ selectToFromValue(e, "from")}
+ disable={false}
+ />
+
+
+
+
+ ) : (
+
+ {t(`CAMPAIGN_VALUE_LABEL`)}
+
+ {attribute?.attribute?.code === "Gender" ? (
+ selectGender(value)}
+ optionKey="code"
+ t={t}
+ />
+ ) : (
+
+ )}
+
+
+ )}
+
+ );
+};
+
+const AddAttributeWrapper = ({ targetedData, deliveryRuleIndex, delivery, deliveryRules, setDeliveryRules, index, key }) => {
+ const { campaignData, dispatchCampaignData, filteredDeliveryConfig } = useContext(CycleContext);
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const { isLoading: attributeConfigLoading, data: attributeConfig } = Digit.Hooks.useCustomMDMS(
+ tenantId,
+ "HCM-ADMIN-CONSOLE",
+ [{ name: "attributeConfig" }],
+ {
+ select: (data) => {
+ return data?.["HCM-ADMIN-CONSOLE"]?.attributeConfig;
+ },
+ }
+ );
+ const { isLoading: operatorConfigLoading, data: operatorConfig } = Digit.Hooks.useCustomMDMS(
+ tenantId,
+ "HCM-ADMIN-CONSOLE",
+ [{ name: "operatorConfig" }],
+ {
+ select: (data) => {
+ return data?.["HCM-ADMIN-CONSOLE"]?.operatorConfig;
+ },
+ }
+ );
+ const { isLoading: genderConfigLoading, data: genderConfig } = Digit.Hooks.useCustomMDMS(tenantId, "common-masters", [{ name: "GenderType" }], {
+ select: (data) => {
+ return data?.["common-masters"]?.GenderType?.filter((i) => i.active !== false);
+ },
+ });
+ const [attributes, setAttributes] = useState([{ key: 1, deliveryRuleIndex, attribute: "", operator: "", value: "" }]);
+ const reviseIndexKeys = () => {
+ setAttributes((prev) => prev.map((unit, index) => ({ ...unit, key: index + 1 })));
+ };
+
+ const addMoreAttribute = () => {
+ setDeliveryRules((prev) =>
+ prev.map((item, index) =>
+ index + 1 === deliveryRuleIndex
+ ? {
+ ...item,
+ attributes: [...item.attributes, { key: item.attributes.length + 1, attribute: "", operator: "", value: "" }],
+ }
+ : item
+ )
+ );
+ };
+
+ const deleteAttribute = (_, d) => {
+ // setAttributes((prev) => prev.filter((i) => i.key !== item.key));
+ const newData = deliveryRules.map((item) => {
+ if (item.ruleKey === deliveryRuleIndex) {
+ // If ruleKey matches, remove the specified attribute from attributes array
+ const updatedAttributes = item.attributes.filter((attribute) => attribute.key !== _.key);
+
+ // Reassign keys in sequential order
+ const updatedAttributesSequential = makeSequential(updatedAttributes, "key");
+
+ return {
+ ...item,
+ attributes: updatedAttributesSequential,
+ };
+ }
+ return item;
+ });
+ setDeliveryRules(newData);
+ };
+
+ return (
+
+ {filteredDeliveryConfig?.customAttribute && filteredDeliveryConfig?.projectType === "LLIN-mz"
+ ? delivery.attributes.map((item, index) => (
+ deleteAttribute(item, deliveryRuleIndex)}
+ operatorConfig={operatorConfig}
+ genderConfig={genderConfig}
+ />
+ ))
+ : delivery.attributes.map((item, index) => (
+ deleteAttribute(item, deliveryRuleIndex)}
+ attributeConfig={attributeConfig}
+ operatorConfig={operatorConfig}
+ genderConfig={genderConfig}
+ />
+ ))}
+ {!filteredDeliveryConfig?.attrAddDisable && delivery.attributes.length !== attributeConfig?.length && (
+ }
+ onButtonClick={addMoreAttribute}
+ />
+ )}
+
+ );
+};
+
+const AddDeliveryRule = ({ targetedData, deliveryRules, setDeliveryRules, index, key, delivery, onDelete }) => {
+ const { campaignData, dispatchCampaignData, filteredDeliveryConfig } = useContext(CycleContext);
+ const [showModal, setShowModal] = useState(false);
+ const [showToast, setShowToast] = useState(null);
+ const { t } = useTranslation();
+ const prodRef = useRef();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const closeToast = () => setShowToast(null);
+ const { isLoading: deliveryTypeConfigLoading, data: deliveryTypeConfig } = Digit.Hooks.useCustomMDMS(
+ tenantId,
+ "HCM-ADMIN-CONSOLE",
+ [{ name: "deliveryTypeConfig" }],
+ {
+ select: (data) => {
+ return data?.["HCM-ADMIN-CONSOLE"]?.deliveryTypeConfig;
+ },
+ }
+ );
+ useEffect(() => {
+ if (showToast) {
+ setTimeout(closeToast, 5000);
+ }
+ }, [showToast]);
+
+ const confirmResources = () => {
+ const isValid = prodRef.current?.every((item) => item?.count !== null && item?.value !== null);
+ if (!isValid) {
+ setShowToast({ key: "error", label: "CAMPAIGN_PRODUCT_MISSING_ERROR" });
+ return;
+ }
+ dispatchCampaignData({
+ type: "ADD_PRODUCT",
+ payload: {
+ productData: prodRef.current,
+ delivery: delivery,
+ },
+ });
+ setShowModal(false);
+ };
+
+ const removeProduct = (item) => {
+ const temp = delivery;
+ setDeliveryRules((prevState) => {
+ const updatedDeliveryRules = prevState.map((delivery) => {
+ if (delivery.ruleKey === temp.ruleKey) {
+ const updatedProducts = delivery.products
+ .filter((product) => product.value !== item.value)
+ .map((product, index) => ({ ...product, key: index + 1 }));
+ return { ...delivery, products: updatedProducts };
+ }
+ return delivery;
+ });
+ return updatedDeliveryRules;
+ });
+ };
+
+ const updateDeliveryType = (value) => {
+ const temp = delivery;
+ setDeliveryRules((prevState) => {
+ const updatedDeliveryRules = prevState.map((delivery) => {
+ if (delivery.ruleKey === temp.ruleKey) {
+ return { ...delivery, deliveryType: value?.code };
+ }
+ return delivery;
+ });
+ return updatedDeliveryRules;
+ });
+ };
+
+ return (
+ <>
+
+
+
+ {t(`CAMPAIGN_DELIVERY_RULE_LABEL`)} {delivery.ruleKey}
+
+ {deliveryRules.length !== 1 && (
+ onDelete()}
+ style={{
+ fontWeight: "600",
+ fontSize: "1rem",
+ color: PRIMARY_COLOR,
+ display: "flex",
+ gap: "0.5rem",
+ alignItems: "center",
+ cursor: "pointer",
+ }}
+ >
+ {t(`CAMPAIGN_DELETE_CONDITION_LABEL`)}
+
+ )}
+
+ {filteredDeliveryConfig?.customAttribute && filteredDeliveryConfig?.projectType !== "LLIN-mz" && (
+
+
+ {`${t("HCM_DELIVERY_TYPE")}`}
+
+ i?.code === delivery?.deliveryType)}
+ optionsKey="code"
+ onSelect={(value) => updateDeliveryType(value)}
+ t={t}
+ disabled={
+ filteredDeliveryConfig?.deliveryConfig?.find((i, n) => n === targetedData?.deliveryIndex - 1)?.conditionConfig?.[delivery?.ruleKey - 1]
+ ?.disableDeliveryType
+ ? true
+ : false
+ }
+ />
+
+ )}
+
+
+ {delivery?.products?.length > 0 &&
+ delivery?.products?.map((i) => {
+ return i?.value && i?.count ? (
+ removeProduct(i)}
+ />
+ ) : null;
+ })}
+
+ }
+ onButtonClick={() => setShowModal(true)}
+ />
+
+ {showModal && (
+ setShowModal(false)}>
+
+
+ }
+ children={
+
+ }
+ />
+ )}
+ >
+ );
+};
+
+const AddDeliveryRuleWrapper = ({}) => {
+ const { campaignData, dispatchCampaignData, filteredDeliveryConfig } = useContext(CycleContext);
+ const [targetedData, setTargetedData] = useState(campaignData?.find((i) => i?.active === true)?.deliveries?.find((d) => d?.active === true));
+ const [deliveryRules, setDeliveryRules] = useState(targetedData?.deliveryRules);
+ const { t } = useTranslation();
+
+ useEffect(() => {
+ const dd = campaignData?.find((i) => i?.active === true)?.deliveries?.find((d) => d?.active === true);
+ setTargetedData(dd);
+ }, [campaignData]);
+
+ useEffect(() => {
+ const tt = targetedData?.deliveryRules;
+ setDeliveryRules(tt);
+ }, [targetedData]);
+
+ useEffect(() => {
+ dispatchCampaignData({
+ type: "UPDATE_CAMPAIGN_DATA",
+ payload: {
+ currentDeliveryRules: deliveryRules,
+ },
+ });
+ }, [deliveryRules]);
+
+ const addMoreDelivery = () => {
+ dispatchCampaignData({
+ type: "ADD_DELIVERY_RULE",
+ payload: {
+ currentDeliveryRules: deliveryRules,
+ },
+ });
+ };
+
+ const deleteDeliveryRule = (item) => {
+ dispatchCampaignData({
+ type: "REMOVE_DELIVERY_RULE",
+ payload: {
+ item: item,
+ },
+ });
+ };
+
+ return (
+ <>
+ {deliveryRules?.map((item, index) => (
+ deleteDeliveryRule(item)}
+ />
+ ))}
+ {!filteredDeliveryConfig?.deliveryAddDisable && deliveryRules?.length < 5 && (
+ }
+ onButtonClick={addMoreDelivery}
+ />
+ )}
+ >
+ );
+};
+
+export default AddDeliveryRuleWrapper;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js
new file mode 100644
index 00000000000..75e0afe5c2c
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js
@@ -0,0 +1,290 @@
+import { AddIcon, Button, CardText, Label, LabelFieldPair } from "@egovernments/digit-ui-react-components";
+import React, { Fragment, useContext, useEffect, useState } from "react";
+import PlusMinusInput from "../../../components/PlusMinusInput";
+import { useTranslation } from "react-i18next";
+import { Dropdown, TextInput, Toast } from "@egovernments/digit-ui-components";
+import { Link } from "react-router-dom";
+import { CycleContext } from ".";
+import { PRIMARY_COLOR } from "../../../utils";
+
+const DustbinIcon = () => (
+
+);
+function AddProducts({ stref, selectedDelivery, showToast, closeToast }) {
+ const { t } = useTranslation();
+ const oldSessionData = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ const { campaignData, dispatchCampaignData } = useContext(CycleContext);
+ const tenantId = Digit.ULBService.getStateId();
+ const updateSession = () => {
+ const newData = {
+ ...oldSessionData,
+ HCM_CAMPAIGN_DELIVERY_DATA: {
+ deliveryRule: campaignData,
+ },
+ };
+ window.Digit.SessionStorage.set("HCM_CAMPAIGN_MANAGER_FORM_DATA", newData);
+ };
+ const searchParams = new URLSearchParams(location.search);
+ const id = searchParams.get("id");
+ const [products, setProducts] = useState([
+ {
+ key: 1,
+ count: 1,
+ value: null,
+ },
+ ]);
+ const data = Digit.Hooks.campaign.useProductList(tenantId);
+
+ const filteredData = data?.filter((item) => !selectedDelivery?.products?.some((entry) => entry?.value === item?.id));
+ const temp = filteredData?.filter((item) => !products?.some((entry) => entry?.value?.id === item?.id));
+
+ // const onDeleteProduct = (i, c) => {
+ // const updatedProducts = selectedDelivery.products.filter((product) => product.key !== i.key);
+ // const updatedProductsSequentialKeys = updatedProducts.map((product, index) => ({ ...product, key: index + 1 }));
+ // const updatedDelivery = { ...selectedDelivery, products: updatedProductsSequentialKeys };
+ // const updatedCampaignData = campaignData.map((cycle) => {
+ // if (cycle.active) {
+ // cycle.deliveries.forEach((delivery) => {
+ // if (delivery.active) {
+ // const deliveryRule = delivery.deliveryRules.find((rule) => rule.ruleKey === updatedDelivery.ruleKey);
+ // if (deliveryRule) {
+ // // Update the delivery rule with the updated delivery
+ // deliveryRule.products = updatedDelivery.products;
+ // }
+ // }
+ // });
+ // }
+ // return cycle;
+ // });
+ // setCampaignData(updatedCampaignData);
+ // };
+
+ // const incrementCount = (item, d) => {
+ // const updatedProducts = selectedDelivery.products.map((i) => {
+ // if (i.key === item.key) {
+ // return {
+ // ...i,
+ // count: d,
+ // };
+ // }
+ // return i;
+ // });
+ // const updatedDelivery = { ...selectedDelivery, products: updatedProducts };
+ // const updatedCampaignData = campaignData.map((cycle) => {
+ // if (cycle.active) {
+ // cycle.deliveries.forEach((delivery) => {
+ // if (delivery.active) {
+ // const deliveryRule = delivery.deliveryRules.find((rule) => rule.ruleKey === updatedDelivery.ruleKey);
+ // if (deliveryRule) {
+ // // Update the delivery rule with the updated delivery
+ // deliveryRule.products = updatedDelivery.products;
+ // }
+ // }
+ // });
+ // }
+ // return cycle;
+ // });
+ // setCampaignData(updatedCampaignData);
+ // setProducts(updatedProducts);
+ // };
+
+ // const updatedProductValue = (item, d) => {
+ // const updatedProducts = selectedDelivery.products.map((i) => {
+ // if (i.key === item.key) {
+ // return {
+ // ...i,
+ // value: d.id,
+ // };
+ // }
+ // return i;
+ // });
+ // const updatedDelivery = { ...selectedDelivery, products: updatedProducts };
+ // const updatedCampaignData = campaignData.map((cycle) => {
+ // if (cycle.active) {
+ // cycle.deliveries.forEach((delivery) => {
+ // if (delivery.active) {
+ // const deliveryRule = delivery.deliveryRules.find((rule) => rule.ruleKey === updatedDelivery.ruleKey);
+ // if (deliveryRule) {
+ // // Update the delivery rule with the updated delivery
+ // deliveryRule.products = updatedDelivery.products;
+ // }
+ // }
+ // });
+ // }
+ // return cycle;
+ // });
+ // setCampaignData(updatedCampaignData);
+ // setProducts(updatedProducts);
+ // };
+
+ // const addMoreResource = () => {
+ // const updatedState = campaignData.map((cycle) => {
+ // if (cycle.active) {
+ // const updatedDeliveries = cycle.deliveries.map((dd) => {
+ // if (dd.active) {
+ // const updatedRules = dd.deliveryRules.map((rule) => {
+ // if (rule.ruleKey === selectedDelivery.ruleKey) {
+ // const productToAdd = {
+ // key: rule.products.length + 1,
+ // value: null,
+ // count: 1, // You can set the initial count as per your requirement
+ // };
+ // return {
+ // ...rule,
+ // products: [...rule.products, productToAdd],
+ // };
+ // }
+ // return rule;
+ // });
+ // return {
+ // ...dd,
+ // deliveryRules: updatedRules,
+ // };
+ // }
+ // return dd;
+ // });
+ // return {
+ // ...cycle,
+ // deliveries: updatedDeliveries,
+ // };
+ // }
+ // return cycle;
+ // });
+ // setCampaignData(updatedState);
+ // };
+
+ const add = () => {
+ setProducts((prevState) => [
+ ...prevState,
+ {
+ key: prevState.length + 1,
+ value: null,
+ count: 1,
+ },
+ ]);
+ };
+
+ const deleteItem = (data) => {
+ const fil = products.filter((i) => i.key !== data.key);
+ const up = fil.map((item, index) => ({ ...item, key: index + 1 }));
+ setProducts(up);
+ };
+
+ const incrementC = (data, value) => {
+ if (value?.target?.value.trim() === "") return;
+ if (value?.target?.value.trim() === 0 || value?.target?.value.trim() > 10) return;
+ if (value === 0) return;
+ if (value > 10) return;
+ setProducts((prevState) => {
+ return prevState.map((item) => {
+ if (item.key === data.key) {
+ return { ...item, count: value?.target?.value ? Number(value?.target?.value) : value };
+ }
+ return item;
+ });
+ });
+ };
+
+ const updateValue = (key, newValue) => {
+ setProducts((prevState) => {
+ return prevState.map((item) => {
+ if (item.key === key.key) {
+ return { ...item, value: newValue };
+ }
+ return item;
+ });
+ });
+ };
+
+ useEffect(() => {
+ stref.current = products; // Update the ref with the latest child state
+ }, [products, stref]);
+
+ return (
+
+ {products.map((i, c) => (
+
+
+
+ {t(`CAMPAIGN_RESOURCE`)} {c + 1}
+
+ {products?.length > 1 ? (
+
deleteItem(i, c)}>
+
+
+ ) : null}
+
+
+
+
+ updateValue(i, d)}
+ optionKey="displayName"
+ />
+
+
+
+
+ incrementC(i, d)} />
+
+
+
+ ))}
+ {(temp === undefined || temp.length > 0) && (
+
}
+ onButtonClick={add}
+ />
+ )}
+
+
{t("CAMPAIGN_NEW_PRODUCT_TEXT")}
+
+
+ {t("ES_CAMPAIGN_ADD_PRODUCT_LINK")}
+
+
+
+ {showToast && (
+
+ )}
+
+ );
+}
+
+export default AddProducts;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js
new file mode 100644
index 00000000000..e99f0a36de9
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js
@@ -0,0 +1,265 @@
+import React, { Fragment, useContext, useState } from "react";
+import { Card, Header, Paragraph, CardHeader, CardSubHeader, CardText } from "@egovernments/digit-ui-react-components";
+import AddDeliveryRuleWrapper from "./AddDeliverycontext";
+import { CycleContext } from ".";
+import { useTranslation } from "react-i18next";
+import { InfoCard } from "@egovernments/digit-ui-components";
+//just pass campaign data here
+// function restructureData(data) {
+// const restructuredData = [];
+
+// data.forEach((cycle) => {
+// cycle.deliveries.forEach((delivery) => {
+// delivery.deliveryRules.forEach((rule) => {
+// const restructuredRule = {
+// startDate: 1665497225000, // Hardcoded for now
+// endDate: 1665497225000, // Hardcoded for now
+// cycleNumber: parseInt(cycle.cycleIndex),
+// deliveryNumber: parseInt(delivery.deliveryIndex),
+// deliveryRuleNumber: parseInt(rule.ruleKey), // New key added
+// products: [],
+// conditions: [],
+// };
+
+// rule.attributes.forEach((attribute) => {
+// restructuredRule.conditions.push({
+// attribute: attribute.attribute ? attribute.attribute.code : null,
+// operator: attribute.operator ? attribute.operator.code : null,
+// value: parseInt(attribute.value),
+// });
+// });
+
+// restructuredData.push(restructuredRule);
+// });
+// });
+// });
+
+// return restructuredData;
+// }
+
+//with between logic
+// function restructureData(data) {
+// const restructuredData = [];
+
+// data.forEach((cycle) => {
+// cycle.deliveries.forEach((delivery) => {
+// delivery.deliveryRules.forEach((rule) => {
+// const restructuredRule = {
+// startDate: 1665497225000, // Hardcoded for now
+// endDate: 1665497225000, // Hardcoded for now
+// cycleNumber: parseInt(cycle.cycleIndex),
+// deliveryNumber: parseInt(delivery.deliveryIndex),
+// deliveryRuleNumber: parseInt(rule.ruleKey),
+// products: [],
+// conditions: [],
+// };
+
+// rule.attributes.forEach((attribute) => {
+// if (attribute.operator && attribute.operator.code === "IN_BETWEEN") {
+// // Replace "IN_BETWEEN" with "LESS_THAN" and "GREATER_THAN"
+// restructuredRule.conditions.push({
+// attribute: attribute.attribute ? attribute.attribute.code : null,
+// operator: "LESS_THAN",
+// value: parseInt(attribute.fromValue),
+// });
+// restructuredRule.conditions.push({
+// attribute: attribute.attribute ? attribute.attribute.code : null,
+// operator: "GREATER_THAN",
+// value: parseInt(attribute.toValue),
+// });
+// } else {
+// restructuredRule.conditions.push({
+// attribute: attribute.attribute ? attribute.attribute.code : null,
+// operator: attribute.operator ? attribute.operator.code : null,
+// value: parseInt(attribute.value),
+// });
+// }
+// });
+
+// restructuredData.push(restructuredRule);
+// });
+// });
+// });
+
+// return restructuredData;
+// }
+
+// for retransform just pass the deliveries
+// function bbb(data) {
+// const reversedData = [];
+// let currentCycleIndex = null;
+// let currentDeliveryIndex = null;
+// let currentCycle = null;
+// let currentDelivery = null;
+
+// data.forEach((item, index) => {
+// if (currentCycleIndex !== item.cycleNumber) {
+// currentCycleIndex = item.cycleNumber;
+// currentCycle = {
+// cycleIndex: currentCycleIndex.toString(),
+// active: index === 0, // Set active to true only for the first index
+// deliveries: [],
+// };
+// reversedData.push(currentCycle);
+// }
+
+// if (currentDeliveryIndex !== item.deliveryNumber) {
+// currentDeliveryIndex = item.deliveryNumber;
+// currentDelivery = {
+// deliveryIndex: currentDeliveryIndex.toString(),
+// active: index === 0, // Set active to true only for the first index
+// deliveryRules: [],
+// };
+// currentCycle.deliveries.push(currentDelivery);
+// }
+
+// currentDelivery.deliveryRules.push({
+// ruleKey: currentDelivery.deliveryRules.length + 1,
+// delivery: {},
+// attributes: item.conditions.map((i, c) => ({ key: c + 1, ...i })),
+// products: [...item.products],
+// });
+// });
+
+// return reversedData;
+// }
+
+const Tabs = ({ onTabChange }) => {
+ const { campaignData, dispatchCampaignData } = useContext(CycleContext);
+ const { t } = useTranslation();
+
+ return (
+
+ {campaignData.map((_, index) => (
+
onTabChange(_.cycleIndex, index)}
+ >
+
+ {t(`CAMPAIGN_CYCLE`)} {index + 1}
+
+
+ ))}
+
+ );
+};
+
+const TabContent = ({ activeSubTab, subTabCount = 3, onSubTabChange, project }) => {
+ const { campaignData, dispatchCampaignData } = useContext(CycleContext);
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {t(`CAMPAIGN_TAB_TEXT`)}
+ {t(`CAMPAIGN_TAB_SUB_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)}
+
+ {/* Add content specific to each tab as needed */}
+ ,
+
+ {t(`CAMPAIGN_TAB_INFO_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)}
+
+ ]}
+ label={"Info"}
+ />
+
+ );
+};
+
+const SubTabs = ({ onSubTabChange }) => {
+ const { campaignData, dispatchCampaignData } = useContext(CycleContext);
+ const { t } = useTranslation();
+
+ return (
+
+ {campaignData
+ ?.find((i) => i?.active === true)
+ ?.deliveries.map((_, index) => (
+ onSubTabChange(_.deliveryIndex, index)}
+ >
+ {t(`CAMPAIGN_DELIVERY`)} {index + 1}
+
+ ))}
+
+ );
+};
+
+const MultiTab = ({ tabCount = 3, subTabCount = 2 }) => {
+ const [activeTab, setActiveTab] = useState(0);
+ const [activeSubTab, setActiveSubTab] = useState(0);
+ const { campaignData, dispatchCampaignData } = useContext(CycleContext);
+ const { t } = useTranslation();
+ const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ const handleTabChange = (tabIndex, index) => {
+ dispatchCampaignData({
+ type: "TAB_CHANGE_UPDATE",
+ payload: { tabIndex: tabIndex, index: index }, // Your updated campaign data
+ });
+ setActiveTab(index);
+ setActiveSubTab(0); // Reset sub-tab when changing the main tab
+ };
+
+ const handleSubTabChange = (subTabIndex, itemIndex) => {
+ dispatchCampaignData({
+ type: "SUBTAB_CHANGE_UPDATE",
+ payload: { subTabIndex: subTabIndex }, // Your updated campaign data
+ });
+ };
+
+ return (
+ <>
+
+ {t(
+ `CAMPAIGN_PROJECT_${
+ tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code
+ ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase()
+ : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase()
+ }`
+ )}
+
+
+
+ >
+ );
+};
+
+export default MultiTab;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js
new file mode 100644
index 00000000000..ebdf2c5088f
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js
@@ -0,0 +1,531 @@
+import React, { createContext, useContext, useEffect, useReducer, useState } from "react";
+import MultiTab from "./MultiTabcontext";
+import { Loader } from "@egovernments/digit-ui-react-components";
+// import { deliveryConfig } from "../../../configs/deliveryConfig";
+
+const CycleContext = createContext();
+
+function makeSequential(jsonArray, keyName) {
+ return jsonArray.map((item, index) => ({
+ ...item,
+ [keyName]: index + 1,
+ }));
+}
+
+function DeliverySetup({ onSelect, config, formData, control, tabCount = 2, subTabCount = 3, ...props }) {
+ // Campaign Tab Skeleton function
+ const [cycleData, setCycleData] = useState(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure);
+ const saved = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule;
+ const selectedProjectType = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_TYPE?.projectType?.code;
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const searchParams = new URLSearchParams(location.search);
+ const activeCycle = searchParams.get("activeCycle");
+ const { isLoading: deliveryConfigLoading, data: filteredDeliveryConfig } = Digit.Hooks.useCustomMDMS(
+ tenantId,
+ "HCM-ADMIN-CONSOLE",
+ [{ name: "deliveryConfig" }],
+ {
+ select: (data) => {
+ const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig;
+ return temp?.find((i) => i?.projectType === selectedProjectType);
+ // return deliveryConfig?.find((i) => i?.projectType === selectedProjectType);
+ },
+ }
+ );
+ // const [filteredDeliveryConfig, setFilteredDeliveryConfig] = useState(deliveryConfig?.find((i) => i?.projectType === selectedProjectType));
+ // useEffect(() => {
+ // if (!deliveryConfigLoading) {
+ // const temp = deliveryConfig?.find((i) => i?.projectType === selectedProjectType);
+ // setFilteredDeliveryConfig(temp);
+ // }
+ // }, [deliveryConfigLoading, filteredDeliveryConfig]);
+ // const filteredDeliveryConfig = deliveryConfig.find((i) => i.projectType === selectedProjectType);
+ useEffect(() => {
+ setCycleData(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure);
+ }, [config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure]);
+
+ const generateTabsData = (tabs, subTabs) => {
+ if (!saved || saved?.length === 0) {
+ return [...Array(tabs)].map((_, tabIndex) => ({
+ cycleIndex: `${tabIndex + 1}`,
+ active: activeCycle == tabIndex + 1 ? true : tabIndex === 0 ? true : false,
+ deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({
+ deliveryIndex: `${subTabIndex + 1}`,
+ active: subTabIndex === 0 ? true : false,
+ deliveryRules:
+ filteredDeliveryConfig?.projectType === "LLIN-mz"
+ ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => {
+ return {
+ ruleKey: index + 1,
+ delivery: {},
+ attributes: item?.attributeConfig
+ ? item?.attributeConfig?.map((i, c) => {
+ if (i?.operatorValue === "IN_BETWEEN") {
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ toValue: i?.fromValue,
+ fromValue: i?.toValue,
+ };
+ }
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ value: i?.value,
+ };
+ })
+ : [{ key: 1, attribute: null, operator: null, value: "" }],
+ // products: [],
+ products: item?.productConfig
+ ? item?.productConfig?.map((i, c) => ({
+ ...i,
+ }))
+ : [],
+ };
+ })
+ : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]
+ ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => {
+ if (item) {
+ return {
+ ruleKey: index + 1,
+ delivery: {},
+ deliveryType: item?.deliveryType,
+ attributes: item?.attributeConfig
+ ? item?.attributeConfig?.map((i, c) => {
+ if (i?.operatorValue === "IN_BETWEEN") {
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ toValue: i?.fromValue,
+ fromValue: i?.toValue,
+ };
+ }
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ value: i?.value,
+ };
+ })
+ : [{ key: 1, attribute: null, operator: null, value: "" }],
+ // products: [],
+ products: item?.productConfig
+ ? item?.productConfig?.map((i, c) => ({
+ ...i,
+ }))
+ : [],
+ };
+ } else {
+ return {
+ ruleKey: index + 1,
+ delivery: {},
+ deliveryType: null,
+ attributes: [{ key: 1, attribute: null, operator: null, value: "" }],
+ products: [],
+ };
+ }
+ })
+ : [
+ {
+ ruleKey: 1,
+ delivery: {},
+ attributes:
+ filteredDeliveryConfig && filteredDeliveryConfig?.attributeConfig
+ ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ value: i?.value,
+ }))
+ : // : filteredDeliveryConfig?.projectType === "LLIN-mz"
+ // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ key: c + 1, attribute: i.attrValue, operator: null, value: "" }))
+ [{ key: 1, attribute: null, operator: null, value: "" }],
+ products: [],
+ },
+ ],
+ })),
+ }));
+ }
+ // if no change
+ if (saved && saved?.length == tabs && saved?.[0]?.deliveries?.length === subTabs) {
+ return saved.map((i, n) => {
+ return {
+ ...i,
+ active: activeCycle ? (activeCycle == n + 1 ? true : false) : n === 0 ? true : false,
+ };
+ });
+ }
+ // if cycle number decrease
+ if (saved?.length > tabs) {
+ // const temp = saved;
+ saved.splice(tabs);
+ // return temp;
+ }
+ // if cycle number increase
+ if (tabs > saved?.length) {
+ // const temp = saved;
+ for (let i = saved.length + 1; i <= tabs; i++) {
+ const newIndex = i.toString();
+ saved.push({
+ cycleIndex: newIndex,
+ active: false,
+ deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({
+ deliveryIndex: `${subTabIndex + 1}`,
+ active: subTabIndex === 0,
+ deliveryRules:
+ filteredDeliveryConfig?.projectType === "LLIN-mz"
+ ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => {
+ return {
+ ruleKey: index + 1,
+ delivery: {},
+ attributes: item?.attributeConfig
+ ? item?.attributeConfig?.map((i, c) => {
+ if (i?.operatorValue === "IN_BETWEEN") {
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ toValue: i?.fromValue,
+ fromValue: i?.toValue,
+ };
+ }
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ value: i?.value,
+ };
+ })
+ : [{ key: 1, attribute: null, operator: null, value: "" }],
+ // products: [],
+ products: item?.productConfig
+ ? item?.productConfig?.map((i, c) => ({
+ ...i,
+ }))
+ : [],
+ };
+ })
+ : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig
+ ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => {
+ if (item) {
+ return {
+ ruleKey: index + 1,
+ delivery: {},
+ deliveryType: item?.deliveryType,
+ attributes: item?.attributeConfig
+ ? item?.attributeConfig?.map((i, c) => {
+ if (i?.operatorValue === "IN_BETWEEN") {
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ toValue: i?.fromValue,
+ fromValue: i?.toValue,
+ };
+ }
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ value: i?.value,
+ };
+ })
+ : [{ key: 1, attribute: null, operator: null, value: "" }],
+ // products: [],
+ products: item?.productConfig
+ ? item?.productConfig?.map((i, c) => ({
+ ...i,
+ }))
+ : [],
+ };
+ } else {
+ return {
+ ruleKey: index + 1,
+ delivery: {},
+ deliveryType: null,
+ attributes: [{ key: 1, attribute: null, operator: null, value: "" }],
+ products: [],
+ };
+ }
+ })
+ : [
+ {
+ ruleKey: 1,
+ delivery: {},
+ deliveryType: null,
+ attributes:
+ // filteredDeliveryConfig?.projectType === "MR-DN"
+ // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({
+ // key: c + 1,
+ // attribute: { code: i?.attrValue },
+ // operator: { code: i?.operatorValue },
+ // value: i?.value,
+ // }))
+ // : filteredDeliveryConfig?.projectType === "LLIN-mz"
+ // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({
+ // key: c + 1,
+ // attribute: i.attrValue,
+ // operator: null,
+ // value: "",
+ // }))
+ // :
+ [{ key: 1, attribute: null, operator: null, value: "" }],
+ // products: [],
+ products: [],
+ },
+ ],
+ })),
+ });
+ }
+ // return temp;
+ }
+ // if delivery number decrease
+
+ saved.forEach((cycle) => {
+ // Remove deliveries if there are more deliveries than the specified number
+ if (cycle.deliveries.length > subTabs) {
+ cycle.deliveries.splice(subTabs);
+ }
+
+ // Add deliveries if there are fewer deliveries than the specified number
+ if (subTabs > cycle.deliveries.length) {
+ for (let i = cycle.deliveries.length + 1; i <= subTabs; i++) {
+ const newIndex = i.toString();
+ cycle.deliveries.push({
+ deliveryIndex: newIndex,
+ active: false,
+ deliveryRules:
+ filteredDeliveryConfig?.projectType === "LLIN-mz"
+ ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => {
+ return {
+ ruleKey: index + 1,
+ delivery: {},
+ attributes: item?.attributeConfig
+ ? item?.attributeConfig?.map((i, c) => {
+ if (i?.operatorValue === "IN_BETWEEN") {
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ toValue: i?.fromValue,
+ fromValue: i?.toValue,
+ };
+ }
+ return {
+ key: c + 1,
+ attribute: { code: i?.attrValue },
+ operator: { code: i?.operatorValue },
+ value: i?.value,
+ };
+ })
+ : [{ key: 1, attribute: null, operator: null, value: "" }],
+ // products: [],
+ products: item?.productConfig
+ ? item?.productConfig?.map((i, c) => ({
+ ...i,
+ }))
+ : [],
+ };
+ })
+ : [
+ {
+ ruleKey: 1,
+ delivery: {},
+ attributes: [{ key: 1, attribute: null, operator: null, value: "" }],
+ products: [],
+ },
+ ],
+ });
+ }
+ }
+ });
+
+ return saved;
+ // if delivery number increase
+
+ //if no above case
+ };
+
+ // Reducer function
+ const campaignDataReducer = (state, action) => {
+ switch (action.type) {
+ case "GENERATE_CAMPAIGN_DATA":
+ return generateTabsData(action.cycle, action.deliveries);
+ case "UPDATE_CAMPAIGN_DATA":
+ const changeUpdate = state.map((i) => {
+ if (i.active) {
+ const activeDelivery = i.deliveries.find((j) => j.active === true);
+ if (activeDelivery) {
+ return {
+ ...i,
+ deliveries: i.deliveries.map((j) => ({
+ ...j,
+ deliveryRules: j.active ? action.payload.currentDeliveryRules : j.deliveryRules,
+ })),
+ };
+ }
+ }
+ return i;
+ });
+ return changeUpdate;
+ case "TAB_CHANGE_UPDATE":
+ const temp = state.map((i) => ({
+ ...i,
+ active: i.cycleIndex == action.payload.tabIndex ? true : false,
+ }));
+ return temp;
+ // return action.payload;
+ case "SUBTAB_CHANGE_UPDATE":
+ const tempSub = state.map((camp, index) => {
+ if (camp.active === true) {
+ return {
+ ...camp,
+ deliveries: camp.deliveries.map((deliver) => ({
+ ...deliver,
+ active: deliver.deliveryIndex == action.payload.subTabIndex ? true : false,
+ })),
+ };
+ }
+ return camp;
+ });
+ return tempSub;
+ case "ADD_DELIVERY_RULE":
+ const updatedDeliveryRules = [
+ ...action.payload.currentDeliveryRules,
+ {
+ ruleKey: action.payload.currentDeliveryRules.length + 1,
+ delivery: {},
+ attributes: [{ key: 1, attribute: null, operator: null, value: "" }],
+ products: [],
+ },
+ ];
+ const updatedData = state.map((i) => {
+ if (i.active) {
+ const activeDelivery = i.deliveries.find((j) => j.active);
+ if (activeDelivery) {
+ return {
+ ...i,
+ deliveries: i.deliveries.map((j) => ({
+ ...j,
+ deliveryRules: j.active ? updatedDeliveryRules : j.deliveryRules,
+ })),
+ };
+ }
+ }
+ return i;
+ });
+ return updatedData;
+ case "REMOVE_DELIVERY_RULE":
+ const updatedDeleted = state.map((i) => {
+ if (i.active) {
+ const activeDelivery = i.deliveries.find((j) => j.active);
+ const w = makeSequential(
+ activeDelivery.deliveryRules.filter((j) => j.ruleKey != action.payload.item.ruleKey),
+ "ruleKey"
+ );
+ if (activeDelivery) {
+ return {
+ ...i,
+ deliveries: i.deliveries.map((j) => ({
+ ...j,
+ deliveryRules: j.active ? w : j.deliveryRules,
+ })),
+ };
+ }
+ }
+ return i;
+ });
+ return updatedDeleted;
+ case "UPDATE_DELIVERY_RULE":
+ return action.payload;
+ case "ADD_ATTRIBUTE":
+ return action.payload;
+ case "REMOVE_ATTRIBUTE":
+ return action.payload;
+ case "UPDATE_ATTRIBUTE":
+ return action.payload;
+ case "ADD_PRODUCT":
+ const prodTemp = action.payload.productData.map((i) => ({ ...i, value: i?.value?.id, name: i?.value?.displayName }));
+ const updatedState = state.map((cycle) => {
+ if (cycle.active) {
+ const updatedDeliveries = cycle.deliveries.map((dd) => {
+ if (dd.active) {
+ const updatedRules = dd.deliveryRules.map((rule) => {
+ if (rule.ruleKey === action.payload.delivery.ruleKey) {
+ return {
+ ...rule,
+ products: [...rule.products, ...prodTemp],
+ };
+ }
+ return rule;
+ });
+ return {
+ ...dd,
+ deliveryRules: updatedRules,
+ };
+ }
+ return dd;
+ });
+ return {
+ ...cycle,
+ deliveries: updatedDeliveries,
+ };
+ }
+ return cycle;
+ });
+ return updatedState;
+ case "REMOVE_PRODUCT":
+ return action.payload;
+ case "UPDATE_PRODUCT":
+ return action.payload;
+ default:
+ return state;
+ }
+ };
+
+ const [campaignData, dispatchCampaignData] = useReducer(
+ campaignDataReducer,
+ generateTabsData(cycleData?.cycleConfgureDate?.cycle, cycleData?.cycleConfgureDate?.deliveries)
+ );
+ const [executionCount, setExecutionCount] = useState(0);
+
+ useEffect(() => {
+ dispatchCampaignData({
+ type: "GENERATE_CAMPAIGN_DATA",
+ cycle: cycleData?.cycleConfgureDate?.cycle,
+ deliveries: cycleData?.cycleConfgureDate?.deliveries,
+ });
+ }, [cycleData]);
+
+ useEffect(() => {
+ onSelect("deliveryRule", campaignData);
+ }, [campaignData]);
+
+ useEffect(() => {
+ if (executionCount < 5) {
+ onSelect("deliveryRule", campaignData);
+ setExecutionCount((prevCount) => prevCount + 1);
+ }
+ });
+
+ if (deliveryConfigLoading) {
+ return ;
+ }
+ return (
+
+
+
+ );
+}
+
+export default DeliverySetup;
+export { CycleContext };
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js
new file mode 100644
index 00000000000..2353f85fc50
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js
@@ -0,0 +1,102 @@
+import React, { useEffect } from "react";
+import { Switch, useLocation } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import { PrivateRoute, AppContainer, BreadCrumb } from "@egovernments/digit-ui-react-components";
+// import CampaignHeader from "../../components/CampaignHeader";
+import SetupCampaign from "./SetupCampaign";
+import SelectingBoundaries from "../../components/SelectingBoundaries";
+
+/**
+ * The CampaignBreadCrumb function generates breadcrumb navigation for a campaign setup page in a React
+ * application.
+ * @returns The CampaignBreadCrumb component is returning a BreadCrumb component with the specified
+ * crumbs array and spanStyle prop. The crumbs array contains two objects with path, content, and show
+ * properties for each breadcrumb item. The spanStyle prop is set to { maxWidth: "min-content" }.
+ */
+const CampaignBreadCrumb = ({ location, defaultPath }) => {
+ const { t } = useTranslation();
+ const search = useLocation().search;
+ const pathVar = location.pathname.replace(defaultPath + "/", "").split("?")?.[0];
+
+ const crumbs = [
+ {
+ path: `/${window?.contextPath}/employee`,
+ content: t("CAMPAIGN_HOME"),
+ show: true,
+ },
+ {
+ path: pathVar === "my-campaign" ? "" : `/${window?.contextPath}/employee/campaign/my-campaign`,
+ content: t("MY_CAMPAIGN"),
+ show: pathVar === "my-campaign" ? true : false,
+ },
+ {
+ path: pathVar === "setup-campaign" ? "" : `/${window?.contextPath}/employee/campaign/setup-campaign`,
+ content: t("CREATE_NEW_CAMPAIGN"),
+ show: pathVar === "setup-campaign" ? true : false,
+ },
+ ];
+
+ return ;
+};
+
+/**
+ * The `App` function in JavaScript defines a component that handles different routes and renders
+ * corresponding components based on the path provided.
+ * @returns The `App` component is returning a JSX structure that includes a `div` with a className of
+ * "wbh-header-container" containing a `CampaignBreadCrumb` component and a `Switch` component. Inside
+ * the `Switch` component, there are several `PrivateRoute` components with different paths and
+ * corresponding components such as `UploadBoundaryData`, `CycleConfiguration`, `DeliveryRule`, `
+ */
+const App = ({ path, BOUNDARY_HIERARCHY_TYPE }) => {
+ const location = useLocation();
+ const UploadBoundaryData = Digit?.ComponentRegistryService?.getComponent("UploadBoundaryData");
+ const CycleConfiguration = Digit?.ComponentRegistryService?.getComponent("CycleConfiguration");
+ const DeliveryRule = Digit?.ComponentRegistryService?.getComponent("DeliveryRule");
+ const MyCampaign = Digit?.ComponentRegistryService?.getComponent("MyCampaign");
+ const CampaignSummary = Digit?.ComponentRegistryService?.getComponent("CampaignSummary");
+ const Response = Digit?.ComponentRegistryService?.getComponent("Response");
+ const AddProduct = Digit?.ComponentRegistryService?.getComponent("AddProduct");
+
+ useEffect(() => {
+ if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") {
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID");
+ }
+ if (window.location.pathname === "/workbench-ui/employee/campaign/response") {
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID");
+ }
+ return () => {
+ if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") {
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA");
+ window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID");
+ }
+ };
+ }, []);
+ return (
+
+
+ {window?.location?.pathname === "/workbench-ui/employee/campaign/add-product" ||
+ window?.location?.pathname === "/workbench-ui/employee/campaign/response" ? null : (
+
+ )}
+ {/* */}
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+ );
+};
+
+export default App;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js
new file mode 100644
index 00000000000..5ab880c52cf
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js
@@ -0,0 +1,144 @@
+export const TourSteps = {
+ '/workbench-ui/employee/workbench/manage-master-data':[
+ {
+ content:
+ 'Welcome to Manage Master Data screen. Here you can search and update any master data that is configured for the logged in user tenant',
+ target: '.manage-master-wrapper',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'Select any module name where the master is present',
+ target: '.wbh-mdms-module-name',
+ disableBeacon: true,
+ placement: 'center',
+ title:"Manage Master Data"
+ },
+
+ {
+ content:
+ 'Select any master name where the master is present',
+ target: '.wbh-mdms-master-name',
+ disableBeacon: true,
+ placement: 'center',
+ title:"Manage Master Data"
+ },
+ ],
+ '/workbench-ui/employee/workbench/mdms-search-v2':[
+ {
+ content:
+ 'Welcome to the master data search screen. Here you can search the master data added under this master',
+ target: '.search-wrapper',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'Select any field value and enter the text by which data can be filtered',
+ target: '.label-field-pair',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'Filter the master data by clicking on this search by selecting any field and exact value',
+ target: '.search-button-wrapper',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'To add new master data under this master click on the Add Master Data button',
+ target: '.mdms-add-btn',
+ disableBeacon: true,
+ placement: 'auto',
+ title:"Manage Master Data"
+ },
+
+ ],
+ '/workbench-ui/employee/workbench/mdms-add-v2':[
+ {
+ content:
+ 'Welcome to the master data search screen. Here you can search the master data added under this master',
+ target: '.field-string',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'select the Reference master data',
+ target: '.form-select ',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'Fill all the details by clicking on the Add Master Data',
+ target: '.submit-bar',
+ disableBeacon: true,
+ placement: 'auto',
+ title:"Manage Master Data"
+ },
+
+ ],
+ '/workbench-ui/employee/workbench/mdms-view':[
+ {
+ content:
+ 'Welcome to the master data search screen. Here you can search the master data added under this master',
+ target: '.action-bar-wrap',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'select the Reference master data',
+ target: '.menu-wrap',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ }
+ ],
+ '/workbench-ui/employee/workbench/localisation-search':[
+ {
+ content:
+ 'Welcome to the master data search screen. Here you can search the master data added under this master',
+ target: '.search-wrapper',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'Select any field value and enter the text by which data can be filtered',
+ target: '.label-field-pair',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'Filter the master data by clicking on this search by selecting any field and exact value',
+ target: '.search-button-wrapper',
+ disableBeacon: true,
+ placement: 'bottom',
+ title:"Manage Master Data"
+ },
+ {
+ content:
+ 'To add new master data under this master click on the Add Master Data button',
+ target: '.mdms-add-btn',
+ disableBeacon: true,
+ placement: 'auto',
+ title:"Manage Master Data"
+ },
+
+ ],
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js
new file mode 100644
index 00000000000..978ea2bfd74
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js
@@ -0,0 +1,46 @@
+import axios from "axios";
+
+/* Fetching sheet as json object from the API , converting them into blob and downloading it.
+ * Way to use the function. Just import the funtion downloadExcelWithCustomName and pass the filestoreid and customName you want to download the file.
+ * Rest this function will take care for you and download it in your system.
+ *
+ * Eg. ->
+ * const handleDownload = (id, name) => {
+ * downloadExcelWithCustomName({fileStoreId: id, customName: name});
+ * }
+ *
+ */
+
+export const downloadExcelWithCustomName = ({ fileStoreId = null, customName = null }) => {
+ const downloadExcel = (blob, fileName) => {
+ const link = document.createElement("a");
+ link.href = URL.createObjectURL(blob);
+ link.download = fileName + ".xlsx";
+ document.body.append(link);
+ link.click();
+ link.remove();
+ setTimeout(() => URL.revokeObjectURL(link.href), 7000);
+ };
+
+ if (fileStoreId) {
+ axios
+ .get("/filestore/v1/files/id", {
+ responseType: "arraybuffer",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ "auth-token": Digit.UserService.getUser()?.["access_token"],
+ },
+ params: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ fileStoreId: fileStoreId,
+ },
+ })
+ .then(async (res) => {
+ downloadExcel(
+ new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }),
+ customName ? customName : "download"
+ );
+ });
+ }
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js
new file mode 100644
index 00000000000..5e308bf82f7
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js
@@ -0,0 +1,6 @@
+import _ from "lodash";
+import { downloadExcelWithCustomName } from "./downloadExcel";
+
+export default {};
+export { downloadExcelWithCustomName };
+export const PRIMARY_COLOR = "#C84C0E";
diff --git a/health/micro-ui/web/micro-ui-internals/publish-develop.sh b/health/micro-ui/web/micro-ui-internals/publish-develop.sh
new file mode 100644
index 00000000000..4909658c697
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/publish-develop.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+BASEDIR="$(cd "$(dirname "$0")" && pwd)"
+
+msg() {
+ echo -e "\n\n\033[32;32m$1\033[0m"
+}
+
+
+# msg "Pre-building all packages"
+# yarn build
+# sleep 5
+
+msg "Building and publishing css"
+cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0
+
+
+# msg "Building and publishing libraries"
+# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0
+
diff --git a/health/micro-ui/web/micro-ui-internals/publish.sh b/health/micro-ui/web/micro-ui-internals/publish.sh
new file mode 100644
index 00000000000..4909658c697
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/publish.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+BASEDIR="$(cd "$(dirname "$0")" && pwd)"
+
+msg() {
+ echo -e "\n\n\033[32;32m$1\033[0m"
+}
+
+
+# msg "Pre-building all packages"
+# yarn build
+# sleep 5
+
+msg "Building and publishing css"
+cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0
+
+
+# msg "Building and publishing libraries"
+# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0
+
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/create.sh b/health/micro-ui/web/micro-ui-internals/scripts/create.sh
new file mode 100755
index 00000000000..9de72331774
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/scripts/create.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./scripts/run.sh core utilities
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/deploy.sh b/health/micro-ui/web/micro-ui-internals/scripts/deploy.sh
new file mode 100755
index 00000000000..5b0c7b831ed
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/scripts/deploy.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+curl -v -X POST https://builds.digit.org/job/builds/job/digit-ui/buildWithParameters \
+ --user saurabh-egov:114cbf3df675835931688b2d3f0014a1f7 \
+ --data-urlencode json='{"parameter": [{"name":"BRANCH", "value":"origin/'$1'"}]}'
+
+# curl https://builds.digit.org/job/builds/job/digit-ui/lastBuild/api/json | grep --color result\":null
+
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/jenkins.sh b/health/micro-ui/web/micro-ui-internals/scripts/jenkins.sh
new file mode 100755
index 00000000000..a1711fec55b
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/scripts/jenkins.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./scripts/deploy.sh dev
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/run.sh b/health/micro-ui/web/micro-ui-internals/scripts/run.sh
new file mode 100755
index 00000000000..f00c59f13b8
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/scripts/run.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+MODULES=( "components" "core" "libraries" "example" )
+
+RUNARGS=()
+BUILDARGS=()
+
+for var in "$@"
+do
+ BUILDARGS=( ${BUILDARGS[@]} build:"$var" )
+ RUNARGS=( ${RUNARGS[@]} dev:"$var" )
+done
+
+a=0
+while [ "$a" -lt 3 ]
+do
+ BUILD[$a]=build:${MODULES[$a]}
+ a=` expr $a + 1 `
+done
+
+echo "BUILDING MODULES:-" ${BUILD[*]} ${BUILDARGS[*]}
+yarn run-p ${BUILD[*]} ${BUILDARGS[*]}
+
+b=0
+while [ "$b" -lt 4 ]
+do
+ RUN[$b]=dev:${MODULES[$b]}
+ b=` expr $b + 1 `
+done
+
+echo "SERVING MODULES:-" ${RUN[*]} ${RUNARGS[*]}
+yarn run-p ${RUN[*]} ${RUNARGS[*]}
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/test.js b/health/micro-ui/web/micro-ui-internals/test.js
new file mode 100644
index 00000000000..60c958d0bac
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/test.js
@@ -0,0 +1,31 @@
+const middleWare_1 = (data, _break, _next) => {
+ data.a = "a";
+ _next(data);
+};
+
+
+const middleWare_2 = (data, _break, _next) => {
+ data.b = "b";
+ // _break();
+ _next(data);
+};
+
+const middleWare_3 = (data, _break, _next) => {
+ data.c = "c";
+ _next(data);
+};
+
+let middleWares = [middleWare_1, middleWare_2, middleWare_3];
+
+const callMiddlewares = () => {
+ let applyBreak = false;
+ let itr = -1;
+ let _break = () => (applyBreak = true);
+ let _next = (data) => {
+ if (!applyBreak && ++itr < middleWares.length) middleWares[itr](data, _break, _next);
+ else return;
+ };
+ _next({});
+};
+
+callMiddlewares();
diff --git a/health/micro-ui/web/package.json b/health/micro-ui/web/package.json
new file mode 100644
index 00000000000..59ebb7ece05
--- /dev/null
+++ b/health/micro-ui/web/package.json
@@ -0,0 +1,85 @@
+{
+ "name": "micro-ui",
+ "version": "1.0.0",
+ "author": "Jagankumar ",
+ "license": "MIT",
+ "private": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "workspaces": [
+ "micro-ui-internals/packages/libraries",
+ "micro-ui-internals/packages/react-components",
+ "micro-ui-internals/packages/modules/*"
+ ],
+ "homepage": "/digit-ui",
+ "dependencies": {
+ "@egovernments/digit-ui-libraries": "1.8.1-beta.4",
+ "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16",
+ "@egovernments/digit-ui-module-core": "1.8.2-beta.2",
+ "@egovernments/digit-ui-module-hrms": "1.8.0-beta.2",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-components": "0.0.2-beta.1",
+ "@egovernments/digit-ui-module-dss": "1.8.0-beta",
+ "@egovernments/digit-ui-module-common": "1.8.0-beta",
+ "@egovernments/digit-ui-module-utilities": "1.0.0-beta",
+ "@egovernments/digit-ui-module-engagement": "1.5.20",
+ "babel-loader": "8.1.0",
+ "clean-webpack-plugin": "4.0.0",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "jsonpath": "^1.1.1",
+ "react-router-dom": "5.3.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "1.1.2",
+ "terser-brunch": "^4.1.0",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "css-loader": "5.2.6",
+ "style-loader": "2.0.0",
+ "webpack-cli": "4.10.0"
+ },
+ "devDependencies": {
+ "@babel/plugin-proposal-private-property-in-object": "7.21.0",
+ "http-proxy-middleware": "1.3.1",
+ "lodash": "4.17.21",
+ "microbundle-crl": "0.13.11",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0",
+ "husky": "7.0.4",
+ "lint-staged": "12.3.7",
+ "npm-run-all": "4.1.5",
+ "prettier": "2.1.2"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build",
+ "build:prepare": "./build.sh",
+ "build:libraries": "cd micro-ui-internals && yarn build",
+ "build:prod": "webpack --mode production",
+ "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod",
+ "clean": "rm -rf node_modules"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/public/index.html b/health/micro-ui/web/public/index.html
new file mode 100644
index 00000000000..9da00f7e1de
--- /dev/null
+++ b/health/micro-ui/web/public/index.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DIGIT
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/health/micro-ui/web/public/robots.txt b/health/micro-ui/web/public/robots.txt
new file mode 100644
index 00000000000..e9e57dc4d41
--- /dev/null
+++ b/health/micro-ui/web/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/health/micro-ui/web/src/App.js b/health/micro-ui/web/src/App.js
new file mode 100644
index 00000000000..d871f8e8f4c
--- /dev/null
+++ b/health/micro-ui/web/src/App.js
@@ -0,0 +1,74 @@
+import React from "react";
+import { initLibraries } from "@egovernments/digit-ui-libraries";
+import {
+ paymentConfigs,
+ PaymentLinks,
+ PaymentModule,
+} from "@egovernments/digit-ui-module-common";
+import { DigitUI,initCoreComponents } from "@egovernments/digit-ui-module-core";
+import { initDSSComponents } from "@egovernments/digit-ui-module-dss";
+import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement";
+import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms";
+import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
+import { UICustomizations } from "./Customisations/UICustomizations";
+import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
+// import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench";
+
+window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
+
+const enabledModules = [
+ "DSS",
+ "NDSS",
+ "Utilities",
+ "HRMS",
+ "Engagement",
+ "Workbench",
+ "Microplanning"
+];
+
+const moduleReducers = (initData) => ({
+ initData,
+});
+
+const initDigitUI = () => {
+ window.Digit.ComponentRegistryService.setupRegistry({
+ PaymentModule,
+ ...paymentConfigs,
+ PaymentLinks,
+ });
+ initCoreComponents();
+ initDSSComponents();
+ initHRMSComponents();
+ initEngagementComponents();
+ initUtilitiesComponents();
+ initWorkbenchComponents();
+
+ window.Digit.Customizations = {
+ PGR: {},
+ commonUiConfig: UICustomizations,
+ };
+};
+
+initLibraries().then(() => {
+ initDigitUI();
+});
+
+function App() {
+ window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
+ const stateCode =
+ window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") ||
+ process.env.REACT_APP_STATE_LEVEL_TENANT_ID;
+ if (!stateCode) {
+ return stateCode is not defined
;
+ }
+ return (
+
+ );
+}
+
+export default App;
diff --git a/health/micro-ui/web/src/ComponentRegistry.js b/health/micro-ui/web/src/ComponentRegistry.js
new file mode 100644
index 00000000000..9bafce3dc89
--- /dev/null
+++ b/health/micro-ui/web/src/ComponentRegistry.js
@@ -0,0 +1,11 @@
+class Registry {
+ constructor(registry = {}) {
+ this._registry = registry;
+ }
+
+ getComponent(id) {
+ return this._registry[id];
+ }
+}
+
+export default Registry;
diff --git a/health/micro-ui/web/src/Customisations/UICustomizations.js b/health/micro-ui/web/src/Customisations/UICustomizations.js
new file mode 100644
index 00000000000..6d17ab0d51b
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/UICustomizations.js
@@ -0,0 +1,428 @@
+import { Link } from "react-router-dom";
+import _ from "lodash";
+
+//create functions here based on module name set in mdms(eg->SearchProjectConfig)
+//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName]
+// these functions will act as middlewares
+var Digit = window.Digit || {};
+
+
+
+const businessServiceMap = {
+
+ "muster roll": "MR"
+};
+
+const inboxModuleNameMap = {
+ "muster-roll-approval": "muster-roll-service",
+};
+
+export const UICustomizations = {
+ businessServiceMap,
+ updatePayload: (applicationDetails, data, action, businessService) => {
+
+ if (businessService === businessServiceMap.estimate) {
+ const workflow = {
+ comment: data.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ estimate: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap.contract) {
+ const workflow = {
+ comment: data?.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ contract: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap?.["muster roll"]) {
+ const workflow = {
+ comment: data?.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ musterRoll: applicationDetails,
+ workflow,
+ };
+ }
+ if(businessService === businessServiceMap?.["works.purchase"]){
+ const workflow = {
+ comment: data.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ const additionalFieldsToSet = {
+ projectId:applicationDetails.additionalDetails.projectId,
+ invoiceDate:applicationDetails.billDate,
+ invoiceNumber:applicationDetails.referenceId.split('_')?.[1],
+ contractNumber:applicationDetails.referenceId.split('_')?.[0],
+ documents:applicationDetails.additionalDetails.documents
+ }
+ return {
+ bill: {...applicationDetails,...additionalFieldsToSet},
+ workflow,
+ };
+ }
+ },
+ enableModalSubmit:(businessService,action,setModalSubmit,data)=>{
+ if(businessService === businessServiceMap?.["muster roll"] && action.action==="APPROVE"){
+ setModalSubmit(data?.acceptTerms)
+ }
+ },
+ enableHrmsSearch: (businessService, action) => {
+ if (businessService === businessServiceMap.estimate) {
+ return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD");
+ }
+ if (businessService === businessServiceMap.contract) {
+ return action.action.includes("VERIFY_AND_FORWARD");
+ }
+ if (businessService === businessServiceMap?.["muster roll"]) {
+ return action.action.includes("VERIFY");
+ }
+ if(businessService === businessServiceMap?.["works.purchase"]){
+ return action.action.includes("VERIFY_AND_FORWARD")
+ }
+ return false;
+ },
+ getBusinessService: (moduleCode) => {
+ if (moduleCode?.includes("estimate")) {
+ return businessServiceMap?.estimate;
+ } else if (moduleCode?.includes("contract")) {
+ return businessServiceMap?.contract;
+ } else if (moduleCode?.includes("muster roll")) {
+ return businessServiceMap?.["muster roll"];
+ }
+ else if (moduleCode?.includes("works.purchase")) {
+ return businessServiceMap?.["works.purchase"];
+ }
+ else if (moduleCode?.includes("works.wages")) {
+ return businessServiceMap?.["works.wages"];
+ }
+ else if (moduleCode?.includes("works.supervision")) {
+ return businessServiceMap?.["works.supervision"];
+ }
+ else {
+ return businessServiceMap;
+ }
+ },
+ getInboxModuleName: (moduleCode) => {
+ if (moduleCode?.includes("estimate")) {
+ return inboxModuleNameMap?.estimate;
+ } else if (moduleCode?.includes("contract")) {
+ return inboxModuleNameMap?.contracts;
+ } else if (moduleCode?.includes("attendence")) {
+ return inboxModuleNameMap?.attendencemgmt;
+ } else {
+ return inboxModuleNameMap;
+ }
+ },
+
+ AttendanceInboxConfig: {
+ preProcess: (data) => {
+
+ //set tenantId
+ data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId();
+
+ const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim();
+ if(musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber
+
+ const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim();
+ if(attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName
+
+ // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side)
+ const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee);
+ delete data.body.inbox.moduleSearchCriteria.assignee;
+ if (assignee?.code === "ASSIGNED_TO_ME") {
+ data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid;
+ }
+
+ //cloning locality and workflow states to format them
+ // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []);
+
+ let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null);
+ delete data.body.inbox.moduleSearchCriteria.orgId;
+ if(selectedOrg) {
+ data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber;
+ }
+
+ // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null);
+ // delete data.body.inbox.moduleSearchCriteria.ward;
+ // if(selectedWard) {
+ // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code;
+ // }
+
+ let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []);
+ let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []);
+ // delete data.body.inbox.moduleSearchCriteria.locality;
+ delete data.body.inbox.moduleSearchCriteria.state;
+ delete data.body.inbox.moduleSearchCriteria.ward;
+
+ // locality = locality?.map((row) => row?.code);
+ states = Object.keys(states)?.filter((key) => states[key]);
+ ward = ward?.map((row) => row?.code);
+
+
+ // //adding formatted data to these keys
+ // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality;
+ if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states;
+ if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward;
+ const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {});
+ if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code;
+
+ //adding tenantId to moduleSearchCriteria
+ data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId();
+
+ //setting limit and offset becoz somehow they are not getting set in muster inbox
+ data.body.inbox .limit = data.state.tableForm.limit
+ data.body.inbox.offset = data.state.tableForm.offset
+ delete data.state
+ return data;
+ },
+ postProcess: (responseArray, uiConfig) => {
+ const statusOptions = responseArray?.statusMap
+ ?.filter((item) => item.applicationstatus)
+ ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` }));
+ if (uiConfig?.type === "filter") {
+ let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus");
+ if (fieldConfig.length) {
+ fieldConfig[0].populators.options = statusOptions;
+ }
+ }
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ if (key === "ATM_MUSTER_ROLL_ID") {
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+ }
+ if (key === "ATM_ATTENDANCE_WEEK") {
+ const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate(
+ value?.endDate,
+ "dd/MM/yyyy"
+ )}`;
+ return {week}
;
+ }
+ if (key === "ATM_NO_OF_INDIVIDUALS") {
+ return {value?.length}
;
+ }
+ if(key === "ATM_AMOUNT_IN_RS"){
+ return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")};
+ }
+ if (key === "ATM_SLA") {
+ return parseInt(value) > 0 ? (
+ {t(value) || ""}
+ ) : (
+ {t(value) || ""}
+ );
+ }
+ if (key === "COMMON_WORKFLOW_STATES") {
+ return {t(`WF_MUSTOR_${value}`)}
+ }
+ //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default
+ return {t(`CASE_NOT_HANDLED`)}
+ },
+ MobileDetailsOnClick: (row, tenantId) => {
+ let link;
+ Object.keys(row).map((key) => {
+ if (key === "ATM_MUSTER_ROLL_ID")
+ link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`;
+ });
+ return link;
+ },
+ populateReqCriteria: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ return {
+ url: "/org-services/organisation/v1/_search",
+ params: { limit: 50, offset: 0 },
+ body: {
+ SearchCriteria: {
+ tenantId: tenantId,
+ functions : {
+ type : "CBO"
+ }
+ },
+ },
+ config: {
+ enabled: true,
+ select: (data) => {
+ return data?.organisations;
+ },
+ },
+ };
+ },
+ },
+ SearchWageSeekerConfig: {
+ customValidationCheck: (data) => {
+ //checking both to and from date are present
+ const { createdFrom, createdTo } = data;
+ if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === ""))
+ return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" };
+
+ return false;
+ },
+ preProcess: (data) => {
+ data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() };
+
+ let requestBody = { ...data.body.Individual };
+ const pathConfig = {
+ name: "name.givenName",
+ };
+ const dateConfig = {
+ createdFrom: "daystart",
+ createdTo: "dayend",
+ };
+ const selectConfig = {
+ wardCode: "wardCode[0].code",
+ socialCategory: "socialCategory.code",
+ };
+ const textConfig = ["name", "individualId"]
+ let Individual = Object.keys(requestBody)
+ .map((key) => {
+ if (selectConfig[key]) {
+ requestBody[key] = _.get(requestBody, selectConfig[key], null);
+ } else if (typeof requestBody[key] == "object") {
+ requestBody[key] = requestBody[key]?.code;
+ } else if (textConfig?.includes(key)) {
+ requestBody[key] = requestBody[key]?.trim()
+ }
+ return key;
+ })
+ .filter((key) => requestBody[key])
+ .reduce((acc, curr) => {
+ if (pathConfig[curr]) {
+ _.set(acc, pathConfig[curr], requestBody[curr]);
+ } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) {
+ _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr]));
+ } else {
+ _.set(acc, curr, requestBody[curr]);
+ }
+ return acc;
+ }, {});
+
+ data.body.Individual = { ...Individual };
+ return data;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ //here we can add multiple conditions
+ //like if a cell is link then we return link
+ //first we can identify which column it belongs to then we can return relevant result
+ switch (key) {
+ case "MASTERS_WAGESEEKER_ID":
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+
+ case "MASTERS_SOCIAL_CATEGORY":
+ return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA");
+
+ case "CORE_COMMON_PROFILE_CITY":
+ return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA");
+
+ case "MASTERS_WARD":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+
+ case "MASTERS_LOCALITY":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+ default:
+ return t("ES_COMMON_NA");
+ }
+ },
+ MobileDetailsOnClick: (row, tenantId) => {
+ let link;
+ Object.keys(row).map((key) => {
+ if (key === "MASTERS_WAGESEEKER_ID")
+ link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`;
+ });
+ return link;
+ },
+ additionalValidations: (type, data, keys) => {
+ if (type === "date") {
+ return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true;
+ }
+ }
+ },
+};
diff --git a/health/micro-ui/web/src/Customisations/index.js b/health/micro-ui/web/src/Customisations/index.js
new file mode 100644
index 00000000000..803b1e8763e
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/index.js
@@ -0,0 +1,19 @@
+import { ptComponents } from "./pt";
+import { tlComponents } from "./tl";
+
+var Digit = window.Digit || {};
+
+const customisedComponent = {
+ ...ptComponents,
+ ...tlComponents
+}
+
+
+
+export const initCustomisationComponents = () => {
+ Object.entries(customisedComponent).forEach(([key, value]) => {
+ Digit.ComponentRegistryService.setComponent(key, value);
+ });
+};
+
+
diff --git a/health/micro-ui/web/src/Customisations/pt/index.js b/health/micro-ui/web/src/Customisations/pt/index.js
new file mode 100644
index 00000000000..0063fcd4774
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/pt/index.js
@@ -0,0 +1,13 @@
+import PropertyUsageType from "./pageComponents/PropertyUsageType";
+import PTVasikaDetails from "./pageComponents/PTVasikaDetails";
+import PTAllotmentDetails from "./pageComponents/PTAllotmentDetails";
+import PTBusinessDetails from "./pageComponents/PTBusinessDetails";
+
+
+
+export const ptComponents = {
+ PropertyUsageType: PropertyUsageType,
+ PTVasikaDetail:PTVasikaDetails,
+ PTAllotmentDetails:PTAllotmentDetails,
+ PTBusinessDetails:PTBusinessDetails
+};
diff --git a/health/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js b/health/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js
new file mode 100644
index 00000000000..569aa45e409
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js
@@ -0,0 +1,64 @@
+import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components";
+import React, { useState } from "react";
+var validation ={};
+const PTAllotmentDetails = ({ t, config, onSelect, value, userType, formData }) => {
+
+ const [
+ val, setValue
+ ] = useState(formData?.[config.key]?.alotmentDetails||"");
+
+ const goNext = () => {
+ onSelect(config.key, {alotmentDetails:val});
+ };
+
+
+ if (userType === "employee") {
+ return (
+
+
+ {t("PT_VASIKA_NO_LABEL") }
+
+ setValue(e?.target?.value)}
+ // autoFocus={presentInModifyApplication}
+ />
+
+
+
+ );
+ }
+ return (
+
+
+
+ {`${t("PT_VASIKA_ALLOTMENT_LABEL")}`}
+ setValue(e?.target?.value)}
+
+ />
+
+
+ {}
+
+ );
+};
+
+export default PTAllotmentDetails;
diff --git a/health/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js b/health/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js
new file mode 100644
index 00000000000..3d28785e7e5
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js
@@ -0,0 +1,68 @@
+import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components";
+import React, { useState } from "react";
+var validation ={};
+const PTBusinessDetails = ({ t, config, onSelect, value, userType, formData }) => {
+
+
+ const [
+ val, setValue
+ ] = useState(formData?.[config.key]?.businessDetails||"");
+
+ const goNext = () => {
+ onSelect(config.key, {businessDetails:val});
+ };
+
+
+ if (userType === "employee") {
+ return (
+
+
+ {t("PT_VASIKA_NO_LABEL") }
+
+ setValue(e?.target?.value)}
+ // autoFocus={presentInModifyApplication}
+ />
+
+
+
+
+ );
+ }
+ return (
+
+
+
+
+ {`${t("PT_VASIKA_BUS_DETAILS_LABEL")}`}
+ setValue(e?.target?.value)}
+
+ />
+
+
+
+ {}
+
+ );
+};
+
+export default PTBusinessDetails;
diff --git a/health/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js b/health/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js
new file mode 100644
index 00000000000..0e4b6895745
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js
@@ -0,0 +1,79 @@
+import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components";
+import React, { useState } from "react";
+var validation ={};
+const PTVasikaDetails = ({ t, config, onSelect, value, userType, formData }) => {
+
+
+ const [
+ val, setValue
+ ] = useState(formData?.[config.key]?.vasikaNo||"");
+ const [
+ other, setOther
+ ] = useState(formData?.[config.key]?.vasikaArea||"");
+ const goNext = () => {
+ onSelect(config.key, {vasikaNo:val,vasikaArea:other});
+ };
+
+
+ if (userType === "employee") {
+ return (
+
+
+ {t("PT_VASIKA_NO_LABEL") }
+
+ setValue(e?.target?.value)}
+ // autoFocus={presentInModifyApplication}
+ />
+
+
+
+
+ );
+ }
+ return (
+
+
+
+
+ {`${t("PT_VASIKA_NO_LABEL")}`}
+ setValue(e?.target?.value)}
+
+ />
+
+ {`${t("PT_VASIKA_AREA_LABEL")}`}
+ setOther(e?.target?.value)}
+ />
+
+ {}
+
+ );
+};
+
+export default PTVasikaDetails;
diff --git a/health/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js b/health/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js
new file mode 100644
index 00000000000..deade4fc2ad
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js
@@ -0,0 +1,134 @@
+import {
+ CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons
+} from "@egovernments/digit-ui-react-components";
+import React, { useEffect, useState } from "react";
+import { useLocation } from "react-router-dom";
+
+var Digit = window.Digit || {};
+
+const PropertyUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => {
+ const [usageCategoryMajor, setPropertyPurpose] = useState(
+ formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS"
+ ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` }
+ : formData?.usageCategoryMajor
+ );
+
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const stateId = tenantId.split(".")[0];
+ const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { };
+ let usagecat = [];
+ usagecat = Menu?.PropertyTax?.UsageCategory || [];
+ let i;
+ let menu = [];
+
+ const { pathname } = useLocation();
+ const presentInModifyApplication = pathname.includes("modify");
+
+ function usageCategoryMajorMenu(usagecat) {
+ if (userType === "employee") {
+ const catMenu = usagecat
+ ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL")
+ ?.map((item) => {
+ const arr = item?.code.split(".");
+ if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code };
+ else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code };
+ });
+ return catMenu;
+ } else {
+ for (i = 0; i < 10; i++) {
+ if (
+ Array.isArray(usagecat) &&
+ usagecat.length > 0 &&
+ usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" &&
+ usagecat[i].code.split(".").length == 2
+ ) {
+ menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code });
+ }
+ }
+ return menu;
+ }
+ }
+
+ useEffect(() => {
+ if (!menuLoading && presentInModifyApplication && userType === "employee") {
+ const original = formData?.originalData?.usageCategory;
+ const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0];
+ setPropertyPurpose(selectedOption);
+ }
+ }, [menuLoading]);
+
+ const onSkip = () => onSelect();
+
+
+ function selectPropertyPurpose(value) {
+ setPropertyPurpose(value);
+ }
+
+ function goNext() {
+ if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") {
+ usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL";
+ onSelect(config.key, usageCategoryMajor);
+ } else {
+ onSelect(config.key, usageCategoryMajor);
+ }
+ }
+
+ useEffect(() => {
+ if (userType === "employee") {
+ if (!usageCategoryMajor) {
+ setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) });
+ } else {
+ clearErrors(config.key);
+ }
+ goNext();
+ }
+ }, [usageCategoryMajor]);
+
+ if (userType === "employee") {
+ return (
+
+
+ {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"}
+ {
+ selectPropertyPurpose(e);
+ }}
+ optionKey="i18nKey"
+ onBlur={onBlur}
+ t={t}
+ />
+
+ {formState.touched[config.key] ? (
+
+ {formState.errors?.[config.key]?.message}
+
+ ) : null}
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ {}
+
+ );
+};
+
+export default PropertyUsageType;
diff --git a/health/micro-ui/web/src/Customisations/tl/TLCustomisation.js b/health/micro-ui/web/src/Customisations/tl/TLCustomisation.js
new file mode 100644
index 00000000000..642acc52090
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/tl/TLCustomisation.js
@@ -0,0 +1,5 @@
+export const TLCustomisations = {
+ customiseCreateFormData: (formData, licenceObject) => licenceObject,
+ customiseRenewalCreateFormData: (formData, licenceObject) => licenceObject,
+ customiseSendbackFormData: (formData, licenceObject) => licenceObject
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/src/Customisations/tl/index.js b/health/micro-ui/web/src/Customisations/tl/index.js
new file mode 100644
index 00000000000..fe2ae4f4e6a
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/tl/index.js
@@ -0,0 +1,7 @@
+import TLUsageType from "./pageComponents/PropertyUsageType";
+
+
+
+export const tlComponents = {
+ TLPropertyUsageType: TLUsageType,
+};
diff --git a/health/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js b/health/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js
new file mode 100644
index 00000000000..5520a66fc5a
--- /dev/null
+++ b/health/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js
@@ -0,0 +1,136 @@
+import {
+ CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons
+} from "@egovernments/digit-ui-react-components";
+import React, { useEffect, useState } from "react";
+import { useLocation } from "react-router-dom";
+
+var Digit = window.Digit || {};
+
+const TLUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => {
+ const [usageCategoryMajor, setPropertyPurpose] = useState(
+ formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS"
+ ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` }
+ : formData?.usageCategoryMajor
+ );
+
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const stateId = tenantId.split(".")[0];
+ const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { };
+ let usagecat = [];
+ usagecat = Menu?.PropertyTax?.UsageCategory || [];
+ let i;
+ let menu = [];
+
+ const { pathname } = useLocation();
+ const presentInModifyApplication = pathname.includes("modify");
+
+ function usageCategoryMajorMenu(usagecat) {
+ if (userType === "employee") {
+ const catMenu = usagecat
+ ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL")
+ ?.map((item) => {
+ const arr = item?.code.split(".");
+ if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code };
+ else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code };
+ });
+ return catMenu;
+ } else {
+ for (i = 0; i < 10; i++) {
+ if (
+ Array.isArray(usagecat) &&
+ usagecat.length > 0 &&
+ usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" &&
+ usagecat[i].code.split(".").length == 2
+ ) {
+ menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code });
+ }
+ }
+ return menu;
+ }
+ }
+
+ useEffect(() => {
+ if (!menuLoading && presentInModifyApplication && userType === "employee") {
+ const original = formData?.originalData?.usageCategory;
+ const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0];
+ setPropertyPurpose(selectedOption);
+ }
+ }, [menuLoading]);
+
+ const onSkip = () => onSelect();
+
+
+ function selectPropertyPurpose(value) {
+ setPropertyPurpose(value);
+ }
+
+ function goNext() {
+ if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") {
+ usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL";
+ onSelect(config.key, usageCategoryMajor);
+ } else {
+ onSelect(config.key, usageCategoryMajor);
+ }
+ }
+
+ useEffect(() => {
+ if (userType === "employee") {
+ if (!usageCategoryMajor) {
+ setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) });
+ } else {
+ clearErrors(config.key);
+ }
+ goNext();
+ }
+ }, [usageCategoryMajor]);
+
+ if (userType === "employee") {
+ return (
+
+
+ {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"}
+ {
+ selectPropertyPurpose(e);
+ }}
+ optionKey="i18nKey"
+ onBlur={onBlur}
+ t={t}
+ />
+
+ {formState.touched[config.key] ? (
+
+ {formState.errors?.[config.key]?.message}
+
+ ) : null}
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ to say this is different element
+
+
+ {}
+
+ );
+};
+
+export default TLUsageType;
diff --git a/health/micro-ui/web/src/index.css b/health/micro-ui/web/src/index.css
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/health/micro-ui/web/src/index.js b/health/micro-ui/web/src/index.js
new file mode 100644
index 00000000000..9f20bf1b506
--- /dev/null
+++ b/health/micro-ui/web/src/index.js
@@ -0,0 +1,62 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { initLibraries } from "@egovernments/digit-ui-libraries";
+import "./index.css";
+import App from './App';
+import { TLCustomisations } from './Customisations/tl/TLCustomisation';
+
+
+initLibraries();
+
+
+window.Digit.Customizations = { PGR: {} ,TL:TLCustomisations};
+
+const user = window.Digit.SessionStorage.get("User");
+
+if (!user || !user.access_token || !user.info) {
+ // login detection
+
+ const parseValue = (value) => {
+ try {
+ return JSON.parse(value)
+ } catch (e) {
+ return value
+ }
+ }
+
+ const getFromStorage = (key) => {
+ const value = window.localStorage.getItem(key);
+ return value && value !== "undefined" ? parseValue(value) : null;
+ }
+
+ const token = getFromStorage("token")
+
+ const citizenToken = getFromStorage("Citizen.token")
+ const citizenInfo = getFromStorage("Citizen.user-info")
+ const citizenTenantId = getFromStorage("Citizen.tenant-id")
+
+ const employeeToken = getFromStorage("Employee.token")
+ const employeeInfo = getFromStorage("Employee.user-info")
+ const employeeTenantId = getFromStorage("Employee.tenant-id")
+ const userType = token === citizenToken ? "citizen" : "employee";
+
+ window.Digit.SessionStorage.set("user_type", userType);
+ window.Digit.SessionStorage.set("userType", userType);
+
+ const getUserDetails = (access_token, info) => ({ token: access_token, access_token, info })
+
+ const userDetails = userType === "citizen" ? getUserDetails(citizenToken, citizenInfo) : getUserDetails(employeeToken, employeeInfo)
+
+ window.Digit.SessionStorage.set("User", userDetails);
+ window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId);
+ window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId);
+ // end
+}
+
+ReactDOM.render(
+
+
+ ,
+ document.getElementById('root')
+);
+
diff --git a/health/micro-ui/web/src/setupProxy.js b/health/micro-ui/web/src/setupProxy.js
new file mode 100644
index 00000000000..1b8eda94a19
--- /dev/null
+++ b/health/micro-ui/web/src/setupProxy.js
@@ -0,0 +1,30 @@
+const { createProxyMiddleware } = require("http-proxy-middleware");
+const createProxy = createProxyMiddleware({
+ target: process.env.REACT_APP_PROXY_URL,
+ changeOrigin: true,
+});
+module.exports = function (app) {
+ [
+ "/egov-mdms-service",
+ "/egov-location",
+ "/localization",
+ "/egov-workflow-v2",
+ "/pgr-services",
+ "/filestore",
+ "/egov-hrms",
+ "/user-otp",
+ "/user",
+ "/fsm",
+ "/billing-service",
+ "/collection-services",
+ "/pdf-service",
+ "/pg-service",
+ "/vehicle",
+ "/vendor",
+ "/property-services",
+ "/fsm-calculator/v1/billingSlab/_search",
+ "/muster-roll"
+ ].forEach((location) =>
+ app.use(location, createProxy)
+ );
+};
diff --git a/health/micro-ui/web/webpack.config.js b/health/micro-ui/web/webpack.config.js
new file mode 100644
index 00000000000..5f3dc46967a
--- /dev/null
+++ b/health/micro-ui/web/webpack.config.js
@@ -0,0 +1,43 @@
+const path = require("path");
+const HtmlWebpackPlugin = require("html-webpack-plugin");
+const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
+
+module.exports = {
+ // mode: 'development',
+ entry: "./src/index.js",
+ devtool: "none",
+ module: {
+ rules: [
+ {
+ test: /\.(js)$/,
+ use: ["babel-loader"],
+ },
+ {
+ test: /\.css$/i,
+ use: ["style-loader", "css-loader"],
+ }
+ ],
+ },
+ output: {
+ filename: "[name].bundle.js",
+ path: path.resolve(__dirname, "build"),
+ publicPath: "/digit-ui/",
+ },
+ optimization: {
+ splitChunks: {
+ chunks: 'all',
+ minSize:20000,
+ maxSize:50000,
+ enforceSizeThreshold:50000,
+ minChunks:1,
+ maxAsyncRequests:30,
+ maxInitialRequests:30
+ },
+ },
+ plugins: [
+ new CleanWebpackPlugin(),
+ // new BundleAnalyzerPlugin(),
+ new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }),
+ ],
+};
\ No newline at end of file
diff --git a/health/micro-ui/web/workbench/App.js b/health/micro-ui/web/workbench/App.js
new file mode 100644
index 00000000000..93b15440c5e
--- /dev/null
+++ b/health/micro-ui/web/workbench/App.js
@@ -0,0 +1,72 @@
+/**
+ * The above code initializes various Digit UI modules and components, sets up customizations, and
+ * renders the DigitUI component based on the enabled modules and state code.
+ * @returns The `App` component is being returned, which renders the `DigitUI` component with the
+ * specified props such as `stateCode`, `enabledModules`, `moduleReducers`, and `defaultLanding`. The
+ * `DigitUI` component is responsible for rendering the UI based on the provided configuration and
+ * modules.
+ */
+import React from "react";
+import { initLibraries } from "@egovernments/digit-ui-libraries";
+import { DigitUI } from "@egovernments/digit-ui-module-core";
+// import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms";
+import { UICustomizations } from "./Customisations/UICustomizations";
+import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
+import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
+import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench";
+import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager"
+
+window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
+
+const enabledModules = [
+ "DSS",
+ "NDSS",
+ "Utilities",
+ // "HRMS",
+ "Engagement",
+ "Workbench",
+ "HCMWORKBENCH",
+ "Campaign"
+];
+
+const moduleReducers = (initData) => ({
+ initData,
+});
+
+const initDigitUI = () => {
+ window.Digit.ComponentRegistryService.setupRegistry({});
+ window.Digit.Customizations = {
+ PGR: {},
+ commonUiConfig: UICustomizations,
+ };
+ // initHRMSComponents();
+ initUtilitiesComponents();
+ initWorkbenchComponents();
+ initWorkbenchHCMComponents();
+ initCampaignComponents();
+
+};
+
+initLibraries().then(() => {
+ initDigitUI();
+});
+
+function App() {
+ window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
+ const stateCode =
+ window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") ||
+ process.env.REACT_APP_STATE_LEVEL_TENANT_ID;
+ if (!stateCode) {
+ return stateCode is not defined
;
+ }
+ return (
+
+ );
+}
+
+export default App;
diff --git a/health/micro-ui/web/workbench/Dockerfile b/health/micro-ui/web/workbench/Dockerfile
new file mode 100644
index 00000000000..31b3912759b
--- /dev/null
+++ b/health/micro-ui/web/workbench/Dockerfile
@@ -0,0 +1,29 @@
+FROM egovio/alpine-node-builder-14:yarn AS build
+#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build
+RUN apk update && apk upgrade
+RUN apk add --no-cache git>2.30.0
+ARG WORK_DIR
+WORKDIR /app
+ENV NODE_OPTIONS "--max-old-space-size=4792"
+
+COPY ${WORK_DIR} .
+RUN ls -lah
+
+#RUN node web/envs.js
+RUN cd web/ \
+ && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \
+ && node -e 'console.log("core only")' \
+ && cd workbench/ \
+ && ./install-deps.sh \
+ && cd ../ \
+ && yarn install \
+ && yarn build:webpack
+
+FROM nginx:mainline-alpine
+#FROM ghcr.io/egovernments/nginx:mainline-alpine
+ENV WORK_DIR=/var/web/workbench-ui
+
+RUN mkdir -p ${WORK_DIR}
+
+COPY --from=build /app/web/build ${WORK_DIR}/
+COPY --from=build /app/web/workbench/nginx.conf /etc/nginx/conf.d/default.conf
diff --git a/health/micro-ui/web/workbench/install-deps.sh b/health/micro-ui/web/workbench/install-deps.sh
new file mode 100755
index 00000000000..54b8a4c3d7f
--- /dev/null
+++ b/health/micro-ui/web/workbench/install-deps.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+BRANCH="$(git branch --show-current)"
+
+echo "Main Branch: $BRANCH"
+
+INTERNALS="micro-ui-internals"
+cd ..
+
+cp workbench/App.js src
+cp workbench/package.json package.json
+cp workbench/webpack.config.js webpack.config.js
+cp workbench/inter-package.json $INTERNALS/package.json
+
+cp $INTERNALS/example/src/UICustomizations.js src/Customisations
+
+echo "UI :: workbench " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages"
+
diff --git a/health/micro-ui/web/workbench/inter-package.json b/health/micro-ui/web/workbench/inter-package.json
new file mode 100644
index 00000000000..5216443ec23
--- /dev/null
+++ b/health/micro-ui/web/workbench/inter-package.json
@@ -0,0 +1,58 @@
+{
+ "name": "egovernments",
+ "version": "1.0.0",
+ "main": "index.js",
+ "workspaces": [
+ "example",
+ "packages/css",
+ "packages/modules/*"
+ ],
+ "author": "JaganKumar ",
+ "license": "MIT",
+ "private": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "scripts": {
+ "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev",
+ "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script",
+ "start:dev": "run-p dev:**",
+ "start:script": "./scripts/create.sh",
+ "dev:css": "cd packages/css && yarn start",
+ "publish:css": "cd packages/css && yarn publish --access public",
+ "dev:example": "cd example && yarn start",
+ "dev:campaign": "cd packages/modules/campaign-manager && yarn start",
+ "build": "run-p build:**",
+ "build:campaign": "cd packages/modules/campaign-manager && yarn build",
+ "deploy:jenkins": "./scripts/jenkins.sh",
+ "clean": "rm -rf node_modules"
+ },
+ "resolutions": {
+ "**/@babel/runtime": "7.20.1",
+ "**/babel-preset-react-app": "10.0.0",
+ "**/ajv": "8.11.2",
+ "fast-uri":"2.1.0"
+ },
+ "devDependencies": {
+ "husky": "7.0.4",
+ "lint-staged": "12.3.7",
+ "npm-run-all": "4.1.5",
+ "prettier": "2.1.2"
+ },
+ "husky": {},
+ "lint-staged": {
+ "*.{js,css,md}": "prettier --write"
+ },
+ "dependencies": {
+ "lodash": "4.17.21",
+ "microbundle-crl": "0.13.11",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.1",
+ "@egovernments/digit-ui-components": "0.0.2-beta.1",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0"
+ }
+}
diff --git a/health/micro-ui/web/workbench/nginx.conf b/health/micro-ui/web/workbench/nginx.conf
new file mode 100644
index 00000000000..974ef82f241
--- /dev/null
+++ b/health/micro-ui/web/workbench/nginx.conf
@@ -0,0 +1,12 @@
+server
+{
+ listen 80;
+ underscores_in_headers on;
+
+ location /workbench-ui
+ {
+ root /var/web;
+ index index.html index.htm;
+ try_files $uri $uri/ /workbench-ui/index.html;
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/workbench/package.json b/health/micro-ui/web/workbench/package.json
new file mode 100644
index 00000000000..7cc60ef7bff
--- /dev/null
+++ b/health/micro-ui/web/workbench/package.json
@@ -0,0 +1,89 @@
+{
+ "name": "micro-ui",
+ "version": "1.0.0",
+ "author": "Jagankumar ",
+ "license": "MIT",
+ "private": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "workspaces": [
+ "micro-ui-internals/packages/modules/*"
+ ],
+ "homepage": "/workbench-ui",
+ "dependencies": {
+ "@egovernments/digit-ui-libraries": "1.8.2-beta.1",
+ "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3",
+ "@egovernments/digit-ui-components": "0.0.2-beta.1",
+ "@egovernments/digit-ui-module-core": "1.8.2-beta.2",
+ "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
+ "@egovernments/digit-ui-module-campaign-manager": "0.0.1",
+ "babel-loader": "8.1.0",
+ "clean-webpack-plugin": "4.0.0",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "jsonpath": "^1.1.1",
+ "react-router-dom": "5.3.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "1.1.2",
+ "terser-brunch": "^4.1.0",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "css-loader": "5.2.6",
+ "style-loader": "2.0.0",
+ "webpack-cli": "4.10.0"
+ },
+ "devDependencies": {
+ "@babel/plugin-proposal-private-property-in-object": "7.21.0",
+ "http-proxy-middleware": "1.3.1",
+ "lodash": "4.17.21",
+ "microbundle-crl": "0.13.11",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0",
+ "husky": "7.0.4",
+ "lint-staged": "12.3.7",
+ "npm-run-all": "4.1.5",
+ "prettier": "2.1.2"
+ },
+ "resolutions": {
+ "**/babel-loader": "8.2.2",
+ "**/@babel/core": "7.14.0",
+ "**/@babel/preset-env": "7.14.0",
+ "**/@babel/plugin-transform-modules-commonjs": "7.14.0",
+ "**/polished":"4.2.2",
+ "fast-uri":"2.1.0"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build",
+ "build:prepare": "./build.sh",
+ "build:libraries": "cd micro-ui-internals && yarn build",
+ "build:prod": "webpack --mode production",
+ "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod",
+ "clean": "rm -rf node_modules"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/health/micro-ui/web/workbench/webpack.config.js b/health/micro-ui/web/workbench/webpack.config.js
new file mode 100644
index 00000000000..c19e631fe01
--- /dev/null
+++ b/health/micro-ui/web/workbench/webpack.config.js
@@ -0,0 +1,44 @@
+const path = require("path");
+const HtmlWebpackPlugin = require("html-webpack-plugin");
+const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
+
+module.exports = {
+ // mode: 'development',
+ entry: "./src/index.js",
+ devtool: "none",
+ module: {
+ rules: [
+ {
+ test: /\.(js)$/,
+ exclude: /node_modules/,
+ use: ["babel-loader"],
+ },
+ {
+ test: /\.css$/i,
+ use: ["style-loader", "css-loader"],
+ }
+ ],
+ },
+ output: {
+ filename: "[name].bundle.js",
+ path: path.resolve(__dirname, "build"),
+ publicPath: "/workbench-ui/",
+ },
+ optimization: {
+ splitChunks: {
+ chunks: 'all',
+ minSize:20000,
+ maxSize:50000,
+ enforceSizeThreshold:50000,
+ minChunks:1,
+ maxAsyncRequests:30,
+ maxInitialRequests:30
+ },
+ },
+ plugins: [
+ new CleanWebpackPlugin(),
+ // new BundleAnalyzerPlugin(),
+ new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }),
+ ],
+};
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 00000000000..fb57ccd13af
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
From c29df694486901f8012e26407164abc4163c4eb5 Mon Sep 17 00:00:00 2001
From: siddhant-nawale-egov
<162107530+siddhant-nawale-egov@users.noreply.github.com>
Date: Wed, 26 Jun 2024 21:00:37 +0530
Subject: [PATCH 09/83] Microplan v1 UI Changes merging to master under health
folder along with Campaign changes (#961)
* HLM-5154 removing chloropleth part
* Update Mapping.js
* updated project type
* HLM-5208 basic chloropleth setup
* HLM-5208 review changes and bug HLM-5866
* HLM-5208 review changes
* work in progress
* work in progress
* work in progress
* work in progress
* HLM-5156 filter lyaer in map
* HLM-5156 adding filter layer is mapping section HLM-5880 bug
* HLM-5156 updating UIconfigurations
* HLM-5891 microplan success screen bug
* Update UICustomizations.js
* HLM-5891 updating how data is processed and then stored in ssn storage
* reverting the digit svg version
* HLM-5156 adding isFilterPropertyOfMapSection to ajv
* HLM-5156 minor fixes
* changing shapefile content name validation
* HLM-5156 review changes
* HLM-5156 review changes
* HLM-5208 adding choropleth UI
* Updated schema property name
* downgrading digit ui react components
* HLM-5926 UI audit changes and enabling upload of multi sheet data
* HLM-5926 upgrading css pkg
* HLM-5926 changeing id to name in success screen
* HLM-5926 review changes
* Update package.json
* HLM-5926 review chagnes
* HLM-5926 upgrading microplan css pkg version
* HLM-5926 dropdowns to digit dropdowns
* HLM-5926 adding base color changes
* HLM-5926 increasing css pkg version
* HLM-5926 adding review changes
* removing debugger
* Update updateSessionUtils.js
* work in progress
* HLM-5926 api integration for active status
* HLM-5926 review changes
* increasing microplan css version
* adding additional prop load check in navigator
* HLM-5926 download translated microlan
* HLM-5926 removing duplicate children in mapping
* HLM-5926 adding review changes
* HLM-5926 review changes
* demo fixes
* demo changes
* HLM-5926 demo changes for preview and modal buttons
* HLM-5926 campaign date change
* HLM-5926 review changes
* HLM-5926 overriding login page css
* Update microplanning.scss
* HLM-6011 campaign date
* Update UICustomizations.js
* HLM-5926 resource mapping errors
* HLM-6019 adding show error in upload preview screen and navigation restrictions
* HLM-6019 review changes
* Update JsonPreviewInExcelForm.js
* HLM-6019 download template
* HLM-6019 enabling download
* HLM-6019 review changes
* HLM-6019 review change
* Update Upload.js
* HLM-6019 reverted digit core
* HLM-5125 download template
* HLM-5925 adding review changes
* Update RuleEngine.js
* HLM-6172 template download and save and highlight the data after data is adjusted in microplan generation page.
* HLM-6172 adding review changes
* HLM-6172 Notice and instruction page needs to be hidden or should contian sample data and Check localisation for geojson and shape file Mapping
* HLM-5172 Column heading has to be freezed
* HLM-6172 review changes
* HLM-6172 debuggers
* HLM-6172 review changes
* HLM-5925 help feature bug fixes
* HLM-6172 downlgrading ui core version
* HLM-6172 campaigntype automation
* HLM-6172 Tool tip of formula configuration and Hover over the errors in preview screen add localization and template download changes
* HLM-6172 avj fixes
* adding review changes
* HLM-6172 removing MDMS data
* work in progress
* HLM-6172 removing mdms data and removing heirarchy mapping from facilities
* field length validation for geojson and shape files
* HLM-6172 reinstating setting upload error
* adding review changes
* Update Upload.js
* error correction for handle excel
* work in progress
* work in progress
* work in progress
* work in progress
* work in progress
* Update Upload.js
* work in progress
* work in progress
* Update Upload.js
* Update Upload.js
* Update Upload.js
* Update Upload.js
* work in progress
* work in progress
* HLM-6172 adding audit changes
* HLM-6172 adding required data for smc and demo review comment changes
* cleaning up code
* HLM-6172 removing mdms files and adding review changes
* HLM-6172 removing unnecessary dependancy and activating process hold with api throws an error
* HLM-6172 adding review changes
* Update index.js
* Update excelValidations.js
* HLM-6172 Navigation via fixed keyboard for Popups is not working
* HLM-6172 adding review changes
* HLM-6172 adding microplan name validation
* HLM-6172 adding review changes
* HLM-6172 adding review changes
* Update CommonComponents.js
* Update updateSessionUtils.js
* improving error handling
* HLM-6172 changed how microplan nameing error is shown, rule logic correction
* HLM-6172 adding naming convention info box
* upgraded microplan css version
* HLM-6172 adding select all corrections
* HLM-6172 adding campaign end date restriction, and other required changes
* HLM-6172 modal focus changes
* HLM-6172 example data filling
* HLM-6172 review changes
* Update processHierarchyAndData.js
* HLM-6172 mapping page correction and api call data corrections
* adding review changes
* HLM-6172 adding required changes for facility data upload and removing prerequisites from upload data section
* HLM-6172 adding review changes
* Update Upload.js
* Update Upload.js
* Update Upload.js
* HLM-6172 allowing user to enter 0.somehing in hypothesis section
* HLM-6172 adding upload propogation restriction on error
* Update Upload.js
* HLM-6172 changing the upload page navigation
* Update MicroplanDetails.js
* HLM-6172 shifting toast to create microplan
* work in progress
* work in progress
* upgrade microplan css version
* work in progress
* work in progress
* work in progress
* work in progress
* HLM-6234 HLM-6235 HLM-6237 HLM-6238 HLM-6239 HLM-6240
* adding review changes and protection of cell in downloaded templates
* increasing microplan css pkg version
* removing MDMS data and adding review changes
* adding review changes
* adding review changes
* hiding unique identifier column
* HLM-6172 adding upload guidelines
* Update Upload.js
* micro css changes and comfirm mcroplan pop up
* Update MicroplanPreview.js
* HLM-6172 updating operation to match api changes
* updating operation to match api changes
* removing unused code and updating readme file
* adding UploadGuidelines
* Update index.js
* HLM-6258 , HLM-6251 adding readme for templates and enabling user to uplaod comma separated boundary code in facility
* updating microplan scss version
* reducing complexities of various funcitons
* reducing complexities of various funcitons
* Update MicroplanPreview.js
* adding review changes and removing MDMS data
* adding review changes
* adding style for generated microplan
* Update coreOverride.scss
* overriding microplan success header class and updates shape file handling
* HLM-6298 adding active inactive field in template
* adding review chagnes
* reducing function complicity
* adding review changes
* Update CreateMicroplan.js
* updating microplan css pkg
* translating error column header for styling
* geojson shapefile active inactive changes
* updating css pkg version
* adding review changes
* Update index.js
* moving microplaning from micro-ui/ to health/micro-ui/
* Update CODEOWNERS
* shifting health service frontend data to digit fronend
* removed template
---------
Co-authored-by: Nipun Arora
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
---
.github/workflows/publishAllPackages.yml | 2 +-
.vscode/settings.json | 2 +-
CODEOWNERS | 3 +-
README.md | 29 +-
health/micro-ui/package.json | 2 +-
health/micro-ui/web/install-deps.sh | 0
.../micro-ui-internals/example/package.json | 3 +-
.../example/public/index.html | 2 +
.../example/src/UICustomizations.js | 302 +++--
.../micro-ui-internals/example/src/index.js | 4 +-
.../example/src/setupProxy.js | 1 +
.../web/micro-ui-internals/package.json | 2 +
.../modules/hcm-microplanning/package.json | 62 +
.../modules/hcm-microplanning/src/Module.js | 99 ++
.../src/components/CommonComponents.js | 61 +
.../src/components/CustomScaleControl.js | 41 +
.../src/components/Hypothesis.js | 631 +++++++++
.../src/components/JsonPreviewInExcelForm.js | 113 ++
.../src/components/Mapping.js | 442 +++++++
.../src/components/MappingHelperComponents.js | 513 ++++++++
.../src/components/MicroplanCreatedScreen.js | 111 ++
.../src/components/MicroplanDetails.js | 295 +++++
.../src/components/MicroplanPreview.js | 470 +++++++
.../MicroplanPreviewHelperCompoenents.js | 434 +++++++
.../src/components/MicroplanningCard.js | 34 +
.../src/components/MicroplanningHeader.js | 29 +
.../hcm-microplanning/src/components/Modal.js | 158 +++
.../src/components/Nagivator.js | 307 +++++
.../src/components/RuleEngine.js | 875 +++++++++++++
.../src/components/Upload.js | 1154 +++++++++++++++++
.../src/components/UploadHelperComponents.js | 299 +++++
.../src/components/ZoomControl.js | 29 +
.../src/components/resourceMapping.js | 187 +++
.../src/configs/UICustomizations.js | 324 +++++
.../src/configs/constants.js | 38 +
.../src/configs/timeLineOptions.json | 40 +
.../src/configs/tourSteps.js | 193 +++
.../hcm-microplanning/src/hooks/index.js | 42 +
.../src/hooks/useCreatePlanConfig.js | 8 +
.../src/hooks/useGenerateIdCampaign.js | 26 +
.../src/hooks/useNumberFormatter.js | 21 +
.../src/hooks/useSavedMicroplans.js | 23 +
.../src/hooks/useSearchCampaign.js | 8 +
.../src/hooks/useSearchPlanConfig.js | 8 +
.../src/hooks/useUpdatePlanConfig.js | 8 +
.../hcm-microplanning/src/icons/Svg.js | 217 ++++
.../src/pages/employee/CreateMicroplan.js | 296 +++++
.../src/pages/employee/Guidelines.js | 54 +
.../src/pages/employee/SavedMicroplans.js | 204 +++
.../src/pages/employee/SelectCampaign.js | 226 ++++
.../src/pages/employee/index.js | 135 ++
.../src/services/CreatePlanConfig.js | 19 +
.../hcm-microplanning/src/services/Search.js | 181 +++
.../src/services/SearchCampaignConfig.js | 22 +
.../src/services/SearchPlanConfig.js | 19 +
.../src/services/UpdatePlanConfig.js | 18 +
.../src/services/searchSavedPlans.js | 67 +
.../hcm-microplanning/src/utils/context.js | 31 +
.../src/utils/createTemplate.js | 485 +++++++
.../hcm-microplanning/src/utils/excelUtils.js | 153 +++
.../src/utils/excelValidations.js | 199 +++
.../src/utils/exceltojson.js | 99 ++
.../src/utils/geojsonValidations.js | 234 ++++
.../hcm-microplanning/src/utils/index.js | 478 +++++++
.../src/utils/jsonToExcelBlob.js | 72 +
.../src/utils/mappingUtils.js | 763 +++++++++++
.../src/utils/microplanPreviewUtils.js | 413 ++++++
.../src/utils/processHierarchyAndData.js | 351 +++++
.../src/utils/updateSessionUtils.js | 484 +++++++
.../src/utils/uploadUtils.js | 1030 +++++++++++++++
.../web/micro-ui-internals/scripts/create.sh | 0
.../web/micro-ui-internals/scripts/deploy.sh | 0
.../web/micro-ui-internals/scripts/jenkins.sh | 0
.../web/micro-ui-internals/scripts/run.sh | 0
health/micro-ui/web/microplan/App.js | 61 +
health/micro-ui/web/microplan/Dockerfile | 30 +
health/micro-ui/web/microplan/install-deps.sh | 18 +
.../micro-ui/web/microplan/inter-package.json | 61 +
health/micro-ui/web/microplan/nginx.conf | 12 +
health/micro-ui/web/microplan/package.json | 80 ++
.../micro-ui/web/microplan/webpack.config.js | 52 +
health/micro-ui/web/package.json | 2 +-
health/micro-ui/web/public/index.html | 1 +
health/micro-ui/web/workbench/install-deps.sh | 0
node_modules/.yarn-integrity | 12 +
85 files changed, 13899 insertions(+), 115 deletions(-)
mode change 100755 => 100644 health/micro-ui/web/install-deps.sh
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js
mode change 100755 => 100644 health/micro-ui/web/micro-ui-internals/scripts/create.sh
mode change 100755 => 100644 health/micro-ui/web/micro-ui-internals/scripts/deploy.sh
mode change 100755 => 100644 health/micro-ui/web/micro-ui-internals/scripts/jenkins.sh
mode change 100755 => 100644 health/micro-ui/web/micro-ui-internals/scripts/run.sh
create mode 100644 health/micro-ui/web/microplan/App.js
create mode 100644 health/micro-ui/web/microplan/Dockerfile
create mode 100644 health/micro-ui/web/microplan/install-deps.sh
create mode 100644 health/micro-ui/web/microplan/inter-package.json
create mode 100644 health/micro-ui/web/microplan/nginx.conf
create mode 100644 health/micro-ui/web/microplan/package.json
create mode 100644 health/micro-ui/web/microplan/webpack.config.js
mode change 100755 => 100644 health/micro-ui/web/workbench/install-deps.sh
create mode 100644 node_modules/.yarn-integrity
diff --git a/.github/workflows/publishAllPackages.yml b/.github/workflows/publishAllPackages.yml
index f41ce8f9e72..042de6f5d70 100644
--- a/.github/workflows/publishAllPackages.yml
+++ b/.github/workflows/publishAllPackages.yml
@@ -2,7 +2,7 @@ name: Node.js Publish Health UI Packages
on:
push:
- branches: [ 'develop','campaign' ]
+ branches: [ 'develop','campaign' ,'microplan']
paths:
- 'health/micro-ui/web/micro-ui-internals/**'
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 14f60307eb1..2b8c08a8854 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,3 @@
{
- "editor.inlineSuggest.showToolbar": "onHover"
+ "editor.inlineSuggest.showToolbar": "always"
}
\ No newline at end of file
diff --git a/CODEOWNERS b/CODEOWNERS
index 0ce19c4b01e..9f8971138f6 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1 +1,2 @@
-* @egovernments/core-ui-reviewers
+- @egovernments/core-ui-reviewers
+
diff --git a/README.md b/README.md
index b0ad104ede6..efa87d123c6 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-
# DIGIT UI
A React App built on top of DIGIT UI Core.
@@ -12,9 +11,7 @@ DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India'
DIGIT platform is microservices based API platform enabling quick rebundling of services as per specific needs. This is a repo that lays down the core platform on top of which other mission services depend.
-
-# DIGIT UI
-
+# DIGIT UI
This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries.
@@ -22,7 +19,6 @@ Workbench module is used to Manage the master data (MDMS V2 Service) used across
It is also used to manage the Localisation data present in the system (Localisation service)
-
## Run Locally
Clone the project
@@ -32,6 +28,7 @@ Clone the project
```
Go to the Sub directory to run UI
+
```bash
cd into micro-ui/web/micro-ui-internals
```
@@ -43,6 +40,7 @@ Install dependencies
```
Add .env file
+
```bash
micro-ui/web/micro-ui-internals/example/.env
```
@@ -53,18 +51,17 @@ Start the server
yarn start
```
-
## Environment Variables
To run this project, you will need to add the following environment variables to your .env file
-`REACT_APP_PROXY_API` :: `{{server url}}`
+`REACT_APP_PROXY_API` :: `{{server url}}`
-`REACT_APP_GLOBAL` :: `{{server url}}`
+`REACT_APP_GLOBAL` :: `{{server url}}`
-`REACT_APP_PROXY_ASSETS` :: `{{server url}}`
+`REACT_APP_PROXY_ASSETS` :: `{{server url}}`
-`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}`
+`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}`
`SKIP_PREFLIGHT_CHECK` :: `true`
@@ -72,7 +69,7 @@ To run this project, you will need to add the following environment variables to
## Tech Stack
-**Libraries:**
+**Libraries:**
[React](https://react.dev/)
@@ -88,22 +85,18 @@ To run this project, you will need to add the following environment variables to
[MIT](https://choosealicense.com/licenses/mit/)
-
## Author
- [@jagankumar-egov](https://www.github.com/jagankumar-egov)
-
## Documentation
[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui)
-
## Support
For support, add the issues in https://github.com/egovernments/DIGIT-core/issues.
-
## Modules
1. Core
@@ -115,18 +108,18 @@ For support, add the issues in https://github.com/egovernments/DIGIT-core/issues
## Starting with Digit-UI App (Impelmentation Teams) - MICRO-UI
-
Go to the Sub directory to run UI
```bash
cd into micro-ui/web
```
-
+
```bash
yarn install
```
Add .env file
+
```bash
micro-ui/web/.env
```
@@ -137,6 +130,4 @@ Start the server
yarn start
```
-
![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png)
-
diff --git a/health/micro-ui/package.json b/health/micro-ui/package.json
index 19a3c47d6ee..78ab4e7aa40 100644
--- a/health/micro-ui/package.json
+++ b/health/micro-ui/package.json
@@ -1,4 +1,4 @@
{
"name": "workbench-ui",
- "version": "1.0.0"
+ "version": "0.1.0"
}
\ No newline at end of file
diff --git a/health/micro-ui/web/install-deps.sh b/health/micro-ui/web/install-deps.sh
old mode 100755
new mode 100644
diff --git a/health/micro-ui/web/micro-ui-internals/example/package.json b/health/micro-ui/web/micro-ui-internals/example/package.json
index 7c60f4a1d6c..2d8c8857b45 100644
--- a/health/micro-ui/web/micro-ui-internals/example/package.json
+++ b/health/micro-ui/web/micro-ui-internals/example/package.json
@@ -17,6 +17,7 @@
"@egovernments/digit-ui-react-components": "1.8.2-beta.6",
"@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
"@egovernments/digit-ui-module-campaign-manager": "0.0.1",
+ "@egovernments/digit-ui-module-hcmmicroplanning": "0.0.1",
"http-proxy-middleware": "^1.0.5",
"react": "17.0.2",
"react-dom": "17.0.2",
@@ -36,4 +37,4 @@
"last 1 safari version"
]
}
-}
\ No newline at end of file
+}
diff --git a/health/micro-ui/web/micro-ui-internals/example/public/index.html b/health/micro-ui/web/micro-ui-internals/example/public/index.html
index d42798fc275..6c5bb32010c 100644
--- a/health/micro-ui/web/micro-ui-internals/example/public/index.html
+++ b/health/micro-ui/web/micro-ui-internals/example/public/index.html
@@ -17,6 +17,8 @@
+
+
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
index d21e82500b7..dff584d9ab2 100644
--- a/health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
+++ b/health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
@@ -16,6 +16,56 @@ const inboxModuleNameMap = {
"muster-roll-approval": "muster-roll-service",
};
+function filterUniqueByKey(arr, key) {
+ const uniqueValues = new Set();
+ const result = [];
+
+ arr.forEach((obj) => {
+ const value = obj[key];
+ if (!uniqueValues.has(value)) {
+ uniqueValues.add(value);
+ result.push(obj);
+ }
+ });
+
+ return result;
+}
+
+const epochTimeForTomorrow12 = () => {
+ const now = new Date();
+
+ // Create a new Date object for tomorrow at 12:00 PM
+ const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0);
+
+ // Format the date as "YYYY-MM-DD"
+ const year = tomorrowNoon.getFullYear();
+ const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed
+ const day = String(tomorrowNoon.getDate()).padStart(2, "0");
+
+ return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`);
+};
+
+function cleanObject(obj) {
+ for (const key in obj) {
+ if (Object.hasOwn(obj, key)) {
+ if (Array.isArray(obj[key])) {
+ if (obj[key].length === 0) {
+ delete obj[key];
+ }
+ } else if (
+ obj[key] === undefined ||
+ obj[key] === null ||
+ obj[key] === false ||
+ obj[key] === "" || // Check for empty string
+ (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0)
+ ) {
+ delete obj[key];
+ }
+ }
+ }
+ return obj;
+}
+
export const UICustomizations = {
businessServiceMap,
updatePayload: (applicationDetails, data, action, businessService) => {
@@ -435,70 +485,61 @@ export const UICustomizations = {
const searchParams = new URLSearchParams(location.search);
const paths = {
- "SearchProjectConfig": {
- basePath: "Projects",
+ SearchProjectConfig: {
+ basePath: "Projects",
pathConfig: {
// id: "id[0]",
tenantId: "tenantId",
},
dateConfig: {
endDate: "dayend",
- startDate: "daystart"
- },
- selectConfig: {
+ startDate: "daystart",
},
- textConfig :["id", "tenantId", "name", "projectNumber", "projectSubType" , "projectType"]
+ selectConfig: {},
+ textConfig: ["id", "tenantId", "name", "projectNumber", "projectSubType", "projectType"],
},
- "SearchProductConfig": {
- basePath: "Product",
+ SearchProductConfig: {
+ basePath: "Product",
pathConfig: {
id: "id[0]",
},
- dateConfig: {
- },
- selectConfig: {
- },
- textConfig :["id", "manufacturer", "name", "type"]
+ dateConfig: {},
+ selectConfig: {},
+ textConfig: ["id", "manufacturer", "name", "type"],
},
- "SearchHouseholdConfig": {
- basePath: "Household",
+ SearchHouseholdConfig: {
+ basePath: "Household",
pathConfig: {
id: "id[0]",
clientReferenceId: "clientReferenceId[0]",
},
- dateConfig: {
- },
- selectConfig: {
- },
- textConfig :["boundaryCode", "clientReferenceId", "id"]
+ dateConfig: {},
+ selectConfig: {},
+ textConfig: ["boundaryCode", "clientReferenceId", "id"],
},
- "SearchProductVariantConfig": {
- basePath: "ProductVariant",
+ SearchProductVariantConfig: {
+ basePath: "ProductVariant",
pathConfig: {
id: "id[0]",
},
- dateConfig: {
- },
- selectConfig: {
- },
- textConfig :["productId", "sku", "variation"]
+ dateConfig: {},
+ selectConfig: {},
+ textConfig: ["productId", "sku", "variation"],
},
- "SearchProjectBeneficiaryConfig": {
- basePath: "ProjectBeneficiary",
+ SearchProjectBeneficiaryConfig: {
+ basePath: "ProjectBeneficiary",
pathConfig: {
id: "id[0]",
clientReferenceId: "clientReferenceId[0]",
-
},
dateConfig: {
- dateOfRegistration: "daystart"
- },
- selectConfig: {
+ dateOfRegistration: "daystart",
},
- textConfig :["beneficiaryId", "projectId"]
+ selectConfig: {},
+ textConfig: ["beneficiaryId", "projectId"],
},
- "SearchProjectStaffConfig": {
- basePath: "ProjectStaff",
+ SearchProjectStaffConfig: {
+ basePath: "ProjectStaff",
pathConfig: {
id: "id[0]",
},
@@ -506,23 +547,20 @@ export const UICustomizations = {
startDate: "daystart",
endDate: "dayend",
},
- selectConfig: {
- },
- textConfig :["projectId", "userId"]
+ selectConfig: {},
+ textConfig: ["projectId", "userId"],
},
- "SearchProjectResourceConfig": {
- basePath: "ProjectResource",
+ SearchProjectResourceConfig: {
+ basePath: "ProjectResource",
pathConfig: {
- id: "id[0]"
- },
- dateConfig: {
- },
- selectConfig: {
+ id: "id[0]",
},
- textConfig : []
+ dateConfig: {},
+ selectConfig: {},
+ textConfig: [],
},
- "SearchProjectTaskConfig": {
- basePath: "Task",
+ SearchProjectTaskConfig: {
+ basePath: "Task",
pathConfig: {
id: "id[0]",
clientReferenceId: "clientReferenceId[0]",
@@ -533,49 +571,44 @@ export const UICustomizations = {
actualEndDate: "dayend",
actualStartDate: "daystart",
},
- selectConfig: {
- },
- textConfig :["projectId","localityCode", "projectBeneficiaryId", "status"]
+ selectConfig: {},
+ textConfig: ["projectId", "localityCode", "projectBeneficiaryId", "status"],
},
- "SearchFacilityConfig": {
- basePath: "Facility",
+ SearchFacilityConfig: {
+ basePath: "Facility",
pathConfig: {
- id: "id[0]"
- },
- dateConfig: {
- },
- selectConfig: {
+ id: "id[0]",
},
- textConfig :["faciltyUsage","localityCode", "storageCapacity","id"]
+ dateConfig: {},
+ selectConfig: {},
+ textConfig: ["faciltyUsage", "localityCode", "storageCapacity", "id"],
},
- "SearchProjectFacilityConfig": {
- basePath: "ProjectFacility",
+ SearchProjectFacilityConfig: {
+ basePath: "ProjectFacility",
pathConfig: {
id: "id[0]",
projectId: "projectId[0]",
- facilityId: "facilityId[0]"
- },
- dateConfig: {
- },
- selectConfig: {
+ facilityId: "facilityId[0]",
},
- textConfig :[]
+ dateConfig: {},
+ selectConfig: {},
+ textConfig: [],
},
- }
-
- const id = searchParams.get("config")|| masterName;
-
- if(!paths||!paths?.[id]){
+ };
+
+ const id = searchParams.get("config") || masterName;
+
+ if (!paths || !paths?.[id]) {
return data;
}
let requestBody = { ...data.body[paths[id]?.basePath] };
const pathConfig = paths[id]?.pathConfig;
const dateConfig = paths[id]?.dateConfig;
const selectConfig = paths[id]?.selectConfig;
- const textConfig = paths[id]?.textConfig
+ const textConfig = paths[id]?.textConfig;
- if(paths[id].basePath == "Projects"){
- data.state.searchForm={...data.state.searchForm,tenantId:"mz"}
+ if (paths[id].basePath == "Projects") {
+ data.state.searchForm = { ...data.state.searchForm, tenantId: "mz" };
}
let Product = Object.keys(requestBody)
.map((key) => {
@@ -599,12 +632,10 @@ export const UICustomizations = {
}
return acc;
}, {});
-
- if(paths[id].basePath == "Projects"){
-
- data.body[paths[id].basePath] = [{ ...Product}];
- }
- else data.body[paths[id].basePath] = { ...Product};
+
+ if (paths[id].basePath == "Projects") {
+ data.body[paths[id].basePath] = [{ ...Product }];
+ } else data.body[paths[id].basePath] = { ...Product };
return data;
},
additionalCustomizations: (row, key, column, value, t, searchResult) => {
@@ -613,13 +644,9 @@ export const UICustomizations = {
//first we can identify which column it belongs to then we can return relevant result
switch (key) {
case "ID":
-
return (
-
-
+
);
@@ -659,5 +686,104 @@ export const UICustomizations = {
return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true;
}
},
- }
+ },
+ SearchCampaign: {
+ preProcess: (data, additionalDetails) => {
+ const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {};
+ data.body.CampaignDetails = {};
+ data.body.CampaignDetails.pagination = data?.state?.tableForm;
+ data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId();
+ // data.body.CampaignDetails.boundaryCode = boundaryCode;
+ data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid;
+ data.body.CampaignDetails.campaignName = campaignName;
+ data.body.CampaignDetails.status = ["drafted"];
+ if (startDate) {
+ data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate);
+ } else {
+ data.body.CampaignDetails.startDate = epochTimeForTomorrow12();
+ }
+ if (endDate) {
+ data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate);
+ }
+ data.body.CampaignDetails.projectType = projectType?.[0]?.code;
+
+ cleanObject(data.body.CampaignDetails);
+
+ return data;
+ },
+ populateProjectType: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ return {
+ url: "/egov-mdms-service/v1/_search",
+ params: { tenantId },
+ body: {
+ MdmsCriteria: {
+ tenantId,
+ moduleDetails: [
+ {
+ moduleName: "HCM-PROJECT-TYPES",
+ masterDetails: [
+ {
+ name: "projectTypes",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ changeQueryName: "projectType",
+ config: {
+ enabled: true,
+ select: (data) => {
+ const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => {
+ return {
+ ...row,
+ i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`),
+ };
+ });
+ return dropdownData;
+ },
+ },
+ };
+ },
+ customValidationCheck: (data) => {
+ //checking if both to and from date are present then they should be startDate<=endDate
+ const { startDate, endDate } = data;
+ const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate);
+ const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate);
+
+ if (startDate && endDate && startDateEpoch > endDateEpoch) {
+ return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" };
+ }
+ return false;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ if (key === "CAMPAIGN_DATE") {
+ return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`;
+ }
+ },
+ },
+ SearchMicroplan: {
+ preProcess: (data, additionalDetails) => {
+ const { name, status } = data?.state?.searchForm || {};
+
+ data.body.PlanConfigurationSearchCriteria = {};
+ data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit;
+ // data.body.PlanConfigurationSearchCriteria.limit = 10
+ data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset;
+ data.body.PlanConfigurationSearchCriteria.name = name;
+ data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid;
+ // delete data.body.PlanConfigurationSearchCriteria.pagination
+ data.body.PlanConfigurationSearchCriteria.status = status?.status;
+ cleanObject(data.body.PlanConfigurationSearchCriteria);
+ return data;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ if (key === "CAMPAIGN_DATE") {
+ return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`;
+ }
+ },
+ },
};
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/index.js b/health/micro-ui/web/micro-ui-internals/example/src/index.js
index 2f01957d5b8..c186da539bd 100644
--- a/health/micro-ui/web/micro-ui-internals/example/src/index.js
+++ b/health/micro-ui/web/micro-ui-internals/example/src/index.js
@@ -6,12 +6,12 @@ import { initLibraries } from "@egovernments/digit-ui-libraries";
import { DigitUI } from "@egovernments/digit-ui-module-core";
import "@egovernments/digit-ui-css/example/index.css";
-import { pgrCustomizations } from "./pgr";
import { UICustomizations } from "./UICustomizations";
import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager"
import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench";
import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities";
import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench";
+import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning";
var Digit = window.Digit || {};
@@ -57,7 +57,6 @@ const initTokens = (stateCode) => {
const initDigitUI = () => {
window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH") || "digit-ui";
window.Digit.Customizations = {
- PGR: pgrCustomizations,
commonUiConfig: UICustomizations
};
window?.Digit.ComponentRegistryService.setupRegistry({
@@ -69,6 +68,7 @@ const initDigitUI = () => {
initWorkbenchComponents();
initWorkbenchHCMComponents();
initCampaignComponents();
+ initMicroplanningComponents();
const moduleReducers = (initData) => initData;
diff --git a/health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js b/health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
index fbc52c4a879..9fbb1258ba9 100644
--- a/health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
+++ b/health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
@@ -94,6 +94,7 @@ module.exports = function (app) {
"/project-factory",
"/boundary-service",
"/product",
+ "/plan-service",
].forEach((location) => app.use(location, createProxy));
["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy));
["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy));
diff --git a/health/micro-ui/web/micro-ui-internals/package.json b/health/micro-ui/web/micro-ui-internals/package.json
index 92f1e334d77..d15c627d3ab 100644
--- a/health/micro-ui/web/micro-ui-internals/package.json
+++ b/health/micro-ui/web/micro-ui-internals/package.json
@@ -22,8 +22,10 @@
"publish:css": "cd packages/css && yarn && npm publish --tag workbench-1.0",
"dev:example": "cd example && yarn start",
"dev:campaign": "cd packages/modules/campaign-manager && yarn start",
+ "dev:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn start",
"build": "run-p build:**",
"build:campaign": "cd packages/modules/campaign-manager && yarn build",
+ "build:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn build",
"deploy:jenkins": "./scripts/jenkins.sh",
"clean": "rm -rf node_modules"
},
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json
new file mode 100644
index 00000000000..6fcb736c4e5
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json
@@ -0,0 +1,62 @@
+{
+ "name": "@egovernments/digit-ui-module-hcmmicroplanning",
+ "version": "0.0.1",
+ "description": "HCM-Microplanning",
+ "main": "dist/index.js",
+ "module": "dist/index.modern.js",
+ "source": "src/Module.js",
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "start": "microbundle-crl watch --no-compress --format modern,cjs",
+ "build": "microbundle-crl --compress --no-sourcemap --format cjs",
+ "prepublish": "yarn build"
+ },
+ "peerDependencies": {
+ "react": "17.0.2",
+ "react-router-dom": "5.3.0"
+ },
+ "dependencies": {
+ "@cyntler/react-doc-viewer": "1.10.3",
+ "@egovernments/digit-ui-components": "0.0.2-beta.2",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.4",
+ "@egovernments/digit-ui-svg-components": "1.0.8",
+ "@rjsf/core": "5.10.0",
+ "@rjsf/utils": "5.10.0",
+ "@rjsf/validator-ajv8": "5.10.0",
+ "@turf/turf": "^6.5.0",
+ "ajv": "^8.12.0",
+ "axios": "^1.6.8",
+ "chroma-js": "^2.4.2",
+ "exceljs": "^4.4.0",
+ "focus-trap-react": "^10.2.3",
+ "geojson-validation": "^1.0.2",
+ "jszip": "^3.10.1",
+ "leaflet": "^1.9.4",
+ "react": "17.0.2",
+ "react-date-range": "^1.4.0",
+ "react-dom": "17.0.2",
+ "react-drag-drop-files": "^2.3.10",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-joyride": "2.5.5",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0",
+ "react-select": "5.7.4",
+ "safe-buffer": "^5.2.1",
+ "shpjs": "^4.0.4",
+ "uuid": "^9.0.1",
+ "xlsx": "0.17.5"
+ },
+ "license": "MIT",
+ "keywords": [
+ "digit",
+ "egov",
+ "dpg",
+ "digit-ui",
+ "workbench",
+ "workbench-hcm",
+ "hcm-microplanning"
+ ]
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js
new file mode 100644
index 00000000000..b27e7b19922
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js
@@ -0,0 +1,99 @@
+import { Loader, TourProvider } from "@egovernments/digit-ui-react-components";
+import React from "react";
+import { useRouteMatch } from "react-router-dom";
+import EmployeeApp from "./pages/employee";
+import { CustomisedHooks } from "./hooks";
+import { UICustomizations } from "./configs/UICustomizations";
+// import WorkbenchCard from "./components/WorkbenchCard";
+import MicroplanningCard from "./components/MicroplanningCard";
+import MicroplanDetails from "./components/MicroplanDetails";
+import { ProviderContext } from "./utils/context";
+
+const MicroplanningModule = ({ stateCode, userType, tenants }) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], {
+ select: (data) => {
+ return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy;
+ },
+ });
+ const moduleCode = ["Microplanning", `boundary-${BOUNDARY_HIERARCHY_TYPE}`, "hcm-admin-schemas"];
+ const { path, url } = useRouteMatch();
+ const language = Digit.StoreData.getCurrentLanguage();
+ const { isLoading, data: store } = Digit.Services.useStore({
+ stateCode,
+ moduleCode,
+ language,
+ });
+
+ if (isLoading) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+ );
+};
+
+const componentsToRegister = {
+ MicroplanningModule,
+ MicroplanningCard,
+ MicroplanDetails,
+ // DigitJSONForm,
+ // DSSCard: null, // TO HIDE THE DSS CARD IN HOME SCREEN as per workbench
+ // HRMSCard // Overridden the HRMS card as per workbench
+};
+
+const overrideHooks = () => {
+ Object.keys(CustomisedHooks).map((ele) => {
+ if (ele === "Hooks") {
+ Object.keys(CustomisedHooks[ele]).map((hook) => {
+ Object.keys(CustomisedHooks[ele][hook]).map((method) => {
+ setupHooks(hook, method, CustomisedHooks[ele][hook][method]);
+ });
+ });
+ } else if (ele === "Utils") {
+ Object.keys(CustomisedHooks[ele]).map((hook) => {
+ Object.keys(CustomisedHooks[ele][hook]).map((method) => {
+ setupHooks(hook, method, CustomisedHooks[ele][hook][method], false);
+ });
+ });
+ } else {
+ Object.keys(CustomisedHooks[ele]).map((method) => {
+ setupLibraries(ele, method, CustomisedHooks[ele][method]);
+ });
+ }
+ });
+};
+
+/* To Overide any existing hook we need to use similar method */
+const setupHooks = (HookName, HookFunction, method, isHook = true) => {
+ window.Digit = window.Digit || {};
+ window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {};
+ window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {};
+ window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method;
+};
+/* To Overide any existing libraries we need to use similar method */
+const setupLibraries = (Library, service, method) => {
+ window.Digit = window.Digit || {};
+ window.Digit[Library] = window.Digit[Library] || {};
+ window.Digit[Library][service] = method;
+};
+
+/* To Overide any existing config/middlewares we need to use similar method */
+const updateCustomConfigs = () => {
+ setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations });
+};
+
+const initMicroplanningComponents = () => {
+ overrideHooks();
+ updateCustomConfigs();
+ Object.entries(componentsToRegister).forEach(([key, value]) => {
+ Digit.ComponentRegistryService.setComponent(key, value);
+ });
+};
+
+export { initMicroplanningComponents };
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js
new file mode 100644
index 00000000000..a358dbbedb1
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js
@@ -0,0 +1,61 @@
+import { AutoRenew, Close, FileDownload } from "@egovernments/digit-ui-svg-components";
+import React, { useCallback } from "react";
+import PropTypes from "prop-types";
+
+export const ButtonType1 = (props) => {
+ return (
+
+ );
+};
+
+ButtonType1.propTypes = {
+ text: PropTypes.string.isRequired,
+};
+
+export const ButtonType2 = (props) => {
+ return (
+
+ {props.showDownloadIcon && (
+
+
+
+ )}
+
{props.text}
+
+ );
+};
+
+ButtonType2.propTypes = {
+ text: PropTypes.string.isRequired,
+ showDownloadIcon: PropTypes.bool,
+};
+
+export const ModalHeading = (props) => {
+ return (
+
+ {props.label}
+
+ );
+};
+
+ModalHeading.propTypes = {
+ label: PropTypes.string.isRequired,
+ className: PropTypes.string,
+ style: PropTypes.object,
+};
+
+export const CloseButton = ({ clickHandler, style = {} }) => {
+ return (
+
+ {" "}
+
+
+ );
+};
+
+CloseButton.propTypes = {
+ clickHandler: PropTypes.func.isRequired,
+ style: PropTypes.object,
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js
new file mode 100644
index 00000000000..f2deacbd46d
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js
@@ -0,0 +1,41 @@
+import React, { useEffect, useState } from "react";
+
+const CustomScaleControl = ({ map }) => {
+ if (!map) return null;
+ const [scaleText, setScaleText] = useState("");
+ // Function to calculate and update the scale text
+ const updateScale = () => {
+ // Calculate the scale based on the map's current zoom level
+ const maxWidthMeters = map.containerPointToLatLng([0, map.getSize().y]).distanceTo(map.containerPointToLatLng([100, map.getSize().y]));
+ const scale = maxWidthMeters / 1000; // Convert to kilometers
+
+ // Format the scale text
+ const scaleTextData = scale < 1 ? `${Math.round(scale * 1000)} m` : `${Math.round(Math.round(scale.toFixed(0) / 10) * 10)} km`;
+
+ // Update the scale text in the container element
+ setScaleText(scaleTextData);
+ };
+
+ // Effect to update the scale text when the map component mounts and on map zoom change
+ useEffect(() => {
+ // Update the scale text initially
+ updateScale();
+
+ // Register the map's zoom events to update the scale text
+ map.on("zoomend", updateScale);
+
+ // Clean up event listener when the component unmounts
+ return () => {
+ map.off("zoomend", updateScale);
+ };
+ }, [map]);
+
+ return (
+
+ );
+};
+
+export default CustomScaleControl;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js
new file mode 100644
index 00000000000..ab6bba8a7a3
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js
@@ -0,0 +1,631 @@
+import React, { useState, useEffect, useCallback, Fragment, useRef } from "react";
+import { useTranslation } from "react-i18next";
+import { Trash } from "@egovernments/digit-ui-svg-components";
+import { CloseButton, ModalHeading } from "./CommonComponents";
+import { Dropdown, TextInput, Toast } from "@egovernments/digit-ui-components";
+import { useMyContext } from "../utils/context";
+import { tourSteps } from "../configs/tourSteps";
+import { v4 as uuidv4 } from "uuid";
+import { PlusWithSurroundingCircle } from "../icons/Svg";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+import { Button, Modal } from "@egovernments/digit-ui-react-components";
+const page = "hypothesis";
+
+const Hypothesis = ({
+ campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType,
+ microplanData,
+ setMicroplanData,
+ checkDataCompletion,
+ setCheckDataCompletion,
+ currentPage,
+ pages,
+ setToast,
+}) => {
+ const { t } = useTranslation();
+
+ // States
+ const [editable, setEditable] = useState(true);
+ const [modal, setModalState] = useState("none");
+ const [assumptions, setAssumptions] = useState([]);
+ const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]);
+ const [itemForDeletion, setItemForDeletion] = useState();
+ const [exampleOption, setExampleOption] = useState("");
+ // const [toast, setToast] = useState();
+ const [autofillHypothesis, setAutofillHypothesis] = useState([]);
+ const { state, dispatch } = useMyContext();
+ const [orignalHypothesisCount, setOrignalHypothesisCount] = useState(0);
+ const [initialHypothesisData, setInitialHypothesisData] = useState([]);
+ // Set TourSteps
+ useEffect(() => {
+ const tourData = tourSteps(t)?.[page] || {};
+ if (state?.tourStateData?.name === page) return;
+ dispatch({
+ type: "SETINITDATA",
+ state: { tourStateData: tourData },
+ });
+ }, []);
+
+ useEffect(() => {
+ if (microplanData?.hypothesis) setInitialHypothesisData(microplanData?.hypothesis);
+ }, []);
+
+ const setModal = (modalString) => {
+ const elements = document.querySelectorAll(".popup-wrap-rest-unfocus");
+ elements.forEach((element) => {
+ element.classList.toggle("popup-wrap-rest-unfocus-active");
+ });
+ setModalState(modalString);
+ };
+
+ // UseEffect to extract data on first render
+ useEffect(() => {
+ if (pages) {
+ const previouspage = pages[currentPage?.id - 1];
+ if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false);
+ else setEditable(true);
+ }
+ if (microplanData?.hypothesis) {
+ const temp = microplanData?.hypothesis;
+ setAssumptions(temp);
+ }
+
+ fetchDataAndUpdateState();
+ }, []);
+
+ const fetchDataAndUpdateState = useCallback(() => {
+ const hypothesisAssumptions = state?.HypothesisAssumptions || [];
+ const temp = hypothesisAssumptions.find((item) => item.campaignType === campaignType);
+ if (!temp?.assumptions) return;
+
+ const hypothesisAssumptionsList = Array.isArray(temp.assumptions) ? temp.assumptions : [];
+ setOrignalHypothesisCount(hypothesisAssumptionsList.length);
+ setExampleOption(hypothesisAssumptionsList.length !== 0 ? hypothesisAssumptionsList[0] : "");
+
+ const currentHypothesis = microplanData?.hypothesis || assumptions;
+ const newAssumptions = setAutofillHypothesisData(hypothesisAssumptionsList, currentHypothesis, setAssumptions);
+
+ const newHypothesislist = filterHypothesisList(
+ newAssumptions.length !== 0 ? newAssumptions : microplanData.hypothesis,
+ hypothesisAssumptionsList
+ );
+ setHypothesisAssumptionsList(newHypothesislist);
+ }, [campaignType, microplanData, state, assumptions, setAssumptions]);
+
+ // UseEffect for checking completeness of data before moveing to next section
+ useEffect(() => {
+ if (!assumptions || checkDataCompletion !== "true" || !setCheckDataCompletion) return;
+ // uncomment to activate data change save check
+ // if (!microplanData?.hypothesis || !_.isEqual(assumptions, microplanData.hypothesis)) setModal("data-change-check");
+ // else
+ updateData(true);
+ }, [checkDataCompletion]);
+
+ // UseEffect to store current data
+ useEffect(() => {
+ if (!assumptions || !setMicroplanData) return;
+ setMicroplanData((previous) => ({ ...previous, hypothesis: assumptions }));
+ }, [assumptions]);
+
+ // UseEffect to add a event listener for keyboard
+ useEffect(() => {
+ window.addEventListener("keydown", handleKeyPress);
+
+ return () => window.removeEventListener("keydown", handleKeyPress);
+ }, [modal]);
+
+ const handleKeyPress = (event) => {
+ // if (modal !== "upload-guidelines") return;
+ if (["x", "Escape"].includes(event.key)) {
+ // Perform the desired action when "x" or "esc" is pressed
+ // if (modal === "upload-guidelines")
+ setCheckDataCompletion("false");
+ setModal("none");
+ }
+ };
+
+ // check if data has changed or not
+ const updateData = useCallback(
+ (check) => {
+ if (!assumptions || !setMicroplanData) return;
+ if (check) {
+ if (assumptions.some((item) => item.active && parseFloat(item.value) === 0)) {
+ setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") });
+ setCheckDataCompletion("false");
+ return;
+ }
+ let newAssumptions = assumptions.map((item) => {
+ if (parseFloat(item.value) === 0) {
+ return { ...item, value: 0.01 };
+ }
+ return item;
+ });
+ if (!deepEqual(newAssumptions, initialHypothesisData)) {
+ setMicroplanData((previous) => ({
+ ...previous,
+ hypothesis: newAssumptions,
+ status: { ...previous?.status, FORMULA_CONFIGURATION: false },
+ }));
+ } else {
+ setMicroplanData((previous) => ({ ...previous, hypothesis: newAssumptions }));
+ }
+ setAssumptions(newAssumptions);
+ let checkValid = validateAssumptions(assumptions);
+ checkValid = checkValid && assumptions.filter((subItem) => subItem?.active).length !== 0;
+
+ if (checkValid) setCheckDataCompletion("valid");
+ else setCheckDataCompletion("invalid");
+ } else {
+ let checkValid = microplanData?.hypothesis?.every((item) => Object.values(item).every((data) => data !== ""));
+ checkValid = checkValid && assumptions.length !== 0;
+ if (checkValid) setCheckDataCompletion("valid");
+ else setCheckDataCompletion("invalid");
+ }
+ },
+ [assumptions, setMicroplanData, microplanData, setCheckDataCompletion, initialHypothesisData]
+ );
+
+ const validateAssumptions = useCallback((assumptions) => {
+ return assumptions.filter((item) => item?.active).every((item) => Object.values(item).every((data) => data !== "")) && assumptions.length !== 0;
+ }, []);
+
+ const cancelUpdateData = useCallback(() => {
+ setCheckDataCompletion("false");
+ setModal("none");
+ }, [setCheckDataCompletion, setModal]);
+
+ const closeModal = useCallback(() => {
+ setModal("none");
+ }, []);
+
+ // Function to Delete an assumption
+ const deleteAssumptionHandlerCallback = useCallback(() => {
+ deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t);
+ closeModal();
+ }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, closeModal, setToast, t]);
+
+ const sectionClass = `jk-header-btn-wrapper hypothesis-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus `;
+
+ return (
+ <>
+
+
+ {/* NonInterractable Section */}
+
+ {/* Interractable Section that includes the example as well as the assumptions */}
+
+
+
}
+ className="add-button"
+ onButtonClick={() => addAssumptionsHandler(setAssumptions)}
+ label={t("ADD_ROW")}
+ isDisabled={assumptions?.filter((item) => item.active)?.length === orignalHypothesisCount}
+ />
+
+
+ {modal === "delete-conformation" && (
+
}
+ actionCancelLabel={t("YES")}
+ actionCancelOnSubmit={deleteAssumptionHandlerCallback}
+ actionSaveLabel={t("NO")}
+ actionSaveOnSubmit={closeModal}
+ >
+
+
{t("HYPOTHESIS_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}
+
+
+ )}
+
+ >
+ );
+};
+
+// Function to add a new assumption
+const addAssumptionsHandler = (setAssumptions) => {
+ const uuid = uuidv4();
+ setAssumptions((previous) => [
+ ...previous,
+ {
+ id: uuid,
+ // previous.length ? previous[previous.length - 1].id + 1 : 0,
+ key: "",
+ value: "",
+ active: true,
+ },
+ ]);
+};
+
+// Defination for NonInterractable Section
+const NonInterractableSection = React.memo(({ t }) => {
+ return (
+
+
{t("HEADING_HYPOTHESIS")}
+
{t("INSTRUCTION_HYPOTHESIS")}
+
+ );
+});
+
+// Defination for NonInterractable Section
+const InterractableSection = React.memo(
+ ({ assumptions, setAssumptions, hypothesisAssumptionsList, setHypothesisAssumptionsList, setModal, setItemForDeletion, exampleOption, t }) => {
+ const itemRefs = useRef([]);
+ const [expandedIndex, setExpandedIndex] = useState(null);
+ const scrollContainerRef = useRef(null);
+ const [renderCycle, setRenderCycle] = useState(0);
+
+ useEffect(() => {
+ if (expandedIndex !== null) {
+ setRenderCycle(0); // Reset render cycle count when expandedIndex changes
+ }
+ }, [expandedIndex]);
+
+ useEffect(() => {
+ // Scroll to the expanded item after the state has updated and the DOM has re-rendered
+ if (renderCycle < 2) {
+ setRenderCycle((prev) => prev + 1); // Increment render cycle count
+ } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) {
+ try {
+ const parentElement = itemRefs.current[expandedIndex];
+ const childElement = itemRefs.current[expandedIndex].children[1];
+
+ if (parentElement) {
+ const scrollContainer = scrollContainerRef.current;
+ const parentRect = parentElement.getBoundingClientRect();
+ const containerRect = scrollContainer.getBoundingClientRect();
+
+ // Calculate the offset from the top of the container
+ const offset = parentRect.top - containerRect.top;
+
+ // Scroll the container
+ scrollContainer.scrollTo({
+ top: scrollContainer.scrollTop + offset - 10,
+ behavior: "smooth",
+ });
+ }
+
+ if (childElement) {
+ childElement.focus();
+ }
+ } catch (error) {
+ console.error("Error scrolling to element:", error);
+ }
+ }
+ }, [renderCycle, expandedIndex]);
+
+ useEffect(() => {
+ if (expandedIndex !== null) {
+ const observer = new MutationObserver(() => {
+ setRenderCycle((prev) => prev + 1); // Trigger render cycle when the DOM changes
+ });
+
+ if (itemRefs.current[expandedIndex]) {
+ observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true });
+ }
+
+ return () => observer.disconnect();
+ }
+ }, [expandedIndex]);
+
+ const toggleExpand = (index) => {
+ setExpandedIndex(index === expandedIndex ? null : index);
+ };
+
+ // Handler for deleting an assumption on conformation
+ const deleteHandler = useCallback(
+ (item) => {
+ setModal("delete-conformation");
+ setItemForDeletion(item);
+ },
+ [setModal, setItemForDeletion]
+ );
+
+ return (
+
+
+
+
+
+
+
+
deleteHandler(item)}>
+ {Trash && }
+ {t("DELETE")}
+
+
+
+ {assumptions
+ ?.filter((item) => item.active)
+ ?.map((item, index) => (
+
item.active)?.length - 1 ? "last-container" : ""
+ } `}
+ >
+
{
+ itemRefs.current[index] = el;
+ }}
+ onClick={() => {
+ toggleExpand(index);
+ }}
+ >
+
+
+
+
+
+
+
deleteHandler(item)}
+ onKeyDown={(e) => e.key === "Enter" && deleteHandler(item)}
+ aria-label={t("DELETE")}
+ role="button"
+ >
+ {Trash && }
+ {t("DELETE")}
+
+
+
+ ))}
+
+
+ );
+ }
+);
+
+const Example = ({ exampleOption, t }) => {
+ return (
+
+
{t("EXAMPLE")}
+
+
+
{t("KEY")}
+
+
{t("HYPOTHESIS_KEY_HELP_TEXT")}
+
+
+
{t("VALUE")}
+
+
{t("HYPOTHESIS_VALUE_HELP_TEXT")}
+
+
+
+ );
+};
+
+const deleteAssumptionHandler = (item, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t) => {
+ let add = true;
+ setAssumptions((previous) => {
+ if (!previous.length) return [];
+ if (previous.filter((item) => item.active)?.length <= 1) {
+ setToast({ state: "error", message: t("ERROR_CANNOT_DELETE_LAST_HYPOTHESIS") });
+ add = false;
+ return previous;
+ }
+ // const filteredData = previous.filter((data) => data.id !== item.id);
+ const deletionElementIndex = previous.findIndex((data) => data.id === item.id);
+ const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data));
+ return filteredData || [];
+ });
+ if (add && item && item.key)
+ setHypothesisAssumptionsList((previous) => {
+ if (!previous.includes(item.key)) return [...previous, item.key];
+ return previous; // Return previous array if key already exists
+ });
+ setItemForDeletion();
+};
+
+const Select = React.memo(({ item, assumptions, setAssumptions, disabled = false, options, setOptions, t }) => {
+ const [selected, setSelected] = useState();
+ const [filteredOptions, setFilteredOptions] = useState([]);
+
+ useEffect(() => {
+ if (item?.key) setSelected({ code: item.key });
+ }, [item]);
+
+ useEffect(() => {
+ if (!options) return;
+ const filteredOptions = options.length ? options : [];
+ if (item?.key && !filteredOptions.includes(item.key)) {
+ setFilteredOptions([item.key, ...filteredOptions]);
+ } else setFilteredOptions(filteredOptions);
+ }, [options]);
+
+ const selectChangeHandler = useCallback(
+ (e) => {
+ const existingEntry = assumptions.find((item) => item?.active && item?.key === e?.code);
+ if (existingEntry) return;
+ const newDataSegment = {
+ ...item,
+ id: item.id,
+ key: e?.code,
+ value: item.value,
+ };
+ setAssumptions((previous) => {
+ const filteredAssumptionsList = previous.map((data) => {
+ if (data.id === item.id) return newDataSegment;
+ return data;
+ });
+ return filteredAssumptionsList;
+ });
+
+ setOptions((previous) => {
+ let newOptions = previous.filter((item) => item !== e?.code);
+ if (selected && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code);
+ return newOptions;
+ });
+ },
+ [assumptions, item, selected, setAssumptions, setOptions]
+ );
+
+ return (
+ ({ code: item }))}
+ selected={selected}
+ optionKey="code"
+ select={selectChangeHandler}
+ // style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)", position:"sticky" }}
+ optionCardStyles={{ position: "absolute" }}
+ placeholder={t("SELECT_OPTION")}
+ showToolTip={true}
+ />
+ );
+});
+
+const Input = React.memo(({ item, setAssumptions, t, disabled = false }) => {
+ const [inputValue, setInputValue] = useState("");
+
+ useEffect(() => {
+ if (item) setInputValue(item.value);
+ }, [item]);
+
+ const inputChangeHandler = useCallback(
+ (e) => {
+ if (e.target.value.includes("+") || e.target.value.includes("e")) return;
+ if ((e.target.value < 0 || e.target.value > 10000000000) && e.target.value !== "") return;
+ let value;
+ const decimalIndex = e.target.value.indexOf(".");
+ if (decimalIndex !== -1) {
+ const numDecimals = e.target.value.length - decimalIndex - 1;
+ value = e.target.value;
+ if (numDecimals <= 2) {
+ value = e.target.value;
+ } else if (numDecimals > 2) {
+ value = value.substring(0, decimalIndex + 3);
+ }
+ } else value = Number.parseFloat(e.target.value);
+
+ setInputValue(!Number.isNaN(value) ? value : "");
+ const newDataSegment = {
+ ...item,
+ id: item.id,
+ key: item.key,
+ value: !Number.isNaN(value) ? value : "",
+ };
+ setAssumptions((previous) => {
+ const filteredAssumptionsList = previous.map((data) => {
+ if (data.id === item.id) {
+ return newDataSegment;
+ }
+ return data;
+ });
+ return filteredAssumptionsList;
+ });
+ },
+ [item, setAssumptions]
+ );
+
+ return (
+
+ );
+});
+
+const setAutofillHypothesisData = (autofillHypothesis, assumptions, setAssumptions) => {
+ if (assumptions?.length !== 0) return [];
+ let newAssumptions = [];
+ for (let i in autofillHypothesis) {
+ const uuid = uuidv4();
+ newAssumptions.push({
+ id: uuid,
+ key: autofillHypothesis[Number(i)],
+ value: "",
+ active: true,
+ });
+ }
+ setAssumptions(newAssumptions);
+ return newAssumptions;
+};
+
+const filterHypothesisList = (assumptions, hypothesisList) => {
+ let alreadySelectedHypothesis = assumptions.filter((item) => item?.active).map((item) => item?.key) || [];
+ return hypothesisList.filter((item) => !alreadySelectedHypothesis.includes(item));
+};
+
+const deepEqual = (obj1, obj2) => {
+ if (obj1 === obj2) return true;
+ if (obj1 == null || obj2 == null || typeof obj1 !== "object" || typeof obj2 !== "object") return false;
+
+ const keys1 = Object.keys(obj1),
+ keys2 = Object.keys(obj2);
+ if (keys1.length !== keys2.length) return false;
+
+ return keys1.every((key) => keys2.includes(key) && deepEqual(obj1[key], obj2[key]));
+};
+
+export default Hypothesis;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js
new file mode 100644
index 00000000000..742afcaa2b4
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js
@@ -0,0 +1,113 @@
+import { Button, DownloadIcon, SVG } from "@egovernments/digit-ui-react-components";
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+
+export const JsonPreviewInExcelForm = (props) => {
+ const { t } = useTranslation();
+ const sheetsData = props?.sheetsData;
+ const [currentSheetName, setCurrentSheetName] = useState(Object.keys(sheetsData).length > 0 ? Object.keys(sheetsData)[0] : undefined);
+ return (
+
+
+ }
+ type="button"
+ onButtonClick={() => props?.onBack()}
+ />
+ }
+ type="button"
+ onButtonClick={() => props?.onDownload()}
+ />
+
+
+ {props?.errorLocationObject?.[currentSheetName] &&
{t("USER_DIRECTIONS_FOR_ERROR_MESSAGE")}
}
+ {/* {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( */}
+
+
+
+
+ {sheetsData?.[currentSheetName]?.[0]
+ ?.filter((header) => header)
+ .map((header) => (
+ {t(header)} |
+ ))}
+
+
+
+ {sheetsData?.[currentSheetName]?.slice(1).map((rowData, rowIndex) => (
+
+ {Object.values(sheetsData?.[currentSheetName]?.[0])?.map((_, cellIndex) => {
+ const headerName = sheetsData?.[currentSheetName]?.[0]?.[cellIndex];
+ const error = headerName ? props?.errorLocationObject?.[currentSheetName]?.[rowIndex]?.[headerName] : undefined;
+ let convertedError;
+ if (typeof error?.[0] === "object") {
+ let { error: actualError, ...otherProperties } = error[0];
+ convertedError = t(actualError, otherProperties?.values);
+ } else {
+ convertedError = t(error);
+ }
+ const rowHasError =
+ typeof props?.errorLocationObject?.[currentSheetName]?.[rowIndex] === "object"
+ ? Object.keys(props?.errorLocationObject?.[currentSheetName]?.[rowIndex]).length !== 0
+ : undefined;
+ return (
+
+ {cellIndex === 0 && rowHasError && }
+
+ {rowData[cellIndex] || rowData[cellIndex] === 0 ? (typeof rowData[cellIndex] !== "object" ? rowData[cellIndex] : "") : ""}
+ |
+ );
+ })}
+
+ ))}
+
+
+
+
+ {Object.entries(sheetsData).map(([sheetName, sheetData], index) => (
+ {
+ setCurrentSheetName(sheetName);
+ }}
+ style={{
+ ...(props?.errorLocationObject?.[sheetName] ? { backgroundColor: "rgb(250,148,148)", color: "black" } : {}),
+ }}
+ >
+ {sheetName}
+
+ ))}
+
+ {/* ))} */}
+
+
+ );
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js
new file mode 100644
index 00000000000..b0183f5da8d
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js
@@ -0,0 +1,442 @@
+// Importing necessary modules
+import { Card, Header } from "@egovernments/digit-ui-components";
+import L from "leaflet";
+import "leaflet/dist/leaflet.css";
+import React, { useCallback, useEffect, useRef, useState, Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import ZoomControl from "./ZoomControl";
+import CustomScaleControl from "./CustomScaleControl";
+import * as DigitSvgs from "@egovernments/digit-ui-svg-components";
+import { LoaderWithGap } from "@egovernments/digit-ui-react-components";
+import { tourSteps } from "../configs/tourSteps";
+import { useMyContext } from "../utils/context";
+import {
+ MapFilterIndex,
+ MapChoroplethIndex,
+ ChoroplethSelection,
+ FilterSection,
+ BoundarySelection,
+ BaseMapSwitcher,
+} from "./MappingHelperComponents";
+import {
+ enableMapInteractions,
+ disableMapInteractions,
+ removeAllLayers,
+ filterBoundarySelection,
+ findBounds,
+ addGeojsonToMap,
+ addFilterProperties,
+ addChoroplethProperties,
+ prepareGeojson,
+ extractGeoData,
+} from "../utils/mappingUtils";
+
+const page = "mapping";
+
+// Mapping component definition
+const Mapping = ({
+ campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType,
+ microplanData,
+ setMicroplanData,
+ checkDataCompletion,
+ setCheckDataCompletion,
+ currentPage,
+ pages,
+ setToast,
+ ...props
+}) => {
+ //fetch campaign data
+ const { id = "" } = Digit.Hooks.useQueryParams();
+ const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign(
+ {
+ CampaignDetails: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ ids: [id],
+ },
+ },
+ {
+ enabled: !!id,
+ }
+ );
+
+ // request body for boundary hierarchy api
+ var reqCriteria = {
+ url: `/boundary-service/boundary-hierarchy-definition/_search`,
+ params: {},
+ body: {
+ BoundaryTypeHierarchySearchCriteria: {
+ tenantId: Digit.ULBService.getStateId(),
+ // hierarchyType: "Microplan",
+ hierarchyType: campaignData?.hierarchyType,
+ },
+ },
+ config: {
+ enabled: !!campaignData?.hierarchyType,
+ select: (data) => {
+ return (
+ data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({
+ ...item,
+ parentBoundaryType: item?.parentBoundaryType
+ ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}`
+ : null,
+ boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`,
+ })) || {}
+ );
+ },
+ },
+ };
+ const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+ // request body for boundary hierarchy api
+ var reqCriteria = {
+ url: `/boundary-service/boundary/_search`,
+ params: { codes: Digit.ULBService.getCurrentTenantId(), tenantId: Digit.ULBService.getCurrentTenantId() },
+ body: {},
+ config: {
+ select: (data) => {
+ return data?.Boundary || {};
+ },
+ },
+ };
+ const { isLoading: isBoundaryLoading, data: Boundary } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+
+ // Setting up state variables
+ const [editable, setEditable] = useState(true);
+ const { t } = useTranslation();
+ var [map, setMap] = useState(null);
+ var [_mapNode, set__mapNode] = useState("map");
+ const [layers, setLayer] = useState([]);
+ const [validationSchemas, setValidationSchemas] = useState([]);
+ const [filterDataOrigin, setFilterDataOrigin] = useState({});
+ const [dataAvailability, setDataAvailability] = useState("true");
+ // const [toast, setToast] = useState();
+ const [baseMaps, setBaseMaps] = useState({});
+ const [selectedBaseMap, setSelectedBaseMap] = useState({});
+ const [selectedBaseMapName, setSelectedBaseMapName] = useState("");
+ const [showBaseMapSelector, setShowBaseMapSelector] = useState(false);
+ const [boundaryData, setBoundaryData] = useState({}); // State for boundary data
+ const [filterData, setFilterData] = useState({}); // State for facility data
+ const [boundarySelections, setBoundarySelections] = useState({});
+ const [isboundarySelectionSelected, setIsboundarySelectionSelected] = useState(false);
+ const { state, dispatch } = useMyContext();
+ const [filterPropertyNames, setFilterPropertyNames] = useState();
+ const [filterProperties, setFilterProperties] = useState();
+ const [showFilterOptions, setShowFilterOptions] = useState(false);
+ const [filterSelections, setFilterSelections] = useState([]);
+ const [choroplethProperties, setChoroplethProperties] = useState([]);
+ const [showChoroplethOptions, setShowChoroplethOptions] = useState(false);
+ const [choroplethProperty, setChoroplethProperty] = useState();
+ const [dataCompleteness, setDataCompleteness] = useState();
+ const basemapRef = useRef();
+ const filterBoundaryRef = useRef();
+ const showChoroplethOptionRef = useRef();
+ const showFilterOptionRef = useRef();
+ const [loader, setLoader] = useState(false);
+
+ // Set TourSteps
+ useEffect(() => {
+ const tourData = tourSteps(t)?.[page] || {};
+ if (state?.tourStateData?.name === page) return;
+ dispatch({
+ type: "SETINITDATA",
+ state: { tourStateData: tourData },
+ });
+ }, []);
+
+ // Effect to initialize map when data is fetched
+ useEffect(() => {
+ if (!state || !Boundary) return;
+ const filterDataOriginList = state?.MappingOrigin?.[0];
+ setFilterDataOrigin(filterDataOriginList);
+ const BaseMapLayers = state?.BaseMapLayers;
+ const schemas = state?.Schemas;
+ if (schemas) setValidationSchemas(schemas);
+ if (!BaseMapLayers || (BaseMapLayers && BaseMapLayers.length === 0)) return;
+ let baseMaps = {};
+ let defaultBaseMap = undefined;
+ BaseMapLayers.forEach((item) => {
+ if (item.url) {
+ const layer = L.tileLayer(item.url, {
+ minZoom: item?.minZoom,
+ maxZoom: item?.maxZoom,
+ attribution: item?.attribution,
+ });
+ baseMaps[item?.name] = {
+ metadata: item,
+ layer,
+ };
+ if (!defaultBaseMap)
+ defaultBaseMap = {
+ name: item?.name,
+ layer,
+ };
+ }
+ });
+ setSelectedBaseMapName(defaultBaseMap?.name);
+ setBaseMaps(baseMaps);
+ if (!map) {
+ init(_mapNode, defaultBaseMap, Boundary);
+ }
+ }, [Boundary]);
+
+ useEffect(() => {
+ if (map && filterDataOrigin && Object.keys(filterDataOrigin).length !== 0) {
+ setLoader("LOADING");
+ // Check if all the data is present or not, if it is then extract it in a format that can be used for mapping and other mapping related operations
+ extractGeoData(
+ campaignType,
+ microplanData,
+ filterDataOrigin,
+ validationSchemas,
+ setToast,
+ setDataAvailability,
+ hierarchy,
+ setBoundaryData,
+ setFilterData,
+ setFilterProperties,
+ setFilterSelections,
+ setFilterPropertyNames,
+ state,
+ setChoroplethProperties,
+ setDataCompleteness,
+ t
+ );
+ setLoader(false);
+ }
+ }, [filterDataOrigin, hierarchy]);
+
+ // Function to initialize map
+ const init = (id, defaultBaseMap, Boundary) => {
+ if (map !== null) return;
+
+ // let bounds = findBounds(Boundary);
+
+ let mapConfig = {
+ center: [0, 0],
+ zoomControl: false,
+ zoom: 3,
+ scrollwheel: true,
+ minZoom: 3,
+ };
+
+ let map_i = L.map(id, mapConfig);
+ var verticalBounds = L.latLngBounds(L.latLng(-90, -170), L.latLng(85, 190));
+ map_i.on("drag", () => {
+ map_i.panInsideBounds(verticalBounds, { animate: true });
+ });
+ map_i.on("zoom", () => {
+ map_i.panInsideBounds(verticalBounds, { animate: true });
+ });
+ const defaultBaseLayer = defaultBaseMap?.layer.addTo(map_i);
+ // if (bounds) map_i.fitBounds(bounds);
+ setSelectedBaseMap(defaultBaseLayer);
+ setMap(map_i);
+ };
+
+ const handleBaseMapToggle = (newBaseMap) => {
+ if (map) {
+ const currentBaseLayer = selectedBaseMap;
+ if (currentBaseLayer) {
+ currentBaseLayer.remove();
+ }
+ const newBaseLayer = baseMaps[newBaseMap].layer.addTo(map);
+ // Add the new base layer to the bottom of the layer stack
+ newBaseLayer.addTo(map);
+
+ // Update the baseLayer state
+ setSelectedBaseMap(newBaseLayer);
+ setSelectedBaseMapName(newBaseMap);
+ }
+ };
+
+ // showing selected boundary data
+ useEffect(() => {
+ if (!boundarySelections && !choroplethProperty && !filterSelections) return;
+ setLoader("LOADING");
+ try {
+ removeAllLayers(map, layers);
+ const { filteredSelection, childrenList } = filterBoundarySelection(boundaryData, boundarySelections);
+ let newLayer = [];
+ let addOn = {
+ fillColor: "rgba(255, 107, 43, 0)",
+ weight: 3.5,
+ opacity: 1,
+ color: "rgba(176, 176, 176, 1)",
+ fillOpacity: 0,
+ fill: "rgb(4,136,219,1)",
+ child: !childrenList || childrenList.length === 0, // so that this layer also has mounse in and mouse out events
+ };
+ let geojsonsBase = prepareGeojson(boundaryData, "ALL", addOn);
+ if (geojsonsBase) {
+ let baseLayer = addGeojsonToMap(map, geojsonsBase, t);
+ if (baseLayer) newLayer.push(baseLayer);
+ let bounds = findBounds(geojsonsBase);
+ if (bounds) map.fitBounds(bounds);
+ }
+
+ addOn = {
+ fillColor: "rgba(255, 107, 43, 1)",
+ weight: 2.5,
+ opacity: 1,
+ color: "rgba(255, 255, 255, 1)",
+ fillOpacity: 0.22,
+ fill: "rgb(4,136,219)",
+ };
+
+ let geojsonLayer;
+ if (choroplethProperty) {
+ if (dataCompleteness === "partial" || dataCompleteness === "false" || dataCompleteness === undefined) {
+ setToast({
+ state: "warning",
+ message: t("DISPLAYING_DATA_ONLY_FOR_UPLOADED_BOUNDARIES"),
+ });
+ }
+
+ let choroplethGeojson = prepareGeojson(boundaryData, "ALL", { ...addOn, child: true, fillColor: "rgb(0,0,0,0)" }) || [];
+ if (choroplethGeojson && choroplethGeojson.length !== 0)
+ choroplethGeojson = addChoroplethProperties(choroplethGeojson, choroplethProperty, filteredSelection);
+ geojsonLayer = addGeojsonToMap(map, choroplethGeojson, t);
+ if (geojsonLayer) {
+ newLayer.push(geojsonLayer);
+ }
+ }
+ geojsonLayer = null;
+ const geojsons = prepareGeojson(boundaryData, filteredSelection, addOn);
+ if (geojsons && geojsons.length > 0) {
+ geojsonLayer = addGeojsonToMap(map, geojsons, t);
+ newLayer.push(geojsonLayer);
+ let bounds = findBounds(geojsons);
+ if (bounds) map.fitBounds(bounds);
+ }
+
+ const childrenGeojson = prepareGeojson(boundaryData, childrenList, { ...addOn, opacity: 0, fillOpacity: 0, child: true });
+ let childrenGeojsonLayer = addGeojsonToMap(map, childrenGeojson, t);
+ if (childrenGeojsonLayer) newLayer.push(childrenGeojsonLayer);
+
+ //filters
+ const filterGeojsons = prepareGeojson(filterData, filteredSelection && filteredSelection.length !== 0 ? filteredSelection : "ALL", addOn);
+ const filterGeojsonWithProperties = addFilterProperties(filterGeojsons, filterSelections, filterPropertyNames, state?.MapFilters);
+ let filterGeojsonLayer = addGeojsonToMap(map, filterGeojsonWithProperties, t);
+ if (filterGeojsonLayer) newLayer.push(filterGeojsonLayer);
+
+ setLayer(newLayer);
+ } catch (error) {
+ console.error("Error while adding geojson to map: ", error.message);
+ }
+ setLoader(false);
+ }, [boundarySelections, choroplethProperty, filterSelections]);
+
+ const handleOutsideClickAndSubmitSimultaneously = useCallback(() => {
+ if (isboundarySelectionSelected) setIsboundarySelectionSelected(false);
+ if (showBaseMapSelector) setShowBaseMapSelector(false);
+ if (showFilterOptions) setShowFilterOptions(false);
+ if (showChoroplethOptions) setShowChoroplethOptions(false);
+ }, [
+ isboundarySelectionSelected,
+ showBaseMapSelector,
+ showFilterOptions,
+ showChoroplethOptions,
+ setIsboundarySelectionSelected,
+ setShowBaseMapSelector,
+ setShowFilterOptions,
+ setShowChoroplethOptions,
+ ]);
+ Digit?.Hooks.useClickOutside(filterBoundaryRef, handleOutsideClickAndSubmitSimultaneously, isboundarySelectionSelected, { capture: true });
+ Digit?.Hooks.useClickOutside(basemapRef, handleOutsideClickAndSubmitSimultaneously, showBaseMapSelector, { capture: true });
+ Digit?.Hooks.useClickOutside(showFilterOptionRef, handleOutsideClickAndSubmitSimultaneously, showFilterOptions, { capture: true });
+ Digit?.Hooks.useClickOutside(showChoroplethOptionRef, handleOutsideClickAndSubmitSimultaneously, showChoroplethOptions, { capture: true });
+
+ // function to stop mouse event propogation from custom comopents to leaflet map
+ const handleMouseDownAndScroll = (event) => {
+ event?.stopPropagation();
+ disableMapInteractions(map);
+ };
+
+ const handleMouseUpAndScroll = (event) => {
+ enableMapInteractions(map);
+ };
+ useEffect(() => {
+ if (isboundarySelectionSelected || showBaseMapSelector || showFilterOptions || showChoroplethOptions) handleMouseDownAndScroll();
+ else handleMouseUpAndScroll();
+ }, [isboundarySelectionSelected, showBaseMapSelector, showFilterOptions, showChoroplethOptions, choroplethProperty, filterPropertyNames]);
+
+ // Rendering component
+ return (
+
+
+
+
+ {/* Container for map */}
+
+
+
+
+
+
+ {filterProperties && Object.keys(filterProperties).length !== 0 && (
+
+ )}
+
+
+
+
+
+
+ {DigitSvgs.NorthArrow && }
+
+
+
+
+
+ {filterSelections && filterSelections.length > 0 && (
+
+ )}
+ {choroplethProperty && }
+
+
+
+
+ {loader &&
}
+
+ );
+};
+
+// Exporting Mapping component
+export default Mapping;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js
new file mode 100644
index 00000000000..9cea19a943f
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js
@@ -0,0 +1,513 @@
+// Importing necessary modules
+import { Card, CardLabel, MultiSelectDropdown, Button, CheckBox, RadioButtons } from "@egovernments/digit-ui-components";
+import "leaflet/dist/leaflet.css";
+import React, { memo, useCallback, useEffect, useMemo, useRef, useState, Fragment } from "react";
+import * as DigitSvgs from "@egovernments/digit-ui-svg-components";
+import { CardSectionHeader, InfoIconOutline, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components";
+import { fetchDropdownValues } from "../utils/processHierarchyAndData";
+import { MapChoroplethGradientColors, PRIMARY_THEME_COLOR } from "../configs/constants";
+import { ModalHeading } from "./CommonComponents";
+import * as MicroplanIconCollection from "../icons/Svg";
+import { generatePreviewUrl } from "../utils/mappingUtils";
+
+const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs };
+
+export function checkTruthyKeys(obj) {
+ for (let key in obj) {
+ if (Object.hasOwn(obj, key)) {
+ if (obj[key] && !(Array.isArray(obj[key]) && obj[key].length === 0)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+export const MapFilterIndex = ({ filterSelections, MapFilters, t }) => {
+ return (
+
+ {filterSelections && filterSelections.length > 0 ? (
+ <>
+ {filterSelections.map((item, index) => (
+ //
+ ))}
+ >
+ ) : (
+ ""
+ )}
+
+ );
+};
+
+// Function to create the gradient from the colors array for choropleth index
+export const MapChoroplethIndex = ({ t, choroplethProperty }) => {
+ const createGradientString = (colors) => {
+ return colors.map((color) => `${color.color} ${color.percent}%`).join(", ");
+ };
+
+ const gradientString = createGradientString(MapChoroplethGradientColors);
+ const gradientStyle = {
+ background: `linear-gradient(to right, ${gradientString})`,
+ };
+
+ return (
+
+
+
{t(choroplethProperty)}
+
+ );
+};
+
+export const FilterItemBuilder = ({ item, MapFilters, t }) => {
+ let temp = MapFilters?.find((e) => e?.name === item)?.icon?.index;
+ let DynamicIcon = IconCollection?.[temp];
+ // let icon;
+ // if (typeof DynamicIcon === "function") icon = DynamicIcon({});
+ return DynamicIcon && typeof DynamicIcon === "function" ? (
+
+ ) : (
+ //
+ ""
+ );
+};
+
+export const ChoroplethSelection = memo(
+ ({
+ choroplethProperties,
+ showChoroplethOptions,
+ showChoroplethOptionRef,
+ setShowChoroplethOptions,
+ choroplethProperty,
+ setChoroplethProperty,
+ t,
+ }) => {
+ const handleChange = useCallback(
+ (value) => {
+ setChoroplethProperty(value?.code);
+ },
+ [choroplethProperties]
+ );
+
+ return (
+
+
setShowChoroplethOptions((previous) => !previous)}
+ onKeyUp={() => setShowChoroplethOptions((previous) => !previous)}
+ tabIndex={0}
+ >
+
{t("VISUALIZATIONS")}
+
+ {DigitSvgs.FilterAlt && }
+
+
+ {showChoroplethOptions && (
+
+
+ ({ name: item, id: item, code: item }))}
+ optionsKey="name"
+ onSelect={handleChange}
+ selectedOption={choroplethProperty}
+ />
+
+
setChoroplethProperty()}
+ />
+
+ )}
+
+ );
+ }
+);
+
+export const FilterSection = memo(
+ ({ filterProperties, showFilterOptionRef, showFilterOptions, setShowFilterOptions, filterSelections, setFilterSelections, t }) => {
+ const handleChange = useCallback(
+ (e, item) => {
+ let tempFilterSelections = [...filterSelections]; // Clone the array to avoid mutating state directly
+ if (filterSelections.includes(item)) {
+ tempFilterSelections = tempFilterSelections.filter((element) => element !== item);
+ } else {
+ tempFilterSelections.push(item);
+ }
+ setFilterSelections(tempFilterSelections);
+ },
+ [filterSelections]
+ );
+
+ return (
+
+
setShowFilterOptions((previous) => !previous)}
+ onKeyUp={() => setShowFilterOptions((previous) => !previous)}
+ tabIndex={0}
+ >
+
{t("FILTERS")}
+
+ {DigitSvgs.FilterAlt && }
+
+
+ {showFilterOptions && (
+
+
+ {filterProperties.map((item) => (
+
+ handleChange(e, item)}
+ label={t(item)}
+ checked={!!filterSelections.includes(item)}
+ mainClassName="mainClassName"
+ labelClassName="labelClassName"
+ inputWrapperClassName="inputWrapperClassName"
+ inputClassName="inputClassName"
+ inputIconClassname="inputIconClassname"
+ iconFill={PRIMARY_THEME_COLOR}
+ onLabelClick={(e) => handleChange(e, item)}
+ />
+
+ ))}
+
+
setFilterSelections([])}
+ />
+
+ )}
+
+ );
+ }
+);
+
+export const BoundarySelection = memo(
+ ({
+ boundarySelections,
+ setBoundarySelections,
+ boundaryData,
+ hierarchy,
+ filterBoundaryRef,
+ isboundarySelectionSelected,
+ setIsboundarySelectionSelected,
+ t,
+ }) => {
+ const [processedHierarchy, setProcessedHierarchy] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [showConfirmationModal, setShowConformationModal] = useState(false);
+ const itemRefs = useRef([]);
+ const [expandedIndex, setExpandedIndex] = useState(null);
+ const scrollContainerRef = useRef(null);
+ const [changedBoundaryType, setChangedBoundaryType] = useState("");
+ const [isScrollable, setIsScrollable] = useState(false);
+
+ useEffect(() => {
+ // Scroll to the expanded item's child element after the state has updated and the DOM has re-rendered
+ if (expandedIndex !== null && itemRefs.current[expandedIndex]) {
+ // Use a timeout to ensure the DOM has updated
+ setTimeout(() => {
+ const childElement = itemRefs.current[expandedIndex].children[0]; // Assuming child content is the second child
+ // if (childElement) {
+ // childElement.scrollIntoView({ behavior: 'smooth' });
+ // }
+ if (childElement) {
+ const scrollContainer = scrollContainerRef.current;
+ const childElementBound = childElement.getBoundingClientRect();
+ const containerRect = scrollContainer.getBoundingClientRect();
+
+ // Calculate the offset from the top of the container
+ const offset = childElementBound.top - containerRect.top;
+
+ // Scroll the container
+ scrollContainer.scrollTo({
+ top: scrollContainer.scrollTop + offset - 10,
+ behavior: "smooth",
+ });
+ }
+ }, 0);
+ }
+ }, [expandedIndex]);
+
+ const toggleExpand = (index) => {
+ setExpandedIndex(index === expandedIndex ? null : index);
+ };
+
+ // Filtering out dropdown values
+ useEffect(() => {
+ if (!boundaryData || !hierarchy) return;
+ const processedHierarchyTemp = fetchDropdownValues(
+ boundaryData,
+ processedHierarchy.length !== 0 ? processedHierarchy : hierarchy,
+ boundarySelections,
+ changedBoundaryType
+ );
+ setProcessedHierarchy(processedHierarchyTemp);
+ setIsLoading(false);
+ }, [boundaryData, hierarchy, boundarySelections]);
+
+ const handleClearAll = () => {
+ setShowConformationModal(true);
+ };
+
+ const handleSubmitConfModal = () => {
+ setBoundarySelections({});
+ setShowConformationModal(false);
+ };
+
+ const handleCancelConfModal = () => {
+ setShowConformationModal(false);
+ };
+
+ const checkScrollbar = () => {
+ if (scrollContainerRef.current) {
+ setIsScrollable(scrollContainerRef.current.scrollHeight > scrollContainerRef.current.clientHeight);
+ }
+ };
+
+ useEffect(() => {
+ // Initial check
+ checkScrollbar();
+
+ // Check on resize
+ window.addEventListener("resize", checkScrollbar);
+
+ // Cleanup event listeners on component unmount
+ return () => {
+ window.removeEventListener("resize", checkScrollbar);
+ };
+ }, [isboundarySelectionSelected]);
+
+ useEffect(() => {
+ const content = scrollContainerRef.current;
+ content.addEventListener("scroll", checkScrollbar);
+
+ return () => {
+ content.removeEventListener("scroll", checkScrollbar);
+ };
+ }, [scrollContainerRef]);
+
+ return (
+
+ {isLoading &&
}
+
setIsboundarySelectionSelected((previous) => !previous)}
+ />
+
+
+ {t("SELECT_A_BOUNDARY")}
+
+
+
+ {processedHierarchy?.map((item, index) => (
+
{
+ itemRefs.current[index] = el;
+ }}
+ onClick={() => toggleExpand(index)}
+ >
+ {t(item?.boundaryType)}
+ {item?.parentBoundaryType === null ? (
+ 5 ? { height: "13.75rem" } : {}}
+ type={"multiselectdropdown"}
+ t={t}
+ options={item?.dropDownOptions || []}
+ optionsKey="name"
+ addSelectAllCheck={true}
+ onSelect={(e) => {
+ setChangedBoundaryType(item?.boundaryType);
+ Digit.Utils.microplan.handleSelection(
+ e,
+ item?.boundaryType,
+ boundarySelections,
+ hierarchy,
+ setBoundarySelections,
+ boundaryData,
+ setIsLoading
+ );
+ }}
+ />
+ ) : (
+ 5 ? { height: "13.75rem" } : {}}
+ type={"multiselectdropdown"}
+ t={t}
+ options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []}
+ optionsKey="name"
+ addSelectAllCheck={true}
+ onSelect={(e) => {
+ setChangedBoundaryType(item?.boundaryType);
+ Digit.Utils.microplan.handleSelection(
+ e,
+ item?.boundaryType,
+ boundarySelections,
+ hierarchy,
+ setBoundarySelections,
+ boundaryData,
+ setIsLoading
+ );
+ }}
+ variant="nestedmultiselect"
+ />
+ )}
+
+ ))}
+
+ {checkTruthyKeys(boundarySelections) && (
+
+ )}
+ {showConfirmationModal && (
+
+
}
+ actionCancelLabel={t("YES")}
+ actionCancelOnSubmit={handleSubmitConfModal}
+ actionSaveLabel={t("NO")}
+ actionSaveOnSubmit={handleCancelConfModal}
+ >
+
+
{t("CLEAR_ALL_CONFIRMATION_MSG")}
+
+
+
+ )}
+
+
+ );
+ }
+);
+
+export const BaseMapSwitcher = ({
+ baseMaps,
+ showBaseMapSelector,
+ setShowBaseMapSelector,
+ handleBaseMapToggle,
+ selectedBaseMapName,
+ basemapRef,
+ t,
+}) => {
+ if (!baseMaps) return null;
+ return (
+
+
setShowBaseMapSelector((previous) => !previous)}
+ onKeyUp={() => setShowBaseMapSelector((previous) => !previous)}
+ tabIndex={0}
+ >
+
{t("LAYERS")}
+
{DigitSvgs.Layers && }
+
+
+ {showBaseMapSelector && (
+
+ {Object.entries(baseMaps).map(([name, baseMap], index) => {
+ return (
+
+
handleBaseMapToggle(name)}
+ />
+
{t(name)}
+
+ );
+ })}
+
+ )}
+
+
+ );
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js
new file mode 100644
index 00000000000..b6a2fb9a205
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js
@@ -0,0 +1,111 @@
+import React, { memo } from "react";
+import { ActionBar, ArrowForward, Banner } from "@egovernments/digit-ui-components";
+import { useTranslation } from "react-i18next";
+import { ArrowBack, FileDownload } from "@egovernments/digit-ui-svg-components";
+import { convertJsonToXlsx, writeWorkbookToBuffer } from "../utils/jsonToExcelBlob";
+import { Button } from "@egovernments/digit-ui-react-components";
+import { useHistory } from "react-router-dom";
+import { Link } from "react-router-dom/cjs/react-router-dom.min";
+import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants";
+import { colorHeaders } from "../utils/uploadUtils";
+
+const MicroplanCreatedScreen = memo(({ microplanData, ...props }) => {
+ const { t } = useTranslation();
+ const history = useHistory();
+
+ const downloadMicroplan = async () => {
+ try {
+ if (!microplanData?.microplanPreview) return;
+ const data = _.cloneDeep(microplanData?.microplanPreview?.previewData);
+ const commonColumnIndex = data[0]?.findIndex((item) => item === commonColumn);
+ data[0] = data[0].map((item) => t(item));
+
+ for (const i in data) {
+ data[i] = data[i].map((item, index) =>
+ item ? (typeof item === "number" ? item : index === commonColumnIndex ? item : t(item)) : t("NO_DATA")
+ );
+ }
+
+ const headers = data?.[0] || [];
+ const workbook = await convertJsonToXlsx({ [microplanData?.microplanDetails?.name]: data }, {}, true);
+ colorHeaders(workbook, headers, [], []);
+ const blob = await writeWorkbookToBuffer(workbook);
+
+ if (!blob) {
+ return;
+ }
+
+ const url = URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = url;
+
+ const fileNameParts = microplanData?.microplanDetails?.name;
+ if (!fileNameParts) {
+ return;
+ }
+
+ link.download = fileNameParts;
+ link.click();
+ URL.revokeObjectURL(url);
+ } catch (error) {
+ console.error(`Failed to download microplan: ${error.message}`, error);
+ }
+ };
+
+ const clickGoHome = () => {
+ history.push("/microplan-ui/employee");
+ };
+
+ return (
+
+
+
+
+
+
{t("MICROPLAN_GENERATED_SUCCESSFULLY_DESCRIPTIION")}
+
+ }
+ isSuffix={false}
+ />
+
+
+
+
+ {/* Back button */}
+ }
+ />
+ {/* Next/Submit button */}
+
+
+
+
+
+ );
+});
+
+export default MicroplanCreatedScreen;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js
new file mode 100644
index 00000000000..a54b7419ed8
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js
@@ -0,0 +1,295 @@
+import React, { Fragment, useState, useEffect, useCallback } from "react";
+import {
+ Card,
+ CardSubHeader,
+ CardSectionHeader,
+ StatusTable,
+ Row,
+ Loader,
+ LabelFieldPair,
+ CardLabel,
+ TextInput,
+ LoaderWithGap,
+} from "@egovernments/digit-ui-react-components";
+import { useTranslation } from "react-i18next";
+import { tourSteps } from "../configs/tourSteps";
+import { useMyContext } from "../utils/context";
+import { InfoCard, Modal, Toast } from "@egovernments/digit-ui-components";
+import { CloseButton, ModalHeading } from "./CommonComponents";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+import SearchPlanConfig from "../services/SearchPlanConfig";
+
+const page = "microplanDetails";
+
+const MicroplanDetails = ({
+ MicroplanName = "default",
+ campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType,
+ microplanData,
+ setMicroplanData,
+ checkDataCompletion,
+ setCheckDataCompletion,
+ currentPage,
+ pages,
+ setToast,
+ ...props
+}) => {
+ const { t } = useTranslation();
+ const [microplan, setMicroplan] = useState(Digit.SessionStorage.get("microplanData")?.microplanDetails?.name);
+ const { state, dispatch } = useMyContext();
+ const [modal, setModal] = useState("none");
+ // const [toast, setToast] = useState();
+ const [showNamingConventions, setShowNamingConventions] = useState(false);
+ const [loader, setLoader] = useState(false);
+
+ //fetch campaign data
+ const { id = "" } = Digit.Hooks.useQueryParams();
+ const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign(
+ {
+ CampaignDetails: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ ids: [id],
+ },
+ },
+ {
+ enabled: !!id,
+ select: (data) => {
+ const campaignCard = [
+ {
+ label: t("CAMPAIGN_NAME"),
+ value: data?.campaignName ? data?.campaignName : t("ES_COMMON_NA"),
+ },
+ {
+ label: t(`CAMPAIGN_TYPE`),
+ value: data?.projectType ? t(`CAMPAIGN_TYPE_${data?.projectType}`) : t("ES_COMMON_NA"),
+ },
+ {
+ label: t(`CAMPAIGN_BENEFICIARY_TYPE`),
+ value: data?.additionalDetails?.beneficiaryType
+ ? t(`CAMPAIGN_BENEFICIARY_TYPE${data?.additionalDetails?.beneficiaryType}`)
+ : t("ES_COMMON_NA"),
+ },
+ {
+ label: t("CAMPAIGN_DATE"),
+ value: data.startDate
+ ? data.endDate
+ ? `${Digit.DateUtils.ConvertEpochToDate(data.startDate)} - ${Digit.DateUtils.ConvertEpochToDate(data.endDate)}`
+ : Digit.DateUtils.ConvertEpochToDate(data.startDate)
+ : t("ES_COMMON_NA"),
+ },
+ ];
+ return campaignCard;
+ },
+ }
+ );
+
+ // Set TourSteps
+ useEffect(() => {
+ const tourData = tourSteps(t)?.[page] || {};
+ if (state?.tourStateData?.name === page) return;
+ dispatch({
+ type: "SETINITDATA",
+ state: { tourStateData: tourData },
+ });
+ }, []);
+
+ // Save data to ssn of data change
+ useEffect(() => {
+ setMicroplanData((previous) => ({
+ ...previous,
+ microplanDetails: {
+ name: microplan,
+ },
+ }));
+ }, [microplan]);
+
+ useEffect(() => {
+ if (checkDataCompletion !== "true" || !setCheckDataCompletion) return;
+
+ updateData(true);
+ }, [checkDataCompletion]);
+
+ // UseEffect to add a event listener for keyboard
+ useEffect(() => {
+ window.addEventListener("keydown", handleKeyPress);
+
+ return () => window.removeEventListener("keydown", handleKeyPress);
+ }, [modal]);
+
+ const handleKeyPress = (event) => {
+ // if (modal !== "upload-guidelines") return;
+ if (["x", "Escape"].includes(event.key)) {
+ // Perform the desired action when "x" or "esc" is pressed
+ // if (modal === "upload-guidelines")
+ setCheckDataCompletion("false");
+ setModal("none");
+ }
+ };
+ const validateMicroplanName = async () => {
+ try {
+ setLoader("LOADING");
+ const body = {
+ PlanConfigurationSearchCriteria: {
+ name: microplan,
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ },
+ };
+ const response = await SearchPlanConfig(body);
+ if (response?.PlanConfiguration?.length === 0) {
+ setLoader();
+ return true;
+ }
+ if (response?.PlanConfiguration?.length === 1) {
+ if (response?.PlanConfiguration[0].id === microplanData?.planConfigurationId) {
+ setLoader();
+ return true;
+ }
+ }
+ setLoader();
+ return false;
+ } catch (error) {
+ console.error("Error while checking microplan name duplication: ", error.message);
+ setLoader();
+ return false;
+ }
+ };
+ // check if data has changed or not
+ const updateData = useCallback(
+ async (check) => {
+ if (checkDataCompletion !== "true" || !setCheckDataCompletion) return;
+ if (!microplan || !validateName(microplan)) {
+ setCheckDataCompletion("false");
+ setShowNamingConventions(true);
+ return setToast({ state: "error", message: t("ERROR_MICROPLAN_NAME_CRITERIA") });
+ }
+ const valid = await validateMicroplanName();
+ if (!valid) {
+ setToast({ state: "error", message: t("ERROR_DUPLICATE_MICROPLAN_NAME") });
+ setCheckDataCompletion("false");
+ return;
+ }
+ if (check) {
+ setMicroplanData((previous) => ({
+ ...previous,
+ microplanDetails: {
+ name: microplan,
+ },
+ }));
+ if (!["", null, undefined].includes(microplan)) {
+ setCheckDataCompletion("valid");
+ } else {
+ setCheckDataCompletion("invalid");
+ }
+ } else {
+ if (!["", null, undefined].includes(microplanData?.microplanDetails?.name)) {
+ setCheckDataCompletion("valid");
+ } else {
+ setCheckDataCompletion("invalid");
+ }
+ }
+ },
+ [checkDataCompletion, microplan, microplanData, setCheckDataCompletion, setMicroplanData, validateMicroplanName]
+ );
+
+ // const cancelUpdateData = useCallback(() => {
+ // setCheckDataCompletion(false);
+ // setModal('none');
+ // }, [setCheckDataCompletion, setModal]);
+ function validateName(name) {
+ const microplanNamingRegxString = state?.MicroplanNamingRegx?.[0]?.data;
+ const namePattern = new RegExp(microplanNamingRegxString);
+ return namePattern.test(name);
+ }
+ const onChangeMicroplanName = (e) => {
+ setMicroplan(e.target.value);
+ };
+
+ if (isCampaignLoading) {
+ return ;
+ }
+
+ return (
+ <>
+ {loader && }
+
+
+ {t("CAMPAIGN_DETAILS")}
+
+
+
+ {campaignData?.length > 0 &&
+ campaignData?.map((row, idx) => {
+ return (
+
+ );
+ })}
+
+
+
+ {t("NAME_YOUR_MP")}
+ {t("MP_FOOTER")}
+
+
+ {`${t("NAME_OF_MP")} `} *
+
+
+
+
+
+
+
+ {state?.MicroplanNamingConvention?.[0]?.data?.map((item, index) => (
+
+
+ {t(index + 1)}.
+
+
+ {t(item)}
+
+
+ ))}
+ ,
+ ]}
+ />
+ >
+ );
+};
+
+export default MicroplanDetails;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js
new file mode 100644
index 00000000000..3ca2d08b160
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js
@@ -0,0 +1,470 @@
+import { Header, Loader } from "@egovernments/digit-ui-components";
+import React, { useCallback, useEffect, useMemo, useState, Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import { processHierarchyAndData } from "../utils/processHierarchyAndData";
+import { ModalHeading } from "./CommonComponents";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components";
+import { tourSteps } from "../configs/tourSteps";
+import { useMyContext } from "../utils/context";
+import {
+ fetchMicroplanPreviewData,
+ filterObjects,
+ updateHyothesisAPICall,
+ filterMicroplanDataToShowWithHierarchySelection,
+} from "../utils/microplanPreviewUtils";
+import {
+ HypothesisValues,
+ BoundarySelection,
+ DataPreview,
+ AppplyChangedHypothesisConfirmation,
+ Aggregates,
+} from "./MicroplanPreviewHelperCompoenents";
+
+const page = "microplanPreview";
+
+const MicroplanPreview = ({
+ campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType,
+ microplanData,
+ setMicroplanData,
+ checkDataCompletion,
+ setCheckDataCompletion,
+ currentPage,
+ pages,
+ navigationEvent,
+ setToast,
+ ...props
+}) => {
+ const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig();
+ const userInfo = Digit.SessionStorage.get("User")?.info;
+ const { id: campaignId = "" } = Digit.Hooks.useQueryParams();
+ const { t } = useTranslation();
+ const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]);
+ const [data, setData] = useState([]);
+ const [dataToShow, setDataToShow] = useState([]);
+ const [validationSchemas, setValidationSchemas] = useState([]);
+ const [resources, setResources] = useState([]);
+ const [formulaConfiguration, setFormulaConfiguration] = useState([]);
+ const [boundarySelections, setBoundarySelections] = useState({}); // state for hierarchy from the data available from uploaded data
+ const [boundaryData, setBoundaryData] = useState({}); // State for boundary data
+ // const [toast, setToast] = useState();
+ const [modal, setModal] = useState("none");
+ const [operatorsObject, setOperatorsObject] = useState([]);
+
+ const [loaderActivation, setLoaderActivation] = useState(false);
+
+ const [userEditedResources, setUserEditedResources] = useState({}); // state to maintain a record of the resources that the user has edited ( boundaryCode : {resource : value})
+ const [microplanPreviewAggregates, setMicroplaPreviewAggregates] = useState();
+ const { state, dispatch } = useMyContext();
+ const [updateHypothesis, setUpdateHypothesis] = useState(false);
+ //fetch campaign data
+ const { id = "" } = Digit.Hooks.useQueryParams();
+ const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign(
+ {
+ CampaignDetails: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ ids: [id],
+ },
+ },
+ {
+ enabled: !!id,
+ }
+ );
+
+ // request body for boundary hierarchy api
+ const reqCriteria = {
+ url: `/boundary-service/boundary-hierarchy-definition/_search`,
+ params: {},
+ body: {
+ BoundaryTypeHierarchySearchCriteria: {
+ tenantId: Digit.ULBService.getStateId(),
+ hierarchyType: campaignData?.hierarchyType,
+ },
+ },
+ config: {
+ enabled: !!campaignData?.hierarchyType,
+ select: (data) => {
+ return (
+ data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({
+ ...item,
+ parentBoundaryType: item?.parentBoundaryType
+ ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}`
+ : null,
+ boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`,
+ })) || {}
+ );
+ },
+ },
+ };
+ const { isLoading: ishierarchyLoading, data: hierarchyRawData } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+ const hierarchy = useMemo(() => {
+ return hierarchyRawData?.map((item) => item?.boundaryType);
+ }, [hierarchyRawData]);
+ // Set TourSteps
+ useEffect(() => {
+ const tourData = tourSteps(t)?.[page] || {};
+ if (state?.tourStateData?.name === page) return;
+ dispatch({
+ type: "SETINITDATA",
+ state: { tourStateData: tourData },
+ });
+ }, []);
+
+ // UseEffect to extract data on first render
+ useEffect(() => {
+ if (microplanData && (microplanData?.ruleEngine || microplanData?.hypothesis)) {
+ const hypothesisAssumptions = microplanData?.hypothesis || [];
+ const formulaConfiguration = microplanData?.ruleEngine?.filter((item) => Object.values(item).every((key) => key !== "")) || [];
+ if (hypothesisAssumptions.length !== 0 && hypothesisAssumptionsList.length === 0) {
+ setHypothesisAssumptionsList(hypothesisAssumptions);
+ }
+ if (formulaConfiguration.length !== 0) {
+ setFormulaConfiguration(formulaConfiguration);
+ }
+ }
+ if (microplanData?.microplanPreview?.userEditedResources) {
+ setUserEditedResources(microplanData?.microplanPreview?.userEditedResources);
+ }
+ }, []);
+
+ // Fetch and assign MDMS data
+ useEffect(() => {
+ if (!state) return;
+ const schemas = state?.Schemas;
+ let resourcelist = state?.Resources;
+ let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates;
+ microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data;
+ if (schemas) setValidationSchemas(schemas);
+ resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data;
+ if (resourcelist) setResources(resourcelist);
+ if (state?.RuleConfigureOperators) {
+ setOperatorsObject(state.RuleConfigureOperators);
+ }
+ if (microplanPreviewAggregatesList) setMicroplaPreviewAggregates(microplanPreviewAggregatesList);
+ }, []);
+
+ // UseEffect for checking completeness of data before moveing to next section
+ useEffect(() => {
+ if (!dataToShow || checkDataCompletion !== "true" || !setCheckDataCompletion) return;
+ const check = filterObjects(hypothesisAssumptionsList, microplanData?.hypothesis);
+ if (check.length === 0) {
+ if (navigationEvent?.name === "next") return setModal("confirm-microplan-generation");
+ return createMicroplan(false, false);
+ }
+ setModal("confirm-apply-changed-hypothesis");
+ }, [checkDataCompletion]);
+
+ // check if data has changed or not
+ const updateData = useCallback(
+ (doPerform) => {
+ // Update the microplan data with selected hierarchy and resources
+ // This function also handles setting the completion check based on the action to be performed
+ if (!setMicroplanData) return;
+ try {
+ let tempData = filterMicroplanDataToShowWithHierarchySelection(data, {}, hierarchy);
+ // Adding resources to the data we need to show
+ tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow(
+ tempData,
+ resources,
+ hypothesisAssumptionsList,
+ formulaConfiguration,
+ userEditedResources,
+ t
+ );
+ setMicroplanData((previous) => ({
+ ...previous,
+ microplanPreview: {
+ previewData: tempData,
+ userEditedResources,
+ },
+ }));
+ if (doPerform) {
+ return setCheckDataCompletion("perform-action");
+ }
+ setCheckDataCompletion("false");
+ } catch (error) {
+ console.error("Failed to update data:", error);
+ }
+ },
+ [
+ resources,
+ boundarySelections,
+ hierarchy,
+ hypothesisAssumptionsList,
+ formulaConfiguration,
+ userEditedResources,
+ setMicroplanData,
+ setCheckDataCompletion,
+ ]
+ );
+
+ const cancelUpdateData = useCallback(() => {
+ setUpdateHypothesis(false);
+ if (navigationEvent?.name === "next") setModal("confirm-microplan-generation");
+ else createMicroplan(false, false);
+ }, [setCheckDataCompletion, setModal]);
+
+ useEffect(() => {
+ if (boundarySelections && Object.values(boundarySelections).every((item) => item.length === 0) && hierarchy) {
+ const tempBoundarySelection = {};
+ for (const item of hierarchy) {
+ tempBoundarySelection[item] = [];
+ }
+ setBoundarySelections(tempBoundarySelection);
+ }
+ }, [hierarchy]);
+
+ // UseEffect to add a event listener for keyboard
+ useEffect(() => {
+ window.addEventListener("keydown", handleKeyPress);
+
+ return () => window.removeEventListener("keydown", handleKeyPress);
+ }, [modal]);
+
+ const handleKeyPress = (event) => {
+ // if (modal !== "upload-guidelines") return;
+ if (["x", "Escape"].includes(event.key)) {
+ // Perform the desired action when "x" or "esc" is pressed
+ setCheckDataCompletion("false");
+ setModal("none");
+ }
+ };
+
+ const cancleNavigation = () => {
+ if (navigationEvent?.name !== "next") setCheckDataCompletion("false");
+ setModal("none");
+ };
+
+ const createMicroplan = useCallback(
+ (doCreation, updateHypothesis) => {
+ if (!hypothesisAssumptionsList || !setMicroplanData) return;
+ const updateDataWrapper = () => {
+ if (doCreation || navigationEvent?.name !== "next") {
+ return updateData(true);
+ }
+ updateData(false);
+ };
+ const setCheckDataCompletionWrapper = (value) => {
+ if (!doCreation) {
+ return setCheckDataCompletion("false");
+ }
+ setCheckDataCompletion(value);
+ };
+ const microData = updateHypothesis ? updateMicroplanData(hypothesisAssumptionsList) : microplanData;
+ setLoaderActivation(true);
+ updateHyothesisAPICall(
+ microData,
+ setMicroplanData,
+ operatorsObject,
+ microData?.microplanDetails?.name,
+ campaignId,
+ UpdateMutate,
+ setToast,
+ updateDataWrapper,
+ setLoaderActivation,
+ doCreation && navigationEvent?.name === "next" ? "GENERATED" : "DRAFT",
+ cancleNavigation,
+ state,
+ campaignType,
+ navigationEvent,
+ setCheckDataCompletionWrapper,
+ t
+ );
+
+ setUpdateHypothesis(false);
+ setModal("none");
+ },
+ [
+ hypothesisAssumptionsList,
+ setMicroplanData,
+ operatorsObject,
+ campaignId,
+ UpdateMutate,
+ setToast,
+ updateData,
+ setLoaderActivation,
+ navigationEvent,
+ t,
+ ]
+ );
+
+ const updateMicroplanData = useCallback(
+ (hypothesisAssumptionsList) => {
+ let microData = {};
+ setMicroplanData((previous) => {
+ microData = { ...previous, hypothesis: hypothesisAssumptionsList };
+ return microData;
+ });
+ return microData;
+ },
+ [setMicroplanData]
+ );
+
+ // Set microplan preview data
+ useEffect(() => {
+ if (data?.length !== 0 || !hierarchyRawData || !hierarchy || validationSchemas?.length === 0) return;
+
+ const combinedData = fetchMicroplanPreviewData(campaignType, microplanData, validationSchemas, hierarchy);
+ // process and form hierarchy
+ if (combinedData && hierarchy) {
+ const { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchyRawData, [combinedData]);
+ setBoundaryData({ Microplan: { hierarchyLists, hierarchicalData } });
+ }
+ if (combinedData) {
+ setData(combinedData);
+ setDataToShow(combinedData);
+ }
+ }, [hierarchy, hierarchyRawData, microplanData]);
+
+ useEffect(() => {
+ if (!boundarySelections && !resources) return;
+ let tempData = filterMicroplanDataToShowWithHierarchySelection(data, boundarySelections, hierarchy);
+ // Adding resources to the data we need to show
+ tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow(
+ tempData,
+ resources,
+ hypothesisAssumptionsList,
+ formulaConfiguration,
+ userEditedResources,
+ t
+ );
+ setDataToShow(tempData);
+ setMicroplanData((previous) => ({ ...previous, microplanPreview: { ...previous.microplanPreview, previewData: tempData, userEditedResources } }));
+ }, [boundarySelections, resources, hypothesisAssumptionsList, userEditedResources]);
+
+ if (isCampaignLoading || ishierarchyLoading) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+ <>
+
+
+
{t(campaignData?.campaignName)}
+
{t(microplanData?.microplanDetails?.name)}
+
{t("MICROPLAN_PREVIEW_CREATE_BY", { username: userInfo?.name })}
+
+
+
+
+
+
{t("MICROPLAN_PREVIEW_HYPOTHESIS_HEADING")}
+
{t("MICROPLAN_PREVIEW_HYPOTHESIS_INSTRUCTIONS")}
+
+
+
+ {dataToShow?.length != 0 ? (
+
+ ) : (
+
{t("NO_DATA_AVAILABLE")}
+ )}
+
+
+ {modal === "confirm-apply-changed-hypothesis" && (
+
}
+ actionCancelLabel={t("YES")}
+ actionCancelOnSubmit={() => {
+ setUpdateHypothesis(true);
+ if (navigationEvent?.name === "next") setModal("confirm-microplan-generation");
+ else createMicroplan(false, true);
+ }}
+ actionSaveLabel={t("NO")}
+ actionSaveOnSubmit={cancelUpdateData}
+ formId="modal-action"
+ >
+
+
+ )}
+ {modal === "confirm-microplan-generation" && (
+
}
+ actionCancelLabel={t("YES")}
+ actionCancelOnSubmit={() => createMicroplan(true, updateHypothesis)}
+ actionSaveLabel={t("NO")}
+ actionSaveOnSubmit={() => createMicroplan(false, updateHypothesis)}
+ formId="modal-action"
+ >
+
+
{t("INSTRUCTIONS_MICROPLAN_GENERATION_CONFIRMATION")}
+
+
+ )}
+
+ {loaderActivation && }
+ >
+ );
+};
+
+export default MicroplanPreview;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js
new file mode 100644
index 00000000000..e92335d6581
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js
@@ -0,0 +1,434 @@
+import { CardLabel, Loader, MultiSelectDropdown, TextInput } from "@egovernments/digit-ui-components";
+import React, { memo, useCallback, useEffect, useMemo, useState, Fragment, useRef } from "react";
+import { fetchDropdownValues } from "../utils/processHierarchyAndData";
+import { CloseButton, ModalHeading } from "./CommonComponents";
+import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants";
+import { Button, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components";
+import { useNumberFormatter } from "../hooks/useNumberFormatter";
+import { calculateAggregateValue, filterObjects, useHypothesis } from "../utils/microplanPreviewUtils";
+
+export const HypothesisValues = memo(({ boundarySelections, hypothesisAssumptionsList, setHypothesisAssumptionsList, setToast, setModal, t }) => {
+ const [tempHypothesisList, setTempHypothesisList] = useState(hypothesisAssumptionsList || []);
+ const { valueChangeHandler } = useHypothesis(tempHypothesisList, hypothesisAssumptionsList);
+ const contentRef = useRef(null);
+ const [isScrollable, setIsScrollable] = useState(false);
+
+ const applyNewHypothesis = () => {
+ if (tempHypothesisList.some((item) => item.active && (Number.isNaN(parseFloat(item.value)) || parseFloat(item.value) === 0))) {
+ setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") });
+ return;
+ }
+ if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0))
+ return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") });
+ setHypothesisAssumptionsList(tempHypothesisList);
+ };
+ const checkScrollbar = () => {
+ if (contentRef.current) {
+ setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight);
+ }
+ };
+
+ useEffect(() => {
+ // Initial check
+ checkScrollbar();
+
+ // Check on resize
+ window.addEventListener("resize", checkScrollbar);
+
+ // Cleanup event listeners on component unmount
+ return () => {
+ window.removeEventListener("resize", checkScrollbar);
+ };
+ }, []);
+
+ useEffect(() => {
+ const content = contentRef.current;
+ content.addEventListener("scroll", checkScrollbar);
+
+ return () => {
+ content.removeEventListener("scroll", checkScrollbar);
+ };
+ }, [contentRef]);
+
+ return (
+
+
+ {tempHypothesisList
+ .filter((item) => item?.active)
+ ?.filter((item) => item.key !== "")
+ .map((item, index) => (
+
+
{t(item?.key)}
+
+ {/* Dropdown for boundaries */}
+
+ valueChangeHandler({ item, newValue: value?.target?.value }, setTempHypothesisList, boundarySelections, setToast, t)
+ }
+ disable={false}
+ />
+
+
+ ))}
+
+
+
+
+
+ );
+});
+
+export const BoundarySelection = memo(({ boundarySelections, setBoundarySelections, boundaryData, hierarchy, t }) => {
+ const [processedHierarchy, setProcessedHierarchy] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [changedBoundaryType, setChangedBoundaryType] = useState("");
+
+ // Filtering out dropdown values
+ useEffect(() => {
+ if (!boundaryData || !hierarchy) return;
+
+ const processedHierarchyTemp = fetchDropdownValues(
+ boundaryData,
+ processedHierarchy.length !== 0 ? processedHierarchy : hierarchy,
+ boundarySelections,
+ changedBoundaryType
+ );
+ setProcessedHierarchy(processedHierarchyTemp);
+ setIsLoading(false);
+ }, [boundaryData, hierarchy, boundarySelections]);
+
+ return (
+
+ {isLoading &&
}
+ {processedHierarchy?.map((item, index) => (
+
+ {t(item?.boundaryType)}
+ {item?.parentBoundaryType === null ? (
+ 5 ? { height: "13.75rem" } : {}}
+ type={"multiselectdropdown"}
+ t={t}
+ options={item?.dropDownOptions || []}
+ optionsKey="name"
+ addSelectAllCheck={true}
+ onSelect={(e) => {
+ setChangedBoundaryType(item?.boundaryType);
+ Digit.Utils.microplan.handleSelection(
+ e,
+ item?.boundaryType,
+ boundarySelections,
+ hierarchy,
+ setBoundarySelections,
+ boundaryData,
+ setIsLoading
+ );
+ }}
+ />
+ ) : (
+ 5 ? { height: "13.75rem" } : {}}
+ type={"multiselectdropdown"}
+ t={t}
+ options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []}
+ optionsKey="name"
+ addSelectAllCheck={true}
+ onSelect={(e) => {
+ setChangedBoundaryType(item?.boundaryType);
+ Digit.Utils.microplan.handleSelection(
+ e,
+ item?.boundaryType,
+ boundarySelections,
+ hierarchy,
+ setBoundarySelections,
+ boundaryData,
+ setIsLoading
+ );
+ }}
+ variant="nestedmultiselect"
+ />
+ )}
+
+ ))}
+
+ );
+});
+
+export const DataPreview = memo(
+ ({ previewData, isCampaignLoading, ishierarchyLoading, resources, userEditedResources, setUserEditedResources, modal, setModal, data, t }) => {
+ if (!previewData) return;
+ const [tempResourceChanges, setTempResourceChanges] = useState(userEditedResources);
+ const [selectedRow, setSelectedRow] = useState();
+ const conmmonColumnIndex = useMemo(() => {
+ return previewData?.[0]?.indexOf(commonColumn);
+ }, [previewData]);
+ if (isCampaignLoading || ishierarchyLoading) {
+ return (
+
+
+
+ );
+ }
+
+ const rowClick = useCallback((rowIndex) => {
+ setSelectedRow(rowIndex);
+ setModal("change-preview-data");
+ }, []);
+
+ const finaliseRowDataChange = () => {
+ setUserEditedResources(tempResourceChanges);
+ setModal("none");
+ setSelectedRow(undefined);
+ };
+
+ const modalCloseHandler = () => {
+ setModal("none");
+ setSelectedRow(undefined);
+ };
+
+ return (
+
+
+
+
+
+ {previewData[0].map((header, columnIndex) => (
+
+ {t(header)}
+ |
+ ))}
+
+
+
+ {previewData.slice(1).map((rowData, rowIndex) => {
+ const rowDataList = Object.values(previewData[0]).map((header, cellIndex) => (
+
+ {cellIndex === 0 &&
+ userEditedResources?.[rowData?.[conmmonColumnIndex]] &&
+ Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !== 0 && }
+
+ {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : t("NO_DATA")}
+ |
+ ));
+ return (
+ {
+ rowClick(rowIndex + 1);
+ }}
+ // style={{...(userEditedResources?.[rowData?.[conmmonColumnIndex]] && Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !==0
+ // ? { borderL: "1px solid rgba(244, 119, 56, 0.12)" }
+ // : {}),}}
+ >
+ {rowDataList}
+
+ );
+ })}
+
+
+
+ {modal === "change-preview-data" && (
+
+ }
+ headerBarEnd={}
+ actionCancelLabel={t("CANCLE")}
+ actionCancelOnSubmit={modalCloseHandler}
+ actionSaveLabel={t("SAVE_CHANGES")}
+ actionSaveOnSubmit={finaliseRowDataChange}
+ formId="modal-action"
+ >
+
+
+
+ )}
+
+ );
+ }
+);
+
+export const AppplyChangedHypothesisConfirmation = ({ newhypothesisList, hypothesisList, t }) => {
+ const data = filterObjects(newhypothesisList, hypothesisList);
+ return (
+
+
+
{t("INSTRUCTION_PROCEED_WITH_NEW_HYPOTHESIS")}
+
+
+ {t("MICROPLAN_PREVIEW_HYPOTHESIS")}
+
+
+
+
+
+ {t("KEYS")} |
+ {t("OLD_VALUE")} |
+ {t("NEW_VALUE")} |
+
+
+
+ {data?.map((row, index) => (
+
+ {t(row?.key)} |
+ {t(row?.oldValue)} |
+ {t(row?.value)} |
+
+ ))}
+
+
+
+
+ );
+};
+
+export const EditResourceData = ({ previewData, selectedRow, resources, tempResourceChanges, setTempResourceChanges, data, t }) => {
+ const conmmonColumnData = useMemo(() => {
+ const index = previewData?.[0]?.indexOf(commonColumn);
+ if (index === -1) return;
+ return previewData?.[selectedRow]?.[index];
+ }, [previewData]);
+
+ const valueChangeHandler = (item, value) => {
+ if (!conmmonColumnData) return;
+ if (isNaN(value) || (!isFinite(value) && value !== "")) return;
+ let changedDataAgainstBoundaryCode = tempResourceChanges?.[conmmonColumnData] || {};
+ changedDataAgainstBoundaryCode[item] = value === "" ? undefined : parseFloat(value);
+ setTempResourceChanges((previous) => ({ ...previous, [conmmonColumnData]: changedDataAgainstBoundaryCode }));
+ };
+
+ return (
+
+
+
+
+ {t("COLUMNS")} |
+ {t("OLD_VALUE")} |
+ {t("NEW_VALUE")} |
+
+
+
+ {data[0].map((item) => {
+ let index = data?.[0]?.indexOf(item);
+ if (index === -1) return;
+ const currentData = data?.[selectedRow]?.[index];
+ return (
+
+
+ {t(item)}
+ |
+
+ {currentData || t("NO_DATA")}
+ |
+
+
+ |
+
+ );
+ })}
+ {resources.map((item) => {
+ let index = previewData?.[0]?.indexOf(item);
+ if (index === -1) return;
+ const currentData = previewData?.[selectedRow]?.[index];
+
+ return (
+
+
+ {t(item)}
+ |
+
+ {currentData || t("NO_DATA")}
+ |
+
+ valueChangeHandler(item, value.target.value)}
+ />
+ |
+
+ );
+ })}
+
+
+
+ );
+};
+
+export const Aggregates = memo(({ microplanPreviewAggregates, dataToShow, NumberFormatMappingForTranslation, t }) => {
+ const { formatNumber } = useNumberFormatter(NumberFormatMappingForTranslation?.reduce((acc, obj) => Object.assign(acc, obj), {}));
+
+ if (!microplanPreviewAggregates) return null;
+ return (
+
+ {microplanPreviewAggregates.map((item, index) => {
+ const aggregate = calculateAggregateValue(item, dataToShow);
+ return (
+
+
{isNaN(parseInt(aggregate)) ? 0 : formatNumber(parseInt(aggregate))}
+
{typeof item === "object" && item.name ? t(item.name) : t(item)}
+
+ );
+ })}
+
+ );
+});
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js
new file mode 100644
index 00000000000..9a1dd8f5500
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js
@@ -0,0 +1,34 @@
+import { EmployeeModuleCard, WorksMgmtIcon } from "@egovernments/digit-ui-react-components";
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+const ROLES = {
+ MICROPLAN: ["MICROPLAN_ADMIN"],
+};
+
+const MicroplanningCard = () => {
+ const { t } = useTranslation();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ const generateLink = (labelKey, pathSuffix) => {
+ return {
+ label: t(labelKey),
+ link: `/${window?.contextPath}/employee/microplanning/${pathSuffix}`,
+ roles: ROLES.MICROPLAN,
+ };
+ };
+
+ let links = [generateLink("CREATE_NEW_MICROPLAN", "select-campaign"), generateLink("OPEN_SAVED_MICROPLANS", "saved-microplans")];
+
+ links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true));
+
+ const propsForModuleCard = {
+ Icon: ,
+ moduleName: t("Microplanning"),
+ kpis: [],
+ links: links,
+ };
+ return ;
+};
+
+export default MicroplanningCard;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js
new file mode 100644
index 00000000000..2a35e9c0995
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js
@@ -0,0 +1,29 @@
+import { Help, Tutorial, useTourState } from "@egovernments/digit-ui-react-components";
+import React, { Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import { useLocation } from "react-router-dom";
+import { useMyContext } from "../utils/context";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+
+const MicroplanningHeader = () => {
+ const { tourState, setTourState } = useTourState();
+ const { state } = useMyContext();
+ const { t } = useTranslation();
+ //using location.pathname we can update the stepIndex accordingly when help is clicked from any other screen(other than home screen)
+ const { pathname } = useLocation();
+
+ const startTour = () => {
+ if (state?.tourStateData) setTourState(state.tourStateData);
+ };
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
+
+export default MicroplanningHeader;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js
new file mode 100644
index 00000000000..0792ee2e52d
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js
@@ -0,0 +1,158 @@
+import React, { useEffect } from "react";
+import { PopUp, HeaderBar, Toast, CloseButton, ButtonSelector } from "@egovernments/digit-ui-react-components";
+import { Close } from "@egovernments/digit-ui-svg-components";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+
+const Modal = ({
+ headerBarMain,
+ headerBarEnd,
+ popupStyles,
+ children = {},
+ actionCancelLabel,
+ actionCancelOnSubmit,
+ actionSaveLabel,
+ actionSaveOnSubmit,
+ error,
+ setError,
+ formId,
+ isDisabled,
+ hideSubmit,
+ style = {},
+ footerLeftButtonstyle = {},
+ footerRightButtonstyle = {},
+ footerLeftButtonBody,
+ footerRightButtonBody,
+ popupModuleMianStyles,
+ headerBarMainStyle,
+ isOBPSFlow = false,
+ popupModuleActionBarStyles = {},
+}) => {
+ /**
+ * TODO: It needs to be done from the desgin changes
+ */
+ const mobileView = Digit.Utils.browser.isMobile();
+ useEffect(() => {
+ document.body.style.overflowY = "hidden";
+ return () => {
+ document.body.style.overflowY = "auto";
+ };
+ }, []);
+
+ return (
+
+
+
+
+ {children}
+
+ {actionCancelLabel || footerLeftButtonBody ? (
+ 0 ? style : footerLeftButtonstyle}
+ />
+ ) : null}
+ {!hideSubmit ? (
+ 0 ? style : footerRightButtonstyle}
+ />
+ ) : null}
+
+
+
+ {error && setError(null)} type="error" />}
+
+ );
+};
+
+const moduleActionBarStyle = (isOBPSFlow, popupModuleActionBarStyles) => {
+ return isOBPSFlow
+ ? !mobileView
+ ? { marginRight: "18px" }
+ : { position: "absolute", bottom: "5%", right: "10%", left: window.location.href.includes("employee") ? "0%" : "7%" }
+ : popupModuleActionBarStyles;
+};
+
+// Wrapper for modal
+export const ModalWrapper = ({
+ closeModal,
+ LeftButtonHandler,
+ RightButtonHandler,
+ footerLeftButtonBody,
+ footerRightButtonBody,
+ header,
+ bodyText,
+ body,
+ popupStyles,
+ headerBarMainStyle,
+ popupModuleActionBarStyles,
+ hideSubmit,
+ closeButton = false,
+ actionCancelLabel,
+}) => {
+ return (
+
+ {" "}
+
+
+ ) : (
+ ""
+ )
+ }
+ actionCancelOnSubmit={LeftButtonHandler}
+ actionSaveOnSubmit={RightButtonHandler}
+ formId="microplanning"
+ popupStyles={{ width: "33.375rem", borderRadius: "0.25rem", ...(popupStyles ? popupStyles : {}) }}
+ headerBarMainStyle={{ margin: 0, width: "33.375rem", overflow: "hidden", ...(headerBarMainStyle ? headerBarMainStyle : {}) }}
+ popupModuleMianStyles={{ margin: 0, padding: 0 }}
+ popupModuleActionBarStyles={popupModuleActionBarStyles ? popupModuleActionBarStyles : { justifyContent: "space-between", padding: "1rem" }}
+ style={{}}
+ hideSubmit={hideSubmit ? hideSubmit : false}
+ footerLeftButtonstyle={{
+ padding: 0,
+ alignSelf: "flex-start",
+ height: "fit-content",
+ textStyles: { fontWeight: "600" },
+ backgroundColor: "rgba(255, 255, 255, 1)",
+ color: PRIMARY_THEME_COLOR,
+ minWidth: "15.063rem",
+ border: `0.063rem solid ${PRIMARY_THEME_COLOR}`,
+ }}
+ footerRightButtonstyle={{
+ padding: 0,
+ alignSelf: "flex-end",
+ height: "fit-content",
+ textStyles: { fontWeight: "500" },
+ backgroundColor: PRIMARY_THEME_COLOR,
+ color: "rgba(255, 255, 255, 1)",
+ minWidth: "15.063rem",
+ boxShadow: "0px -2px 0px 0px rgba(11, 12, 12, 1) inset",
+ }}
+ footerLeftButtonBody={footerLeftButtonBody}
+ footerRightButtonBody={footerRightButtonBody}
+ actionCancelLabel={actionCancelLabel}
+ >
+ {bodyText && (
+
+ )}
+ {body ? body : ""}
+
+ );
+};
+
+export default Modal;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js
new file mode 100644
index 00000000000..b896f7537e4
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js
@@ -0,0 +1,307 @@
+import { ActionBar, Stepper, Toast } from "@egovernments/digit-ui-components";
+import PropTypes from "prop-types";
+import React, { useState, useEffect, useCallback } from "react";
+import { useTranslation } from "react-i18next";
+import { Button } from "@egovernments/digit-ui-react-components";
+import { ArrowBack, ArrowForward } from "@egovernments/digit-ui-svg-components";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+import { memo } from "react";
+
+/**
+ *
+ * @param { config: Object, checkDataCompleteness: boolean, components: Object, childProps: Object, stepNavigationActive: boolean, nextEventAddon: function, setCurrentPageExternally: function, completeNavigation } props
+ * @returns
+ *
+ */
+// Main component for creating a microplan
+const Navigator = memo((props) => {
+ // States
+ const [currentPage, setCurrentPage] = useState();
+ // const [toast, setToast] = useState();
+ const [navigationEvent, setNavigationEvent] = useState();
+ const [activeSteps, setActiveSteps] = useState(Digit.SessionStorage.get("microplanHelperData")?.activeSteps || -1);
+ /**
+ * checkDataCompletion
+ * "true": check for data completeness
+ * "false": do nothing
+ * "valid": data is present
+ * "invalid": whole or a part of the data is missing
+ * "perform-action": move to the respective step ( had to add this as mutate addons need some buffer time)
+ */
+ const [checkDataCompletion, setCheckDataCompletion] = useState("false");
+
+ const { t } = useTranslation();
+
+ // Effect to set initial current page when timeline options change
+ useEffect(() => {
+ if (!props.config || props.config.length === 0) return;
+ let response;
+ if (props.setCurrentPageExternally) {
+ response = props.setCurrentPageExternally({ setCurrentPage, method: "set" });
+ }
+ if (!response) setCurrentPage(props.config[0]);
+ }, [props.config]);
+
+ // Might need it later
+ // Effect to handle data completion validation and show toast
+ useEffect(() => {
+ if (checkDataCompletion === "invalid") {
+ if (navigationEvent && navigationEvent.name === "next") {
+ props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") });
+ } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) {
+ if (navigationEvent.step > currentPage.id)
+ props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") });
+ else onStepClick(navigationEvent.step);
+ } else if (navigationEvent && navigationEvent.name === "previousStep") previousStep();
+ setCheckDataCompletion("false");
+ }
+ }, [checkDataCompletion]);
+
+ const checkStatusTillPageToNavigate = (status) => {
+ let check = true;
+ if (navigationEvent?.step) {
+ const navigateTo = props.config?.[navigationEvent?.step]?.name;
+ for (const item of props.config) {
+ if (item.name === navigateTo) break;
+ check = check && status[item.name];
+ }
+ }
+ return check;
+ };
+
+ // Effect to handle navigation events and transition between steps
+ useEffect(() => {
+ // if (checkDataCompletion !== "valid" || navigationEvent === undefined) return;
+ if (
+ checkDataCompletion === "valid" &&
+ ((navigationEvent.step && navigationEvent.step <= activeSteps + 1) || !navigationEvent.step) &&
+ (!props?.status || checkStatusTillPageToNavigate(props?.status) || navigationEvent.step === currentPage.id + 1)
+ ) {
+ if (typeof props.nextEventAddon === "function") {
+ if (LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null)
+ props.nextEventAddon(currentPage, checkDataCompletion, setCheckDataCompletion);
+ else props.nextEventAddon(currentPage, true, setCheckDataCompletion);
+ } else {
+ setCheckDataCompletion("perform-action");
+ }
+ }
+ }, [navigationEvent, checkDataCompletion, props.nextEventAddon]);
+
+ useEffect(() => {
+ handleNavigationEvent(
+ checkDataCompletion,
+ navigationEvent,
+ currentPage,
+ setCheckDataCompletion,
+ setNavigationEvent,
+ onStepClick,
+ nextStep,
+ previousStep,
+ props
+ );
+ }, [checkDataCompletion, navigationEvent]);
+
+ // Function to navigate to the next step
+ const nextStep = useCallback(() => {
+ if (!currentPage) return;
+ changeCurrentPage(props.config[currentPage?.id + 1]);
+ if (currentPage?.id + 1 > props.config.length - 1) return;
+ setCurrentPage((previous) => props.config[previous?.id + 1]);
+ }, [currentPage]);
+
+ // Function to navigate to the previous step
+ const previousStep = useCallback(() => {
+ changeCurrentPage(props.config[currentPage?.id - 1]);
+ setCurrentPage((previous) => props.config[previous?.id - 1]);
+ }, [currentPage]);
+
+ // Function to handle step click and navigate to the selected step
+ const onStepClick = useCallback((index) => {
+ const newCurrentPage = props.config.find((item) => item.id === index);
+ changeCurrentPage(newCurrentPage);
+ setCurrentPage(newCurrentPage);
+ });
+
+ // Function to handle next button click
+ const previousbuttonClickHandler = useCallback(() => {
+ if (
+ (props.checkDataCompleteness &&
+ props?.config[currentPage?.id]?.checkForCompleteness &&
+ LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) ||
+ currentPage?.id === props.config[props.config.length - 1].id
+ ) {
+ setNavigationEvent({ name: "previousStep" });
+ setCheckDataCompletion("true");
+ } else {
+ if (typeof props?.setMicroplanData === "function") {
+ props?.setMicroplanData((previous) => ({
+ ...previous,
+ status: { ...previous?.status, [currentPage?.name]: true },
+ }));
+ }
+ previousStep();
+ }
+ }, [props.checkDataCompleteness, previousStep, setNavigationEvent]);
+
+ // Function to handle next button click
+ const nextbuttonClickHandler = useCallback(() => {
+ if (
+ props.checkDataCompleteness &&
+ props?.config[currentPage?.id]?.checkForCompleteness &&
+ LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null
+ ) {
+ setCheckDataCompletion("true");
+ setNavigationEvent({ name: "next" });
+ } else {
+ if (typeof props?.setMicroplanData === "function") {
+ props?.setMicroplanData((previous) => ({
+ ...previous,
+ status: { ...previous?.status, [currentPage?.name]: true },
+ }));
+ }
+ nextStep();
+ }
+ }, [props.checkDataCompleteness, nextStep, setNavigationEvent]);
+
+ // Function to handle step click
+ const stepClickHandler = useCallback(
+ (index) => {
+ if (index === currentPage?.id) return;
+ if (!props.stepNavigationActive) return;
+ if (
+ (props.checkDataCompleteness &&
+ props?.config[currentPage?.id]?.checkForCompleteness &&
+ LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) ||
+ currentPage?.id === props.config[props.config.length - 1].id
+ ) {
+ setCheckDataCompletion("true");
+ setNavigationEvent({ name: "step", step: index });
+ } else {
+ if (typeof props?.setMicroplanData === "function") {
+ props?.setMicroplanData((previous) => ({
+ ...previous,
+ status: { ...previous?.status, [currentPage?.name]: true },
+ }));
+ }
+ onStepClick(index);
+ }
+ },
+ [props.checkDataCompleteness, props.stepNavigationActive, onStepClick]
+ );
+
+ // Function to set current page
+ const changeCurrentPage = (newPage) => {
+ if (props.setCurrentPageExternally) {
+ props.setCurrentPageExternally({ currentPage: newPage, method: "save" });
+ }
+ };
+
+ const completeNavigation = () => {
+ setNavigationEvent({ name: "next" });
+ setCheckDataCompletion("true");
+ };
+
+ // changing active state
+ useEffect(() => {
+ if (currentPage?.id > activeSteps) {
+ setActiveSteps(currentPage?.id);
+ Digit.SessionStorage.set("microplanHelperData", { ...(Digit.SessionStorage.get("microplanHelperData") || {}), activeSteps: currentPage?.id });
+ }
+ }, [currentPage]);
+
+ return (
+
+ {/* Stepper component */}
+
t(item.name))}
+ direction="horizontal"
+ activeSteps={activeSteps >= 0 ? activeSteps + 1 : null}
+ onStepClick={stepClickHandler}
+ />
+
+ {/* Load custom component based on current page */}
+ {props?.components[currentPage?.component] ? (
+ LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null ? (
+
+ ) : (
+ {t("COMMON_DATA_NOT_PRESENT")}
+ )
+ ) : (
+ ""
+ )}
+
+ {/* Action bar */}
+
+ {/* Back button */}
+ {currentPage?.id > 0 && (
+ }
+ />
+ )}
+ {/* Next/Submit button */}
+
+
+
+
+
+ );
+});
+
+// Component to load custom component based on current page
+const LoadCustomComponent = (props) => {
+ if (props && !props.component) return null;
+ const secondaryProps = props.secondaryProps;
+ return ;
+};
+LoadCustomComponent.propTypes = {
+ component: PropTypes.elementType.isRequired,
+ secondaryProps: PropTypes.object,
+};
+
+const handleNavigationEvent = (
+ checkDataCompletion,
+ navigationEvent,
+ currentPage,
+ setCheckDataCompletion,
+ setNavigationEvent,
+ onStepClick,
+ nextStep,
+ previousStep,
+ props
+) => {
+ if (checkDataCompletion === "perform-action") {
+ if (navigationEvent && navigationEvent.name === "next") {
+ if (currentPage?.id === props.config.length - 1 && typeof props?.completeNavigation === "function") {
+ return props?.completeNavigation();
+ }
+ nextStep();
+ } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) onStepClick(navigationEvent.step);
+ else if (navigationEvent && navigationEvent.name === "previousStep") previousStep();
+ setCheckDataCompletion("false");
+ setNavigationEvent(undefined);
+ }
+};
+
+export default Navigator;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js
new file mode 100644
index 00000000000..c1ad8e38860
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js
@@ -0,0 +1,875 @@
+import React, { useState, useEffect, useCallback, Fragment, useRef } from "react";
+import { useTranslation } from "react-i18next";
+import { Info, Trash } from "@egovernments/digit-ui-svg-components";
+import { ModalHeading } from "./CommonComponents";
+import { Button, Modal } from "@egovernments/digit-ui-react-components";
+import { Dropdown, InfoCard, Toast } from "@egovernments/digit-ui-components";
+import { tourSteps } from "../configs/tourSteps";
+import { useMyContext } from "../utils/context";
+import { v4 as uuidv4 } from "uuid";
+import { PlusWithSurroundingCircle } from "../icons/Svg";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+
+const page = "ruleEngine";
+
+const RuleEngine = ({
+ campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType,
+ microplanData,
+ setMicroplanData,
+ checkDataCompletion,
+ setCheckDataCompletion,
+ currentPage,
+ pages,
+ setToast,
+}) => {
+ const { t } = useTranslation();
+
+ // States
+ const [editable, setEditable] = useState(true);
+ const [modal, setModalState] = useState("none");
+ const [rules, setRules] = useState([]);
+ const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]);
+ const [itemForDeletion, setItemForDeletion] = useState();
+ const [exampleOption, setExampleOption] = useState("");
+ const [inputs, setInputs] = useState([]);
+ const [outputs, setOutputs] = useState([]);
+ const [operators, setOperators] = useState([]);
+ const [validationSchemas, setValidationSchemas] = useState([]);
+ const [autofillData, setAutoFillData] = useState([]);
+ const { state, dispatch } = useMyContext();
+ const [originalRuleOutputCount, setOriginalRuleOutputCount] = useState(0);
+ // const [toast, setToast] = useState();
+ const [pureInputList, setPureInputList] = useState([]);
+ // Set TourSteps
+ useEffect(() => {
+ const tourData = tourSteps(t)?.[page] || {};
+ if (state?.tourStateData?.name === page) return;
+ dispatch({
+ type: "SETINITDATA",
+ state: { tourStateData: tourData },
+ });
+ }, []);
+
+ const setModal = (modalString) => {
+ const elements = document.querySelectorAll(".popup-wrap-rest-unfocus");
+ elements.forEach((element) => {
+ element.classList.toggle("popup-wrap-rest-unfocus-active");
+ });
+ setModalState(modalString);
+ };
+
+ // UseEffect to extract data on first render
+ useEffect(() => {
+ if (pages) {
+ const previouspage = pages[currentPage?.id - 1];
+ if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false);
+ else setEditable(true);
+ }
+ }, []);
+
+ // UseEffect for checking completeness of data before moveing to next section
+ useEffect(() => {
+ if (!rules || checkDataCompletion !== "true" || !setCheckDataCompletion) return;
+ // uncomment to activate data change save check
+ // if (!microplanData?.ruleEngine || !_.isEqual(rules, microplanData.ruleEngine)) setModal("data-change-check");
+ // else
+ updateData(true);
+ }, [checkDataCompletion]);
+
+ // UseEffect to store current data
+ useEffect(() => {
+ if (!rules || !setMicroplanData) return;
+ setMicroplanData((previous) => ({ ...previous, ruleEngine: rules }));
+ }, [rules]);
+
+ // UseEffect to add a event listener for keyboard
+ useEffect(() => {
+ window.addEventListener("keydown", handleKeyPress);
+
+ return () => window.removeEventListener("keydown", handleKeyPress);
+ }, [modal]);
+
+ const handleKeyPress = (event) => {
+ // if (modal !== "upload-guidelines") return;
+ if (["x", "Escape"].includes(event.key)) {
+ // Perform the desired action when "x" or "esc" is pressed
+ // if (modal === "upload-guidelines")
+ setCheckDataCompletion("false");
+ setModal("none");
+ }
+ };
+
+ // check if data has changed or not
+ const updateData = useCallback(
+ (check) => {
+ if (!rules || !setMicroplanData) return;
+ if (check) {
+ setMicroplanData((previous) => ({ ...previous, ruleEngine: rules }));
+ const activeRules = rules.filter((item) => item.active);
+ const isValid = activeRules.every((item) => Object.values(item).every((data) => data !== "")) && activeRules.length !== 0;
+ if (isValid) setCheckDataCompletion("valid");
+ else setCheckDataCompletion("invalid");
+ } else {
+ let isValid = microplanData?.ruleEngine?.every((item) => Object.values(item).every((data) => data !== ""));
+ isValid = isValid && rules.length !== 0;
+ if (isValid) setCheckDataCompletion("valid");
+ else setCheckDataCompletion("invalid");
+ }
+ },
+ [rules, setMicroplanData, microplanData, setCheckDataCompletion]
+ );
+
+ const cancelUpdateData = useCallback(() => {
+ setCheckDataCompletion(false);
+ setModal("none");
+ }, [setCheckDataCompletion, setModal]);
+
+ // useEffect to initialise the data from MDMS
+ useEffect(() => {
+ if (!state) return;
+ const schemas = state?.Schemas;
+ const hypothesisAssumptions = [];
+ microplanData?.hypothesis?.filter((item) => item.active).forEach((item) => (item.key !== "" ? hypothesisAssumptions.push(item.key) : null));
+ const ruleConfigureOutput = state?.RuleConfigureOutput;
+ const ruleConfigureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas) || [];
+ let AutoFilledRuleConfigurationsList = state?.AutoFilledRuleConfigurations;
+ AutoFilledRuleConfigurationsList = AutoFilledRuleConfigurationsList.find((item) => item.campaignType === campaignType)?.data;
+ microplanData?.ruleEngine?.forEach((item) => {
+ if (Object.values(item).every((e) => e !== "")) ruleConfigureInputs.push(item?.output);
+ });
+ if (schemas) setValidationSchemas(schemas);
+
+ let temp;
+ setHypothesisAssumptionsList(hypothesisAssumptions);
+ let outputs;
+ if (ruleConfigureOutput) temp = ruleConfigureOutput?.find((item) => item.campaignType === campaignType);
+ if (temp?.data) {
+ let data = temp.data;
+ setOriginalRuleOutputCount(data.length);
+ microplanData?.ruleEngine?.forEach((item) => {
+ if (item.active) {
+ const filteredData = data.filter((e) => e !== item?.output);
+ data = filteredData;
+ }
+ });
+ outputs = data;
+ setOutputs(data);
+ }
+
+ if (ruleConfigureInputs) setInputs(ruleConfigureInputs);
+ let operator;
+ temp = state?.RuleConfigureOperators;
+ if (temp) {
+ temp = temp.map((item) => item.name);
+ operator = temp;
+ setOperators(temp);
+ }
+ // if (AutoFilledRuleConfigurationsList) setAutoFillData(AutoFilledRuleConfigurationsList);
+ // Pure inputs - output not there
+ const pureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas);
+ setPureInputList(pureInputs);
+
+ const ssnRuleOutputs = microplanData?.ruleEngine?.reduce((acc, item) => {
+ if (item?.active && item?.output) acc.push(item?.output);
+ return acc;
+ }, []);
+ const tempOutput = [...outputs, ...(ssnRuleOutputs ? ssnRuleOutputs : [])];
+ setExampleOption({
+ output: tempOutput?.length ? tempOutput[0] : "",
+ input: pureInputs?.length ? pureInputs[0] : "",
+ operator: operator?.length ? operator[0] : "",
+ assumptionValue: hypothesisAssumptions?.length ? hypothesisAssumptions[0] : "",
+ });
+
+ let filteredRules = [];
+ let response;
+ if (microplanData?.ruleEngine && microplanData?.hypothesis) {
+ const hypothesisAssumptions = microplanData?.hypothesis?.filter((item) => item.active && item.key !== "").map((item) => item.key) || [];
+ if (hypothesisAssumptions.length !== 0) {
+ setHypothesisAssumptionsList(hypothesisAssumptions);
+ response = filterRulesAsPerConstrains(
+ microplanData.ruleEngine,
+ [],
+ hypothesisAssumptions,
+ tempOutput,
+ operator,
+ pureInputs,
+ setInputs,
+ setOutputs,
+ false
+ );
+ filteredRules = response?.rules;
+
+ // setRuleEngineDataFromSsn(microplanData.ruleEngine, hypothesisAssumptions, setRules);
+ }
+ }
+ if (response?.rulesDeleted)
+ setToast({
+ state: "warning",
+ message: t("WARNING_RULES_DELETED_DUE_TO_PRIOR_SECTION_DATA_CHANGES"),
+ });
+ if (!AutoFilledRuleConfigurationsList || !outputs || !hypothesisAssumptions || !schemas) return;
+
+ response = filterRulesAsPerConstrains(
+ AutoFilledRuleConfigurationsList,
+ filteredRules,
+ hypothesisAssumptions,
+ outputs,
+ operator,
+ pureInputs,
+ setInputs,
+ setOutputs,
+ true
+ );
+
+ if (response?.rules) setRules(response?.rules);
+ }, []);
+
+ const closeModal = useCallback(() => {
+ setModal("none");
+ }, [setModal]);
+
+ // Function to Delete an assumption
+ const deleteAssumptionHandlerCallback = useCallback(() => {
+ deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList);
+ closeModal();
+ }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setRules, setOutputs, setInputs, closeModal, pureInputList]);
+
+ const sectionClass = `jk-header-btn-wrapper rule-engine-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus`;
+ return (
+ <>
+
+
+
+ {/* NonInterractable Section */}
+
+ {/* Interractable Section that includes the example as well as the rules */}
+
+
+
+
}
+ className="add-button"
+ onButtonClick={() => addRulesHandler(setRules)}
+ label={t("ADD_ROW")}
+ isDisabled={rules?.filter((item) => item.active)?.length === originalRuleOutputCount}
+ />
+
+
+ {/* delete conformation */}
+
+ {modal === "delete-conformation" && (
+
}
+ actionCancelLabel={t("YES")}
+ actionCancelOnSubmit={deleteAssumptionHandlerCallback}
+ actionSaveLabel={t("NO")}
+ actionSaveOnSubmit={closeModal}
+ >
+
+
{t("RULE_ENGINE_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}
+
+
+ )}
+
+ >
+ );
+};
+
+// Function to add a new assumption
+const addRulesHandler = (setRules) => {
+ const uuid = uuidv4();
+ setRules((previous) => [
+ ...previous,
+ {
+ id: uuid,
+ // previous.length ? previous[previous.length - 1].id + 1 : 0,
+ output: "",
+ input: "",
+ operator: "",
+ assumptionValue: "",
+ active: true,
+ },
+ ]);
+};
+
+// Defination for NonInterractable Section
+const NonInterractableSection = React.memo(({ t }) => {
+ return (
+
+
{t("HEADING_RULE_ENGINE")}
+
{t("INSTRUCTION_RULE_ENGINE")}
+
+ );
+});
+
+// Defination for NonInterractable Section
+const InterractableSection = React.memo(
+ ({
+ rules,
+ setRules,
+ hypothesisAssumptionsList,
+ setHypothesisAssumptionsList,
+ setModal,
+ setItemForDeletion,
+ exampleOption,
+ inputs,
+ outputs,
+ operators,
+ setInputs,
+ setOutputs,
+ setOperators,
+ pureInputList,
+ t,
+ }) => {
+ // References to the items in the list
+ const itemRefs = useRef([]);
+ // State to keep track of the currently expanded item index
+ const [expandedIndex, setExpandedIndex] = useState(null);
+ // Reference to the scroll container
+ const scrollContainerRef = useRef(null);
+ // State to track the render cycle count
+ const [renderCycle, setRenderCycle] = useState(0);
+
+ // Effect to reset the render cycle count whenever the expandedIndex changes
+ useEffect(() => {
+ if (expandedIndex !== null) {
+ setRenderCycle(0);
+ }
+ }, [expandedIndex]);
+
+ // Effect to handle scrolling to the expanded item after the DOM has updated
+ useEffect(() => {
+ if (renderCycle < 3) {
+ // Increment render cycle count to ensure multiple render checks
+ setRenderCycle((prev) => prev + 1);
+ } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) {
+ try {
+ const parentElement = itemRefs.current[expandedIndex];
+ const childElement = itemRefs.current[expandedIndex].children[1];
+
+ if (parentElement) {
+ const scrollContainer = scrollContainerRef.current;
+ const parentRect = parentElement.getBoundingClientRect();
+ const containerRect = scrollContainer.getBoundingClientRect();
+
+ // Calculate the offset from the top of the container
+ const offset = parentRect.top - containerRect.top;
+
+ // Scroll the container to the target position
+ scrollContainer.scrollTo({
+ top: scrollContainer.scrollTop + offset - 100,
+ behavior: "smooth",
+ });
+ }
+
+ if (childElement) {
+ // Focus the child element if it exists
+ childElement.focus();
+ }
+ } catch (error) {
+ console.error("Error scrolling to element:", error);
+ }
+ }
+ }, [renderCycle, expandedIndex]);
+
+ // Effect to observe DOM changes in the expanded item and trigger render cycle
+ useEffect(() => {
+ if (expandedIndex !== null) {
+ const observer = new MutationObserver(() => {
+ setRenderCycle((prev) => prev + 1);
+ });
+
+ if (itemRefs.current[expandedIndex]) {
+ observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true });
+ }
+
+ return () => observer.disconnect();
+ }
+ }, [expandedIndex]);
+
+ // Function to toggle the expanded state of an item
+ const toggleExpand = (index) => {
+ setExpandedIndex(index === expandedIndex ? null : index);
+ };
+
+ // Handler for deleting an assumption on conformation
+ const deleteHandler = useCallback(
+ (item) => {
+ setModal("delete-conformation");
+ setItemForDeletion(item);
+ },
+ [setModal, setItemForDeletion]
+ );
+
+ return (
+
+
+
+
+
+
=
+
+
{t("RULE_ENGINE_INPUT")}
+
+
+
{t("RULE_ENGINE_OPERATOR")}
+
+
+
+
deleteHandler(item)} aria-label={t("DELETE")} role="button" type="button">
+ {Trash && }
+ {t("DELETE")}
+
+
+
+ {rules
+ .filter((item) => item.active)
+ .map((item, index) => (
+
{
+ itemRefs.current[index] = el;
+ }}
+ onClick={() => toggleExpand(index)}
+ >
+
+
+
+
+
=
+
+
+
+
+
+
+
+
+
+
+
+
deleteHandler(item)}
+ onKeyDown={(e) => e.key === "Enter" && deleteHandler(item)}
+ aria-label={t("DELETE")}
+ role="button"
+ type="button"
+ >
+ {Trash && }
+ {t("DELETE")}
+
+
+
+ ))}
+
+
+ );
+ }
+);
+
+const Example = ({ exampleOption, t }) => {
+ return (
+
+
+
{t("EXAMPLE")}
+
+
+
{t("VALUE")}
+
+
{t("RULE_ENGINE_VALUE_HELP_TEXT")}
+
+
+
+
+
+
{t("RULE_ENGINE_INPUT")}
+
+
{t("RULE_ENGINE_INPUT_HELP_TEXT")}
+
+
+
{t("RULE_ENGINE_OPERATOR")}
+
+
{t("RULE_ENGINE_OPERATOR_HELP_TEXT")}
+
+
+
{t("KEY")}
+
+
{t("RULE_ENGINE_KEY_HELP_TEXT")}
+
+
+
+
+
+ {Trash && }
+ {t("DELETE")}
+
+
+
+ );
+};
+
+const deleteAssumptionHandler = (item, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList) => {
+ try {
+ const outputToRemove = [];
+ setRules((previous) => {
+ if (!previous.length) return [];
+ const deletionElementIndex = previous.findIndex((data) => data.id === item.id);
+ const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data));
+ const newRules = filteredData.reduce((acc, dataItem, index) => {
+ if (dataItem.active) {
+ const possibleOutputs = acc.reduce((reducedData, element, index) => {
+ if (element.active && !Object.values(element).some((e) => e === "")) reducedData.push(element?.output);
+ return reducedData;
+ }, []);
+ possibleOutputs.push(...pureInputList);
+ if (!possibleOutputs.includes(dataItem?.input)) {
+ if (dataItem?.output !== "") outputToRemove.push(dataItem.output);
+ acc.push({ ...dataItem, input: "", oldInput: dataItem?.input ? dataItem?.input : dataItem?.oldInput });
+ } else {
+ acc.push(dataItem);
+ }
+ } else {
+ acc.push(dataItem);
+ }
+ return acc;
+ }, []);
+
+ return newRules || [];
+ });
+ if (item?.output) {
+ setOutputs((previous) => {
+ if (!previous?.includes(item.output)) return previous ? [...previous, item.output] : [item.output];
+ });
+ setInputs((previous) => {
+ return previous?.filter((e) => e !== item.output && !outputToRemove.includes(e));
+ });
+ }
+ setItemForDeletion();
+ } catch (error) {
+ console.error("Error while deleting a rule: ", error.message);
+ }
+};
+
+const Select = React.memo(
+ ({ item, rules, setRules, disabled = false, options, setOptions, toChange, unique, setInputs, outputs, pureInputList, t }) => {
+ const [selected, setSelected] = useState("");
+ const [filteredOptions, setFilteredOptions] = useState([]);
+
+ useEffect(() => {
+ if (item) {
+ if (outputs?.some((e) => e === item.input)) {
+ if (rules.filter((item) => item.active).some((e) => e?.output === item?.input)) setSelected({ code: item?.[toChange] });
+ } else setSelected({ code: item[toChange] });
+ }
+ }, [item]);
+
+ useEffect(() => {
+ if (!options) return;
+ const filteredOptions = options.length ? options : [];
+ let filteredOptionPlaceHolder = [];
+ if (item?.[toChange] && !filteredOptions.includes(item[toChange])) {
+ filteredOptionPlaceHolder = [item[toChange], ...filteredOptions];
+ } else filteredOptionPlaceHolder = filteredOptions;
+
+ if (toChange === "input") {
+ const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id);
+ filteredOptionPlaceHolder = filteredOptionPlaceHolder.filter((data) => {
+ let priorOutputs = [];
+ if (currentRuleIndex !== -1) {
+ priorOutputs = rules.reduce((acc, item, index) => {
+ if (item.active && index < currentRuleIndex) acc.push(item?.output);
+ return acc;
+ }, []);
+ }
+ priorOutputs.push(...pureInputList);
+ return data !== item.output && priorOutputs.includes(data);
+ });
+ }
+ setFilteredOptions(filteredOptionPlaceHolder);
+ }, [options]);
+
+ const selectChangeHandler = useCallback(
+ (e) => {
+ if (e.code === "SELECT_OPTION") return;
+ const existingEntry = rules.find((item) => item.active && item[toChange] === e.code);
+ if (existingEntry && unique) {
+ console.error("Attempted to add a duplicate entry where uniqueness is required.");
+ return;
+ }
+ const newDataSegment = { ...item };
+ newDataSegment[toChange] = e.code;
+ setRules((previous) => {
+ const filteredAssumptionsList = previous.map((data) => {
+ if (data.id === item.id) return newDataSegment;
+ return data;
+ });
+ return filteredAssumptionsList;
+ });
+ if (typeof setInputs === "function") {
+ setInputs((previous) => {
+ let temp = _.cloneDeep(previous);
+ if (toChange === "output") {
+ temp = temp.filter((item) => item !== selected?.code);
+ }
+ if (!temp.includes(newDataSegment.output) && Object.values(newDataSegment).every((item) => item !== ""))
+ temp = [...temp, newDataSegment.output];
+
+ const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id);
+ temp = temp.filter((data) => {
+ let priorOutputs = [];
+ if (currentRuleIndex !== -1) {
+ priorOutputs = rules.reduce((acc, item, index) => {
+ if (index < currentRuleIndex) acc.push(item?.output);
+ return acc;
+ }, []);
+ }
+ priorOutputs.push(...pureInputList);
+ return data !== item.output && priorOutputs.includes(data);
+ });
+ return temp;
+ });
+ }
+ if (unique)
+ setOptions((previous) => {
+ const newOptions = previous.filter((item) => item !== e.code);
+ if (selected?.code && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code);
+ return newOptions;
+ });
+ },
+ [rules, item, selected, setRules, setOptions, setInputs]
+ );
+
+ return (
+ ({ code: item }))}
+ selected={selected}
+ select={selectChangeHandler}
+ optionKey="code"
+ placeholder={t("SELECT_OPTION")}
+ showToolTip={true}
+ />
+ );
+ }
+);
+
+// get schema for validation
+const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => {
+ if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return [];
+ const sortData = [];
+ if (!schemas) return;
+ for (const value of microplanData?.upload?.filter((value) => value?.active && value?.error === null) || []) {
+ sortData.push({ section: value?.section, fileType: value?.fileType });
+ }
+ const filteredSchemas =
+ schemas?.filter((schema) => {
+ if (schema.campaignType) {
+ return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type);
+ }
+ return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type);
+ }) || [];
+ const finalData = filteredSchemas
+ ?.flatMap((item) =>
+ Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.isRuleConfigureInputs) {
+ acc.push(key);
+ }
+ return acc;
+ }, [])
+ )
+ .filter((item) => !!item);
+ return [...new Set(finalData)];
+};
+
+// This function adding the rules configures in MDMS with respect to the canpaign when rule section is empty
+const filterRulesAsPerConstrains = (autofillData, rules, hypothesisAssumptionsList, outputs, operators, inputs, setInputs, setOutputs, autofill) => {
+ if (rules && rules.filter((item) => item.active).length !== 0) return { rules };
+
+ let wereRulesNotDeleted = true;
+ const newRules = [];
+ const ruleOuputList = rules ? rules.filter((item) => item.active).map((item) => item?.output) : [];
+ let rulePlusInputs;
+ if (ruleOuputList) rulePlusInputs = [...inputs, ...ruleOuputList];
+ else rulePlusInputs = inputs;
+ for (const item of autofillData) {
+ let active = !(item && item.active === false);
+ const ruleNotCompleteCheck = (!autofill && item && Object.values(item).filter((e) => e === "").length === 0) || autofill;
+ if (
+ (ruleOuputList?.includes(item?.output) ||
+ (outputs && !outputs.includes(item?.output)) ||
+ (rulePlusInputs && !rulePlusInputs.includes(item?.input)) ||
+ (operators && !operators.includes(item?.operator)) ||
+ (hypothesisAssumptionsList && !hypothesisAssumptionsList.includes(item?.assumptionValue)) ||
+ !outputs ||
+ !rulePlusInputs ||
+ !operators ||
+ !hypothesisAssumptionsList) &&
+ ruleNotCompleteCheck
+ ) {
+ if (autofill) {
+ continue;
+ }
+ if (active) {
+ wereRulesNotDeleted = false;
+ active = false;
+ }
+ }
+ if (!item["id"]) {
+ const uuid = uuidv4();
+ item["id"] = uuid;
+ }
+ item.active = active;
+ newRules.push(item);
+ if (active && ruleNotCompleteCheck) {
+ rulePlusInputs?.push(item?.output);
+ ruleOuputList?.push(item?.output);
+ }
+ }
+ if (newRules.length !== 0) {
+ let newOutputs = [];
+ outputs.forEach((e) => {
+ if (!ruleOuputList.includes(e)) {
+ newOutputs.push(e);
+ }
+ });
+ setOutputs(newOutputs);
+ setInputs(rulePlusInputs);
+ // setRules((previous) => [...previous, ...newRules]);
+ }
+
+ return { rules: [...(rules ? rules : []), ...newRules], rulesDeleted: !autofill && !wereRulesNotDeleted };
+};
+
+export default RuleEngine;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js
new file mode 100644
index 00000000000..9e0ed13d39b
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js
@@ -0,0 +1,1154 @@
+import React, { useState, useEffect, useMemo, Fragment, useCallback } from "react";
+import { useTranslation } from "react-i18next";
+import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components";
+import { ModalWrapper } from "./Modal";
+import { geojsonPropertiesValidation } from "../utils/geojsonValidations";
+import { SpatialDataPropertyMapping } from "./resourceMapping";
+import { JsonPreviewInExcelForm } from "./JsonPreviewInExcelForm";
+import { ButtonType1, ButtonType2, CloseButton, ModalHeading } from "./CommonComponents";
+import { Loader } from "@egovernments/digit-ui-components";
+import { EXCEL, FILE_STORE, GEOJSON, PRIMARY_THEME_COLOR, SHAPEFILE, UPLOADED_DATA_ACTIVE_STATUS } from "../configs/constants";
+import { tourSteps } from "../configs/tourSteps";
+import { useMyContext } from "../utils/context";
+import { v4 as uuidv4 } from "uuid";
+import {
+ handleExcelFile,
+ validateNamingConvention,
+ findReadMe,
+ downloadTemplate,
+ getSchema,
+ prepareExcelFileBlobWithErrors,
+ boundaryDataGeneration,
+ handleGeojsonFile,
+ handleShapefiles,
+ convertToSheetArray,
+ findGuideLine,
+ delay,
+} from "../utils/uploadUtils";
+import { UploadGuideLines, UploadedFile, FileUploadComponent, UploadComponents, UploadInstructions, UploadSection } from "./UploadHelperComponents";
+
+const page = "upload";
+
+const Upload = ({
+ MicroplanName = "default",
+ campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType,
+ microplanData,
+ setMicroplanData,
+ checkDataCompletion,
+ setCheckDataCompletion,
+ currentPage,
+ pages,
+ navigationEvent,
+ setToast,
+}) => {
+ const { t } = useTranslation();
+
+ // States
+ const [editable, setEditable] = useState(true);
+ const [sections, setSections] = useState([]);
+ const [selectedSection, setSelectedSection] = useState(null);
+ const [modal, setModalState] = useState("none");
+ const [selectedFileType, setSelectedFileType] = useState(null);
+ const [dataPresent, setDataPresent] = useState(false);
+ const [dataUpload, setDataUpload] = useState(false);
+ const [loader, setLoader] = useState(false);
+ const [fileData, setFileData] = useState();
+ const [uploadedFileError, setUploadedFileError] = useState();
+ const [fileDataList, setFileDataList] = useState([]);
+ const [validationSchemas, setValidationSchemas] = useState([]);
+ const [template, setTemplate] = useState([]);
+ const [resourceMapping, setResourceMapping] = useState([]);
+ const [previewUploadedData, setPreviewUploadedData] = useState();
+ const { state, dispatch } = useMyContext();
+
+ //fetch campaign data
+ const { id = "" } = Digit.Hooks.useQueryParams();
+ const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign(
+ {
+ CampaignDetails: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ ids: [id],
+ },
+ },
+ {
+ enabled: !!id,
+ }
+ );
+
+ // request body for boundary hierarchy api
+ const reqCriteria = {
+ url: `/boundary-service/boundary-hierarchy-definition/_search`,
+ params: {},
+ body: {
+ BoundaryTypeHierarchySearchCriteria: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ hierarchyType: campaignData?.hierarchyType,
+ // hierarchyType: "Microplan",
+ },
+ },
+ config: {
+ enabled: !!campaignData?.hierarchyType,
+ select: (data) => {
+ return (
+ data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map(
+ (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`
+ ) || {}
+ );
+ },
+ },
+ };
+ const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+ // Set TourSteps
+ useEffect(() => {
+ const tourData = tourSteps(t)?.[page] || {};
+ if (state?.tourStateData?.name === page) return;
+ dispatch({
+ type: "SETINITDATA",
+ state: { tourStateData: tourData },
+ });
+ }, [t]);
+
+ const setModal = (modalString) => {
+ const elements = document.querySelectorAll(".popup-wrap-rest-unfocus");
+ elements.forEach((element) => {
+ element.classList.toggle("popup-wrap-rest-unfocus-active");
+ });
+ setModalState(modalString);
+ };
+
+ // UseEffect for checking completeness of data before moveing to next section
+ useEffect(() => {
+ if (!fileDataList || checkDataCompletion !== "true" || !setCheckDataCompletion) return;
+ updateData(true);
+ }, [checkDataCompletion]);
+
+ // UseEffect to store current data
+ useEffect(() => {
+ if (!fileDataList || !setMicroplanData) return;
+ setMicroplanData((previous) => ({ ...previous, upload: fileDataList }));
+ }, [fileDataList]);
+
+ // check if data has changed or not
+ const updateData = useCallback(
+ (check) => {
+ if (!fileDataList || !setMicroplanData) return;
+
+ // if user has selected a file type and wants to go back to file type selection he/she can click back buttom
+ const currentSectionIndex = sections.findIndex((item) => item.id === selectedSection.id);
+ if (!dataPresent) {
+ if (navigationEvent?.name !== "step") {
+ if (navigationEvent?.name === "next") {
+ if (currentSectionIndex < sections.length - 1) {
+ setSelectedSection(sections[currentSectionIndex + 1]);
+ setCheckDataCompletion("false");
+ return;
+ }
+ } else if (navigationEvent?.name === "previousStep") {
+ if (dataUpload) {
+ setDataUpload(false);
+ setSelectedFileType(null);
+ setCheckDataCompletion("false");
+ return;
+ }
+ if (currentSectionIndex > 0) {
+ setSelectedSection(sections[currentSectionIndex - 1]);
+ setCheckDataCompletion("false");
+ return;
+ }
+ }
+ }
+ } else {
+ if (navigationEvent?.name === "next") {
+ if (currentSectionIndex < sections.length - 1) {
+ setSelectedSection(sections[currentSectionIndex + 1]);
+ setCheckDataCompletion("false");
+ return;
+ }
+ } else if (navigationEvent?.name === "previousStep") {
+ if (currentSectionIndex > 0) {
+ setSelectedSection(sections[currentSectionIndex - 1]);
+ setCheckDataCompletion("false");
+ return;
+ }
+ }
+ }
+
+ if (check) {
+ setMicroplanData((previous) => ({ ...previous, upload: fileDataList }));
+ const valueList = fileDataList ? fileDataList : [];
+ const sectionCheckList = sections?.filter((item) => item.required);
+
+ if (
+ valueList.length !== 0 &&
+ sectionCheckList.every((item) => {
+ const filteredList = fileDataList?.filter((e) => e.active && e.templateIdentifier === item.id);
+ if (filteredList?.length === 0) return false;
+ return filteredList?.every((element) => element?.error === null) && fileDataList && !fileDataList.some((e) => e?.active && e?.error);
+ })
+ )
+ setCheckDataCompletion("valid");
+ else setCheckDataCompletion("invalid");
+ } else {
+ const valueList = microplanData?.Upload ? Object.values(microplanData?.Upload) : [];
+ if (
+ valueList.length !== 0 &&
+ sectionCheckList.every((item) =>
+ fileDataList?.filter((e) => e.templateIdentifier === item.id)?.every((element) => element.active && element?.error === null)
+ )
+ )
+ setCheckDataCompletion("valid");
+ else setCheckDataCompletion("invalid");
+ }
+ },
+ [fileDataList, setMicroplanData, microplanData, setCheckDataCompletion, dataPresent, dataUpload, navigationEvent]
+ );
+
+ // UseEffect to extract data on first render
+ useEffect(() => {
+ if (microplanData?.upload) {
+ setFileDataList(microplanData.upload);
+ }
+
+ if (pages) {
+ const previouspage = pages[currentPage?.id - 1];
+ if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false);
+ else setEditable(true);
+ }
+ }, []);
+
+ // UseEffect to add a event listener for keyboard
+ useEffect(() => {
+ window.addEventListener("keydown", handleKeyPress);
+
+ return () => window.removeEventListener("keydown", handleKeyPress);
+ }, [modal, previewUploadedData]);
+
+ const handleKeyPress = (event) => {
+ // if (modal !== "upload-guidelines") return;
+ if (["x", "Escape"].includes(event.key)) {
+ // Perform the desired action when "x" or "esc" is pressed
+ if (modal === "upload-guidelines") {
+ setModal("none");
+ }
+ if (previewUploadedData) setPreviewUploadedData(undefined);
+ }
+ };
+
+ // Effect to update sections and selected section when data changes
+ useEffect(() => {
+ if (state) {
+ const uploadSections = state?.UploadConfiguration;
+ const schemas = state?.Schemas;
+ if (schemas) setValidationSchemas(schemas);
+ if (uploadSections) {
+ setSelectedSection(uploadSections.length > 0 ? uploadSections[0] : null);
+ setSections(uploadSections);
+ }
+ }
+ }, []);
+
+ // Memoized section options to prevent unnecessary re-renders
+ const sectionOptions = useMemo(() => {
+ if (!sections) return [];
+ return sections.map((item) => (
+ e.active && e.templateIdentifier === item.id && !e.error)?.length !== 0}
+ />
+ ));
+ }, [sections, selectedSection, fileDataList]);
+
+ const showDownloadTemplate = () => {
+ if (selectedSection?.UploadFileTypes) {
+ const schema = getSchema(campaignType, selectedFileType?.id, selectedSection.id, validationSchemas);
+ if (schema?.template?.showTemplateDownload) return true;
+ }
+ return false;
+ };
+
+ // Handler for when a file type is selected for uplaod
+ const selectFileTypeHandler = (e) => {
+ if (selectedSection?.UploadFileTypes) {
+ const schema = getSchema(campaignType, e.target.name, selectedSection.id, validationSchemas);
+ setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item.id === e.target.name));
+ if (schema?.template?.showTemplateDownload) setModal("upload-modal");
+ else UploadFileClickHandler(false);
+ return;
+ }
+ setToast({
+ state: "error",
+ message: t("ERROR_UNKNOWN"),
+ });
+ setLoader(false);
+ return;
+ };
+
+ // Memoized section components to prevent unnecessary re-renders
+ const sectionComponents = useMemo(() => {
+ if (!sections) return;
+ return sections.map((item) => (
+
+ ));
+ }, [sections, selectedSection, selectedFileType]);
+
+ // Close model click handler
+ const closeModal = () => {
+ setResourceMapping([]);
+ setModal("none");
+ };
+
+ // handler for show file upload screen
+ const UploadFileClickHandler = (download = false) => {
+ if (download) {
+ downloadTemplateHandler();
+ }
+ setModal("none");
+ setDataUpload(true);
+ };
+ const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName");
+ const downloadTemplateHandler = () => {
+ const downloadParams = {
+ campaignType,
+ type: selectedFileType.id,
+ section: selectedSection.id,
+ setToast,
+ campaignData,
+ hierarchyType: campaignData?.hierarchyType,
+ Schemas: validationSchemas,
+ HierarchyConfigurations: state?.HierarchyConfigurations,
+ setLoader,
+ hierarchy,
+ readMeData: state?.ReadMeData,
+ readMeSheetName: readMeConstant ? readMeConstant.value : undefined,
+ t,
+ };
+ downloadTemplate(downloadParams);
+ };
+ // Effect for updating current session data in case of section change
+ useEffect(() => {
+ if (selectedSection) {
+ let file = fileDataList?.find((item) => item.active && item.templateIdentifier === selectedSection.id);
+ if (file?.resourceMapping) {
+ setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item?.id === file?.fileType));
+ setUploadedFileError(file?.error);
+ setFileData(file);
+ setDataPresent(true);
+ } else {
+ resetSectionState();
+ }
+ } else {
+ resetSectionState();
+ }
+ }, [selectedSection]);
+
+ const resetSectionState = () => {
+ setUploadedFileError(null);
+ setSelectedFileType(null);
+ setDataPresent(false);
+ setResourceMapping([]);
+ setDataUpload(false);
+ };
+
+ // Function for handling upload file event
+ const UploadFileToFileStorage = async (file) => {
+ if (!file) return;
+ try {
+ // setting loader
+ setLoader("FILE_UPLOADING");
+ let check;
+ let fileDataToStore;
+ let errorMsg;
+ let errorLocationObject; // object containing the location and type of error
+ let response;
+ let callMapping = false;
+ // Checking if the file follows name convention rules
+ if (!validateNamingConvention(file, selectedFileType["namingConvention"], setToast, t)) {
+ setLoader(false);
+ return;
+ }
+
+ let schemaData;
+ if (selectedFileType.id !== SHAPEFILE) {
+ // Check if validation schema is present or not
+ schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas);
+ if (!schemaData) {
+ setToast({
+ state: "error",
+ message: t("ERROR_VALIDATION_SCHEMA_ABSENT"),
+ });
+ setLoader(false);
+ return;
+ }
+ }
+ let resourceMappingData = [];
+ let additionalSheets = [];
+ // Handling different filetypes
+ switch (selectedFileType.id) {
+ case EXCEL:
+ // let response = handleExcelFile(file,schemaData);
+ try {
+ response = await handleExcelFile(
+ file,
+ schemaData,
+ hierarchy,
+ selectedFileType,
+ {},
+ setUploadedFileError,
+ t,
+ campaignData,
+ state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value
+ );
+ check = response.check;
+ errorMsg = response.errorMsg;
+ errorLocationObject = response.errors;
+ fileDataToStore = response.fileDataToStore;
+ resourceMappingData = response?.tempResourceMappingData || [];
+ additionalSheets = response?.additionalSheets;
+ if (check === true) {
+ if (response?.toast) setToast(response.toast);
+ else setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") });
+ } else if (response.toast) {
+ setToast(response.toast);
+ } else {
+ setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") });
+ }
+ if (response.interruptUpload) {
+ setLoader(false);
+ return;
+ }
+ } catch (error) {
+ console.error("Excel parsing error", error.message);
+ setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") });
+ handleValidationErrorResponse(t("ERROR_UPLOADED_FILE"));
+ return;
+ }
+ break;
+ case GEOJSON:
+ try {
+ response = await handleGeojsonFile(file, schemaData, setUploadedFileError, t);
+ file = new File([file], file.name, { type: "application/geo+json" });
+ if (response.check === false && response.stopUpload) {
+ setLoader(false);
+ setToast(response.toast);
+ return;
+ }
+ check = response.check;
+ errorMsg = response.error;
+ fileDataToStore = response.fileDataToStore;
+ callMapping = true;
+ } catch (error) {
+ // console.error("Geojson parsing error", error.message);
+ setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") });
+ handleValidationErrorResponse(t("ERROR_UPLOADED_FILE"));
+ return;
+ }
+ break;
+ case SHAPEFILE:
+ try {
+ response = await handleShapefiles(file, schemaData, setUploadedFileError, selectedFileType, setToast, t);
+ file = new File([file], file.name, { type: "application/octet-stream" });
+ check = response.check;
+ errorMsg = response.error;
+ fileDataToStore = response.fileDataToStore;
+ callMapping = true;
+ } catch (error) {
+ console.error("Shapefile parsing error", error.message);
+ setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") });
+ handleValidationErrorResponse(t("ERROR_UPLOADED_FILE"));
+ return;
+ }
+ break;
+ default:
+ setToast({
+ state: "error",
+ message: t("ERROR_UNKNOWN_FILETYPE"),
+ });
+ setLoader(false);
+ return;
+ }
+ let filestoreId;
+ if (!errorMsg && !callMapping) {
+ try {
+ const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, file, Digit.ULBService.getCurrentTenantId());
+ if (filestoreResponse?.data?.files?.length > 0) {
+ filestoreId = filestoreResponse?.data?.files[0]?.fileStoreId;
+ } else {
+ errorMsg = t("ERROR_UPLOADING_FILE");
+ setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") });
+ setFileData((previous) => ({ ...previous, error: errorMsg }));
+ setUploadedFileError(errorMsg);
+ }
+ } catch (errorData) {
+ console.error(errorData.message);
+ errorMsg = t("ERROR_UPLOADING_FILE");
+ setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") });
+ setUploadedFileError(errorMsg);
+ handleValidationErrorResponse(t("ERROR_UPLOADING_FILE"));
+ return;
+ }
+ }
+
+ if (selectedFileType.id === EXCEL) {
+ resourceMappingData = resourceMappingData.map((item) => ({ ...item, filestoreId }));
+ }
+ const uuid = uuidv4();
+ // creating a fileObject to save all the data collectively
+ let fileObject = {
+ id: uuid,
+ templateIdentifier: `${selectedSection.id}`,
+ fileName: file.name,
+ section: selectedSection.id,
+ fileType: selectedFileType.id,
+ data: fileDataToStore,
+ file,
+ error: errorMsg ? errorMsg : null,
+ filestoreId,
+ resourceMapping: resourceMappingData,
+ active: true,
+ additionalSheets,
+ errorLocationObject, // contains location and type of error
+ };
+ setFileDataList((prevFileDataList) => {
+ let temp = _.cloneDeep(prevFileDataList);
+ if (!temp) return temp;
+ let index = prevFileDataList?.findIndex((item) => item.active && item.templateIdentifier === selectedSection.id);
+ if (index !== -1)
+ temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false };
+ temp.push(fileObject);
+ return temp;
+ });
+ setFileData(fileObject);
+ if (errorMsg === undefined && callMapping) {
+ setModal("spatial-data-property-mapping");
+ }
+ setDataPresent(true);
+ setLoader(false);
+ } catch (error) {
+ console.error(error.message);
+ console.error("File Upload error", error?.message);
+ setUploadedFileError("ERROR_UPLOADING_FILE");
+ setLoader(false);
+ }
+ };
+
+ // Reupload the selected file
+ const reuplaodFile = () => {
+ setResourceMapping([]);
+ setFileData(undefined);
+ setDataPresent(false);
+ setUploadedFileError(null);
+ setDataUpload(false);
+ setSelectedFileType(null);
+ closeModal();
+ };
+
+ const convertAndCombineFileData = () => {
+ let combinedData = fileData?.data ? Object.entries(fileData.data)?.map(([key, value]) => ({ sheetName: key, data: value })) : [];
+ if (fileData?.additionalSheets) {
+ for (const sheet of fileData.additionalSheets) {
+ if (sheet?.data && sheet.sheetName) {
+ const index = sheet?.position < combinedData.length && sheet.position !== -1 ? sheet.position : combinedData.length;
+ combinedData.splice(index, 0, sheet);
+ }
+ }
+ }
+ return combinedData;
+ };
+
+ // Function for creating blob out of data
+ const dataToBlob = async () => {
+ try {
+ let blob;
+ const schema = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas);
+ const filteredReadMeData = findReadMe(state?.ReadMeData, campaignType, selectedFileType.id, selectedSection.id)?.data || [];
+ let combinedData = convertAndCombineFileData();
+ const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value;
+ const sectionIdList = sections?.map((item) => item.id);
+ switch (fileData.fileType) {
+ case EXCEL:
+ if (fileData?.errorLocationObject?.length !== 0)
+ blob = await prepareExcelFileBlobWithErrors(
+ combinedData,
+ fileData.errorLocationObject,
+ schema,
+ hierarchy,
+ filteredReadMeData,
+ readMeSheetName,
+ sectionIdList,
+ t
+ );
+ else blob = fileData.file;
+ break;
+ case SHAPEFILE:
+ case GEOJSON:
+ if (fileData?.data) {
+ const result = convertToSheetArray(Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section));
+
+ if (fileData?.errorLocationObject?.length !== 0)
+ blob = await prepareExcelFileBlobWithErrors(
+ result,
+ fileData.errorLocationObject,
+ schema,
+ hierarchy,
+ filteredReadMeData,
+ readMeSheetName,
+ sectionIdList,
+ t
+ );
+ }
+ break;
+ }
+ return blob;
+ } catch (error) {
+ console.error("Error generating blob:", error);
+ return;
+ }
+ };
+
+ // Download the selected file
+ const downloadFile = async () => {
+ setLoader("LOADING");
+ try {
+ await delay(100);
+ let blob = await dataToBlob();
+ if (blob) {
+ // Crating a url object for the blob
+ const url = URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = url;
+
+ // Forming a name for downloaded file
+ let fileNameParts = fileData.fileName.split(".");
+ fileNameParts.pop();
+ fileNameParts.push("xlsx");
+ fileNameParts.join(".");
+
+ //Downloading the file
+ link.download = fileNameParts.join(".");
+ link.click();
+ URL.revokeObjectURL(url);
+ } else {
+ let downloadUrl = await Digit.UploadServices.Filefetch([fileData.filestoreId], Digit.ULBService.getCurrentTenantId());
+ const link = document.createElement("a");
+ link.href = downloadUrl;
+ // Forming a name for downloaded file
+ let fileNameParts = fileData.fileName.split(".");
+ fileNameParts.pop();
+ fileNameParts.push("xlsx");
+ fileNameParts.join(".");
+ link.download = fileNameParts; // Replace with the desired file name and extension
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ }
+ } catch (error) {
+ console.error(error.message);
+ setToast({
+ state: "error",
+ message: t("ERROR_UNKNOWN_ERROR"),
+ });
+ }
+ setLoader(false);
+ };
+
+ // delete the selected file
+ const deleteFile = () => {
+ setResourceMapping([]);
+ setFileDataList((previous) => {
+ let temp = _.cloneDeep(previous);
+ if (!temp) return temp;
+ let index = temp?.findIndex((item) => {
+ return item.id === fileData.id;
+ });
+ if (index !== -1)
+ temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false };
+ return temp;
+ });
+ setFileData(undefined);
+ setDataPresent(false);
+ setUploadedFileError(null);
+ setDataUpload(false);
+ setSelectedFileType(null);
+ closeModal();
+ };
+
+ // Function for handling the validations for geojson and shapefiles after mapping of properties
+ const validationForMappingAndDataSaving = async () => {
+ try {
+ setLoader("LOADING");
+ const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas);
+ let error;
+ if (!checkForSchemaData(schemaData)) return;
+
+ const { data, valid, errors } = computeMappedDataAndItsValidations(schemaData);
+ error = errors;
+ if (!valid) return;
+ let filestoreId;
+ if (!error) {
+ filestoreId = await saveFileToFileStore();
+ }
+ let resourceMappingData;
+ if (filestoreId) {
+ resourceMappingData = resourceMapping.map((item) => {
+ return { ...item, filestoreId };
+ });
+ }
+ setResourceMapping([]);
+
+ const boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {};
+ const mappedToList = resourceMappingData.map((item) => item.mappedTo);
+ if (hierarchy.every((item) => !mappedToList.includes(t(item)))) {
+ data.features.forEach((feature) => {
+ const boundaryCode = feature.properties.boundaryCode;
+ const additionalDetails = {};
+ for (let i = 0; i < hierarchy.length; i++) {
+ if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") {
+ additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i];
+ } else {
+ additionalDetails[hierarchy[i]] = "";
+ }
+ }
+ feature.properties = { ...additionalDetails, ...feature.properties };
+ });
+ }
+
+ let fileObject = _.cloneDeep(fileData);
+ fileObject = { ...fileData, data, resourceMapping: resourceMappingData, error: error ? error : null, filestoreId };
+ setFileData(fileObject);
+ setFileDataList((prevFileDataList) => {
+ let temp = _.cloneDeep(prevFileDataList);
+ if (!temp) return temp;
+ let index = prevFileDataList?.findIndex((item) => item.id === fileData.id);
+ if (index !== -1) temp[index] = fileObject;
+ // temp.push(fileObject);
+ return temp;
+ });
+
+ setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") });
+ setLoader(false);
+ } catch (error) {
+ console.error(error.message);
+ setUploadedFileError(t("ERROR_UPLOADING_FILE"));
+ setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") });
+ setLoader(false);
+ handleValidationErrorResponse("ERROR_UPLOADING_FILE");
+ }
+ };
+ const saveFileToFileStore = async () => {
+ try {
+ const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, fileData.file, Digit.ULBService.getCurrentTenantId());
+ if (filestoreResponse?.data?.files?.length > 0) {
+ return filestoreResponse?.data?.files[0]?.fileStoreId;
+ }
+ error = t("ERROR_UPLOADING_FILE");
+ setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") });
+ setResourceMapping([]);
+ setUploadedFileError(error);
+ } catch (errorData) {
+ console.error("Error while uploading file to filestore: ", errorData?.message);
+ let error = t("ERROR_UPLOADING_FILE");
+ handleValidationErrorResponse(error);
+ setResourceMapping([]);
+ return;
+ }
+ };
+ const computeMappedDataAndItsValidations = (schemaData) => {
+ const data = computeGeojsonWithMappedProperties();
+ const response = geojsonPropertiesValidation(data, schemaData.schema, fileData?.section, t);
+ if (!response.valid) {
+ handleValidationErrorResponse(response.message, response.errors);
+ return { data: data, errors: response.errors, valid: response.valid };
+ }
+ return { data: data, valid: response.valid };
+ };
+
+ const handleValidationErrorResponse = (error, errorLocationObject = {}) => {
+ const fileObject = fileData;
+ if (fileObject) {
+ fileObject.error = [error];
+ if (errorLocationObject) fileObject.errorLocationObject = errorLocationObject;
+ setFileData((previous) => ({ ...previous, error, errorLocationObject }));
+ setFileDataList((prevFileDataList) => {
+ let temp = _.cloneDeep(prevFileDataList);
+ if (!temp) return temp;
+ let index = prevFileDataList?.findIndex((item) => item.id === fileData.id);
+ temp[index] = fileObject;
+ return temp;
+ });
+ setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") });
+ if (error) setUploadedFileError(error);
+ }
+ setLoader(false);
+ };
+
+ const checkForSchemaData = (schemaData) => {
+ if (resourceMapping?.length === 0) {
+ setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") });
+ setLoader(false);
+ return false;
+ }
+
+ if (!schemaData || !schemaData.schema || !schemaData.schema["Properties"]) {
+ setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") });
+ setLoader(false);
+ return;
+ }
+
+ let columns = [];
+ if (schemaData?.doHierarchyCheckInUploadedData) {
+ columns.push(...hierarchy);
+ }
+ columns.push(
+ ...Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.isRequired) {
+ acc.push(key);
+ }
+ return acc;
+ }, [])
+ );
+
+ const resourceMappingLength = resourceMapping.filter((e) => !!e?.mappedFrom && columns.includes(e?.mappedTo)).length;
+ if (resourceMappingLength !== columns?.length) {
+ setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") });
+ setLoader(false);
+ return false;
+ }
+ setModal("none");
+ return true;
+ };
+
+ const computeGeojsonWithMappedProperties = () => {
+ const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas);
+ let schemaKeys;
+ if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"]));
+ // Sorting the resourceMapping list inorder to maintain the column sequence
+ const sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping);
+ // Creating a object with input data with MDMS keys
+ const newFeatures = [];
+ for (const item of fileData.data["features"]) {
+ let newProperties = {};
+
+ sortedSecondList.forEach((e) => {
+ newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]];
+ });
+ item["properties"] = newProperties;
+ newFeatures.push(item);
+ }
+ let filteredFeature = [];
+ for (const item of newFeatures) {
+ if (
+ schemaData?.activeInactiveField &&
+ schemaData?.schema?.Properties &&
+ Object.keys(schemaData.schema.Properties).includes(schemaData.activeInactiveField) &&
+ item?.properties?.[schemaData.activeInactiveField] !== t(UPLOADED_DATA_ACTIVE_STATUS)
+ ) {
+ continue;
+ }
+ filteredFeature.push(item);
+ }
+ let data = fileData.data;
+ data["features"] = filteredFeature;
+ return data;
+ };
+
+ // Handler for checing file extension and showing errors in case it is wrong
+ const onTypeErrorWhileFileUpload = () => {
+ switch (selectedFileType.id) {
+ case EXCEL:
+ setToast({ state: "error", message: t("ERROR_EXCEL_EXTENSION") });
+ break;
+ case GEOJSON:
+ setToast({ state: "error", message: t("ERROR_GEOJSON_EXTENSION") });
+ break;
+ case SHAPEFILE:
+ setToast({ state: "error", message: t("ERROR_SHAPE_FILE_EXTENSION") });
+ break;
+ }
+ };
+
+ // Cancle mapping and uplaod in case of geojson and shapefiles
+ const cancelUpload = () => {
+ setFileDataList((previous) => {
+ let temp = previous?.filter((item) => item.id !== fileData?.id);
+ return temp;
+ });
+ setFileData(undefined);
+ setDataPresent(false);
+ setUploadedFileError(null);
+ setDataUpload(false);
+ setSelectedFileType(null);
+ closeModal();
+ };
+
+ const openDataPreview = () => {
+ let data;
+ switch (fileData.fileType) {
+ case EXCEL:
+ data = fileData.data;
+ break;
+ case SHAPEFILE:
+ case GEOJSON:
+ if (!fileData || !fileData.data) {
+ setToast({
+ state: "error",
+ message: t("ERROR_DATA_NOT_PRESENT"),
+ });
+ return;
+ }
+ data = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section);
+ break;
+ }
+ if (!data || Object.keys(data).length === 0 || Object.values(data)?.[0]?.[0].length === 0) {
+ setToast({
+ state: "error",
+ message: t("ERROR_DATA_NOT_PRESENT"),
+ });
+ return;
+ }
+ setPreviewUploadedData(data);
+ };
+
+ if (isCampaignLoading || ishierarchyLoading) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+ <>
+
+
+
+ {!dataPresent ? (
+ dataUpload ? (
+
+ e.id === selectedSection.id)[0]}
+ selectedSection={selectedSection}
+ selectedFileType={selectedFileType}
+ UploadFileToFileStorage={UploadFileToFileStorage}
+ onTypeError={onTypeErrorWhileFileUpload}
+ downloadTemplateHandler={downloadTemplateHandler}
+ showDownloadTemplate={showDownloadTemplate}
+ />
+
+ ) : (
+
{sectionComponents}
+ )
+ ) : (
+
+ {selectedSection != null && fileData !== null && (
+ {
+ setModal("reupload-conformation");
+ }}
+ DownloadFile={downloadFile}
+ DeleteFile={() => {
+ setModal("delete-conformation");
+ }}
+ error={uploadedFileError}
+ openDataPreview={openDataPreview}
+ downloadTemplateHandler={downloadTemplateHandler}
+ showDownloadTemplate={showDownloadTemplate}
+ />
+ )}
+
+ )}
+ {!dataPresent && dataUpload && (
+
{
+ setModal("upload-guidelines");
+ }}
+ t={t}
+ />
+ )}
+
+
+
{sectionOptions}
+
+
+
+ {modal === "upload-modal" && (
+
{
+ closeModal();
+ setSelectedFileType(null);
+ }}
+ LeftButtonHandler={() => UploadFileClickHandler(false)}
+ RightButtonHandler={() => UploadFileClickHandler(true)}
+ sections={sections}
+ popupModuleActionBarStyles={{
+ flex: 1,
+ justifyContent: "space-between",
+ padding: "1rem",
+ gap: "1rem",
+ }}
+ footerLeftButtonBody={}
+ footerRightButtonBody={}
+ header={
+
+ }
+ bodyText={t(`INSTRUCTIONS_DOWNLOAD_TEMPLATE_FOR_${selectedSection.code}_${selectedFileType.code}`)}
+ />
+ )}
+ {modal === "delete-conformation" && (
+ }
+ actionCancelLabel={t("YES")}
+ actionCancelOnSubmit={deleteFile}
+ actionSaveLabel={t("NO")}
+ actionSaveOnSubmit={closeModal}
+ >
+
+
{t("INSTRUCTIONS_DELETE_FILE_CONFIRMATION")}
+
+
+ )}
+ {modal === "reupload-conformation" && (
+ }
+ actionCancelLabel={t("YES")}
+ actionCancelOnSubmit={reuplaodFile}
+ actionSaveLabel={t("NO")}
+ actionSaveOnSubmit={closeModal}
+ >
+
+
{t("INSTRUCTIONS_REUPLOAD_FILE_CONFIRMATION")}
+
+
+ )}
+ {modal === "spatial-data-property-mapping" && (
+ }
+ actionSaveOnSubmit={validationForMappingAndDataSaving}
+ actionSaveLabel={t("COMPLETE_MAPPING")}
+ headerBarEnd={}
+ >
+
+
{t("INSTRUCTION_SPATIAL_DATA_PROPERTY_MAPPING")}
+
+
+
+ )}
+ {modal === "upload-guidelines" && (
+
+ }
+ headerBarEnd={}
+ >
+
+
+ )}
+ {loader && }
+
+ {previewUploadedData && (
+
+ setPreviewUploadedData(undefined)}
+ onDownload={downloadFile}
+ />
+
+ )}
+
+
+ >
+ );
+};
+
+export default Upload;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js
new file mode 100644
index 00000000000..5a520c4a1bd
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js
@@ -0,0 +1,299 @@
+import React, { useState, useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import * as Icons from "@egovernments/digit-ui-svg-components";
+import { FileUploader } from "react-drag-drop-files";
+import { InfoButton, InfoCard } from "@egovernments/digit-ui-components";
+import { PRIMARY_THEME_COLOR } from "../configs/constants";
+
+// Component for rendering individual section option
+export const UploadSection = ({ item, selected, setSelectedSection, uploadDone }) => {
+ const { t } = useTranslation();
+ // Handle click on section option
+ const handleClick = () => {
+ setSelectedSection(item);
+ };
+
+ return (
+
+
+
+
+
{t(item.code)}
+ {uploadDone && (
+
+
+
+ )}
+
+ );
+};
+
+export const UploadInstructions = ({ setModal, t }) => {
+ return (
+
+ {t("REFER")}
+
+ {t("INFORMATION_DESCRIPTION_LINK")}
+
+ ,
+ ]}
+ />
+ );
+};
+
+// Component for rendering individual upload option
+export const UploadComponents = ({ item, selected, uploadOptions, selectedFileType, selectFileTypeHandler }) => {
+ const { t } = useTranslation();
+ const title = item.code;
+
+ // Component for rendering individual upload option container
+ const UploadOptionContainer = ({ item, selectedFileType, selectFileTypeHandler }) => {
+ const [isHovered, setIsHovered] = useState(false);
+
+ const handleMouseEnter = () => {
+ setIsHovered(true);
+ };
+
+ const handleMouseLeave = () => {
+ setIsHovered(false);
+ };
+
+ return (
+
+
+
{t(item.code)}
+
+ {selectedFileType.id === item.id && (
+
+ )}
+ {selectedFileType.id === item.id ? t("SELECTED") : t("SELECT")}
+
+
+ );
+ };
+
+ return (
+
+
+
+
{t(`HEADING_UPLOAD_DATA_${title}`)}
+
+
+
{t(`INSTRUCTIONS_DATA_UPLOAD_OPTIONS_${title}`)}
+
+
+ {uploadOptions?.map((item) => (
+
+ ))}
+
+
+ );
+};
+
+// Component for uploading file
+export const FileUploadComponent = ({
+ selectedSection,
+ selectedFileType,
+ UploadFileToFileStorage,
+ section,
+ onTypeError,
+ downloadTemplateHandler,
+ showDownloadTemplate,
+}) => {
+ if (!selectedSection || !selectedFileType) return ;
+ const { t } = useTranslation();
+ let types;
+ section["UploadFileTypes"].forEach((item) => {
+ if (item.id === selectedFileType.id) types = item.fileExtension;
+ });
+ return (
+
+
+
+
{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}
+ {showDownloadTemplate() && (
+
+
+
+
+ {t("DOWNLOAD_TEMPLATE")}
+
+ )}
+
+
{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}
+
+
+
+
+ {t(`INSTRUCTIONS_UPLOAD_${selectedFileType.code}`)}
{t("INSTRUCTIONS_UPLOAD_BROWSE_FILES")}
+
+
+
+
+
+ );
+};
+
+// Component to display uploaded file
+export const UploadedFile = ({
+ selectedSection,
+ selectedFileType,
+ file,
+ ReuplaodFile,
+ DownloadFile,
+ DeleteFile,
+ error,
+ openDataPreview,
+ downloadTemplateHandler,
+ showDownloadTemplate,
+}) => {
+ const { t } = useTranslation();
+ const [errorList, setErrorList] = useState([]);
+ useEffect(() => {
+ let tempErrorList = [];
+ if (file?.errorLocationObject) {
+ for (const [sheetName, values] of Object.entries(file?.errorLocationObject)) {
+ for (const [row, columns] of Object.entries(values)) {
+ for (const [column, errors] of Object.entries(columns)) {
+ for (const error of errors) {
+ let convertedError;
+ if (typeof error === "object") {
+ let { error: actualError, ...otherProperties } = error;
+ convertedError = t(actualError, otherProperties?.values);
+ } else {
+ convertedError = t(error);
+ }
+ tempErrorList.push(
+ t("ERROR_UPLOAD_DATA_LOCATION_AND_MESSAGE", {
+ rowNumber: Number(row) + 1,
+ columnName: t(column),
+ error: convertedError,
+ sheetName: sheetName,
+ })
+ );
+ }
+ }
+ }
+ }
+ }
+ if (tempErrorList.length !== 0) {
+ setErrorList(tempErrorList);
+ }
+ }, [file]);
+ return (
+
+
+
+
{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}
+ {showDownloadTemplate() && (
+
+
+
+
+ {t("DOWNLOAD_TEMPLATE")}
+
+ )}
+
+
{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}
+
+
+
+
+
+
+
{file.fileName}
+
+
+
+
+ {t("Reupload")}
+
+
+
+ {t("Download")}
+
+
+
+ {t("DELETE")}
+
+
+
+
+ {error && Array.isArray(error) && (
+
,
+
+ {error?.map((item) => {
+ if (item !== "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") {
+ return
{t(item)}
;
+ }
+ return null;
+ })}
+ {errorList.length !== 0 && errorList.map((item) =>
{item}
)}
+
,
+ ]}
+ />
+ )}
+
+ );
+};
+
+// Uplaod GuideLines
+export const UploadGuideLines = ({ uploadGuideLines, t }) => {
+ const formMsgFromObject = (item) => {
+ if (!item?.hasLink) {
+ return t(item?.name);
+ }
+ return (
+ <>
+ {t(item?.name)} {t(item?.linkName)}{" "}
+ >
+ );
+ };
+ return (
+
+ {uploadGuideLines?.map((item, index) => (
+
+
+ {t(index + 1)}.
+
+
+ {formMsgFromObject(item)}
+
+
+ ))}
+
+ );
+};
+
+export const CustomIcon = (props) => {
+ if (!props.Icon) return null;
+ return ;
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js
new file mode 100644
index 00000000000..5a0cdabf735
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js
@@ -0,0 +1,29 @@
+import React, { memo, useCallback } from "react";
+import { useTranslation } from "react-i18next";
+
+const ZoomControl = memo(({ map, t }) => {
+ if (!map) return {t("LOADING_MAP")}
;
+
+ const zoomIn = useCallback(() => {
+ map.zoomIn();
+ }, [map]);
+
+ const zoomOut = useCallback(() => {
+ map.zoomOut();
+ }, [map]);
+
+ return (
+
+ );
+});
+
+export default ZoomControl;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js
new file mode 100644
index 00000000000..df1eb78c135
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js
@@ -0,0 +1,187 @@
+import { Dropdown } from "@egovernments/digit-ui-components";
+import { Table } from "@egovernments/digit-ui-react-components";
+import { PaginationFirst, PaginationLast, PaginationNext, PaginationPrevious } from "@egovernments/digit-ui-svg-components";
+import React, { useState, useEffect, useMemo, useRef, useCallback } from "react";
+const SCROLL_OFFSET = 100;
+
+export const SpatialDataPropertyMapping = ({ uploadedData, resourceMapping, setResourceMapping, schema, setToast, hierarchy, close, t }) => {
+ // If no data is uploaded, display a message
+ if (!uploadedData) return {t("NO_DATA_TO_DO_MAPPING")}
;
+
+ const itemRefs = useRef([]);
+ const [expandedIndex, setExpandedIndex] = useState(null);
+ // State to track the render cycle count
+ const [renderCycle, setRenderCycle] = useState(0);
+ const scrollContainerRef = useRef(null);
+
+ // Effect to reset the render cycle count whenever the expandedIndex changes
+ useEffect(() => {
+ if (expandedIndex !== null) {
+ setRenderCycle(0);
+ }
+ }, [expandedIndex]);
+
+ // Effect to handle scrolling to the expanded item after the DOM has updated
+ useEffect(() => {
+ if (renderCycle < 3) {
+ // Increment render cycle count to ensure multiple render checks
+ setRenderCycle((prev) => prev + 1);
+ } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) {
+ try {
+ const parentElement = itemRefs.current[expandedIndex];
+ const childElement = itemRefs.current[expandedIndex].children[1];
+
+ if (parentElement) {
+ const scrollContainer = scrollContainerRef.current;
+ const parentRect = parentElement.getBoundingClientRect();
+ const containerRect = scrollContainer.getBoundingClientRect();
+
+ // Calculate the offset from the top of the container
+ const offset = parentRect.top - containerRect.top;
+ // Scroll the container to the target position
+ scrollContainer.scrollTo({
+ top: scrollContainer.scrollTop + offset - SCROLL_OFFSET,
+ behavior: "smooth",
+ });
+ }
+
+ if (childElement) {
+ // Focus the child element if it exists
+ childElement.focus();
+ }
+ } catch (error) {
+ console.error("Error scrolling to element:", error);
+ }
+ }
+ }, [renderCycle, expandedIndex]);
+
+ // Effect to observe DOM changes in the expanded item and trigger render cycle
+ useEffect(() => {
+ if (expandedIndex !== null) {
+ const observer = new MutationObserver(() => {
+ setRenderCycle((prev) => prev + 1);
+ });
+
+ if (itemRefs.current[expandedIndex]) {
+ observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true });
+ }
+
+ return () => observer.disconnect();
+ }
+ }, [expandedIndex]);
+
+ // State variables
+ const [userColumns, setUserColumns] = useState([]);
+ const [templateColumns, setTemplateColumns] = useState([]);
+
+ // Fetch template columns when schema changes
+ useEffect(() => {
+ if (!schema || !schema["schema"] || !schema.schema["Properties"])
+ return setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") });
+
+ const columns = Object.keys(schema.schema["Properties"]);
+ if (columns) {
+ const newTemplateColumns = schema && !schema.doHierarchyCheckInUploadedData ? columns : [...hierarchy, ...columns];
+ setTemplateColumns(newTemplateColumns);
+ }
+ }, [schema]);
+
+ // Update user columns when uploaded data changes
+ useEffect(() => {
+ const userUploadedColumns = new Set();
+ uploadedData?.["features"]?.forEach((item) => {
+ Object.keys(item["properties"]).forEach((key) => userUploadedColumns.add(key));
+ });
+
+ //field level validations
+ for (const item of userUploadedColumns) {
+ if (item.length < 2) {
+ setToast({ state: "error", message: t("ERROR_FIELD_LENGTH") });
+ close();
+ }
+ }
+ setUserColumns((preUserColumns) => [...preUserColumns, ...userUploadedColumns]);
+ }, [uploadedData]);
+
+ // Dropdown component for selecting user columns
+ const DropDownUserColumnSelect = ({ id, index }) => {
+ const [selectedOption, setSelectedOption] = useState("");
+ useEffect(() => {
+ const obj = resourceMapping.find((item) => item["mappedTo"] === id);
+ if (obj) setSelectedOption({ code: obj["mappedFrom"] });
+ else setSelectedOption();
+ }, [id, resourceMapping]);
+
+ const handleSelectChange = (event) => {
+ const newValue = event.code;
+ setSelectedOption(event);
+ setResourceMapping((previous) => {
+ const revisedData = previous.filter((item) => !(item["mappedTo"] === id || item["mappedFrom"] === newValue));
+ return [...revisedData, { mappedTo: id, mappedFrom: newValue }];
+ });
+ };
+
+ const toggleExpand = (index) => {
+ setExpandedIndex(index === expandedIndex ? null : index);
+ };
+
+ return (
+ {
+ itemRefs.current[index] = el;
+ }}
+ onClick={() => toggleExpand(index)}
+ onKeyDown={() => toggleExpand(index)}
+ >
+ ({ code: item }))}
+ selected={selectedOption}
+ optionKey="code"
+ select={handleSelectChange}
+ style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)" }}
+ showToolTip={true}
+ />
+
+ );
+ };
+
+ const tableColumns = useMemo(
+ () => [
+ {
+ Header: t("COLUMNS_IN_TEMPLATE"),
+ accessor: "COLUMNS_IN_TEMPLATE",
+ },
+ {
+ Header: t("COLUMNS_IN_USER_UPLOAD"),
+ accessor: "COLUMNS_IN_USER_UPLOAD",
+ Cell: ({ cell: { value }, row: { index } }) =>
+ useMemo(() => , [value, index]),
+ },
+ ],
+ [userColumns, setResourceMapping, resourceMapping, t, itemRefs]
+ );
+ const data = useMemo(() => templateColumns.map((item) => ({ COLUMNS_IN_TEMPLATE: t(item), COLUMNS_IN_USER_UPLOAD: item })), [templateColumns]);
+ return (
+
+
{
+ return { style: {} };
+ }}
+ getHeaderProps={(cellInfo) => {
+ return { style: {} };
+ }}
+ />
+
+ );
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js
new file mode 100644
index 00000000000..8f7fd717aba
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js
@@ -0,0 +1,324 @@
+import _ from "lodash";
+
+//create functions here based on module name set in mdms(eg->SearchProjectConfig)
+//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName]
+// these functions will act as middlewares
+// var Digit = window.Digit || {};
+
+const businessServiceMap = {
+ "muster roll": "MR",
+};
+
+const inboxModuleNameMap = {
+ "muster-roll-approval": "muster-roll-service",
+};
+
+function filterUniqueByKey(arr, key) {
+ const uniqueValues = new Set();
+ const result = [];
+
+ arr.forEach((obj) => {
+ const value = obj[key];
+ if (!uniqueValues.has(value)) {
+ uniqueValues.add(value);
+ result.push(obj);
+ }
+ });
+
+ return result;
+}
+
+const epochTimeForTomorrow12 = () => {
+ const now = new Date();
+
+ // Create a new Date object for tomorrow at 12:00 PM
+ const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0);
+
+ // Format the date as "YYYY-MM-DD"
+ const year = tomorrowNoon.getFullYear();
+ const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed
+ const day = String(tomorrowNoon.getDate()).padStart(2, "0");
+
+ return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`);
+};
+
+function cleanObject(obj) {
+ for (const key in obj) {
+ if (Object.hasOwn(obj, key)) {
+ if (Array.isArray(obj[key])) {
+ if (obj[key].length === 0) {
+ delete obj[key];
+ }
+ } else if (
+ obj[key] === undefined ||
+ obj[key] === null ||
+ obj[key] === false ||
+ obj[key] === "" || // Check for empty string
+ (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0)
+ ) {
+ delete obj[key];
+ }
+ }
+ }
+ return obj;
+}
+
+export const UICustomizations = {
+ businessServiceMap,
+ updatePayload: (applicationDetails, data, action, businessService) => {
+ if (businessService === businessServiceMap.estimate) {
+ const workflow = {
+ comment: data.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ estimate: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap.contract) {
+ const workflow = {
+ comment: data?.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ contract: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap?.["muster roll"]) {
+ const workflow = {
+ comment: data?.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ return {
+ musterRoll: applicationDetails,
+ workflow,
+ };
+ }
+ if (businessService === businessServiceMap?.["works.purchase"]) {
+ const workflow = {
+ comment: data.comments,
+ documents: data?.documents?.map((document) => {
+ return {
+ documentType: action?.action + " DOC",
+ fileName: document?.[1]?.file?.name,
+ fileStoreId: document?.[1]?.fileStoreId?.fileStoreId,
+ documentUid: document?.[1]?.fileStoreId?.fileStoreId,
+ tenantId: document?.[1]?.fileStoreId?.tenantId,
+ };
+ }),
+ assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null,
+ action: action.action,
+ };
+ //filtering out the data
+ Object.keys(workflow).forEach((key, index) => {
+ if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key];
+ });
+
+ const additionalFieldsToSet = {
+ projectId: applicationDetails.additionalDetails.projectId,
+ invoiceDate: applicationDetails.billDate,
+ invoiceNumber: applicationDetails.referenceId.split("_")?.[1],
+ contractNumber: applicationDetails.referenceId.split("_")?.[0],
+ documents: applicationDetails.additionalDetails.documents,
+ };
+ return {
+ bill: { ...applicationDetails, ...additionalFieldsToSet },
+ workflow,
+ };
+ }
+ },
+ enableModalSubmit: (businessService, action, setModalSubmit, data) => {
+ if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") {
+ setModalSubmit(data?.acceptTerms);
+ }
+ },
+ enableHrmsSearch: (businessService, action) => {
+ if (businessService === businessServiceMap.estimate) {
+ return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD");
+ }
+ if (businessService === businessServiceMap.contract) {
+ return action.action.includes("VERIFY_AND_FORWARD");
+ }
+ if (businessService === businessServiceMap?.["muster roll"]) {
+ return action.action.includes("VERIFY");
+ }
+ if (businessService === businessServiceMap?.["works.purchase"]) {
+ return action.action.includes("VERIFY_AND_FORWARD");
+ }
+ return false;
+ },
+ getBusinessService: (moduleCode) => {
+ if (moduleCode?.includes("estimate")) {
+ return businessServiceMap?.estimate;
+ } else if (moduleCode?.includes("contract")) {
+ return businessServiceMap?.contract;
+ } else if (moduleCode?.includes("muster roll")) {
+ return businessServiceMap?.["muster roll"];
+ } else if (moduleCode?.includes("works.purchase")) {
+ return businessServiceMap?.["works.purchase"];
+ } else if (moduleCode?.includes("works.wages")) {
+ return businessServiceMap?.["works.wages"];
+ } else if (moduleCode?.includes("works.supervision")) {
+ return businessServiceMap?.["works.supervision"];
+ } else {
+ return businessServiceMap;
+ }
+ },
+ getInboxModuleName: (moduleCode) => {
+ if (moduleCode?.includes("estimate")) {
+ return inboxModuleNameMap?.estimate;
+ } else if (moduleCode?.includes("contract")) {
+ return inboxModuleNameMap?.contracts;
+ } else if (moduleCode?.includes("attendence")) {
+ return inboxModuleNameMap?.attendencemgmt;
+ } else {
+ return inboxModuleNameMap;
+ }
+ },
+ SearchCampaign: {
+ preProcess: (data, additionalDetails) => {
+ const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {};
+ data.body.CampaignDetails = {};
+ data.body.CampaignDetails.pagination = data?.state?.tableForm;
+ data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId();
+ // data.body.CampaignDetails.boundaryCode = boundaryCode;
+ data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid;
+ data.body.CampaignDetails.campaignName = campaignName;
+ data.body.CampaignDetails.status = ["drafted"];
+ if (startDate) {
+ data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate);
+ } else {
+ data.body.CampaignDetails.startDate = epochTimeForTomorrow12();
+ }
+ if (endDate) {
+ data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate);
+ }
+ data.body.CampaignDetails.projectType = projectType?.[0]?.code;
+
+ cleanObject(data.body.CampaignDetails);
+
+ return data;
+ },
+ populateProjectType: () => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+
+ return {
+ url: "/egov-mdms-service/v1/_search",
+ params: { tenantId },
+ body: {
+ MdmsCriteria: {
+ tenantId,
+ moduleDetails: [
+ {
+ moduleName: "HCM-PROJECT-TYPES",
+ masterDetails: [
+ {
+ name: "projectTypes",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ changeQueryName: "projectType",
+ config: {
+ enabled: true,
+ select: (data) => {
+ const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => {
+ return {
+ ...row,
+ i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`),
+ };
+ });
+ return dropdownData;
+ },
+ },
+ };
+ },
+ customValidationCheck: (data) => {
+ //checking if both to and from date are present then they should be startDate<=endDate
+ const { startDate, endDate } = data;
+ const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate);
+ const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate);
+
+ if (startDate && endDate && startDateEpoch > endDateEpoch) {
+ return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" };
+ }
+ return false;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ if (key === "CAMPAIGN_DATE") {
+ return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`;
+ }
+ },
+ },
+ SearchMicroplan: {
+ preProcess: (data, additionalDetails) => {
+ const { name, status } = data?.state?.searchForm || {};
+
+ data.body.PlanConfigurationSearchCriteria = {};
+ data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit;
+ // data.body.PlanConfigurationSearchCriteria.limit = 10
+ data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset;
+ data.body.PlanConfigurationSearchCriteria.name = name;
+ data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid;
+ // delete data.body.PlanConfigurationSearchCriteria.pagination
+ data.body.PlanConfigurationSearchCriteria.status = status?.status;
+ cleanObject(data.body.PlanConfigurationSearchCriteria);
+ return data;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ if (key === "CAMPAIGN_DATE") {
+ return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`;
+ }
+ },
+ },
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js
new file mode 100644
index 00000000000..b43b9f40e2b
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js
@@ -0,0 +1,38 @@
+export const LOCALITY = "Locality";
+
+export const EXCEL = "Excel";
+
+export const GEOJSON = "GeoJSON";
+
+export const SHAPEFILE = "Shapefile";
+
+export const commonColumn = "boundaryCode";
+
+export const ACCEPT_HEADERS = {
+ GeoJSON: "application/geo+json",
+ Shapefile: "application/shapefile",
+ Excel: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+};
+
+// Define the colors of the gradient for choropleth mapping
+export const MapChoroplethGradientColors = [
+ { percent: 0, color: "#edd1cf" },
+ { percent: 100, color: "#b52626" },
+];
+
+export const PRIMARY_THEME_COLOR = "#C84C0E";
+
+export const BOUNDARY_DATA_SHEET = "MICROPLAN_BOUNDARY_DATA_SHEET";
+export const FACILITY_DATA_SHEET = "MICROPLAN_FACILITY_DATA_SHEET";
+
+export const FILE_STORE = "microplan";
+
+export const SHEET_PASSWORD = "eGov_sheet_password";
+
+export const SHEET_COLUMN_WIDTH = 40;
+
+export const SCHEMA_PROPERTIES_PREFIX = "DISPLAY";
+
+export const UNPROTECT_TILL_ROW = "10000";
+
+export const UPLOADED_DATA_ACTIVE_STATUS = "MICROPLAN_ACTIVE";
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json
new file mode 100644
index 00000000000..768e323ef86
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json
@@ -0,0 +1,40 @@
+{
+ "timeLineOptions": [
+ {
+ "id": 0,
+ "name": "MICROPLAN_DETAILS",
+ "component": "MicroplanDetails",
+ "checkForCompleteness": true
+ },
+ {
+ "id": 1,
+ "name": "UPLOAD_DATA",
+ "component": "Upload",
+ "checkForCompleteness": true
+ },
+ {
+ "id": 2,
+ "name": "HYPOTHESIS",
+ "component": "Hypothesis",
+ "checkForCompleteness": true
+ },
+ {
+ "id": 3,
+ "name": "FORMULA_CONFIGURATION",
+ "component": "RuleEngine",
+ "checkForCompleteness": true
+ },
+ {
+ "id": 4,
+ "name": "MAPPING",
+ "component": "Mapping",
+ "checkForCompleteness": false
+ },
+ {
+ "id": 5,
+ "name": "MICROPLAN_GENERATION",
+ "component": "MicroplanPreview",
+ "checkForCompleteness": false
+ }
+ ]
+}
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js
new file mode 100644
index 00000000000..241f8ec64ec
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js
@@ -0,0 +1,193 @@
+export const tourSteps = (t) => {
+ return {
+ microplanDetails: {
+ name: "microplanDetails",
+ run: true,
+ steps: [
+ {
+ content: t("HELP_MICROPLAN_DETAILS_CAMPAIGN_DETAILS"),
+ target: ".microplan-campaign-detials",
+ disableBeacon: true,
+ placement: "bottom",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_MICROPLAN_DETAILS_MICROPLAN_NAME"),
+ target: ".microplan-name",
+ disableBeacon: true,
+ placement: "bottom",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ ],
+ tourActive: true,
+ },
+ upload: {
+ name: "upload",
+ run: true,
+ steps: [
+ {
+ content: t("HELP_UPLOAD_FILETYPE_OPTION_CONTAINER"),
+ target: ".upload-option-container",
+ disableBeacon: true,
+ placement: "top-end",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ ],
+ tourActive: true,
+ },
+ hypothesis: {
+ name: "hypothesis",
+ run: true,
+ steps: [
+ {
+ content: t("HELP_HYPOTHESIS_INTERACTABLE_SECTION"),
+ target: ".hypothesis-help",
+ disableBeacon: true,
+ placement: "right-start",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ // {
+ // content:
+ // t("HELP_RULE_ENGINE_INPUT"),
+ // target: ".last-container .key",
+ // disableBeacon: true,
+ // placement: "top-start",
+ // title: "",
+ // },
+ // {
+ // content:
+ // t("HELP_HYPOTHESIS_DELETE_BUTTON"),
+ // target: ".last-containe .delete-button-help-locator",
+ // disableBeacon: true,
+ // placement: "top-start",
+ // title: "",
+ // },
+ {
+ content: t("HELP_HYPOTHESIS_ADD_BUTTON"),
+ target: ".add-button-help",
+ disableBeacon: true,
+ placement: "top-start",
+ title: "",
+ disableOverlay :true,
+ },
+ ],
+ tourActive: true,
+ },
+ ruleEngine: {
+ name: "ruleEngine",
+ run: true,
+ steps: [
+ {
+ content: t("HELP_RULE_ENGINE_INTERACTABLE_SECTION"),
+ target: ".rule-engine-help",
+ disableBeacon: true,
+ placement: "right-start",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_RULE_ENGINE_INPUT"),
+ target: ".user-input-section .interactable-section .select-and-input-wrapper-first .input",
+ disableBeacon: true,
+ placement: "top-end",
+ title: "",
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_RULE_ENGINE_DELETE_BUTTON"),
+ target: ".select-and-input-wrapper-first .delete-button",
+ disableBeacon: true,
+ placement: "left-start",
+ title: "",
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_RULE_ENGINE_ADD_BUTTON"),
+ target: ".add-button-help",
+ disableBeacon: true,
+ placement: "top-start",
+ title: "",
+ disableOverlay :true,
+ },
+ ],
+ tourActive: true,
+ },
+ mapping: {
+ name: "mapping",
+ run: true,
+ steps: [
+ {
+ content: t("HELP_MAPPING_BOUNDARY_SELECTION"),
+ target: ".filter-by-boundary .button-primary",
+ disableBeacon: true,
+ placement: "right-end",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_MAPPING_BASE_MAP"),
+ target: ".base-map-selector .icon-first",
+ disableBeacon: true,
+ placement: "left-start",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_MAPPING_FILTER"),
+ target: ".filter-icon p",
+ disableBeacon: true,
+ placement: "left-start",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_MAPPING_VIRTUALIZATION"),
+ target: ".virtualization-icon p",
+ disableBeacon: true,
+ placement: "left-start",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ {
+ content: t("HELP_MAPPING_MAP_GEOMETRIES"),
+ target: ".map-container",
+ disableBeacon: true,
+ placement: "top-end",
+ title: "",
+ disableScrolling: true,
+ disableOverlay :true,
+ },
+ ],
+ tourActive: true,
+ },
+ microplanPreview: {
+ name: "microplanPreview",
+ run: true,
+ steps: [
+ {
+ content: t("HELP_MICROPLAN_DETAILS_EDIT_ROWS"),
+ target: ".preview-container",
+ disableBeacon: true,
+ placement: "top-end",
+ title: "",
+ disableOverlay :true,
+ disableScrolling: true,
+ },
+ ],
+ tourActive: true,
+ },
+ };
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js
new file mode 100644
index 00000000000..1241d678738
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js
@@ -0,0 +1,42 @@
+import utils from "../utils";
+import useCreatePlanConfig from "./useCreatePlanConfig";
+import useSearchPlanConfig from "./useSearchPlanConfig";
+import useUpdatePlanConfig from "./useUpdatePlanConfig";
+import useSavedMicroplans from "./useSavedMicroplans";
+import useSearchCampaign from "./useSearchCampaign";
+import { useGenerateIdCampaign } from "./useGenerateIdCampaign";
+const UserService = {};
+
+const microplan = {
+ useCreatePlanConfig,
+ useSearchPlanConfig,
+ useUpdatePlanConfig,
+ useSavedMicroplans,
+ useSearchCampaign,
+ useGenerateIdCampaign,
+};
+
+const contracts = {};
+
+const Hooks = {
+ attendance: {
+ update: () => {},
+ },
+ microplan,
+ contracts,
+};
+
+const Utils = {
+ browser: {
+ sample: () => {},
+ },
+ microplan: {
+ ...utils,
+ },
+};
+
+export const CustomisedHooks = {
+ Hooks,
+ UserService,
+ Utils,
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js
new file mode 100644
index 00000000000..6afb891b15b
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js
@@ -0,0 +1,8 @@
+import { useMutation } from "react-query";
+import CreatePlanConfig from "../services/CreatePlanConfig";
+
+const useCreatePlanConfig = () => {
+ return useMutation(data => CreatePlanConfig(data))
+}
+
+export default useCreatePlanConfig;
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js
new file mode 100644
index 00000000000..f315dda5ff8
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js
@@ -0,0 +1,26 @@
+export const useGenerateIdCampaign = ({ type, hierarchyType, filters, campaignId, config = {} }) => {
+ const updatedFilters = filters?.map(({ type, ...rest }) => ({
+ ...rest,
+ boundaryType: type,
+ }));
+ const reqCriteria = {
+ url: `/project-factory/v1/data/_generate`,
+ changeQueryName: `${type}${hierarchyType}${filters}`,
+ params: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ type: type,
+ forceUpdate: true,
+ hierarchyType: hierarchyType,
+ campaignId: campaignId,
+ },
+ body: type === "boundary" ? (updatedFilters === undefined ? { Filters: null } : { Filters: { boundaries: updatedFilters } }) : {},
+ config: {
+ ...config,
+ cacheTime: 0,
+ staleTime: 0,
+ },
+ };
+ const { data: Data, refetch, isLoading } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+
+ return { isLoading: isLoading, data: Data?.GeneratedResource?.[0]?.id, refetch };
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js
new file mode 100644
index 00000000000..15e423d59e0
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js
@@ -0,0 +1,21 @@
+import { useTranslation } from "react-i18next";
+
+export const useNumberFormatter = (FormatMapping) => {
+ const { i18n } = useTranslation();
+
+ const formatNumber = (value, options) => {
+ try {
+ const currentLanguage = i18n.language;
+ const fallbackLanguage = i18n.options.fallbackLng[0]; // Get the first language in the fallback list
+ const locale = FormatMapping?.[currentLanguage] || FormatMapping?.[fallbackLanguage] || currentLanguage || "";
+ return new Intl.NumberFormat(locale, options).format(value);
+ } catch (error) {
+ console.error("Error formatting number:", error);
+ return value;
+ }
+ };
+
+ return { formatNumber };
+};
+
+export default useNumberFormatter;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js
new file mode 100644
index 00000000000..23c1259c6c4
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js
@@ -0,0 +1,23 @@
+import { useQuery } from "react-query";
+import SearchSavedPlans from "../services/searchSavedPlans";
+
+const useSavedMicroplans = (reqCriteria) => {
+ const { body, config, params, state, url } = reqCriteria;
+ const { isLoading, data, isFetching, refetch } = useQuery(["SAVED_MICROPLANS", url], () => SearchSavedPlans(body), {
+ ...config,
+ cacheTime: 0,
+ staleTime: 0,
+ onError: (err) => console.error("Error fetching saved microplans:", err),
+ });
+
+ return {
+ isLoading,
+ isFetching,
+ data,
+ refetch,
+ revalidate: () => {},
+ };
+};
+
+// () => SearchSavedPlans(data)
+export default useSavedMicroplans;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js
new file mode 100644
index 00000000000..e2644f00ca9
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js
@@ -0,0 +1,8 @@
+import { useQuery } from "react-query";
+import SearchCampaignConfig from "../services/SearchCampaignConfig";
+
+const useSearchCampaign = (data, config = {}) => {
+ return useQuery(["SEARCH_CAMPAIGN",data], () => SearchCampaignConfig(data), { ...config });
+};
+
+export default useSearchCampaign;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js
new file mode 100644
index 00000000000..003fdaa4f51
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js
@@ -0,0 +1,8 @@
+import { useMutation } from "react-query";
+import SearchPlanConfig from "../services/SearchPlanConfig";
+
+const useSearchPlanConfig = (data, config = {}) => {
+ return useQuery([data?.tenantId, data?.id, data?.name, data?.executionPlanId, data?.userUuid, data?.offset, data?.limit], () => SearchPlanConfig(data), { ...config });
+};
+
+export default useSearchPlanConfig;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js
new file mode 100644
index 00000000000..17b16145a08
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js
@@ -0,0 +1,8 @@
+import { useMutation } from "react-query";
+import UpdatePlanConfig from "../services/UpdatePlanConfig";
+
+const useUpdatePlanConfig = () => {
+ return useMutation(data => UpdatePlanConfig(data))
+}
+
+export default useUpdatePlanConfig;
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js
new file mode 100644
index 00000000000..03f82f59456
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js
@@ -0,0 +1,217 @@
+import React from "react";
+
+export const PopulationSvg = (style) => {
+ return `
+
+ `;
+};
+
+export const HelpOutlineIcon = ({ className = "", fill = "", style = {} }) => (
+
+);
+
+export const DefaultMapMarkerSvg = (style) => {
+ return ``;
+};
+
+
+export const WarehouseMarker = ({
+ className = "",
+ fill = "white",
+ fillBackground = "#42BBFF",
+ style = {},
+ width = "3.125rem",
+ height = "3.125rem",
+}) => {
+ return `
+
+ `;
+};
+
+export const Warehouse = ({ className = "", fill = "white", fillBackground = "#42BBFF", style = {}, width = "1.5rem", height = "1.5rem" }) => {
+ return (
+
+ );
+};
+
+export const Church = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "1.5rem", height = "1.5rem" }) => {
+ return (
+
+ );
+};
+
+export const School = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1.5rem", height = "1.5rem" }) => {
+ return (
+
+ );
+};
+
+export const HealthFacility = ({ className = "", fill = "white", fillBackground = "#0C9219", style = {}, width = "1.5rem", height = "1.5rem" , onClick=null}) => {
+ return (
+
+ );
+};
+
+export const ChurchMarker = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "3.125rem", height = "3.125rem" }) => {
+ return `
+
+`;
+};
+
+export const SchoolMarker = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "3.125rem", height = "3.125rem" }) => {
+ return `
+
+`;
+};
+
+export const HealthFacilityMarker = ({
+ className = "",
+ fill = "white",
+ fillBackground = "#0C9219",
+ style = {},
+ width = "3.125rem",
+ height = "3.125rem",
+}) => {
+ return `
+
+`;
+};
+
+
+
+
+
+export const PlusWithSurroundingCircle = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1rem", height = "1rem" ,onClick=null }) => {
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js
new file mode 100644
index 00000000000..97fbe135bd2
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js
@@ -0,0 +1,296 @@
+import React, { useState, useEffect, useCallback, Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import { timeLineOptions } from "../../configs/timeLineOptions.json";
+import Upload from "../../components/Upload";
+import Hypothesis from "../../components/Hypothesis";
+import RuleEngine from "../../components/RuleEngine";
+import Mapping from "../../components/Mapping";
+import Navigator from "../../components/Nagivator";
+import { Toast } from "@egovernments/digit-ui-components";
+import MicroplanPreview from "../../components/MicroplanPreview";
+import MicroplanDetails from "../../components/MicroplanDetails";
+
+export const components = {
+ MicroplanDetails,
+ Upload,
+ Hypothesis,
+ RuleEngine,
+ Mapping,
+ MicroplanPreview,
+};
+
+import MicroplanCreatedScreen from "../../components/MicroplanCreatedScreen";
+import { LoaderWithGap, Tutorial } from "@egovernments/digit-ui-react-components";
+import { useMyContext } from "../../utils/context";
+import { updateSessionUtils } from "../../utils/updateSessionUtils";
+import { render } from "react-dom";
+
+// Main component for creating a microplan
+const CreateMicroplan = () => {
+ // Fetching data using custom MDMS hook
+ const { id: campaignId = "" } = Digit.Hooks.useQueryParams();
+ const { mutate: CreateMutate } = Digit.Hooks.microplan.useCreatePlanConfig();
+ const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig();
+ const [toRender, setToRender] = useState("navigator");
+ const { t } = useTranslation();
+
+ // States
+ const [microplanData, setMicroplanData] = useState();
+ const [operatorsObject, setOperatorsObject] = useState([]);
+ const [toast, setToast] = useState();
+ const [checkForCompleteness, setCheckForCompletion] = useState([]);
+ const [loaderActivation, setLoaderActivation] = useState(false);
+ const { state } = useMyContext();
+
+ //fetch campaign data
+ const { id = "" } = Digit.Hooks.useQueryParams();
+ const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign(
+ {
+ CampaignDetails: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ ids: [id],
+ },
+ },
+ {
+ enabled: !!id,
+ }
+ );
+ // to save microplan helper data to ssn
+ useEffect(() => {
+ if (campaignData) Digit.SessionStorage.set("microplanHelperData", { ...Digit.SessionStorage.get("microplanHelperData"), campaignData });
+ }, [campaignData]);
+
+ const campaignType = campaignData?.projectType;
+
+ // request body for boundary hierarchy api
+ const reqCriteria = {
+ url: `/boundary-service/boundary-hierarchy-definition/_search`,
+ params: {},
+ body: {
+ BoundaryTypeHierarchySearchCriteria: {
+ tenantId: Digit.ULBService.getStateId(),
+ hierarchyType: campaignData?.hierarchyType,
+ },
+ },
+ config: {
+ enabled: !!campaignData?.hierarchyType,
+ select: (data) => {
+ return (
+ data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map(
+ (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`
+ ) || {}
+ );
+ },
+ },
+ };
+ const { isLoading: ishierarchyLoading, data: hierarchyData } = Digit.Hooks.useCustomAPIHook(reqCriteria);
+
+ // useEffect to initialise the data from MDMS
+ useEffect(() => {
+ if (!state || !state.RuleConfigureOperators) return;
+ const temp = state?.RuleConfigureOperators;
+ if (temp) {
+ setOperatorsObject(temp);
+ } else {
+ return;
+ }
+ setOperatorsObject(temp);
+ }, []);
+
+ // useEffect to store data in session storage
+ useEffect(() => {
+ if (!microplanData) return;
+ Digit.SessionStorage.set("microplanData", microplanData);
+ }, [microplanData]);
+
+ // useEffect to store data in session storage
+ useEffect(() => {
+ const data = Digit.SessionStorage.get("microplanData");
+ if (data?.microplanStatus === "GENERATED") setToRender("success-screen");
+ let statusData = {};
+ let toCheckCompletenesData = [];
+ timeLineOptions.forEach((item) => {
+ statusData[item.name] = false;
+ if (item?.checkForCompleteness) toCheckCompletenesData.push(item.name);
+ });
+ if (data && data?.status) {
+ if (Object.keys(data?.status) === 0) setMicroplanData({ ...data, status: statusData });
+ else setMicroplanData({ ...data });
+ }
+ setCheckForCompletion(toCheckCompletenesData);
+ }, []);
+
+ // An addon function to pass to Navigator
+ const nextEventAddon = useCallback(
+ async (currentPage, checkDataCompletion, setCheckDataCompletion) => {
+ if (!microplanData) {
+ setCheckDataCompletion("perform-action");
+ return;
+ }
+ setMicroplanData((previous) => ({
+ ...previous,
+ status: { ...previous?.status, [currentPage?.name]: checkDataCompletion === "valid" },
+ }));
+
+ setCheckDataCompletion("false");
+ let body = Digit.Utils.microplan.mapDataForApi(
+ microplanData,
+ operatorsObject,
+ microplanData?.microplanDetails?.name,
+ campaignId,
+ "DRAFT",
+ microplanData?.planConfigurationId ? "update" : "create"
+ );
+ if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) {
+ setCheckDataCompletion("perform-action");
+ return;
+ }
+ setLoaderActivation(true);
+ try {
+ if (!microplanData?.planConfigurationId) {
+ await createPlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state);
+ } else if (microplanData?.planConfigurationId) {
+ await updatePlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state);
+ }
+ } catch (error) {
+ console.error("Failed to create/update plan configuration:", error);
+ }
+ },
+ [microplanData, UpdateMutate, CreateMutate]
+ );
+
+ const createPlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => {
+ await CreateMutate(body, {
+ onSuccess: async (data) => {
+ const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName");
+ const additionalProps = {
+ hierarchyData: hierarchyData,
+ t,
+ campaignType,
+ campaignData,
+ readMeSheetName: readMeConstant ? readMeConstant.value : undefined,
+ };
+ const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps);
+ if (computedSession) {
+ computedSession.microplanStatus = "DRAFT";
+ setMicroplanData(computedSession);
+ } else {
+ console.error("Failed to compute session data.");
+ }
+ setLoaderActivation(false);
+ setCheckDataCompletion("perform-action");
+ },
+ onError: (error, variables) => {
+ setToast({
+ message: t("ERROR_DATA_NOT_SAVED"),
+ state: "error",
+ transitionTime: 10000,
+ });
+ setTimeout(() => {
+ setLoaderActivation(false);
+ setCheckDataCompletion("false");
+ }, 2000);
+ },
+ });
+ };
+
+ const updatePlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => {
+ body.PlanConfiguration["id"] = microplanData?.planConfigurationId;
+ body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails;
+ await UpdateMutate(body, {
+ onSuccess: async (data) => {
+ const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName");
+ const additionalProps = {
+ hierarchyData: hierarchyData,
+ t,
+ campaignType,
+ campaignData,
+ readMeSheetName: readMeConstant ? readMeConstant.value : undefined,
+ };
+ const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps);
+ if (computedSession) {
+ computedSession.microplanStatus = "DRAFT";
+ setMicroplanData(computedSession);
+ } else {
+ console.error("Failed to compute session data.");
+ }
+ setLoaderActivation(false);
+ setCheckDataCompletion("perform-action");
+ },
+ onError: (error, variables) => {
+ setToast({
+ message: t("ERROR_DATA_NOT_SAVED"),
+ state: "error",
+ transitionTime: 10000,
+ });
+ setTimeout(() => {
+ setLoaderActivation(false);
+ setCheckDataCompletion("false");
+ }, 2000);
+ },
+ });
+ };
+
+ const setCurrentPageExternally = useCallback(
+ (props) => {
+ switch (props.method) {
+ case "set": {
+ let currentPage;
+ const data = Digit.SessionStorage.get("microplanData");
+ if (data?.currentPage) currentPage = data.currentPage;
+ if (currentPage && props?.setCurrentPage && timeLineOptions.find((item) => item.id === currentPage?.id)) {
+ props.setCurrentPage(currentPage);
+ return true;
+ }
+ break;
+ }
+ case "save": {
+ if (props.currentPage) {
+ setMicroplanData((previous) => ({ ...previous, currentPage: props.currentPage }));
+ }
+ break;
+ }
+ }
+ },
+ [microplanData, setMicroplanData, Navigator]
+ );
+
+ const completeNavigation = useCallback(() => {
+ setToRender("success-screen");
+ }, [setToRender]);
+
+ return (
+ <>
+
+ {toRender === "navigator" && (
+
+ )}
+ {toRender === "success-screen" && }
+
+ {toast && (
+ setToast(undefined)}
+ />
+ )}
+ {loaderActivation && }
+ >
+ );
+};
+
+export default CreateMicroplan;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js
new file mode 100644
index 00000000000..7534c1b2af1
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js
@@ -0,0 +1,54 @@
+import React, { Fragment } from "react";
+import { useTranslation } from "react-i18next";
+import { Link } from "react-router-dom";
+import { ArrowForward } from "@egovernments/digit-ui-svg-components";
+import { Button } from "@egovernments/digit-ui-react-components";
+import { useHistory } from "react-router-dom";
+import { ActionBar } from "@egovernments/digit-ui-components";
+
+const Guidelines = ({ path }) => {
+ const { t } = useTranslation();
+ const history = useHistory()
+ // Keeping inline style for now because design for this screen is not given yet
+ const { id = "" } = Digit.Hooks.useQueryParams();
+ const onNextClick = ()=>{
+ history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${id}`);
+ }
+ return (
+ <>
+
+
+ {t("CREATE_MICROPLAN_GUIDELINES")}
+
+
+ {/* Action bar */}
+
+ {/* Next/Submit button */}
+
+
+
+
+ >
+ );
+};
+
+export default Guidelines;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js
new file mode 100644
index 00000000000..39c26661891
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js
@@ -0,0 +1,204 @@
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { Header, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components";
+import { useHistory } from "react-router-dom";
+import { updateSessionUtils } from "../../utils/updateSessionUtils";
+import { useMyContext } from "../../utils/context";
+
+const configs = {
+ label: "SAVED_MICROPLANS",
+ type: "search",
+ apiDetails: {
+ serviceName: "/plan-service/config/_search",
+ requestParam: {},
+ requestBody: {},
+ minParametersForSearchForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "SearchMicroplan",
+ tableFormJsonPath: "requestBody.PlanConfigurationSearchCriteria.pagination",
+ searchFormJsonPath: "requestBody.PlanConfigurationSearchCriteria",
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ type: "search",
+ typeMobile: "filter",
+ headerLabel: "SAVED_MICROPLANS",
+ headerStyle: null,
+ primaryLabel: "ES_COMMON_SEARCH",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 0,
+ // "showFormInstruction": "TQM_SEARCH_HINT",
+ defaultValues: {
+ name: "",
+ status: "",
+ },
+ fields: [
+ {
+ label: "MICROPLAN_NAME",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "name",
+ style: {
+ marginBottom: "0px",
+ },
+ },
+ },
+ {
+ label: "MICROPLAN_STATUS",
+ type: "dropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "status",
+ optionsKey: "status",
+ optionsCustomStyle: {
+ top: "2.3rem",
+ },
+ mdmsConfig: {
+ masterName: "MicroplanStatus",
+ moduleName: "hcm-microplanning",
+ localePrefix: "MICROPLAN_STATUS",
+ },
+ },
+ },
+ ],
+ },
+ label: "",
+ children: {},
+ show: true,
+ // "labelMobile": "TQM_INBOX_SEARCH"
+ },
+ searchResult: {
+ uiConfig: {
+ columns: [
+ {
+ label: "MICROPLAN_NAME",
+ jsonPath: "name",
+ },
+ {
+ label: "MICROPLAN_STATUS",
+ jsonPath: "status",
+ prefix: "MICROPLAN_STATUS_COLUMN_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGNS_ASSIGNED",
+ jsonPath: "CampaignDetails.campaignName",
+ },
+ {
+ label: "CAMPAIGN_DATE",
+ jsonPath: "CampaignDetails.startDate",
+ additionalCustomization: true,
+ },
+ ],
+ showActionBarMobileCard: true,
+ actionButtonLabelMobileCard: "TQM_VIEW_RESULTS",
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "PlanConfiguration",
+ tableClassName: "table pqm-table",
+ noColumnBorder: true,
+ rowClassName: "table-row-mdms table-row-mdms-hover",
+ },
+ children: {},
+ show: true,
+ },
+ },
+ additionalSections: {},
+ persistFormData: true,
+ showAsRemovableTagsInMobile: false,
+ customHookName: "microplan.useSavedMicroplans",
+};
+
+const SavedMicroplans = () => {
+ const [showLoader, setShowLoader] = useState(false);
+ const { state } = useMyContext();
+ const history = useHistory();
+ const { t } = useTranslation();
+
+ const fetchHierarchyData = async (hierarchyType) => {
+ const response = await Digit.CustomService.getResponse({
+ url: "/boundary-service/boundary-hierarchy-definition/_search",
+ useCache: false,
+ method: "POST",
+ userService: false,
+ body: {
+ BoundaryTypeHierarchySearchCriteria: {
+ tenantId: Digit.ULBService.getStateId(),
+ hierarchyType,
+ },
+ },
+ });
+ if (response?.BoundaryHierarchy?.length) {
+ return (
+ response?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map(
+ (item) => `${hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`
+ ) || {}
+ );
+ }
+ console.error("Invalid response structure");
+ };
+
+ const computeAdditionalProps = (row, state, t, hierarchyData) => {
+ const campaignDetails = row?.original?.CampaignDetails;
+ const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value;
+ return {
+ hierarchyData,
+ t,
+ campaignType: campaignDetails?.projectType,
+ campaignData: campaignDetails,
+ readMeSheetName,
+ };
+ };
+
+ const onClickRow = (row) => {
+ const handleClick = async () => {
+ setShowLoader(true);
+ try {
+ const campaignType = row?.original?.CampaignDetails?.projectType;
+ const hierarchyData = await fetchHierarchyData(row?.original?.CampaignDetails?.hierarchyType);
+ const additionalProps = computeAdditionalProps(row, state, t, hierarchyData);
+
+ // Compute the session object based on the row?.original data and then re-route
+ const computedSession = await updateSessionUtils.computeSessionObject(row.original, state, additionalProps);
+ Digit.SessionStorage.set("microplanData", computedSession);
+
+ setShowLoader(false);
+ history.push(`/${window.contextPath}/employee/microplanning/edit-saved-microplan?id=${row?.original?.executionPlanId}`);
+ } catch (error) {
+ console.error(`Failed to process the request: ${error.message}`);
+ setShowLoader(false);
+ }
+ };
+
+ handleClick();
+ };
+
+ const savedMircoplanSession = Digit.Hooks.useSessionStorage("SAVED_MICROPLAN_SESSION", {});
+
+ if (showLoader) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default SavedMicroplans;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js
new file mode 100644
index 00000000000..8f2131eefdd
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js
@@ -0,0 +1,226 @@
+import React, { useEffect, useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import { Header, InboxSearchComposer, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components";
+import { useHistory, useParams } from "react-router-dom";
+
+const configs = {
+ label: "SELECT_CAMPAIGN",
+ type: "search",
+ apiDetails: {
+ serviceName: "/project-factory/v1/project-type/search",
+ requestParam: {},
+ requestBody: {},
+ minParametersForSearchForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "SearchCampaign",
+ tableFormJsonPath: "requestBody.CampaignDetails.pagination",
+ searchFormJsonPath: "requestBody.CampaignDetails",
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ type: "search",
+ // typeMobile: "filter",
+ headerLabel: "SELECT_CAMPAIGN",
+ headerStyle: null,
+ primaryLabel: "ES_COMMON_SEARCH",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 1,
+ // "showFormInstruction": "TQM_SEARCH_HINT",
+ defaultValues: {
+ campaignName: "",
+ projectType: "",
+ startDate: "",
+ endDate: "",
+ boundaryCode: "",
+ },
+ fields: [
+ {
+ label: "CAMPAIGN_NAME",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "campaignName",
+ style: {
+ marginBottom: "0px",
+ },
+ error: "ERR_MIN_LENGTH_CAMPAIGN_NAME",
+ validationErrorStyles: {
+ marginTop: "0.3rem",
+ },
+ validation: {
+ minLength: 2,
+ },
+ },
+ },
+ // {
+ // label: "CAMPAIGN_TYPE",
+ // type: "dropdown",
+ // isMandatory: false,
+ // disable: false,
+ // populators: {
+ // name: "projectType",
+ // optionsKey: "name",
+ // optionsCustomStyle: {
+ // top: "2.3rem",
+ // },
+ // mdmsConfig: {
+ // masterName: "projectTypes",
+ // moduleName: "HCM-PROJECT-TYPES",
+ // localePrefix: "CAMPAIGN_TYPE",
+ // },
+ // },
+ // },
+ {
+ label: "CAMPAIGN_TYPE",
+ type: "apidropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "projectType",
+ optionsKey: "i18nKey",
+ optionsCustomStyle: {
+ top: "2.3rem",
+ },
+ allowMultiSelect: false,
+ masterName: "commonUiConfig",
+ moduleName: "SearchCampaign",
+ customfn: "populateProjectType",
+ },
+ },
+ {
+ label: "CAMPAIGN_START_DATE",
+ type: "date",
+ isMandatory: false,
+ key: "startDate",
+ disable: false,
+ preProcess: {
+ updateDependent: ["populators.max"],
+ },
+ populators: {
+ name: "startDate",
+ style: {
+ marginBottom: "0px",
+ },
+ error: "DATE_VALIDATION_MSG",
+ },
+ },
+ {
+ label: "CAMPAIGN_END_DATE",
+ type: "date",
+ isMandatory: false,
+ disable: false,
+ key: "endDate",
+ preProcess: {
+ updateDependent: ["populators.max"],
+ },
+ populators: {
+ name: "endDate",
+ error: "DATE_VALIDATION_MSG",
+ min: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0, 10),
+ style: {
+ marginBottom: "0px",
+ },
+ },
+ },
+ // {
+ // label: "CAMPAIGN_BOUNDARY",
+ // type: "text",
+ // isMandatory: false,
+ // disable: false,
+ // populators: {
+ // name: "boundaryCode",
+ // style: {
+ // marginBottom: "0px",
+ // },
+ // },
+ // },
+ ],
+ },
+ label: "",
+ children: {},
+ show: true,
+ // "labelMobile": "TQM_INBOX_SEARCH"
+ },
+ searchResult: {
+ uiConfig: {
+ columns: [
+ {
+ label: "CAMPAIGN_NAME",
+ jsonPath: "campaignName",
+ // "additionalCustomization": true
+ },
+ {
+ label: "CAMPAIGN_TYPE",
+ jsonPath: "projectType",
+ // "additionalCustomization": false,
+ prefix: "CAMPAIGN_TYPE_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_BOUNDARY_CAMP",
+ jsonPath: "boundaryCode",
+ // "additionalCustomization": false,
+ prefix: "CAMPAIGN_BOUNDARY_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_BENEFICIARY_TYPE",
+ jsonPath: "additionalDetails.beneficiaryType",
+ prefix: "CAMPAIGN_BENEFICIARY_TYPE_",
+ translate: true,
+ },
+ {
+ label: "CAMPAIGN_DATE",
+ jsonPath: "startDate",
+ additionalCustomization: true,
+ },
+ ],
+ showActionBarMobileCard: true,
+ actionButtonLabelMobileCard: "TQM_VIEW_RESULTS",
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "CampaignDetails",
+ tableClassName: "table pqm-table",
+ rowClassName: "table-row-mdms table-row-mdms-hover",
+ noColumnBorder: true,
+ },
+ children: {},
+ show: true,
+ },
+ },
+ additionalSections: {},
+ persistFormData: true,
+ showAsRemovableTagsInMobile: false,
+};
+const SelectCampaign = () => {
+ const { t } = useTranslation();
+ const history = useHistory();
+
+ const onClickRow = (row) => {
+ // history.push(`/${window.contextPath}/employee/microplanning/help-guidelines?id=${row?.original?.id}`);
+ history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.id}`);
+ };
+
+ const SelectCampaignSession = Digit.Hooks.useSessionStorage("SELECT_CAMPAIGN_SESSION", {});
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default SelectCampaign;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js
new file mode 100644
index 00000000000..653a2fe8dab
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js
@@ -0,0 +1,135 @@
+import React, { useEffect } from "react";
+import { Switch, useLocation } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import { PrivateRoute, AppContainer, BreadCrumb, Loader } from "@egovernments/digit-ui-react-components";
+import MicroplanningHeader from "../../components/MicroplanningHeader";
+import Guidelines from "./Guidelines";
+import CreateMicroplan from "./CreateMicroplan";
+import SavedMicroplans from "./SavedMicroplans";
+import SelectCampaign from "./SelectCampaign";
+import { useMyContext } from "../../utils/context";
+
+const MicroplanningBreadCrumb = ({ location, defaultPath }) => {
+ const { t } = useTranslation();
+ const pathVar = location.pathname.replace(`${defaultPath}/`, "").split("?")?.[0];
+ const { masterName, moduleName, uniqueIdentifier } = Digit.Hooks.useQueryParams();
+ const crumbs = [
+ {
+ path: `/${window?.contextPath}/employee`,
+ content: t("Home"),
+ show: true,
+ },
+ // {
+ // content: t(`UPLOAD`) ,
+ // show: pathVar.includes("upload")?true: false,
+ // },
+ // {
+ // content: t(`HYPOTHESIS`) ,
+ // show: pathVar.includes("hypothesis")?true: false,
+ // },
+ // {
+ // content: t(`RULE_ENGINE`) ,
+ // show: pathVar.includes("rule-engine")?true: false,
+ // },
+ {
+ content: t(`CREATE_MICROPLAN`),
+ show: pathVar === "create-microplan",
+ },
+ {
+ content: t(`SAVED_MICROPLANS_TEXT`),
+ show: pathVar === "saved-microplans",
+ },
+ {
+ content: t(`CREATE_MICROPLAN`),
+ show: pathVar === "select-campaign",
+ },
+ {
+ content: t(`EDIT_MICROPLANS_TEXT`),
+ show: pathVar === "edit-saved-microplan",
+ },
+ ];
+ return ;
+};
+
+const App = ({ path }) => {
+ const { dispatch } = useMyContext();
+
+ const location = useLocation();
+ const MDMSCreateSession = Digit.Hooks.useSessionStorage("MDMS_add", {});
+ const [sessionFormData, setSessionFormData, clearSessionFormData] = MDMSCreateSession;
+
+ const MDMSViewSession = Digit.Hooks.useSessionStorage("MDMS_view", {});
+ const [sessionFormDataView, setSessionFormDataView, clearSessionFormDataView] = MDMSViewSession;
+
+ const { isLoading: isLoadingMdmsBaseData, data } = Digit.Hooks.useCustomMDMS(
+ Digit.ULBService.getCurrentTenantId(),
+ "hcm-microplanning",
+ [
+ { name: "UploadConfiguration" },
+ { name: "Schemas" },
+ { name: "RuleConfigureOutput" },
+ { name: "Resources" },
+ { name: "HypothesisAssumptions" },
+ { name: "BaseMapLayers" },
+ { name: "MicroplanPreviewAggregates" },
+ { name: "AutoFilledRuleConfigurations" },
+ { name: "MapFilters" },
+ { name: "HierarchyConfigurations" },
+ { name: "NumberFormatMappingForTranslation" },
+ { name: "UploadGuidelines" },
+ { name: "ReadMeData" },
+ { name: "CommonConstants" },
+ { name: "MappingOrigin" },
+ { name: "MicroplanNamingConvention" },
+ { name: "MicroplanNamingRegx" },
+ { name: "RuleConfigureOperators" },
+ ],
+ {
+ select: (data) => {
+ dispatch({
+ type: "SETINITDATA",
+ state: {
+ ...data?.["hcm-microplanning"],
+ },
+ });
+ },
+ }
+ );
+
+ //destroying session
+ useEffect(() => {
+ const pathVar = location.pathname.replace(`${path}/`, "").split("?")?.[0];
+ Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan", "edit-saved-microplan"], "microplanData");
+ Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan", "edit-saved-microplan"], "microplanHelperData");
+ Digit.Utils.microplan.destroySessionHelper(pathVar, ["select-campaign"], "SELECT_CAMPAIGN_SESSION");
+ Digit.Utils.microplan.destroySessionHelper(pathVar, ["saved-microplans"], "SAVED_MICROPLAN_SESSION");
+ }, [location]);
+
+ if (isLoadingMdmsBaseData) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+
+
+ {/* } />
+ } />
+ } /> */}
+ } />
+
+ } />
+ } />
+ } />
+ } />
+
+
+
+ );
+};
+
+export default App;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js
new file mode 100644
index 00000000000..cabc9b67b56
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js
@@ -0,0 +1,19 @@
+const CreatePlanConfig = async (body) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/plan-service/config/_create",
+ useCache: false,
+ method: "POST",
+ userService: true,
+ body,
+ });
+ return response;
+ } catch (error) {
+ if (error?.response?.data?.Errors) {
+ throw new Error(error.response.data.Errors[0].message);
+ }
+ throw new Error("An unknown error occurred");
+ }
+};
+
+export default CreatePlanConfig;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js
new file mode 100644
index 00000000000..83d4fb5fc72
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js
@@ -0,0 +1,181 @@
+import _ from "lodash";
+
+const createProjectsArray = (t, project, searchParams, headerLocale) => {
+ let totalProjects = {
+ searchedProject: {},
+ subProjects: [],
+ };
+ let basicDetails = {};
+ let totalProjectsLength = project.length;
+ // for(let projectIndex = 0; projectIndex < totalProjectsLength; projectIndex++) {
+ let currentProject = project[0];
+ const headerDetails = {
+ title: " ",
+ asSectionHeader: true,
+ values: [
+ { title: "WORKS_PROJECT_ID", value: currentProject?.projectNumber || "NA" },
+ { title: "ES_COMMON_PROPOSAL_DATE", value: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA" },
+ { title: "WORKS_PROJECT_NAME", value: currentProject?.name || "NA" },
+ { title: "PROJECT_PROJECT_DESC", value: currentProject?.description || "NA" },
+ ],
+ };
+
+ const projectDetails = {
+ title: "WORKS_PROJECT_DETAILS",
+ asSectionHeader: true,
+ values: [
+ { title: "PROJECT_LOR", value: currentProject?.referenceID || "NA" },
+ {
+ title: "WORKS_PROJECT_TYPE",
+ value: currentProject?.projectType ? t(`COMMON_MASTERS_${Digit.Utils.locale.getTransformedLocale(currentProject?.projectType)}`) : "NA",
+ },
+ {
+ title: "PROJECT_TARGET_DEMOGRAPHY",
+ value: currentProject?.additionalDetails?.targetDemography
+ ? t(`COMMON_MASTERS_${currentProject?.additionalDetails?.targetDemography}`)
+ : "NA",
+ },
+ {
+ title: "PROJECT_ESTIMATED_COST",
+ value: currentProject?.additionalDetails?.estimatedCostInRs
+ ? `₹ ${Digit.Utils.dss.formatterWithoutRound(currentProject?.additionalDetails?.estimatedCostInRs, "number")}`
+ : "NA",
+ },
+ ],
+ };
+
+ const locationDetails = {
+ title: "WORKS_LOCATION_DETAILS",
+ asSectionHeader: true,
+ values: [
+ {
+ title: "WORKS_GEO_LOCATION",
+ value:
+ currentProject?.address?.latitude || currentProject?.address?.longitude
+ ? `${currentProject?.address?.latitude}, ${currentProject?.address?.longitude}`
+ : "NA",
+ },
+ {
+ title: "WORKS_CITY",
+ value: currentProject?.address?.city ? t(`TENANT_TENANTS_${Digit.Utils.locale.getTransformedLocale(currentProject?.address?.city)}`) : "NA",
+ }, //will check with Backend
+ { title: "WORKS_WARD", value: currentProject?.address?.boundary ? t(`${headerLocale}_ADMIN_${currentProject?.address?.boundary}`) : "NA" }, ///backend to update this
+ {
+ title: "WORKS_LOCALITY",
+ value: currentProject?.additionalDetails?.locality ? t(`${headerLocale}_ADMIN_${currentProject?.additionalDetails?.locality}`) : "NA",
+ },
+ ],
+ };
+
+ // const financialDetails = {
+ // title: "WORKS_FINANCIAL_DETAILS",
+ // asSectionHeader: false,
+ // values: [
+ // { title: "WORKS_HEAD_OF_ACCOUNTS", value: currentProject?.additionalDetails?.fund ? t(`COMMON_MASTERS_FUND_${currentProject?.additionalDetails?.fund}`) : "NA" },
+ // ],
+ // };
+
+ let documentDetails = {
+ title: "",
+ asSectionHeader: true,
+ additionalDetails: {
+ documents: [
+ {
+ title: "WORKS_RELEVANT_DOCUMENTS",
+ BS: "Works",
+ values: currentProject?.documents?.map((document) => {
+ if (document?.status !== "INACTIVE") {
+ return {
+ title: document?.documentType === "OTHERS" ? document?.additionalDetails?.otherCategoryName : t(`PROJECT_${document?.documentType}`),
+ documentType: document?.documentType,
+ documentUid: document?.fileStore,
+ fileStoreId: document?.fileStore,
+ };
+ }
+ return {};
+ }),
+ },
+ ],
+ },
+ };
+
+ //filter any empty object
+ documentDetails.additionalDetails.documents[0].values = documentDetails?.additionalDetails?.documents?.[0]?.values?.filter((value) => {
+ if (value?.title) {
+ return value;
+ }
+ });
+
+ // if(currentProject?.projectNumber === searchParams?.Projects?.[0]?.projectNumber) {
+ basicDetails = {
+ projectID: currentProject?.projectNumber,
+ projectProposalDate: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA",
+ projectName: currentProject?.name || "NA",
+ projectDesc: currentProject?.description || "NA",
+ projectHasSubProject: totalProjectsLength > 1 ? "COMMON_YES" : "COMMON_NO",
+ projectParentProjectID: currentProject?.ancestors?.[0]?.projectNumber || "NA",
+ uuid: currentProject?.id,
+ address: currentProject?.address,
+ ward: currentProject?.address?.boundary,
+ locality: currentProject?.additionalDetails?.locality,
+ };
+ totalProjects.searchedProject = {
+ basicDetails,
+ headerDetails,
+ projectDetails,
+ locationDetails,
+ documentDetails,
+ };
+ // }
+ // }
+ return totalProjects;
+};
+
+export const Search = {
+ viewProjectDetailsScreen: async (
+ t,
+ tenantId,
+ searchParams,
+ filters = { limit: 10, offset: 0, includeAncestors: true, includeDescendants: true },
+ headerLocale
+ ) => {
+ const response = await Digit.WorksService?.searchProject(tenantId, searchParams, filters);
+
+ let projectDetails = {
+ searchedProject: {
+ basicDetails: {},
+ details: {
+ projectDetails: [],
+ },
+ },
+ };
+
+ if (response?.Project) {
+ let projects = createProjectsArray(t, response?.Project, searchParams, headerLocale);
+
+ //searched Project details
+ projectDetails.searchedProject["basicDetails"] = projects?.searchedProject?.basicDetails;
+ projectDetails.searchedProject["details"]["projectDetails"] = {
+ applicationDetails: [
+ projects?.searchedProject?.headerDetails,
+ projects?.searchedProject?.projectDetails,
+ projects?.searchedProject?.locationDetails,
+ projects?.searchedProject?.documentDetails,
+ ],
+ }; //rest categories will come here
+ }
+
+ return {
+ projectDetails: response?.Project ? projectDetails : [],
+ response: response?.Project,
+ processInstancesDetails: [],
+ workflowDetails: [],
+ applicationData: {},
+ isNoDataFound: response?.Project?.length === 0,
+ };
+ },
+ searchEstimate: async (tenantId, filters) => {
+ const response = await Digit.WorksService?.estimateSearch({ tenantId, filters });
+ return response?.estimates;
+ },
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js
new file mode 100644
index 00000000000..bb6a9f26916
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js
@@ -0,0 +1,22 @@
+const SearchCampaignConfig = async (body) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/project-factory/v1/project-type/search",
+ useCache: false,
+ method: "POST",
+ userService: false,
+ body,
+ });
+ if (response?.CampaignDetails?.length === 0) {
+ throw new Error("Campaign not found with the given id");
+ }
+ return response?.CampaignDetails?.[0];
+ } catch (error) {
+ if (error?.response?.data?.Errors) {
+ throw new Error(error.response.data.Errors[0].message);
+ }
+ throw new Error("An unknown error occurred");
+ }
+};
+
+export default SearchCampaignConfig;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js
new file mode 100644
index 00000000000..1fe11f206a7
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js
@@ -0,0 +1,19 @@
+const SearchPlanConfig = async (body) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/plan-service/config/_search",
+ useCache: false,
+ method: "POST",
+ userService: true,
+ body,
+ });
+ return response;
+ } catch (error) {
+ if (error?.response?.data?.Errors) {
+ throw new Error(error.response.data.Errors[0].message);
+ }
+ throw new Error("An unknown error occurred");
+ }
+};
+
+export default SearchPlanConfig;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js
new file mode 100644
index 00000000000..d1623cbd167
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js
@@ -0,0 +1,18 @@
+const UpdatePlanConfig = async (body) => {
+ try {
+ const response = await Digit.CustomService.getResponse({
+ url: "/plan-service/config/_update",
+ useCache: false,
+ method: "POST",
+ userService: true,
+ body,
+ });
+ return response;
+ } catch (error) {
+ if (error?.response?.data?.Errors) {
+ throw new Error(error.response.data.Errors[0].message);
+ }
+ throw new Error("An unknown error occurred");
+ }
+};
+export default UpdatePlanConfig;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js
new file mode 100644
index 00000000000..ba4342526a8
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js
@@ -0,0 +1,67 @@
+function mergeArrays(array1, key1, array2, key2) {
+ const mergedArray = [];
+
+ // Create a map of values from array2 using key2
+ const map = new Map();
+ array2.forEach((item) => {
+ map.set(item[key2], item);
+ });
+
+ // Iterate over array1 and merge with matching items from array2
+ array1.forEach((item) => {
+ const matchingItem = map.get(item[key1]);
+ if (matchingItem) {
+ // Merge properties from both items and append to 'CampaignDetails'
+ const mergedItem = { ...item, CampaignDetails: { ...matchingItem } };
+ mergedArray.push(mergedItem);
+ } else {
+ // No matching item found in array2, add array1 item with empty 'CampaignDetails'
+ const mergedItem = { ...item, CampaignDetails: {} };
+ mergedArray.push(mergedItem);
+ }
+ });
+ return mergedArray;
+}
+
+const SearchSavedPlans = async (body) => {
+ try {
+ //here get response from both apis and process data and return
+ const responsePlan = await Digit.CustomService.getResponse({
+ url: "/plan-service/config/_search",
+ useCache: false,
+ method: "POST",
+ userService: false,
+ body,
+ });
+
+ const { PlanConfiguration } = responsePlan;
+ if (!PlanConfiguration || PlanConfiguration.length === 0) return [];
+
+ const executionPlanIds = PlanConfiguration?.map((row) => row?.executionPlanId)?.filter((item) => item);
+ const CampaignDetails = {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ ids: executionPlanIds,
+ };
+
+ const responseCampaign = await Digit.CustomService.getResponse({
+ url: "/project-factory/v1/project-type/search",
+ useCache: false,
+ method: "POST",
+ userService: false,
+ body: {
+ CampaignDetails,
+ },
+ });
+ const finalResult = {
+ PlanConfiguration: mergeArrays(responsePlan?.PlanConfiguration, "executionPlanId", responseCampaign?.CampaignDetails, "id"),
+ };
+ return finalResult;
+ } catch (error) {
+ if (error?.response?.data?.Errors) {
+ throw new Error(error.response.data.Errors[0].message);
+ }
+ throw new Error("An unknown error occurred");
+ }
+};
+
+export default SearchSavedPlans;
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js
new file mode 100644
index 00000000000..5e6c18f699e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js
@@ -0,0 +1,31 @@
+import React,{useContext,createContext,useReducer} from "react"
+
+const MyContext = createContext()
+const initialState = {
+
+}
+
+const reducer = (state=initialState,action) => {
+ switch (action.type) {
+ case "SETINITDATA":
+ return {...state,...action.state}
+ default:
+ return state;
+ }
+}
+
+export const useMyContext = () => {
+
+ return useContext(MyContext)
+}
+
+export const ProviderContext = ({children}) => {
+
+ const [state,dispatch] = useReducer(reducer,initialState)
+
+ return (
+
+ {children}
+
+ )
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js
new file mode 100644
index 00000000000..6ee1f4084f9
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js
@@ -0,0 +1,485 @@
+import { BOUNDARY_DATA_SHEET, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, commonColumn } from "../configs/constants";
+
+export const fetchBoundaryData = async (tenantId, hierarchyType, codes) => {
+ // request for boundary relation api
+ const reqCriteria = {
+ url: "/boundary-service/boundary-relationships/_search",
+ params: { tenantId, hierarchyType, codes, includeChildren: true },
+ body: {},
+ };
+ let response;
+ try {
+ response = (await Digit.CustomService.getResponse(reqCriteria))?.TenantBoundary?.[0]?.boundary || {};
+ } catch (error) {
+ console.error("Error in fetching boundary Data: ", error.message);
+ }
+ return response;
+};
+
+export const getFacilities = async (params, body) => {
+ // request for boundary relation api
+ const reqCriteria = {
+ url: "/facility/v1/_search",
+ params: params,
+ body: body,
+ };
+ let response;
+ try {
+ response = (await Digit.CustomService.getResponse(reqCriteria))?.Facilities || {};
+ } catch (error) {
+ if (error.response) {
+ throw new Error(`Failed to fetch facility data: ${error.response.data.message}`);
+ }
+ if (error.request) {
+ // Network error
+ throw new Error("Network error while fetching facility data");
+ }
+ // Other errors
+ throw new Error(`Error while fetching facility data: ${error.message}`);
+ }
+ return response;
+};
+
+// export const fetchColumnsFromMdms = (schema)=>{
+// return
+// }
+
+/**
+ *
+ * @param {*} xlsxData
+ * @param {*} boundaryData
+ * @returns xlsxData with boundary data added
+ */
+export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => {
+ // Return the original data if there is no boundary data to add
+ if (!boundaryData) return xlsxData;
+
+ // Initialize the array to hold new data
+ let newXlsxData = [];
+
+ // Recursive function to convert boundary data into sheet format
+ const convertBoundaryDataToSheets = (boundaryData, currentBoundaryPredecessor = [], hierarchyAccumulator = [], dataAccumulator = []) => {
+ // Return if boundary data is not valid or not an array
+ if (!boundaryData || !Array.isArray(boundaryData)) return;
+
+ // Clone the current boundary predecessor to avoid modifying the original data
+ const rowData = [...currentBoundaryPredecessor];
+ // Clone the data accumulator to preserve the accumulated data
+ let tempDataAccumulator = [...dataAccumulator];
+ // Use a set to accumulate unique hierarchy levels
+ let tempHierarchyAccumulator = new Set(hierarchyAccumulator);
+
+ // Iterate over each item in the boundary data array
+ for (const item of boundaryData) {
+ if (item?.code) {
+ // Create a new row with the current item's code
+ const tempRow = [...rowData, item?.code];
+ let response;
+ // Add the current item's boundary type to the hierarchy
+ tempHierarchyAccumulator.add(item.boundaryType);
+
+ // If the current item has children, recursively process them
+ if (item.children)
+ response = convertBoundaryDataToSheets(item.children, tempRow, tempHierarchyAccumulator, [...tempDataAccumulator, tempRow]);
+
+ // Update the accumulators with the response from the recursive call
+ if (response) {
+ tempDataAccumulator = response.tempDataAccumulator;
+ tempHierarchyAccumulator = response.tempHierarchyAccumulator;
+ }
+ }
+ }
+
+ // Return the accumulated data and hierarchy
+ return { tempDataAccumulator, tempHierarchyAccumulator };
+ };
+
+ // Convert the boundary data into sheet format and extract the sorted data and hierarchy
+ let { tempDataAccumulator: sortedBoundaryDataForXlsxSheet, tempHierarchyAccumulator: hierarchy } = convertBoundaryDataToSheets(boundaryData);
+
+ // Add the hierarchy as the first row of the sheet
+ hierarchy = [...hierarchy].map((item) => `${hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`);
+ sortedBoundaryDataForXlsxSheet = [[...hierarchy], ...sortedBoundaryDataForXlsxSheet];
+
+ // Determine the maximum row length to ensure all rows have the same length
+ const topIndex = Math.max(...sortedBoundaryDataForXlsxSheet.map((row) => row.length)) - 1;
+
+ // Ensure all rows are of the same length by filling them with empty strings
+ sortedBoundaryDataForXlsxSheet = sortedBoundaryDataForXlsxSheet.map((item, index) => {
+ let newItem = item;
+ if (index !== 0) {
+ if (!newItem) {
+ newItem = [];
+ }
+ const itemLength = newItem.length;
+ while (newItem.length <= topIndex) {
+ newItem.push("");
+ }
+ newItem.push(newItem[itemLength - 1]);
+ } else {
+ newItem.push(commonColumn);
+ }
+
+ return newItem;
+ });
+
+ // Add the new sheet data to the original data
+ newXlsxData = [...xlsxData, ...newXlsxData, { sheetName: BOUNDARY_DATA_SHEET, data: sortedBoundaryDataForXlsxSheet }];
+
+ // Return the updated data
+ return newXlsxData;
+};
+
+const fillDataWithBlanks = (data, tillRow) => {
+ while (data.length < tillRow) {
+ data.push([]);
+ }
+
+ const maxLength = Math.max(...data.map((row) => row.length));
+ return data.map((row) => [...row, ...new Array(maxLength - row.length).fill("")]);
+};
+const generateLocalisationKeyForSchemaProperties = (code) => {
+ if (!code) return code;
+ return `${SCHEMA_PROPERTIES_PREFIX}_${code}`;
+};
+/**
+ *
+ * @param {array} xlsxData , xlsx data
+ * @param {object} schema , schema to refer to
+ * @returns {Array of Object} , xlsxData with schema data added
+ *
+ * adds schema data to sheets
+ */
+const addSchemaData = (xlsxData, schema, extraColumnsToAdd) => {
+ if (!schema) return xlsxData;
+ let columnSchema = schema.schema?.Properties || {};
+ const newXlsxData = [];
+ const columnList = [[], [], [], []]; // Initialize columnList with four empty arrays
+
+ for (const [key, value] of Object.entries(columnSchema)) {
+ if (key === commonColumn) continue;
+
+ columnList[0].push(generateLocalisationKeyForSchemaProperties(key)); // Add key to the first array
+
+ // columnList[1].push(value.type || ""); // Add type to the second array
+
+ // columnList[2].push(value.isRequired ? "MANDATORY" : "OPTIONAL"); // Add requirement status to the third array
+
+ // columnList[3].push(value.pattern || ""); // Add pattern to the fourth array
+ }
+
+ if (extraColumnsToAdd) columnList[0].push(...extraColumnsToAdd);
+
+ for (let { sheetName, data } of xlsxData) {
+ data = fillDataWithBlanks(data, 4);
+ columnList.forEach((item, index) => {
+ // Append the new items to the row
+ if (data[index]) {
+ data[index] = [...data[index], ...item];
+ } else {
+ data[index] = [...item];
+ }
+ });
+
+ newXlsxData.push({ sheetName, data });
+ }
+
+ return newXlsxData;
+};
+
+/**
+ *
+ * @param {Array of Object} xlsxData
+ * @param {string} hierarchyLevelName
+ */
+const devideXlsxDataHierarchyLevelWise = (xlsxData, hierarchyLevelName) => {
+ if (!hierarchyLevelName) return xlsxData; // Return original data if no hierarchy level name
+
+ const result = []; // Initialize result array
+
+ // Iterate over each sheet in the xlsxData
+ for (const sheet of xlsxData) {
+ const sheetData = sheet.data;
+ const hierarchyLevelIndex = sheetData[0].indexOf(hierarchyLevelName);
+
+ // If hierarchy level name not found, skip this sheet
+ if (hierarchyLevelIndex === -1) {
+ result.push(sheet);
+ continue;
+ }
+
+ const { sheetsMap, danglingDataMap } = processSheetData(sheetData, hierarchyLevelIndex);
+
+ // Combine danglingDataMap with sheetsMap
+ for (const key of Object.keys(danglingDataMap)) {
+ if (sheetsMap[key]) {
+ sheetsMap[key].data = [sheetData[0], ...danglingDataMap[key], ...sheetsMap[key].data.slice(1)];
+ } else {
+ sheetsMap[key] = {
+ sheetName: key,
+ data: [...danglingDataMap[key], sheetData[0]],
+ };
+ }
+ }
+
+ // Add sheetsMap values to result
+ result.push(...Object.values(sheetsMap));
+ }
+
+ return result.length > 0 ? result : xlsxData; // Return result or original data if result is empty
+};
+
+// Function to process sheet data and return sheetsMap and danglingDataMap
+const processSheetData = (sheetData, hierarchyLevelIndex) => {
+ const sheetsMap = {};
+ const danglingDataMap = {};
+ let emptyHierarchyRow = [];
+ let lastWasEmpty = true;
+
+ // Iterate through sheet data starting from the second row (skipping header)
+ for (let i = 1; i < sheetData.length; i++) {
+ const row = sheetData[i];
+ const hierarchyValue = row[hierarchyLevelIndex];
+
+ if (emptyHierarchyRow.length && hierarchyValue !== "") {
+ danglingDataMap[hierarchyValue] = emptyHierarchyRow;
+ }
+
+ if (hierarchyValue === "" && lastWasEmpty) {
+ emptyHierarchyRow.push(row);
+ } else {
+ emptyHierarchyRow = [];
+ }
+
+ if (!sheetsMap[hierarchyValue] && hierarchyValue !== "") {
+ sheetsMap[hierarchyValue] = {
+ sheetName: hierarchyValue,
+ data: [sheetData[0]],
+ };
+ }
+
+ if (hierarchyValue === row[hierarchyLevelIndex] && hierarchyValue !== "") {
+ sheetsMap[hierarchyValue].data.push(row);
+ }
+
+ lastWasEmpty = hierarchyValue === "";
+ }
+
+ return { sheetsMap, danglingDataMap };
+};
+
+export const filterBoundaries = (boundaryData, boundaryFilters) => {
+ if (!boundaryFilters) return boundaryData;
+ // Define a helper function to recursively filter boundaries
+ function filterRecursive(boundary) {
+ // Find the filter that matches the current boundary
+ const filter = boundaryFilters?.find((f) => f.code === boundary.code && f.type === boundary.boundaryType);
+
+ // If no filter is found, return the boundary with its children filtered recursively
+ if (!filter) {
+ return {
+ ...boundary,
+ children: boundary.children.map(filterRecursive),
+ };
+ }
+
+ // If the boundary has no children, handle the case where includeAllChildren is false
+ if (!boundary.children.length) {
+ // Return the boundary with an empty children array
+ return {
+ ...boundary,
+ children: [],
+ };
+ }
+
+ // If includeAllChildren is true, return the boundary with all children
+ if (filter.includeAllChildren) {
+ return {
+ ...boundary,
+ children: boundary.children.map(filterRecursive),
+ };
+ }
+
+ // Filter children based on the filters
+ const filteredChildren = boundary.children
+ .filter((child) => boundaryFilters.some((f) => f.code === child.code && f.type === child.boundaryType))
+ .map(filterRecursive);
+
+ // Return the boundary with filtered children
+ return {
+ ...boundary,
+ children: filteredChildren,
+ };
+ }
+
+ // Map through the boundary data and apply the recursive filter function to each boundary
+ const filteredData = boundaryData.map(filterRecursive);
+ return filteredData;
+};
+
+/**
+ * Retrieves all facilities for a given tenant ID.
+ * @param tenantId The ID of the tenant.
+ * @returns An array of facilities.
+ */
+async function getAllFacilities(tenantId) {
+ // Retrieve all facilities for the given tenant ID
+ const facilitySearchBody = {
+ Facility: { isPermanent: true },
+ };
+
+ const facilitySearchParams = {
+ limit: 50,
+ offset: 0,
+ tenantId: tenantId,
+ };
+
+ const searchedFacilities = [];
+ let searchAgain = true;
+
+ while (searchAgain) {
+ const response = await getFacilities(facilitySearchParams, facilitySearchBody);
+ if (response) {
+ searchAgain = response.length >= 50;
+ searchedFacilities.push(...response);
+ facilitySearchParams.offset += 50;
+ } else searchAgain = false;
+ }
+
+ return searchedFacilities;
+}
+
+const addFacilitySheet = (xlsxData, mapping, facilities, schema, t) => {
+ if (!mapping) return xlsxData;
+ // Create header row
+ const headers = Object.keys(mapping);
+
+ // Create data rows
+ const dataRow = [];
+ for (const facility of facilities) {
+ facility.isPermanent = facility.isPermanent ? t("PERMAENENT") : t("TEMPORARY");
+ dataRow.push(headers.map((header) => facility[mapping[header]]));
+ }
+ headers.push(commonColumn);
+ const additionalCols = [];
+ if (schema?.schema?.Properties) {
+ const properties = Object.keys(schema.schema.Properties);
+ for (const col of properties) {
+ if (!headers.includes(col)) {
+ additionalCols.push(col);
+ }
+ }
+ }
+ headers.push(...additionalCols);
+ // Combine headers and data rows
+ const arrayOfArrays = [headers.map((item) => generateLocalisationKeyForSchemaProperties(item)), ...dataRow];
+
+ const facilitySheet = {
+ sheetName: FACILITY_DATA_SHEET,
+ data: arrayOfArrays,
+ };
+ const updatedXlsxData = [facilitySheet, ...xlsxData];
+ return updatedXlsxData;
+};
+
+const addReadMeSheet = (xlsxData, readMeData, readMeSheetName) => {
+ if (!readMeSheetName) return xlsxData;
+ const data = (readMeData?.data || []).reduce((acc, item) => {
+ if (item?.header) {
+ acc.push([item.header], ...(item.points || []).map((item) => [item]), [], [], [], []);
+ }
+ return acc;
+ }, []);
+
+ const readMeSheet = {
+ sheetName: readMeSheetName,
+ data: [[readMeData?.mainHeader || "MICROPLAN_TEMPLATE_README_MAIN_HEADER"], [], [], [], ...data],
+ };
+ xlsxData.unshift(readMeSheet);
+ return xlsxData;
+};
+
+/**
+ * @param {Object} options
+ * @param {boolean} options.hierarchyLevelWiseSheets
+ * @param {string} options.hierarchyLevelName
+ * @param {boolean} options.addFacilityData
+ * @param {Object} options.schema
+ * @param {Object[]} options.boundaries
+ * @param {string} options.tenantId
+ * @param {string} options.hierarchyType
+ * @param {Object} options.readMeData
+ * @param {string} options.readMeSheetName
+ * @param {string} options.t // Assuming t is some context or translation object
+ */
+export const createTemplate = async ({
+ hierarchyLevelWiseSheets = true,
+ hierarchyLevelName,
+ addFacilityData = false,
+ schema,
+ boundaries,
+ tenantId,
+ hierarchyType,
+ readMeData,
+ readMeSheetName,
+ t,
+}) => {
+ // Fetch or retrieve boundary data
+ const filteredBoundaries = await fetchFilteredBoundaries(boundaries, tenantId, hierarchyType);
+
+ // Initialize xlsxData array
+ let xlsxData = [];
+
+ // Add boundary data to xlsxData
+ xlsxData = addBoundaryData(xlsxData, filteredBoundaries, hierarchyType);
+
+ // Handle hierarchy level sheets
+ if (hierarchyLevelWiseSheets) {
+ xlsxData = devideXlsxDataHierarchyLevelWise(xlsxData, hierarchyLevelName);
+ }
+
+ // Handle facility data addition
+ if (addFacilityData) {
+ xlsxData = await addFacilityDataToSheets(xlsxData, schema, tenantId, t);
+ } else {
+ // If no facility data, add schema data directly
+ xlsxData = addSchemaData(xlsxData, schema);
+ }
+
+ // Add readme sheet data if provided
+ xlsxData = addReadMeSheet(xlsxData, readMeData, readMeSheetName);
+
+ return xlsxData;
+};
+
+// Function to fetch filtered boundaries
+const fetchFilteredBoundaries = async (boundaries, tenantId, hierarchyType) => {
+ const rootBoundary = boundaries?.find((boundary) => boundary.isRoot);
+ const sessionData = Digit.SessionStorage.get("microplanHelperData") || {};
+ let boundaryData = sessionData.filteredBoundaries;
+
+ if (!boundaryData) {
+ boundaryData = await fetchBoundaryData(tenantId, hierarchyType, rootBoundary?.code);
+ const filteredBoundaries = await filterBoundaries(boundaryData, boundaries);
+ Digit.SessionStorage.set("microplanHelperData", {
+ ...sessionData,
+ filteredBoundaries: filteredBoundaries,
+ });
+ return filteredBoundaries;
+ }
+ return boundaryData;
+};
+
+// Function to add facility data to sheets
+const addFacilityDataToSheets = async (xlsxData, schema, tenantId, t) => {
+ const facilities = await getAllFacilities(tenantId);
+ if (schema?.template?.facilitySchemaApiMapping) {
+ return addFacilitySheet(xlsxData, schema.template.facilitySchemaApiMapping, facilities, schema, t);
+ }
+ // If no specific facility schema mapping, add default facility data
+ const facilitySheet = {
+ sheetName: FACILITY_DATA_SHEET,
+ data: [],
+ };
+ return addSchemaData([facilitySheet], schema);
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js
new file mode 100644
index 00000000000..025bbac8625
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js
@@ -0,0 +1,153 @@
+import { SHEET_PASSWORD, UNPROTECT_TILL_ROW } from "../configs/constants";
+
+export function updateFontNameToRoboto(worksheet) {
+ worksheet.eachRow({ includeEmpty: true }, (row) => {
+ row.eachCell({ includeEmpty: true }, (cell) => {
+ // Preserve existing font properties
+ const existingFont = cell.font || {};
+
+ // Update only the font name to Roboto
+ cell.font = {
+ ...existingFont, // Spread existing properties
+ name: "Roboto", // Update the font name
+ };
+ });
+ });
+}
+
+export const freezeWorkbookValues = async (workbook) => {
+ workbook.eachSheet((worksheet) => {
+ worksheet.eachRow((row) => {
+ row.eachCell((cell) => {
+ // Lock each cell
+ cell.protection = {
+ locked: true,
+ };
+ });
+ });
+ // Protect the worksheet
+ worksheet.protect(SHEET_PASSWORD, {
+ selectLockedCells: true,
+ selectUnlockedCells: true,
+ });
+ });
+
+ return workbook;
+};
+
+export const unfreezeColumnsByHeader = async (workbook, headers) => {
+ workbook.eachSheet((worksheet) => {
+ const headerRow = worksheet.getRow(1); // Assuming headers are in the first row
+ const columnsToUnfreeze = [];
+
+ headerRow.eachCell((cell, colNumber) => {
+ if (headers.includes(cell.value)) {
+ columnsToUnfreeze.push(colNumber);
+ }
+ });
+
+ worksheet.eachRow((row, rowNumber) => {
+ if (rowNumber === 1) return;
+ columnsToUnfreeze.forEach((colNumber) => {
+ const cell = row.getCell(colNumber);
+ cell.protection = {
+ locked: false,
+ };
+ });
+ });
+
+ // Re-protect the worksheet after modifying cell protection
+ worksheet.protect(SHEET_PASSWORD, {
+ selectLockedCells: true,
+ selectUnlockedCells: true,
+ });
+ });
+
+ return workbook;
+};
+
+export const freezeSheetValues = async (workbook, sheetName) => {
+ const worksheet = workbook.getWorksheet(sheetName);
+ if (!worksheet) return;
+ if (worksheet) {
+ worksheet.eachRow((row) => {
+ row.eachCell((cell) => {
+ // Lock each cell
+ cell.protection = {
+ locked: true,
+ };
+ });
+ });
+ // Protect the worksheet
+ worksheet.protect(SHEET_PASSWORD, {
+ selectLockedCells: true,
+ selectUnlockedCells: true,
+ });
+ }
+
+ return workbook;
+};
+
+export const freezeCellsWithData = async (workbook, sheetName) => {
+ const worksheet = workbook.getWorksheet(sheetName);
+ if (!worksheet) return;
+ if (worksheet) {
+ worksheet.eachRow((row) => {
+ row.eachCell((cell) => {
+ if (cell.value) {
+ // Check if the cell has data
+ cell.protection = {
+ locked: true,
+ };
+ } else {
+ cell.protection = {
+ locked: false,
+ };
+ }
+ });
+ });
+ // Protect the worksheet
+ worksheet.protect(SHEET_PASSWORD, {
+ selectLockedCells: true,
+ selectUnlockedCells: true,
+ });
+ }
+
+ return workbook;
+};
+export const performUnfreezeCells = async (workbook, sheetName) => {
+ const sheet = workbook.getWorksheet(sheetName);
+ if (!sheet) return;
+ let lastFilledColumn = 1;
+ sheet.getRow(1).eachCell((cell, colNumber) => {
+ if (cell.value !== undefined && cell.value !== null && cell.value !== "") {
+ lastFilledColumn = colNumber;
+ }
+ });
+
+ for (let row = 1; row <= parseInt(UNPROTECT_TILL_ROW); row++) {
+ for (let col = 1; col <= lastFilledColumn; col++) {
+ const cell = sheet.getCell(row, col);
+ if (!cell.value && cell.value !== 0) {
+ cell.protection = { locked: false };
+ }
+ }
+ }
+ sheet.protect(SHEET_PASSWORD, { selectLockedCells: true, selectUnlockedCells: true });
+};
+
+export const hideUniqueIdentifierColumn = async (workbook, sheetName, column) => {
+ const sheet = workbook.getWorksheet(sheetName);
+ if (!sheet) return;
+ for (const item of column) {
+ let colIndex;
+ sheet.getRow(1).eachCell((cell, colNumber) => {
+ if (cell.value === item) {
+ colIndex = colNumber;
+ }
+ });
+ if (column && sheet.getColumn(colIndex)) {
+ sheet.getColumn(colIndex).hidden = true;
+ }
+ }
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js
new file mode 100644
index 00000000000..0d2a344a8f1
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js
@@ -0,0 +1,199 @@
+import Ajv from "ajv";
+const ajv = new Ajv({ allErrors: true });
+ajv.addKeyword("isRequired");
+ajv.addKeyword("isLocationDataColumns");
+ajv.addKeyword("isRuleConfigureInputs");
+ajv.addKeyword("isFilterPropertyOfMapSection");
+ajv.addKeyword("isVisualizationPropertyOfMapSection");
+ajv.addKeyword("toShowInMicroplanPreview");
+
+// Function responsible for excel data validation with respect to the template/schema provided
+const translateSchema = (schemaData) => {
+ const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.isRequired) {
+ acc.push(key);
+ }
+ return acc;
+ }, []);
+
+ return { required, properties: schemaData.Properties };
+};
+
+const createSchema = (properties, required) => {
+ return {
+ type: "object",
+ patternProperties: {
+ ".*": {
+ type: "array",
+ items: {
+ type: "object",
+ properties: properties,
+ required: required,
+ additionalProperties: true,
+ },
+ },
+ },
+ minProperties: 1,
+ additionalProperties: false,
+ };
+};
+
+const extractLocationDataColumns = (schemaData) => {
+ return Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.isLocationDataColumns) {
+ acc.push(key);
+ }
+ return acc;
+ }, []);
+};
+
+const setNestedError = (errors, path, error) => {
+ if (!path.length) return;
+
+ let current = errors;
+ for (let i = 0; i < path.length - 1; i++) {
+ if (!current[path[i]]) {
+ current[path[i]] = {};
+ }
+ current = current[path[i]];
+ }
+
+ if (!current[path[path.length - 1]]) {
+ current[path[path.length - 1]] = [];
+ }
+
+ current[path[path.length - 1]] = [...new Set([...current[path[path.length - 1]], error])];
+};
+
+const formatErrors = (validateExcelErrors, locationDataColumns, t) => {
+ const errors = {};
+ let hasDataErrors = "false"; // true, false, missing_properties, unknown
+ const missingColumnsList = new Set();
+ let errorMessages = {};
+
+ validateExcelErrors.forEach((error) => {
+ let tempErrorStore = "";
+ let instancePathTypeGlobal;
+
+ switch (error.keyword) {
+ case "additionalProperties":
+ tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES";
+ hasDataErrors = "true";
+ break;
+ case "type":
+ {
+ const instancePathType = error.instancePath.split("/");
+ const neededType = error.params?.type;
+ instancePathTypeGlobal = instancePathType;
+ tempErrorStore = locationDataColumns.includes(instancePathType[instancePathType.length - 1])
+ ? "ERROR_INCORRECT_LOCATION_COORDINATES"
+ : neededType === "number"
+ ? "ERROR_MUST_BE_A_NUMBER"
+ : "ERROR_MUST_BE_A_STRING";
+ hasDataErrors = "true";
+ }
+ break;
+ case "required":
+ {
+ const missing = error.params.missingProperty;
+ const instancePathType = error.instancePath.split("/");
+ instancePathTypeGlobal = [...instancePathType, missing];
+ tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY";
+ missingColumnsList.add(missing);
+ hasDataErrors = "true";
+ }
+ break;
+ case "maximum":
+ case "minimum":
+ {
+ const instancePathMinMax = error.instancePath.split("/");
+ instancePathTypeGlobal = instancePathMinMax;
+ tempErrorStore = locationDataColumns.includes(instancePathMinMax[instancePathTypeGlobal.length - 1])
+ ? "ERROR_INCORRECT_LOCATION_COORDINATES"
+ : "ERROR_DATA_EXCEEDS_LIMIT_CONSTRAINTS";
+ hasDataErrors = "true";
+ }
+ break;
+ case "pattern":
+ tempErrorStore = "ERROR_VALUE_NOT_ALLOWED";
+ hasDataErrors = "true";
+ break;
+ case "minProperties":
+ hasDataErrors = "minProperties";
+ break;
+ case "enum":
+ {
+ const instancePathType = error.instancePath.split("/");
+ instancePathTypeGlobal = instancePathType;
+ tempErrorStore = {
+ error: "ERROR_UPLOAD_DATA_ENUM",
+ values: { allowedValues: error.params?.allowedValues?.map((item) => t(item)).join(", ") },
+ };
+ hasDataErrors = "true";
+ }
+ break;
+ default:
+ hasDataErrors = "unknown";
+ }
+
+ if (tempErrorStore && instancePathTypeGlobal) {
+ setNestedError(errors, instancePathTypeGlobal.slice(1, 4), tempErrorStore);
+ }
+
+ switch (hasDataErrors) {
+ case "true":
+ errorMessages = { dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" };
+ break;
+ case "minProperties":
+ errorMessages = { minProperties: "ERROR_UPLOADED_DATA_IS_EMPTY" };
+ break;
+ case "unknown":
+ errorMessages = { unknown: "ERROR_UNKNOWN" };
+ break;
+ case "false":
+ break;
+ }
+ });
+
+ return {
+ valid: !hasDataErrors,
+ message: errorMessages ? [...new Set(Object.values(errorMessages))] : [],
+ errors,
+ missingColumnsList,
+ };
+};
+
+export const excelValidations = (data, schemaData, t) => {
+ const { required, properties } = translateSchema(schemaData);
+ const schema = createSchema(properties, required);
+ const validateExcel = ajv.compile(schema);
+ const valid = validateExcel(data);
+ const locationDataColumns = extractLocationDataColumns(schemaData);
+
+ if (!valid) {
+ const validationResult = formatErrors(validateExcel.errors, locationDataColumns, t);
+ ajv.removeSchema();
+ return validationResult;
+ }
+
+ ajv.removeSchema();
+ return { valid };
+};
+
+export const checkForErrorInUploadedFileExcel = async (fileInJson, schemaData, t) => {
+ try {
+ const valid = excelValidations(fileInJson, schemaData, t);
+ if (valid.valid) {
+ return { valid: true };
+ }
+ return {
+ valid: false,
+ message: valid.message,
+ errors: valid.errors,
+ missingProperties: valid.missingColumnsList,
+ };
+ } catch (error) {
+ console.error("Error in excel validations: ", error?.message);
+ return { valid: false, message: ["ERROR_PARSING_FILE"] };
+ }
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js
new file mode 100644
index 00000000000..f2d4f277ba6
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js
@@ -0,0 +1,99 @@
+import ExcelJS from "exceljs";
+
+// input is a xlsx blob
+// options {header}
+// header: true -> have seperate header so data will be in key: value pair
+export const parseXlsxToJsonMultipleSheets = async (file, options = {}) => {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+
+ reader.onload = async (event) => {
+ try {
+ const arrayBuffer = event.target.result;
+ const workbook = await loadWorkbook(arrayBuffer);
+ const jsonData = processWorkbook(workbook, options);
+ resolve(jsonData);
+ } catch (error) {
+ console.error(error);
+ resolve({ error: true });
+ }
+ };
+
+ reader.onerror = (error) => {
+ console.error(error);
+ resolve({ error: true, details: error });
+ };
+
+ reader.readAsArrayBuffer(file);
+ });
+};
+
+const loadWorkbook = async (arrayBuffer) => {
+ const workbook = new ExcelJS.Workbook();
+ await workbook.xlsx.load(arrayBuffer);
+ return workbook;
+};
+
+const processWorkbook = (workbook, options) => {
+ const jsonData = {};
+ workbook.eachSheet((worksheet) => {
+ const jsonSheetData = processSheet(worksheet, options);
+ if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) {
+ jsonData[worksheet.name] = jsonSheetData;
+ }
+ });
+ return jsonData;
+};
+
+const processSheet = (worksheet, options) => {
+ const jsonSheetData = [];
+ let headers = [];
+
+ worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
+ const rowData = cleanRowData(row.values);
+ if (options.header && rowNumber === 1) {
+ headers = rowData;
+ } else if (options.header && headers.length > 0) {
+ jsonSheetData.push(mapRowToHeaders(rowData, headers));
+ } else {
+ jsonSheetData.push(rowData);
+ }
+ });
+
+ removeTrailingEmptyRows(jsonSheetData);
+ return jsonSheetData;
+};
+
+const cleanRowData = (rowData) => {
+ return rowData.slice(1).map((cell) => (typeof cell === "string" ? cell.trim() : cell));
+};
+
+const mapRowToHeaders = (rowData, headers) => {
+ const rowObject = {};
+ headers.forEach((header, index) => {
+ rowObject[header] = rowData[index];
+ });
+ return rowObject;
+};
+
+const removeTrailingEmptyRows = (data) => {
+ while (data.length > 0) {
+ const lastRow = data[data.length - 1];
+ const isEmptyRow = checkIfRowIsEmpty(lastRow);
+ if (isEmptyRow) {
+ data.pop();
+ } else {
+ break;
+ }
+ }
+};
+
+const checkIfRowIsEmpty = (row) => {
+ if (Array.isArray(row)) {
+ return row.filter((item) => item !== "").length === 0;
+ }
+ if (typeof row === "object" && row !== null) {
+ return Object.values(row).filter((item) => item !== "").length === 0;
+ }
+ return false;
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js
new file mode 100644
index 00000000000..c14dbac7a16
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js
@@ -0,0 +1,234 @@
+import gjv from "geojson-validation";
+import Ajv from "ajv";
+const ajv = new Ajv({ allErrors: true });
+ajv.addKeyword("isRequired");
+ajv.addKeyword("isLocationDataColumns");
+ajv.addKeyword("isRuleConfigureInputs");
+ajv.addKeyword("isFilterPropertyOfMapSection");
+ajv.addKeyword("isVisualizationPropertyOfMapSection");
+ajv.addKeyword("toShowInMicroplanPreview");
+
+//the postion must be valid point on the earth, x between -180 and 180
+gjv.define("Position", (position) => {
+ let errors = [];
+ if (position[0] < -180 || position[0] > 180) {
+ errors.push("Location Coordinates Error: the x must be between -180 and 180");
+ }
+ if (position[1] < -90 || position[1] > 90) {
+ errors.push("Location Coordinates Error: the y must be between -90 and 90");
+ }
+ return errors;
+});
+
+// Main functino for geojson validation that includes structural and property validations
+export const geojsonValidations = (data, schemaData, t) => {
+ const valid = geojsonStructureValidation(data);
+ return valid.valid ? { valid: true } : { valid: false, message: valid.message || ["ERROR_INVALID_GEOJSON"] };
+};
+
+// Funciton responsible for structural verification of geojson data
+export const geojsonStructureValidation = (data) => {
+ let valid = true;
+ const trace = {};
+ for (let i = 0; i < data["features"].length; i++) {
+ const check = gjv.valid(data["features"][i]);
+ valid = valid && check;
+ const errors = gjv.isFeature(data["features"][i], true);
+ // check if the location coordinates are according to the provided guidlines
+ if (errors.some((str) => str.includes("Location Coordinates Error:"))) return { valid: false, message: ["ERROR_INCORRECT_LOCATION_COORDINATES"] };
+ if (!check) trace[i] = [errors];
+ // let error;
+ // Object.keys(data["features"][i]["properties"]).forEach((j) => {
+ // if (j.length > 10) error = { valid: false, trace, message: ["ERROR_FIELD_NAME"] };
+ // return j;
+ // });
+ // if (error) return error;
+ }
+ return { valid, trace };
+};
+
+const geometryValidation = (data) => {
+ let firstType;
+ for (const feature of data.features) {
+ if (!feature.geometry || !feature.geometry.type) {
+ return false; // Missing geometry or geometry type
+ }
+ if (!firstType) {
+ firstType = feature.geometry.type;
+ } else {
+ // Check if the current geometry type matches the first one
+ if (feature.geometry.type !== firstType) {
+ return false; // Different geometry types found
+ }
+ }
+ }
+ return true;
+};
+
+// Function responsible for property verification of geojson data
+export const geojsonPropertiesValidation = (data, schemaData, name, t) => {
+ const translate = () => {
+ const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.isRequired) {
+ acc.push(key);
+ }
+ return acc;
+ }, []);
+
+ // const properties = prepareProperties(schemaData.Properties, t);
+ return { required, properties: schemaData.Properties };
+ };
+ const { required, properties } = translate();
+ const schema = {
+ type: "object",
+ properties: {
+ type: { const: "FeatureCollection" },
+ },
+ patternProperties: {
+ "^features$": {
+ type: "array",
+ items: {
+ type: "object",
+ patternProperties: {
+ "^properties$": {
+ type: "object",
+ patternProperties: properties,
+ required: required,
+ additionalProperties: true,
+ },
+ },
+ },
+ },
+ },
+ additionalProperties: true,
+ };
+ const validateGeojson = ajv.compile(schema);
+ const valid = validateGeojson(data);
+ const errors = {};
+ let hasDataErrors = "false"; // true, false, missing_properties, unknown
+ const missingColumnsList = new Set();
+ let errorMessages = [];
+ if (!valid) {
+ for (let i = 0; i < validateGeojson.errors.length; i++) {
+ let tempErrorStore = "";
+ let instancePathTypeGlobal = validateGeojson.errors[i].instancePath.split("/");
+ switch (validateGeojson.errors[i].keyword) {
+ case "additionalProperties": {
+ tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES";
+ hasDataErrors = "true";
+ break;
+ }
+ case "type":
+ {
+ const instancePathType = validateGeojson.errors[i].instancePath.split("/");
+ const neededType = validateGeojson.errors[i].params?.type;
+ instancePathTypeGlobal = instancePathType;
+ tempErrorStore = neededType === "number" ? "ERROR_MUST_BE_A_NUMBER" : "ERROR_MUST_BE_A_STRING";
+ hasDataErrors = "true";
+ }
+ break;
+ case "const": {
+ if (validateGeojson.errors[i].params.allowedValue === "FeatureCollection") tempErrorStore = "ERROR_FEATURECOLLECTION";
+ hasDataErrors = "true";
+ break;
+ }
+ case "required": {
+ const missing = validateGeojson.errors[i].params.missingProperty;
+ const instancePathType = validateGeojson.errors[i].instancePath.split("/");
+ instancePathTypeGlobal = [...instancePathType, missing];
+ tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY";
+ missingColumnsList.add(missing);
+ // hasDataErrors = "missing_properties";
+ hasDataErrors = "true";
+ break;
+ }
+ case "pattern":
+ tempErrorStore = "ERROR_VALUE_NOT_ALLOWED";
+ hasDataErrors = "true";
+ break;
+ case "minProperties": {
+ hasDataErrors = "minProperties";
+ break;
+ }
+ case "enum": {
+ const instancePathType = validateGeojson.errors[i].instancePath.split("/");
+ instancePathTypeGlobal = instancePathType;
+ tempErrorStore = {
+ error: "ERROR_UPLOAD_DATA_ENUM",
+ values: { allowedValues: validateGeojson.errors[i]?.params?.allowedValues?.map((item) => t(item)).join(", ") },
+ };
+ hasDataErrors = "true";
+ break;
+ }
+ default:
+ hasDataErrors = "unknown";
+ break;
+ }
+ if (tempErrorStore)
+ errors[name] = {
+ ...(errors[name] ? errors[name] : {}),
+ [instancePathTypeGlobal[2]]: {
+ ...(errors?.[name]?.[instancePathTypeGlobal[2]] ? errors?.[name]?.[instancePathTypeGlobal[2]] : {}),
+ [instancePathTypeGlobal[4]]: [
+ ...new Set(
+ ...(errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]]
+ ? errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]]
+ : [])
+ ),
+ tempErrorStore,
+ ],
+ },
+ };
+
+ switch (hasDataErrors) {
+ case "true":
+ errorMessages = { ...errorMessages, dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" };
+ break;
+ case "unknown":
+ errorMessages = { ...errorMessages, unkown: "ERROR_UNKNOWN" };
+ break;
+ case "missing_properties":
+ errorMessages = {
+ ...errorMessages,
+ missingProperty: t("ERROR_MISSING_PROPERTY", { properties: [...missingColumnsList].map((item) => t(item)).join(", ") }),
+ };
+ break;
+ case "false":
+ break;
+ }
+ }
+
+ ajv.removeSchema();
+ return {
+ valid: !hasDataErrors,
+ message: errorMessages ? [...new Set(Object.values(errorMessages))] : [],
+ errors,
+ validationError: validateGeojson.errors,
+ };
+ }
+ ajv.removeSchema();
+ if (!geometryValidation(data)) return { valid: false, message: t("ERROR_MULTIPLE_GEOMETRY_TYPES") };
+ return { valid: true };
+};
+
+////////////////////////////
+// // Might be needed
+// function filterOutWordAndLocalise(inputString, operation) {
+// // Define a regular expression to match the string parts
+// var regex = /(\w+)/g; // Matches one or more word characters
+
+// // Replace each match using the provided function
+// var replacedString = inputString.replace(regex, function (match) {
+// // Apply the function to each matched string part
+// return operation(match);
+// });
+
+// return replacedString;
+// }
+// const prepareProperties = (properties, t) => {
+// let newProperties = {};
+// Object.keys(properties).forEach((item) => (newProperties[filterOutWordAndLocalise(item, t)] = properties[item]));
+// return newProperties;
+// };
+
+////////////////////////////
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js
new file mode 100644
index 00000000000..0d21a93ca46
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js
@@ -0,0 +1,478 @@
+import _ from "lodash";
+import { findChildren, findParent } from "../utils/processHierarchyAndData";
+import { EXCEL, LOCALITY, commonColumn } from "../configs/constants";
+
+const formatDates = (value, type) => {
+ let newValue = value;
+ if (type !== "EPOC" && (!newValue || Number.isNaN(Number(newValue)))) {
+ newValue = new Date();
+ }
+ switch (type) {
+ case "date":
+ return new Date(newValue)?.toISOString?.()?.split?.("T")?.[0];
+ case "datetime":
+ return new Date(newValue).toISOString();
+ case "EPOC":
+ return String(new Date(newValue)?.getTime());
+ }
+};
+
+// get schema for validation
+const getSchema = (campaignType, type, section, schemas) => {
+ if (!campaignType || !type || !section || !schemas) return {};
+ return schemas.find((schema) => {
+ if (!schema.campaignType) {
+ return schema.type === type && schema.section === section;
+ }
+ return schema.campaignType === campaignType && schema.type === type && schema.section === section;
+ });
+};
+
+// Sorting 2 lists, The first list is a list of string and second one is list of Objects
+const sortSecondListBasedOnFirstListOrder = (firstList, secondList) => {
+ if (!firstList) return [];
+ // Create a map to store the indices of elements in the first list
+ const indexMap = {};
+ firstList.forEach((value, index) => {
+ indexMap[value] = index;
+ });
+
+ // Sort the second list based on the order of elements in the first list
+ secondList.sort((objecta, objectb) => {
+ // Get the mappedTo values of each object
+ const mappedToA = objecta.mappedTo;
+ const mappedToB = objectb.mappedTo;
+
+ // Get the indices of mappedTo values in the first list
+ const indexA = indexMap[mappedToA];
+ const indexB = indexMap[mappedToB];
+
+ // Compare the indices
+ return indexA - indexB;
+ });
+
+ return secondList;
+};
+
+const computeGeojsonWithMappedProperties = ({ campaignType, fileType, templateIdentifier, validationSchemas }) => {
+ const schemaData = getSchema(campaignType, fileType, templateIdentifier, validationSchemas);
+ let schemaKeys;
+ if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"]));
+ // Sorting the resourceMapping list inorder to maintain the column sequence
+ const sortedSecondList = sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping);
+ // Creating a object with input data with MDMS keys
+ const newFeatures = fileData.data["features"].map((item) => {
+ const newProperties = sortedSecondList.reduce(
+ (acc, e) => ({
+ ...acc,
+ [e["mappedTo"]]: item["properties"][e["mappedFrom"]],
+ }),
+ {}
+ );
+ item["properties"] = newProperties;
+ return item;
+ });
+ const data = fileData.data;
+ data["features"] = newFeatures;
+ return data;
+};
+
+const destroySessionHelper = (currentPath, pathList, sessionName) => {
+ if (!pathList.includes(currentPath)) {
+ sessionStorage.removeItem(`Digit.${sessionName}`);
+ }
+};
+
+const convertGeojsonToExcelSingleSheet = (InputData, fileName) => {
+ if (!InputData || !Array.isArray(InputData) || InputData.length === 0) {
+ return null;
+ }
+
+ // Extract keys from the first feature's properties
+ const keys = Object.keys(InputData?.[0]?.properties);
+
+ if (!keys || keys.length === 0) {
+ return null;
+ }
+
+ // Extract corresponding values for each feature
+ const values = InputData?.map((feature) => {
+ return keys.map((key) => feature.properties[key]);
+ });
+
+ // Group keys and values into the desired format
+ return { [fileName]: [keys, ...values] };
+};
+
+const areObjectsEqual = (obj1, obj2) => {
+ return obj1.name === obj2.name && obj1.code === obj2.code;
+};
+
+const computeDifferences = (data1, data2) => {
+ const removed = {};
+ const added = {};
+
+ for (const key in data1) {
+ if (Object.hasOwn(data2, key)) {
+ removed[key] = data1[key].filter((item1) => !data2[key].some((item2) => areObjectsEqual(item1, item2)));
+ added[key] = data2[key].filter((item2) => !data1[key].some((item1) => areObjectsEqual(item1, item2)));
+ } else {
+ removed[key] = data1[key];
+ added[key] = [];
+ }
+ }
+
+ for (const key in data2) {
+ if (!data1.hasOwnProperty(key)) {
+ added[key] = data2[key];
+ removed[key] = [];
+ }
+ }
+
+ return { removed, added };
+};
+
+const extractNames = (data) => {
+ return Object.values(data)
+ .flatMap((items) => items)
+ .filter((item) => item.name)
+ .map((item) => item.name);
+};
+// function that handles dropdown selection. used in: mapping and microplan preview
+const handleSelection = (e, boundaryType, boundarySelections, hierarchy, setBoundarySelections, boundaryData, setIsLoading) => {
+ setIsLoading(true);
+ if (!e || !boundaryType) return;
+ const selections = e.map((item) => item?.[1]);
+ const newComputedSelection = { ...boundarySelections, [boundaryType]: selections };
+ const { removed, added } = computeDifferences(boundarySelections, newComputedSelection);
+ // for(const item in removed){
+ if (removed && Object.keys(removed).length !== 0 && Object.values(removed)?.flatMap((item) => item).length !== 0) {
+ const filteredRemoved = extractNames(removed);
+ const children = Object.values(findChildren(filteredRemoved, Object.values(boundaryData)?.[0]?.hierarchicalData))?.map((item) => item?.name);
+ for (const key in newComputedSelection) {
+ newComputedSelection[key] = newComputedSelection[key].filter((item) => !children.includes(item?.name));
+ }
+ }
+ setBoundarySelections(newComputedSelection);
+};
+
+// Preventing default action when we scroll on input[number] is that it increments or decrements the number
+const inputScrollPrevention = (e) => {
+ e.target.addEventListener("wheel", (e) => e.preventDefault(), { passive: false });
+};
+
+const mapDataForApi = (data, Operators, microplanName, campaignId, status, reqType = "update") => {
+ const files = extractFiles(data, reqType);
+ const resourceMapping = extractResourceMapping(data, reqType);
+ const assumptions = extractAssumptions(data, reqType);
+ const operations = extractOperations(data, Operators, reqType);
+
+ return createApiRequestBody(status, microplanName, campaignId, files, assumptions, operations, resourceMapping);
+};
+
+const extractFiles = (data, reqType) => {
+ const files = [];
+ if (data && data.upload) {
+ Object.values(data.upload).forEach((item) => {
+ if (isValidFile(item, reqType)) {
+ files.push(mapFile(item));
+ }
+ });
+ }
+ return files;
+};
+
+const isValidFile = (item, reqType) => {
+ if (!item || item.error || !item.filestoreId) return false;
+ if (reqType === "create" && !item.active) return false;
+ return true;
+};
+
+const mapFile = (item) => ({
+ active: item.active,
+ filestoreId: item.filestoreId,
+ inputFileType: item.fileType,
+ templateIdentifier: item.section,
+ id: item.fileId,
+});
+
+const extractResourceMapping = (data, reqType) => {
+ let resourceMapping = [];
+ if (data && data.upload) {
+ Object.values(data.upload).forEach((item) => {
+ if (isValidResourceMapping(item, reqType)) {
+ resourceMapping.push(item.resourceMapping);
+ }
+ });
+ resourceMapping = resourceMapping.flat();
+ }
+ return resourceMapping;
+};
+
+const isValidResourceMapping = (item, reqType) => {
+ if (reqType === "create" && item.resourceMapping && item.resourceMapping.every((i) => i.active === false)) return false;
+ if (!item || !item.resourceMapping || item.error || !Array.isArray(item.resourceMapping)) return false;
+ if (!item.resourceMapping.every((i) => i.mappedFrom && i.mappedTo)) return false;
+ return true;
+};
+
+const extractAssumptions = (data, reqType) => {
+ if (!data || !data.hypothesis) return [];
+ return data.hypothesis.reduce((acc, item) => {
+ if (isValidAssumption(item, reqType)) {
+ acc.push({ ...item });
+ }
+ return acc;
+ }, []);
+};
+
+const isValidAssumption = (item, reqType) => {
+ if (reqType === "create" && !item.active) return false;
+ if (!item.key || !item.value) return false;
+ return true;
+};
+
+const extractOperations = (data, Operators, reqType) => {
+ if (!data || !data.ruleEngine) return [];
+ return data.ruleEngine.reduce((acc, item) => {
+ if (isValidOperation(item, reqType)) {
+ acc.push(mapOperation(item, Operators));
+ }
+ return acc;
+ }, []);
+};
+
+const isValidOperation = (item, reqType) => {
+ if (reqType === "create" && !item.active) return false;
+ if (!item.active && !item.input) return true;
+ if (!item.active && !item.operator && !item.output && !item.input && !item.assumptionValue) return false;
+ return true;
+};
+
+const mapOperation = (item, Operators) => {
+ const data = { ...item };
+ const operator = Operators.find((e) => e.name === data.operator);
+ if (operator && operator.code) data.operator = operator.code;
+ if (data.oldInput) data.input = data.oldInput;
+ return data;
+};
+
+const createApiRequestBody = (status, microplanName, campaignId, files, assumptions, operations, resourceMapping) => ({
+ PlanConfiguration: {
+ status,
+ tenantId: Digit.ULBService.getStateId(),
+ name: microplanName,
+ executionPlanId: campaignId,
+ files,
+ assumptions,
+ operations,
+ resourceMapping,
+ },
+});
+
+const addResourcesToFilteredDataToShow = (previewData, resources, hypothesisAssumptionsList, formulaConfiguration, userEditedResources, t) => {
+ // Clone the preview data to avoid mutating the original data
+ const data = _.cloneDeep(previewData);
+
+ // Helper function to check for user-edited data
+ const checkUserEditedData = (commonColumnData, resourceName) => {
+ if (userEditedResources && userEditedResources[commonColumnData]) {
+ return userEditedResources[commonColumnData][resourceName];
+ }
+ };
+
+ // Ensure the previewData has at least one row and the first row is an array
+ if (!Array.isArray(data) || !Array.isArray(data[0])) {
+ return [];
+ }
+
+ // Identify the index of the common column
+ const conmmonColumnIndex = data[0].indexOf(commonColumn);
+ if (conmmonColumnIndex === -1) {
+ return [];
+ }
+
+ // Ensure resources is a valid array
+ if (!Array.isArray(resources)) {
+ return data;
+ }
+
+ // Process each row of the data
+ const combinedData = data.map((item, index) => {
+ if (!Array.isArray(item)) {
+ return item;
+ }
+
+ if (index === 0) {
+ // Add resource names to the header row
+ resources.forEach((e) => item.push(e));
+ return item;
+ }
+
+ // Process each resource for the current row
+ resources.forEach((resourceName, resourceIndex) => {
+ let savedData = checkUserEditedData(item[conmmonColumnIndex], resourceName);
+ if (savedData !== undefined) {
+ item.push(savedData);
+ } else {
+ let calculations = calculateResource(resourceName, item, formulaConfiguration, previewData[0], hypothesisAssumptionsList, t);
+ if (calculations !== null) calculations = Math.round(calculations);
+ item.push(calculations !== null && calculations !== undefined ? calculations : undefined);
+ }
+ });
+
+ return item;
+ });
+
+ return combinedData;
+};
+
+const calculateResource = (resourceName, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => {
+ let formula = formulaConfiguration?.find((item) => item?.active && item?.output === resourceName);
+ if (!formula) return null;
+
+ // Finding Input
+ // check for Uploaded Data
+ const inputValue = findInputValue(formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t);
+ if (inputValue === undefined || inputValue === null) return null;
+ const assumptionValue = hypothesisAssumptionsList?.find((item) => item?.active && item?.key === formula?.assumptionValue)?.value;
+ if (assumptionValue === undefined) return null;
+
+ return findResult(inputValue, assumptionValue, formula?.operator);
+};
+
+// function to find input value, it calls calculateResource fucntion recurcively until it get a proper value
+const findInputValue = (formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => {
+ const inputIndex = headers?.indexOf(formula?.input);
+ if (inputIndex === -1 || !rowData[inputIndex]) {
+ // let tempFormula = formulaConfiguration.find((item) => item?.output === formula?.input);
+ return calculateResource(formula?.input, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t);
+ } else return rowData[inputIndex];
+};
+
+const findResult = (inputValue, assumptionValue, operator) => {
+ switch (operator) {
+ case "DEVIDED_BY":
+ if (assumptionValue === 0) return;
+ return inputValue / assumptionValue;
+ case "MULTIPLIED_BY":
+ return inputValue * assumptionValue;
+ case "ADDITION":
+ return inputValue + assumptionValue;
+ case "SUBSTRACTION":
+ return inputValue - assumptionValue;
+ case "RAISE_TO":
+ return inputValue ** assumptionValue;
+ default:
+ return;
+ }
+};
+
+const fetchData = (state, campaignType) => {
+ let hypothesis = [];
+ let rulesOutputs = [];
+ let uploadList = [];
+
+ hypothesis = state?.HypothesisAssumptions?.find((item) => item.campaignType === campaignType)?.assumptions;
+ rulesOutputs = state?.RuleConfigureOutput?.find((item) => item.campaignType === campaignType)?.data;
+ uploadList = state?.UploadConfiguration?.reduce((acc, item) => {
+ if (item.required) acc.push(item.id);
+ return acc;
+ }, []);
+ return { hypothesisList: hypothesis, rulesOutputs, uploadList };
+};
+const hypothesisCheck = (hypothesis, validList) => {
+ if (hypothesis && Array.isArray(hypothesis) && hypothesis.length !== 0 && validList && Array.isArray(validList) && validList.length !== 0) {
+ return hypothesis.filter((item) => item.active).every((item) => validList.includes(item.key));
+ }
+ return false;
+};
+const ruleOutputCheck = (rules, ruleOuputList) => {
+ if (
+ rules &&
+ Array.isArray(rules) &&
+ rules.filter((item) => item.active).length !== 0 &&
+ ruleOuputList &&
+ Array.isArray(ruleOuputList) &&
+ ruleOuputList.length !== 0
+ ) {
+ return rules.filter((item) => item.active).every((item) => ruleOuputList.includes(item.output));
+ }
+ return false;
+};
+const emptyRuleCheck = (rules) => {
+ return !rules || rules.filter((item) => item.active && Object.values(item)?.filter((e) => e === "").length !== 0).length === 0;
+};
+const ruleHypothesisCheck = (rules, ruleHypothesis) => {
+ if (rules && Array.isArray(rules) && rules.length !== 0 && ruleHypothesis && Array.isArray(ruleHypothesis) && ruleHypothesis.length !== 0) {
+ return rules.filter((item) => item.active).every((item) => ruleHypothesis.includes(item.assumptionValue));
+ }
+ return false;
+};
+const uploadCheck = (uploads, uploadList) => {
+ if (uploads && Array.isArray(uploads) && uploads.length !== 0 && uploadList && Array.isArray(uploadList) && uploadList.length !== 0) {
+ return uploads.some((item) => uploadList.includes(item.templateIdentifier) && item.active);
+ }
+ return false;
+};
+const planConfigRequestBodyValidator = (data, state, campaignType) => {
+ if (!data || !campaignType || !state) return false;
+
+ const { hypothesisList, rulesOutputs, uploadList } = fetchData(state, campaignType);
+ let checks =
+ // microplan name check
+ (!data || !data.name) &&
+ hypothesisCheck(data?.PlanConfiguration?.assumptions, hypothesisList) &&
+ emptyRuleCheck(data?.PlanConfiguration?.operations) &&
+ ruleOutputCheck(data?.PlanConfiguration?.operations, rulesOutputs) &&
+ ruleHypothesisCheck(
+ data?.PlanConfiguration?.operations,
+ data?.PlanConfiguration?.assumptions?.filter((item) => item.active)?.map((item) => item.key)
+ ) &&
+ uploadCheck(data?.PlanConfiguration?.files, uploadList);
+ return checks;
+ // if()
+};
+
+const processDropdownForNestedMultiSelect = (dropDownOptions) => {
+ if (!dropDownOptions) return dropDownOptions;
+ const result = dropDownOptions.reduce((acc, item) => {
+ const { parent, ...rest } = item;
+
+ // Find the group by parentBoundaryType
+ let group = acc.find((g) => g.name === parent?.name);
+
+ // If not found, create a new group
+ if (!group) {
+ group = { name: parent?.name, options: [] };
+ acc.push(group);
+ }
+
+ // Add the item to the options of the found/created group
+ group.options.push(rest);
+
+ return acc;
+ }, []);
+ return result;
+};
+
+const transformIntoLocalisationCode = (code) => {
+ return code?.toUpperCase();
+};
+
+export default {
+ formatDates,
+ computeGeojsonWithMappedProperties,
+ destroySessionHelper,
+ mapDataForApi,
+ inputScrollPrevention,
+ handleSelection,
+ convertGeojsonToExcelSingleSheet,
+ sortSecondListBasedOnFirstListOrder,
+ addResourcesToFilteredDataToShow,
+ calculateResource,
+ planConfigRequestBodyValidator,
+ getSchema,
+ processDropdownForNestedMultiSelect,
+ transformIntoLocalisationCode,
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js
new file mode 100644
index 00000000000..ae470038a91
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js
@@ -0,0 +1,72 @@
+import ExcelJS from "exceljs";
+import { SHEET_COLUMN_WIDTH } from "../configs/constants";
+
+export const convertJsonToXlsx = async (jsonData, columnWithStyle, returnWorkbook = false) => {
+ const workbook = new ExcelJS.Workbook();
+
+ for (const [sheetName, data] of Object.entries(jsonData)) {
+ const worksheet = workbook.addWorksheet(sheetName);
+ populateWorksheet(worksheet, data, columnWithStyle);
+ }
+
+ if (returnWorkbook) return workbook;
+ return await writeWorkbookToBuffer(workbook);
+};
+
+const populateWorksheet = (worksheet, data, columnWithStyle) => {
+ data.forEach((row, rowIndex) => {
+ const newRow = worksheet.addRow(row);
+ if (columnWithStyle?.errorColumn && rowIndex > 0) {
+ applyStyleToColumn(newRow, data[0], columnWithStyle);
+ }
+ });
+
+ styleHeaderRow(worksheet);
+ setColumnWidths(worksheet);
+};
+
+/**
+ * Applies a specified style to a column in a given row of a spreadsheet.
+ *
+ * @param {Object} newRow - The row object where the style will be applied.
+ * @param {Array} headerRow - The header row array containing column names.
+ * @param {Object} columnWithStyle - An object containing the column name and the style to be applied.
+ * @param {string} columnWithStyle.errorColumn - The name of the column where the style should be applied.
+ * @param {Object} columnWithStyle.style - The style properties to be applied to the cell.
+ */
+const applyStyleToColumn = (newRow, headerRow, columnWithStyle) => {
+ const errorColumnIndex = headerRow.indexOf(columnWithStyle.errorColumn);
+ if (errorColumnIndex !== -1) {
+ const columnIndex = errorColumnIndex + 1;
+ const newCell = newRow.getCell(columnIndex);
+ if (columnWithStyle.style && newCell) {
+ for (const key in columnWithStyle.style) {
+ newCell[key] = columnWithStyle.style[key];
+ }
+ }
+ }
+};
+
+const styleHeaderRow = (worksheet) => {
+ const headerRow = worksheet.getRow(1);
+ if (headerRow) {
+ headerRow.font = { bold: true };
+ }
+};
+
+const setColumnWidths = (worksheet) => {
+ // Iterate over all rows in the worksheet
+ worksheet.eachRow((worksheetRow, rowNumber) => {
+ worksheetRow.eachCell((cell, colNumber) => {
+ // Update column width based on the length of the cell's text
+ const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width
+ const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding
+ worksheet.getColumn(colNumber).width = newWidth;
+ });
+ });
+};
+
+export const writeWorkbookToBuffer = async (workbook) => {
+ const buffer = await workbook.xlsx.writeBuffer({ compression: true });
+ return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js
new file mode 100644
index 00000000000..39f57272d2d
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js
@@ -0,0 +1,763 @@
+import L from "leaflet";
+import "leaflet/dist/leaflet.css";
+import { processHierarchyAndData, findChildren, calculateAggregateForTree } from "../utils/processHierarchyAndData";
+import { EXCEL, GEOJSON, SHAPEFILE, MapChoroplethGradientColors } from "../configs/constants";
+import { PopulationSvg } from "../icons/Svg";
+import chroma from "chroma-js";
+import * as MicroplanIconCollection from "../icons/Svg";
+import * as DigitSvgs from "@egovernments/digit-ui-svg-components";
+
+const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs };
+
+export const generatePreviewUrl = (baseMapUrl, center = [0, 0], zoom = 5) => {
+ const lon = Math.floor(((center[1] + 180) / 360) * Math.pow(0, zoom));
+ const lat = Math.floor(
+ ((1 - Math.log(Math.tan((center[0] * Math.PI) / 180) + 1 / Math.cos((center[0] * Math.PI) / 180)) / Math.PI) / 2) * Math.pow(2, zoom)
+ );
+ if (baseMapUrl) {
+ return baseMapUrl.replace("{z}", zoom).replace("{x}", lat).replace("{y}", lon);
+ }
+ // Return a default preview URL or handle this case as needed
+ return "default-preview-url.jpg"; // todo
+};
+
+// get schema for validation
+export const getSchema = (campaignType, type, section, schemas) => {
+ return schemas.find((schema) => {
+ if (!schema.campaignType) {
+ return schema.type === type && schema.section === section;
+ }
+ return schema.campaignType === campaignType && schema.type === type && schema.section === section;
+ });
+};
+
+export const calculateAggregateForTreeMicroplanWrapper = (entity) => {
+ if (!entity || typeof entity !== "object") return {};
+ let newObject = {};
+ for (let [key, value] of Object.entries(entity)) {
+ if (!value?.["hierarchicalData"]) continue;
+ let aggregatedTree = calculateAggregateForTree(value?.["hierarchicalData"]);
+ newObject[key] = { ...value, hierarchicalData: aggregatedTree };
+ }
+ return newObject;
+};
+
+export const extractGeoData = (
+ campaignType,
+ microplanData,
+ filterDataOrigin,
+ validationSchemas,
+ setToast,
+ setDataAvailability,
+ hierarchy,
+ setBoundaryData,
+ setFilterData,
+ setFilterProperties,
+ setFilterSelections,
+ setFilterPropertyNames,
+ state,
+ setChoroplethProperties,
+ setDataCompleteness,
+ t
+) => {
+ if (!hierarchy) return;
+
+ const initializeDataAvailability = (microplanData) => (microplanData?.upload ? "initialStage" : undefined);
+
+ const checkFileActivity = (fileData) => fileData.active;
+
+ const checkFileSection = (fileData, filterDataOrigin) =>
+ filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section) || filterDataOrigin?.layerDataOrigin?.includes(fileData?.section);
+
+ const getFileValidationSchema = (campaignType, fileData, validationSchemas) =>
+ getSchema(campaignType, fileData?.fileType, fileData?.section, validationSchemas);
+
+ const updateDataAvailabilityCheck = (dataAvailabilityCheck, condition, partialState) =>
+ condition ? partialState : dataAvailabilityCheck === "initialStage" ? "false" : partialState;
+
+ const handleFileDataError = (dataAvailabilityCheck, fileData) =>
+ fileData?.error ? updateDataAvailabilityCheck(dataAvailabilityCheck, true, "partial") : dataAvailabilityCheck;
+
+ const addResourcesToFilteredData = (data, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) =>
+ Digit.Utils.microplan.addResourcesToFilteredDataToShow(
+ data,
+ resources,
+ hypothesisAssumptionsList,
+ formulaConfiguration,
+ microplanData?.microplanPreview?.userEditedResources || [],
+ t
+ );
+
+ const processFileData = (
+ fileData,
+ schema,
+ filterDataOrigin,
+ virtualizationPropertiesCollector,
+ filterPropertiesCollector,
+ filterPropertieNameCollector,
+ resources,
+ hypothesisAssumptionsList,
+ formulaConfiguration,
+ t
+ ) => {
+ const properties = Object.entries(schema?.schema?.Properties || {});
+ const latLngColumns = [];
+ const filterProperty = [];
+
+ for (const [key, value] of properties) {
+ if (value?.isLocationDataColumns) latLngColumns.push(t(key));
+ if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section) && value?.isFilterPropertyOfMapSection) filterProperty.push(key);
+ if (value?.isVisualizationPropertyOfMapSection && filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section))
+ virtualizationPropertiesCollector.add(key);
+ }
+
+ filterProperty.forEach((property) => filterPropertieNameCollector.add(property));
+
+ return { latLngColumns, filterProperty };
+ };
+
+ const processExcelFile = (fileData, latLngColumns, resources, formulaConfiguration, hypothesisAssumptionsList, schema, t) => {
+ let dataAvailabilityCheck = "true";
+ const columnList = Object.values(fileData?.data)?.[0]?.[0];
+ const check = latLngColumns?.every((colName) => columnList?.includes(t(colName)));
+
+ if (!check) dataAvailabilityCheck = "partial";
+
+ let dataWithResources = Object.values(fileData?.data);
+ if (resources && formulaConfiguration && hypothesisAssumptionsList && schema?.showResourcesInMappingSection) {
+ dataWithResources = dataWithResources.map((item) =>
+ addResourcesToFilteredData(item, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t)
+ );
+ }
+
+ const hasLocationData = dataWithResources.some((item) => item.some((row) => row.includes("lat") && row.includes("long")));
+
+ const convertedData = dataWithResources.map((item) =>
+ item.map((row, rowIndex) => {
+ if (rowIndex === 0) {
+ if (row.indexOf("features") === -1) row.push("feature");
+ return row;
+ }
+ const latIndex = item[0].findIndex((cell) => cell === "lat");
+ const lonIndex = item[0].findIndex((cell) => cell === "long");
+ const properties = item[0].reduce((acc, cell, index) => ({ ...acc, [cell]: row[index] }), {});
+ const feature =
+ latIndex !== -1 && lonIndex !== -1
+ ? {
+ type: "Feature",
+ properties,
+ geometry: {
+ type: "Point",
+ coordinates: [row[lonIndex], row[latIndex]],
+ },
+ }
+ : null;
+ row.push(feature);
+ return row;
+ })
+ );
+
+ return { dataAvailabilityCheck, hasLocationData, convertedData };
+ };
+
+ const processGeoJsonFile = (fileData, filterProperty, resources, formulaConfiguration, hypothesisAssumptionsList, t) => {
+ const dataAvailabilityCheck = "true";
+ const keys = [...Object.keys(fileData?.data.features[0].properties), "feature"];
+ const values = fileData?.data.features.map((feature) => keys.map((key) => (key === "feature" ? feature : feature.properties[key] || null)));
+
+ let dataWithResources = [[...keys], ...values];
+ if (resources && formulaConfiguration && hypothesisAssumptionsList) {
+ dataWithResources = addResourcesToFilteredData(dataWithResources, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t);
+ }
+ const processedDataWithResources = dataWithResources.map((item, index) => {
+ if (index === 0) return item;
+ const newProperties = keys.reduce((acc, key, i) => (key !== "feature" ? { ...acc, [key]: item[i] } : acc), {});
+ item[item.length - 1] = { ...item[item.length - 1], properties: newProperties };
+ return item;
+ });
+
+ return { dataAvailabilityCheck, dataWithResources: processedDataWithResources };
+ };
+
+ const updateFilterPropertiesCollector = (fileData, filterProperty, filterPropertiesCollector) => {
+ filterProperty.forEach((item) => {
+ Object.values(fileData?.data).forEach((data) => {
+ const filterPropertyIndex = data[0].indexOf(item);
+ if (filterPropertyIndex !== -1) data.slice(1).forEach((e) => filterPropertiesCollector.add(e[filterPropertyIndex]));
+ });
+ });
+ };
+
+ const setAvailabilityAndToastMessages = (dataAvailabilityCheck, combineList, files, setToast, t) => {
+ if (dataAvailabilityCheck === "true") {
+ const sectionWiseCheck = combineList.every((item) => Object.keys(files).includes(item));
+ if (!sectionWiseCheck) dataAvailabilityCheck = "partial";
+ }
+
+ if (dataAvailabilityCheck === "initialStage" && (combineList.length === 0 || Object.keys(files).length === 0)) dataAvailabilityCheck = "false";
+
+ const toastMessages = {
+ false: { state: "warning", message: t("MAPPING_NO_DATA_TO_SHOW") },
+ partial: { state: "warning", message: t("MAPPING_PARTIAL_DATA_TO_SHOW") },
+ undefined: { state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") },
+ };
+
+ setToast(toastMessages[dataAvailabilityCheck]);
+ return dataAvailabilityCheck;
+ };
+
+ const setFinalDataAndProperties = (
+ dataAvailabilityCheck,
+ setBoundary,
+ setFilter,
+ setBoundaryData,
+ setFilterData,
+ setFilterProperties,
+ setFilterSelections,
+ setFilterPropertyNames,
+ filterPropertiesCollector,
+ filterPropertieNameCollector,
+ virtualizationPropertiesCollector,
+ setChoroplethProperties,
+ resources
+ ) => {
+ setDataCompleteness(dataAvailabilityCheck);
+ setBoundary = calculateAggregateForTreeMicroplanWrapper(setBoundary);
+ setFilter = calculateAggregateForTreeMicroplanWrapper(setFilter);
+ setBoundaryData((previous) => ({ ...previous, ...setBoundary }));
+ setFilterData((previous) => ({ ...previous, ...setFilter }));
+ setFilterProperties([...filterPropertiesCollector]);
+ setFilterSelections([...filterPropertiesCollector]);
+ setFilterPropertyNames([...filterPropertieNameCollector]);
+ const tempVirtualizationPropertiesCollectorArray = [...virtualizationPropertiesCollector];
+ if (tempVirtualizationPropertiesCollectorArray.length !== 0)
+ setChoroplethProperties([...tempVirtualizationPropertiesCollectorArray, ...(resources || [])]);
+ };
+
+ let setBoundary = {};
+ let setFilter = {};
+ const virtualizationPropertiesCollector = new Set();
+ const filterPropertiesCollector = new Set();
+ const filterPropertieNameCollector = new Set();
+ const resources = state?.Resources?.find((item) => item.campaignType === campaignType)?.data;
+ const hypothesisAssumptionsList = microplanData?.hypothesis;
+ const formulaConfiguration = microplanData?.ruleEngine;
+
+ let dataAvailabilityCheck = initializeDataAvailability(microplanData);
+ if (!dataAvailabilityCheck) return setToast({ state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") });
+
+ const files = _.cloneDeep(microplanData.upload);
+ for (const fileData of files) {
+ if (!checkFileActivity(fileData) || !checkFileSection(fileData, filterDataOrigin)) {
+ dataAvailabilityCheck = "false";
+ continue;
+ }
+
+ if (!fileData?.fileType || !fileData?.section) continue;
+
+ const schema = getFileValidationSchema(campaignType, fileData, validationSchemas);
+ dataAvailabilityCheck = handleFileDataError(dataAvailabilityCheck, fileData);
+
+ const { latLngColumns, filterProperty } = processFileData(
+ fileData,
+ schema,
+ filterDataOrigin,
+ virtualizationPropertiesCollector,
+ filterPropertiesCollector,
+ filterPropertieNameCollector,
+ resources,
+ hypothesisAssumptionsList,
+ formulaConfiguration,
+ t
+ );
+
+ if (fileData?.data && Object.keys(fileData?.data).length > 0) {
+ switch (fileData?.fileType) {
+ case EXCEL:
+ const { dataAvailabilityCheck: excelDataAvailabilityCheck, hasLocationData, convertedData } = processExcelFile(
+ fileData,
+ latLngColumns,
+ resources,
+ formulaConfiguration,
+ hypothesisAssumptionsList,
+ schema,
+ t
+ );
+ dataAvailabilityCheck = excelDataAvailabilityCheck;
+ if (hasLocationData) updateFilterPropertiesCollector(fileData, filterProperty, filterPropertiesCollector);
+ const { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } = processHierarchyAndData(hierarchy, convertedData);
+ if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section))
+ setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } };
+ else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section))
+ setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } };
+ break;
+ case GEOJSON:
+ case SHAPEFILE:
+ const { dataAvailabilityCheck: geoJsonDataAvailabilityCheck, dataWithResources } = processGeoJsonFile(
+ fileData,
+ filterProperty,
+ resources,
+ formulaConfiguration,
+ hypothesisAssumptionsList,
+ t
+ );
+ dataAvailabilityCheck = geoJsonDataAvailabilityCheck;
+ const { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } = processHierarchyAndData(hierarchy, [
+ dataWithResources,
+ ]);
+ if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section))
+ setBoundary = {
+ ...setBoundary,
+ [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData },
+ };
+ else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section))
+ setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } };
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ const combineList = [...(filterDataOrigin?.boundriesDataOrigin || []), ...(filterDataOrigin?.layerDataOrigin || [])];
+ dataAvailabilityCheck = setAvailabilityAndToastMessages(dataAvailabilityCheck, combineList, files, setToast, t);
+
+ setFinalDataAndProperties(
+ dataAvailabilityCheck,
+ setBoundary,
+ setFilter,
+ setBoundaryData,
+ setFilterData,
+ setFilterProperties,
+ setFilterSelections,
+ setFilterPropertyNames,
+ filterPropertiesCollector,
+ filterPropertieNameCollector,
+ virtualizationPropertiesCollector,
+ setChoroplethProperties,
+ resources
+ );
+};
+
+//prepare geojson to show on the map
+export const prepareGeojson = (boundaryData, selection, style = {}) => {
+ if (!boundaryData || Object.keys(boundaryData).length === 0) return [];
+ let geojsonRawFeatures = [];
+ if (selection === "ALL") {
+ for (let data of Object.values(boundaryData)) {
+ const templist = fetchFeatures(data?.hierarchicalData, selection, [], style);
+ if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist];
+ }
+ } else if (Array.isArray(selection)) {
+ for (let data of Object.values(boundaryData)) {
+ const templist = fetchFeatures(data?.hierarchicalData, selection, [], style);
+ if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist];
+ }
+ }
+
+ return geojsonRawFeatures.filter(Boolean);
+};
+export const fetchFeatures = (data, parameter = "ALL", outputList = [], addOn = {}) => {
+ let tempStorage = [];
+ if (parameter === "ALL") {
+ // outputList(Object.values(data).flatMap(item=>item?.data?.feature))
+ for (let [entityKey, entityValue] of Object.entries(data)) {
+ if (entityValue?.data?.feature) {
+ let feature = entityValue.data.feature;
+ feature.properties["name"] = entityKey;
+ feature.properties["addOn"] = addOn;
+ if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)];
+ else tempStorage = [...tempStorage, feature];
+ } else {
+ tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)];
+ }
+ }
+ return tempStorage;
+ }
+ if (Array.isArray(parameter)) {
+ for (let [entityKey, entityValue] of Object.entries(data)) {
+ if (parameter.includes(entityKey) && entityValue && entityValue.data && entityValue.data.feature) {
+ let feature = entityValue.data.feature;
+ feature.properties["name"] = entityKey;
+ feature.properties["addOn"] = addOn;
+ if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)];
+ else tempStorage = [...tempStorage, feature];
+ }
+ if (entityValue?.children) tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)];
+ }
+ return tempStorage;
+ }
+};
+
+export const addChoroplethProperties = (geojson, choroplethProperty, filteredSelection) => {
+ // Calculate min and max values of the property
+ const values = geojson.map((feature) => feature.properties[choroplethProperty]).filter((item) => !!item || item === 0) || [];
+ if (!values || values.length === 0) return [];
+ const convertedValues = values.map((item) => (!isNaN(item) ? item : 0));
+ const minValue = Math.min(...convertedValues);
+ const maxValue = Math.max(...convertedValues);
+
+ // Create a new geojson object
+ const newGeojson = geojson.map((feature) => {
+ const newFeature = { ...feature, properties: { ...feature.properties, addOn: { ...feature.properties.addOn } } };
+ let color;
+
+ if (choroplethProperty) {
+ color = interpolateColor(newFeature.properties[choroplethProperty], minValue, maxValue, MapChoroplethGradientColors);
+ }
+
+ newFeature.properties.addOn.fillColor = color;
+ newFeature.properties.addOn.color = "rgba(0, 0, 0, 1)";
+ if (!filteredSelection || filteredSelection.length === 0 || filteredSelection.includes(newFeature.properties.name)) {
+ newFeature.properties.addOn.fillOpacity = 1;
+ } else {
+ newFeature.properties.addOn.fillOpacity = 0.4;
+ newFeature.properties.addOn.opacity = 0.7;
+ }
+
+ return newFeature;
+ });
+ return newGeojson;
+};
+
+/**
+ * filterGeojsons : json
+ * filterSelection : array
+ * MapFilters :
+ */
+export const addFilterProperties = (filterGeojsons, filterSelections, filterPropertyNames, iconMapping) => {
+ try {
+ if (!filterGeojsons || !iconMapping || !filterSelections) return [];
+ let newFilterGeojson = [];
+ filterGeojsons.forEach((item) => {
+ if (filterPropertyNames && filterPropertyNames.length !== 0 && item.properties) {
+ let icon;
+ filterPropertyNames.forEach((name) => {
+ if (item.properties[name]) {
+ let temp = item.properties[name];
+ if (!filterSelections.includes(temp)) return;
+ temp = iconMapping?.find((e) => e?.name == temp)?.icon?.marker;
+ let DynamicIcon = IconCollection?.[temp];
+ if (typeof DynamicIcon === "function") {
+ icon = L.divIcon({
+ className: "custom-svg-icon",
+ html: DynamicIcon({}),
+ iconAnchor: [25, 50],
+ });
+ newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } });
+ } else {
+ icon = DefaultMapMarker({});
+ newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } });
+ }
+ }
+ });
+ }
+ return item;
+ });
+ return newFilterGeojson;
+ } catch (error) {
+ console.error(error.message);
+ }
+};
+
+/**
+ * map: map
+ * geojson: geojson
+ * t: translator
+ */
+
+export const addGeojsonToMap = (map, geojson, t) => {
+ try {
+ if (!map || !geojson) return false;
+ const geojsonLayer = L.geoJSON(geojson, {
+ style: (feature) => {
+ if (Object.keys(feature.properties.addOn).length !== 0) {
+ return feature.properties.addOn;
+ }
+ return {
+ weight: 2,
+ opacity: 1,
+ color: "rgba(176, 176, 176, 1)",
+ fillColor: "rgb(0,0,0,0)",
+ // fillColor: choroplethProperty ? color : "rgb(0,0,0,0)",
+ fillOpacity: 0,
+ // fillOpacity: choroplethProperty ? (feature?.properties?.style?.fillOpacity ? feature.properties.style.fillOpacity : 0.7) : 0,
+ };
+ },
+ pointToLayer: (feature, latlng) => {
+ if (feature.properties.addOn.icon) {
+ let icon = feature.properties.addOn.icon;
+ if (icon) {
+ return L.marker(latlng, {
+ icon: icon,
+ });
+ }
+ }
+ return L.marker(latlng, {
+ icon: MapMarker(feature.properties.addOn),
+ });
+ },
+ onEachFeature: (feature, layer) => {
+ let popupContent;
+ popupContent = "";
+ popupContent += "
";
+ popupContent += `${feature.properties["name"]}
`;
+ for (let prop in feature.properties) {
+ if (prop !== "name" && prop !== "addOn" && prop !== "feature") {
+ let data = feature.properties[prop] ? feature.properties[prop] : t("NO_DATA");
+ popupContent +=
+ "" +
+ t(prop) +
+ " | " +
+ data +
+ " |
";
+ }
+ }
+ popupContent += "
";
+ layer.bindPopup(popupContent, {
+ minWidth: "28rem",
+ padding: "0",
+ });
+ // Adjust map here when pop up closes
+ layer.on("popupclose", () => {
+ map.fitBounds(geojsonLayer.getBounds());
+ });
+ layer.on({
+ mouseover: (e) => {
+ const layer = e.target;
+ if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) {
+ return;
+ }
+ if (layer.setStyle)
+ layer.setStyle({
+ weight: 2.7,
+ opacity: 1,
+ color: "rgba(255, 255, 255, 1)",
+ });
+ // layer.openPopup();
+ },
+ mouseout: (e) => {
+ const layer = e.target;
+ if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) {
+ return;
+ }
+ if (layer.setStyle) {
+ if (layer.feature.properties.addOn && Object.keys(layer.feature.properties.addOn).length !== 0)
+ layer.setStyle({
+ ...layer.feature.properties.addOn,
+ });
+ else
+ layer.setStyle({
+ weight: 2,
+ color: "rgba(176, 176, 176, 1)",
+ });
+ }
+ // layer.closePopup();
+ },
+ });
+ },
+ });
+ geojsonLayer.addTo(map);
+ return geojsonLayer;
+ } catch (error) {
+ console.error(error.message);
+ }
+};
+
+export const interpolateColor = (value, minValue, maxValue, colors) => {
+ // Handle case where min and max values are the same
+ if (minValue === maxValue) {
+ // Return a default color or handle the case as needed
+ return colors[0].color;
+ }
+
+ // Normalize the value to a percentage between 0 and 100
+ const percent = !isNaN(value) ? ((value - minValue) / (maxValue - minValue)) * 100 : 0;
+ // Find the two colors to interpolate between
+ let lowerColor, upperColor;
+ for (let i = 0; i < colors.length - 1; i++) {
+ if (!isNaN(percent) && percent >= colors[i].percent && percent <= colors[i + 1].percent) {
+ lowerColor = colors[i];
+ upperColor = colors[i + 1];
+ break;
+ }
+ }
+ // Interpolate between the two colors
+ const t = (percent - lowerColor.percent) / (upperColor.percent - lowerColor.percent);
+ return chroma.mix(lowerColor.color, upperColor.color, t, "lab").hex();
+};
+
+// Find bounds for multiple geojson together
+export const findBounds = (data, buffer = 0.1) => {
+ if (!Array.isArray(data) || data.length === 0) {
+ return null;
+ }
+
+ // Initialize variables to store bounds
+ var minLat = Number.MAX_VALUE;
+ var maxLat = -Number.MAX_VALUE;
+ var minLng = Number.MAX_VALUE;
+ var maxLng = -Number.MAX_VALUE;
+
+ // Iterate through the data to find bounds
+ data.forEach(function (feature) {
+ if (!feature || !feature.geometry || !feature.geometry.type || !feature.geometry.coordinates) {
+ return null;
+ }
+
+ var coords = feature.geometry.coordinates;
+ var geometryType = feature.geometry.type;
+
+ switch (geometryType) {
+ case "Point":
+ var coord = coords;
+ var lat = coord[1];
+ var lng = coord[0];
+ minLat = Math.min(minLat, lat);
+ maxLat = Math.max(maxLat, lat);
+ minLng = Math.min(minLng, lng);
+ maxLng = Math.max(maxLng, lng);
+ break;
+ case "MultiPoint":
+ coords.forEach(function (coord) {
+ var lat = coord[1];
+ var lng = coord[0];
+ minLat = Math.min(minLat, lat);
+ maxLat = Math.max(maxLat, lat);
+ minLng = Math.min(minLng, lng);
+ maxLng = Math.max(maxLng, lng);
+ });
+ break;
+ case "LineString":
+ case "MultiLineString":
+ case "Polygon":
+ case "MultiPolygon":
+ coords.forEach(function (polygons) {
+ if ((geometryType === "Polygon" || geometryType === "MultiPolygon") && Array.isArray(polygons[0][0])) {
+ polygons.forEach(function (coordinates) {
+ coordinates.forEach(function (coord) {
+ if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") {
+ return null;
+ }
+
+ var lat = coord[1];
+ var lng = coord[0];
+ minLat = Math.min(minLat, lat);
+ maxLat = Math.max(maxLat, lat);
+ minLng = Math.min(minLng, lng);
+ maxLng = Math.max(maxLng, lng);
+ });
+ });
+ } else {
+ polygons.forEach(function (coord) {
+ if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") {
+ return null;
+ }
+
+ var lat = coord[1];
+ var lng = coord[0];
+ minLat = Math.min(minLat, lat);
+ maxLat = Math.max(maxLat, lat);
+ minLng = Math.min(minLng, lng);
+ maxLng = Math.max(maxLng, lng);
+ });
+ }
+ });
+ break;
+ default:
+ return null;
+ }
+ });
+
+ // Check if valid bounds found
+ if (minLat === Number.MAX_VALUE || maxLat === -Number.MAX_VALUE || minLng === Number.MAX_VALUE || maxLng === -Number.MAX_VALUE) {
+ return null;
+ }
+ // Apply buffer to bounds
+ minLat -= buffer;
+ maxLat += buffer;
+ minLng -= buffer;
+ maxLng += buffer;
+
+ // Set bounds for the Leaflet map
+ var bounds = [
+ [minLat, minLng],
+ [maxLat, maxLng],
+ ];
+
+ return bounds;
+};
+
+export const filterBoundarySelection = (boundaryData, boundarySelections) => {
+ if (Object.keys(boundaryData).length === 0 || Object.keys(boundarySelections).length === 0) return [];
+ let selectionList = [];
+ Object.values(boundarySelections).forEach((item) => (selectionList = [...selectionList, ...item.map((e) => e.name)]));
+ let childrenList = [];
+ const set1 = new Set(selectionList);
+ selectionList = selectionList.filter((item) => {
+ const children = findChildren([item], Object.values(boundaryData)?.[0]?.hierarchicalData);
+ if (children) {
+ let childrenKeyList = getAllKeys(children);
+ childrenList = [...childrenList, ...childrenKeyList];
+ const nonePresent = childrenKeyList.every((item) => !set1.has(item));
+ const allPresent = childrenKeyList.every((item) => set1.has(item));
+ return nonePresent ? true : allPresent ? true : false;
+ }
+ return true;
+ });
+ return { filteredSelection: selectionList, childrenList };
+};
+
+// Recursive function to extract all keys
+export const getAllKeys = (obj, keys = []) => {
+ for (let [key, value] of Object.entries(obj)) {
+ keys.push(key);
+ if (value.children) {
+ getAllKeys(value.children, keys);
+ }
+ }
+ return keys;
+};
+
+// Remove all layers from the map
+export const removeAllLayers = (map, layer) => {
+ if (!map) return;
+ layer.forEach((layer) => {
+ map.removeLayer(layer);
+ });
+};
+// Map-Marker
+export const MapMarker = (style = {}) => {
+ return L.divIcon({
+ className: "custom-svg-icon",
+ html: PopulationSvg(style),
+ iconAnchor: [25, 50],
+ });
+};
+export const DefaultMapMarker = (style = {}) => {
+ return L.divIcon({
+ className: "custom-svg-icon",
+ html: IconCollection.DefaultMapMarkerSvg(style),
+ iconAnchor: [25, 50],
+ });
+};
+
+export const disableMapInteractions = (map) => {
+ if (!map) return;
+ map.dragging.disable();
+ map.scrollWheelZoom.disable();
+ map.touchZoom.disable();
+ map.doubleClickZoom.disable();
+ map.boxZoom.disable();
+ map.keyboard.disable();
+};
+
+export const enableMapInteractions = (map) => {
+ if (!map) return;
+ map.dragging.enable();
+ map.scrollWheelZoom.enable();
+ map.touchZoom.enable();
+ map.doubleClickZoom.enable();
+ map.boxZoom.enable();
+ map.keyboard.enable();
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js
new file mode 100644
index 00000000000..ff5cd55208f
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js
@@ -0,0 +1,413 @@
+import { EXCEL, GEOJSON, SHAPEFILE, commonColumn } from "../configs/constants";
+
+export const calculateAggregateValue = (aggregateName, dataToShow) => {
+ if (!aggregateName || !dataToShow || dataToShow.length === 0) return;
+ let aggregateNameList = aggregateName;
+ if (typeof aggregateName !== "object") aggregateNameList = { name: aggregateName, entities: [aggregateName] };
+ let aggregateData = 0;
+ if (aggregateNameList)
+ for (const item of aggregateNameList.entities) {
+ const columnIndex = dataToShow?.[0].indexOf(item);
+ dataToShow.slice(1).forEach((e) => {
+ if (e?.[columnIndex]) aggregateData = aggregateData + Number(e[columnIndex]);
+ });
+ }
+ return aggregateData;
+};
+
+export const fetchMicroplanData = (microplanData, campaignType, validationSchemas) => {
+ if (!microplanData) return [];
+
+ let combinesDataList = [];
+ // Check if microplanData and its upload property exist
+ if (microplanData?.upload) {
+ let files = microplanData?.upload;
+ // Loop through each file in the microplan upload
+ for (let fileData of files) {
+ const schema = getSchema(campaignType, fileData.fileType, fileData.templateIdentifier, validationSchemas);
+
+ // Check if the file is not part of boundary or layer data origins
+ if (!fileData.active || !fileData.fileType || !fileData?.section) continue; // Skip files with errors or missing properties
+
+ // Check if file contains latitude and longitude columns
+ if (fileData?.data) {
+ // Check file type and update data availability accordingly
+ switch (fileData?.fileType) {
+ case EXCEL: {
+ // extract dada
+ const mergedData = schema?.template?.hierarchyLevelWiseSheets ? Object.values(fileData?.data).flat() : Object.values(fileData?.data)?.[0];
+
+ let commonColumnIndex = mergedData?.[0]?.indexOf(commonColumn);
+
+ let uniqueEntries;
+ if (commonColumnIndex !== undefined)
+ uniqueEntries = schema?.template?.hierarchyLevelWiseSheets
+ ? Array.from(new Map(mergedData.map((entry) => [entry[commonColumnIndex], entry])).values())
+ : mergedData;
+ if (uniqueEntries) combinesDataList.push(uniqueEntries);
+ break;
+ }
+ case GEOJSON:
+ case SHAPEFILE: {
+ // Extract keys from the first feature's properties
+ let keys = Object.keys(fileData?.data.features[0].properties);
+
+ // Extract corresponding values for each feature
+ const values = fileData?.data?.features.map((feature) => {
+ // list with features added to it
+ const temp = keys.map((key) => {
+ // if (feature.properties[key] === "") {
+ // return null;
+ // }
+ return feature.properties[key];
+ });
+ return temp;
+ });
+
+ let data = [keys, ...values];
+ combinesDataList.push(data);
+ }
+ }
+ }
+ }
+ }
+ return combinesDataList;
+};
+
+// get schema for validation
+export const getSchema = (campaignType, type, section, schemas) => {
+ return schemas.find((schema) =>
+ schema.campaignType
+ ? schema.campaignType === campaignType && schema.type === type && schema.section === section
+ : schema.type === type && schema.section === section
+ );
+};
+
+export const fetchMicroplanPreviewData = (campaignType, microplanData, validationSchemas, hierarchy) => {
+ try {
+ const filteredSchemaColumns = getFilteredSchemaColumnsList(campaignType, microplanData, validationSchemas, hierarchy);
+ const fetchedData = fetchMicroplanData(microplanData, campaignType, validationSchemas);
+ const dataAfterJoins = performDataJoins(fetchedData, filteredSchemaColumns);
+ return dataAfterJoins;
+ } catch (error) {
+ console.error("Error in fetch microplan data: ", error.message);
+ }
+};
+
+const getFilteredSchemaColumnsList = (campaignType, microplanData, validationSchemas, hierarchy) => {
+ let filteredSchemaColumns = getRequiredColumnsFromSchema(campaignType, microplanData, validationSchemas) || [];
+ if (hierarchy) {
+ filteredSchemaColumns = [...hierarchy, commonColumn, ...filteredSchemaColumns.filter((e) => e !== commonColumn)];
+ }
+ return filteredSchemaColumns;
+};
+
+const performDataJoins = (fetchedData, filteredSchemaColumns) => {
+ return fetchedData.reduce((accumulator, currentData, index) => {
+ if (index === 0) {
+ return innerJoinLists(currentData, null, commonColumn, filteredSchemaColumns);
+ }
+ return innerJoinLists(accumulator, currentData, commonColumn, filteredSchemaColumns);
+ }, null);
+};
+
+export const filterObjects = (arr1, arr2) => {
+ if (!arr1 || !arr2) return [];
+ // Create a new array to store the filtered objects
+ let filteredArray = [];
+
+ // Iterate through the first array
+ arr1.forEach((obj1) => {
+ // Find the corresponding object in the second array
+ let obj2 = _.cloneDeep(arr2.find((item) => item.key === obj1.key));
+
+ // If the object with the same key is found in the second array and their values are the same
+ if (obj2 && obj1.value !== obj2.value) {
+ // Push the object to the filtered array
+ obj1.oldValue = obj2.value;
+ filteredArray.push(obj1);
+ }
+ });
+
+ return filteredArray;
+};
+
+export const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) => {
+ // Handles the change in hypothesis value
+ const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => {
+ // Checks it the boundary filters at at root level ( given constraints )
+ if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0))
+ return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") });
+
+ // validating user input
+ if (e?.newValue.includes("+") || e?.newValue.includes("e")) return;
+ if ((e?.newValue < 0 || e.newValue > 10000000000) && e?.newValue !== "") return;
+ let value;
+ const decimalIndex = e.newValue.indexOf(".");
+ if (decimalIndex !== -1) {
+ const numDecimals = e.newValue.length - decimalIndex - 1;
+ if (numDecimals <= 2) {
+ value = e.newValue;
+ } else if (numDecimals > 2) {
+ value = e.newValue.substring(0, decimalIndex + 3);
+ }
+ } else value = parseFloat(e.newValue);
+ value = !isNaN(value) ? value : "";
+
+ // update the state with user input
+ let newhypothesisEntityIndex = hypothesisAssumptionsList.findIndex((item) => item?.id === e?.item?.id);
+ let unprocessedHypothesisList = _.cloneDeep(tempHypothesisList);
+ if (newhypothesisEntityIndex !== -1) unprocessedHypothesisList[newhypothesisEntityIndex].value = value;
+ setTempHypothesisList(unprocessedHypothesisList);
+ };
+
+ return {
+ valueChangeHandler,
+ };
+};
+
+const validateRequestBody = (body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t) => {
+ if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) {
+ setLoaderActivation(false);
+ if (navigationEvent.name === "next") {
+ setToast({
+ message: t("ERROR_DATA_NOT_SAVED"),
+ state: "error",
+ });
+ setCheckDataCompletion("false");
+ } else {
+ setCheckDataCompletion("perform-action");
+ }
+ return false;
+ }
+ return true;
+};
+
+const handleApiSuccess = (data, updateData, setLoaderActivation, setMicroplanData, status) => {
+ updateData();
+ setLoaderActivation(false);
+ setMicroplanData((previous) => ({ ...previous, microplanStatus: status }));
+};
+
+const handleApiError = (error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t) => {
+ setLoaderActivation(false);
+ setToast({
+ message: t("ERROR_DATA_NOT_SAVED"),
+ state: "error",
+ });
+ if (status === "GENERATED") {
+ cancleNavigation();
+ } else {
+ updateData();
+ }
+};
+
+const constructRequestBody = (microplanData, operatorsObject, MicroplanName, campaignId, status) => {
+ const body = Digit.Utils.microplan.mapDataForApi(microplanData, operatorsObject, MicroplanName, campaignId, status);
+ body.PlanConfiguration["id"] = microplanData?.planConfigurationId;
+ body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails;
+ return body;
+};
+
+export const updateHyothesisAPICall = async (
+ microplanData,
+ setMicroplanData,
+ operatorsObject,
+ MicroplanName,
+ campaignId,
+ UpdateMutate,
+ setToast,
+ updateData,
+ setLoaderActivation,
+ status,
+ cancleNavigation,
+ state,
+ campaignType,
+ navigationEvent,
+ setCheckDataCompletion,
+ t
+) => {
+ try {
+ const body = constructRequestBody(microplanData, operatorsObject, MicroplanName, campaignId, status);
+ const isValid = validateRequestBody(body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t);
+ if (!isValid) return;
+
+ await UpdateMutate(body, {
+ onSuccess: (data) => handleApiSuccess(data, updateData, setLoaderActivation, setMicroplanData, status),
+ onError: (error, variables) => handleApiError(error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t),
+ });
+ } catch (error) {
+ setLoaderActivation(false);
+ setToast({
+ message: t("ERROR_DATA_NOT_SAVED"),
+ state: "error",
+ });
+ }
+};
+
+// get schema for validation
+export const getRequiredColumnsFromSchema = (campaignType, microplanData, schemas) => {
+ if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return [];
+ const sortData = [];
+ if (microplanData?.upload) {
+ for (const value of microplanData.upload) {
+ if (value.active && value?.error === null) {
+ sortData.push({ section: value.section, fileType: value?.fileType });
+ }
+ }
+ }
+ const filteredSchemas =
+ schemas?.filter((schema) => {
+ if (schema.campaignType) {
+ return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type);
+ }
+ return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type);
+ }) || [];
+
+ let finalData = [];
+ let tempdata;
+
+ tempdata = filteredSchemas
+ ?.flatMap((item) =>
+ Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.isRuleConfigureInputs && value?.toShowInMicroplanPreview) {
+ acc.push(key);
+ }
+ return acc;
+ }, [])
+ )
+ .filter((item) => !!item);
+ finalData = [...finalData, ...tempdata];
+
+ tempdata = filteredSchemas
+ ?.flatMap((item) =>
+ Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.toShowInMicroplanPreview) acc.push(key);
+ return acc;
+ }, [])
+ )
+ .filter((item) => !!item);
+ finalData = [...finalData, ...tempdata];
+ return [...new Set(finalData)];
+};
+
+/**
+ * Combines two datasets based on a common column, duplicating rows from data1 for each matching row in data2.
+ * The final dataset's columns and their order are determined by listOfColumnsNeededInFinalData.
+ * If data2 is not provided, rows from data1 are included with null values for missing columns.
+ */
+export const innerJoinLists = (data1, data2, commonColumnName, listOfColumnsNeededInFinalData) => {
+ // Error handling: Check if data1 array is provided
+ if (!Array.isArray(data1)) {
+ throw new Error("The first data input must be an array.");
+ }
+
+ // Error handling: Check if common column name is provided
+ if (typeof commonColumnName !== "string") {
+ throw new Error("Common column name must be a string.");
+ }
+
+ // Error handling: Check if listOfColumnsNeededInFinalData is provided and is an array
+ if (!Array.isArray(listOfColumnsNeededInFinalData)) {
+ throw new Error("listOfColumnsNeededInFinalData must be an array.");
+ }
+
+ // Find the index of the common column in the first dataset
+ const commonColumnIndex1 = data1[0].indexOf(commonColumnName);
+
+ // Error handling: Check if common column exists in the first dataset
+ if (commonColumnIndex1 === -1) {
+ throw new Error(`Common column "${commonColumnName}" not found in the first dataset.`);
+ }
+
+ let commonColumnIndex2 = -1;
+ const data2Map = new Map();
+ if (data2) {
+ // Find the index of the common column in the second dataset
+ commonColumnIndex2 = data2[0].indexOf(commonColumnName);
+
+ // Error handling: Check if common column exists in the second dataset
+ if (commonColumnIndex2 === -1) {
+ throw new Error(`Common column "${commonColumnName}" not found in the second dataset.`);
+ }
+
+ // Create a map for the second dataset for quick lookup by the common column value
+ for (let i = 1; i < data2.length; i++) {
+ const row = data2[i];
+ const commonValue = row[commonColumnIndex2];
+ if (!data2Map.has(commonValue)) {
+ data2Map.set(commonValue, []);
+ }
+ data2Map.get(commonValue).push(row);
+ }
+ }
+
+ // Determine the headers for the final combined dataset based on listOfColumnsNeededInFinalData
+ const combinedHeaders = listOfColumnsNeededInFinalData.filter((header) => data1[0].includes(header) || data2?.[0].includes(header));
+
+ // Combine rows
+ const combinedData = [combinedHeaders];
+ const addedCommonValues = new Set();
+ for (let i = 1; i < data1.length; i++) {
+ const row1 = data1[i];
+ const commonValue = row1[commonColumnIndex1];
+ const rows2 = data2 ? data2Map.get(commonValue) || [[null]] : [[null]]; // Handle missing common values with a placeholder array of null
+
+ // Check if rows2 is the placeholder array
+ const isPlaceholderArray = rows2.length === 1 && rows2[0].every((value) => value === null);
+
+ // Create combined rows for each row in data2
+ if (isPlaceholderArray) {
+ // If no corresponding row found in data2, use row from data1 with null values for missing columns
+ const combinedRow = combinedHeaders.map((header) => {
+ const index1 = data1[0].indexOf(header);
+ return index1 !== -1 ? row1[index1] : null;
+ });
+ combinedData.push(combinedRow);
+ } else {
+ // If corresponding rows found in data2, combine each row from data2 with row from data1
+ rows2.forEach((row2) => {
+ const combinedRow = combinedHeaders.map((header) => {
+ const index1 = data1[0].indexOf(header);
+ const index2 = data2 ? data2[0].indexOf(header) : -1;
+ return index1 !== -1 ? row1[index1] : index2 !== -1 ? row2[index2] : null;
+ });
+ combinedData.push(combinedRow);
+ });
+ }
+ addedCommonValues.add(commonValue);
+ }
+ // Add rows from data2 that do not have a matching row in data1
+ if (data2) {
+ for (let i = 1; i < data2.length; i++) {
+ const row2 = data2[i];
+ const commonValue = row2[commonColumnIndex2];
+ if (!addedCommonValues.has(commonValue)) {
+ const combinedRow = combinedHeaders.map((header) => {
+ // const index1 = data1[0].indexOf(header);
+ const index2 = data2[0].indexOf(header);
+ return index2 !== -1 ? row2[index2] : null;
+ });
+ combinedData.push(combinedRow);
+ }
+ }
+ }
+
+ return combinedData;
+};
+
+// function to filter the microplan data with respect to the hierarchy selected by the user
+export const filterMicroplanDataToShowWithHierarchySelection = (data, selections, hierarchy, hierarchyIndex = 0) => {
+ if (!selections || selections?.length === 0) return data;
+ if (hierarchyIndex >= hierarchy?.length) return data;
+ const filteredHirarchyLevelList = selections?.[hierarchy?.[hierarchyIndex]]?.map((item) => item?.name);
+ if (!filteredHirarchyLevelList || filteredHirarchyLevelList?.length === 0) return data;
+ const columnDataIndexForHierarchyLevel = data?.[0]?.indexOf(hierarchy?.[hierarchyIndex]);
+ if (columnDataIndexForHierarchyLevel === -1) return data;
+ const levelFilteredData = data.filter((item, index) => {
+ if (index === 0) return true;
+ if (item?.[columnDataIndexForHierarchyLevel] && filteredHirarchyLevelList.includes(item?.[columnDataIndexForHierarchyLevel])) return true;
+ return false;
+ });
+ return filterMicroplanDataToShowWithHierarchySelection(levelFilteredData, selections, hierarchy, hierarchyIndex + 1);
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js
new file mode 100644
index 00000000000..09e24a4658e
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js
@@ -0,0 +1,351 @@
+export const processHierarchyAndData = (hierarchy, allData) => {
+ const hierarchyLists = {};
+ let hierarchicalData = {};
+ try {
+ // Process hierarchy
+ hierarchy.forEach((item) => {
+ hierarchyLists[item.boundaryType] = [];
+ });
+
+ // Process all sets of data
+ allData.forEach((data) => {
+ const dataHierarchicalData = {};
+
+ // Process data for this set
+ data.slice(1).forEach((row) => {
+ // Exclude the header row
+ let currentNode = dataHierarchicalData;
+ let parent = null;
+ hierarchy.forEach((item, index) => {
+ const boundaryType = item.boundaryType;
+ const dataIndex = data?.[0].indexOf(boundaryType);
+ if (dataIndex === -1) return;
+ const cellValue = row[dataIndex];
+ if (!cellValue) return;
+ // Populate hierarchy lists
+ if (!hierarchyLists[boundaryType].includes(cellValue) && cellValue !== null && cellValue !== "" && cellValue !== undefined) {
+ hierarchyLists[boundaryType].push(cellValue);
+ }
+
+ // Populate hierarchical data
+ if (!currentNode[cellValue]) {
+ currentNode[cellValue] = {
+ name: cellValue,
+ boundaryType: boundaryType,
+ children: {},
+ data: null,
+ };
+ }
+
+ // Assign row data to the correct hierarchical level
+ if (cellValue) {
+ if (index === hierarchy.length - 1) {
+ currentNode[cellValue].data = createDataObject(data[0], row);
+ } else if (index + 1 < hierarchy.length) {
+ let nextHierarchyList = hierarchy.slice(index + 1);
+ let check = true;
+ nextHierarchyList.forEach((e) => {
+ const boundaryType = e.boundaryType;
+ const dataIndex = data?.[0].indexOf(boundaryType);
+ if (dataIndex === -1) return;
+ check = check && !row[dataIndex];
+ });
+ if (check) currentNode[cellValue].data = createDataObject(data[0], row);
+ }
+ }
+ currentNode = currentNode[cellValue].children;
+ });
+ });
+
+ // Merge dataHierarchicalData into hierarchicalData
+ hierarchicalData = mergeHierarchicalData(hierarchicalData, dataHierarchicalData);
+ });
+
+ // Remove null element from children of each province
+ Object.values(hierarchicalData).forEach((country) => {
+ if (country.children[null]) {
+ country.data = country.children[null].data;
+ country.children[null] = undefined;
+ }
+ });
+ } catch (error) {
+ console.error("Error in processing hierarchy and uploaded data: ", error.message);
+ // Return empty objects in case of error
+ return { hierarchyLists: {}, hierarchicalData: {} };
+ }
+
+ return { hierarchyLists, hierarchicalData };
+};
+
+// Function to merge two hierarchical data objects
+const mergeHierarchicalData = (data1, data2) => {
+ for (const [key, value] of Object.entries(data2)) {
+ if (!data1[key]) {
+ if (!value.data) value.data = {};
+ data1[key] = value || {};
+ } else {
+ data1[key].data = value.data; // Merge data
+ mergeHierarchicalData(data1[key].children, value.children); // Recursively merge children
+ }
+ if (data1[key].data?.feature) {
+ const { feature, ...temp } = value.data ? _.cloneDeep(value.data) : {};
+ data1[key].data.feature.properties = { ...data1[key].data?.feature?.properties, ...temp };
+ }
+ }
+ return data1;
+};
+
+// Function to create a data object with key-value pairs from headers and row data
+const createDataObject = (headers, row) => {
+ const dataObject = {};
+ headers.forEach((header, index) => {
+ dataObject[header] = row[index];
+ });
+ return dataObject;
+};
+
+// Find parent in hierarchy
+export const findParent = (name, hierarchy, parent, accumulator = []) => {
+ if (!name || !hierarchy) return null;
+ for (let key in hierarchy) {
+ if (hierarchy[key]?.name == name) {
+ accumulator.push(parent);
+ }
+ if (hierarchy[key]?.children) {
+ let response = findParent(name, hierarchy[key]?.children, hierarchy[key], accumulator);
+ if (response)
+ response.forEach((item) => {
+ if (!accumulator.includes(item)) {
+ accumulator.push(item);
+ }
+ });
+ } else {
+ return accumulator;
+ }
+ }
+ return accumulator;
+};
+
+/**
+ *
+ * @param {Array of parents} parents
+ * @param {hierarchycal Object data} hierarchy
+ * @returns An Array containing all the cummulative children
+ */
+export const findChildren = (parents, hierarchy) => {
+ const hierarchyTraveller = (parents, hierarchy, accumulator = {}) => {
+ let tempData = [];
+ if (accumulator && Object.keys(accumulator).length !== 0)
+ tempData = {
+ ...accumulator,
+ ...hierarchy.reduce((data, item) => {
+ if (parents.includes(item?.name) && item?.children) {
+ for (const key in item.children) {
+ if (!data[key]) {
+ data[key] = item.children[key];
+ }
+ }
+ }
+ return data;
+ }, {}),
+ };
+ else
+ tempData = hierarchy.reduce((data, item) => {
+ if (parents.includes(item?.name) && item?.children) {
+ for (const key in item.children) {
+ if (!data[key]) {
+ data[key] = item.children[key];
+ }
+ }
+ }
+ return data;
+ }, {});
+ for (let parent of hierarchy) {
+ if (parent?.children) tempData = hierarchyTraveller(parents, Object.values(parent?.children), tempData);
+ }
+ return tempData;
+ };
+ return hierarchyTraveller(parents, Object.values(hierarchy), {});
+};
+
+// Fetched data from tree
+export const fetchDropdownValues = (boundaryData, hierarchy, boundarySelections, changedBoundaryType) => {
+ if (
+ !hierarchy ||
+ !boundaryData ||
+ !boundarySelections ||
+ hierarchy.length === 0 ||
+ Object.keys(hierarchy).length === 0 ||
+ Object.keys(boundaryData).length === 0
+ )
+ return [];
+ let TempHierarchy = _.cloneDeep(hierarchy);
+ if (!boundarySelections || Object.values(boundarySelections)?.every((item) => item?.length === 0)) {
+ for (let i in TempHierarchy) {
+ if (i === "0") {
+ TempHierarchy[0].dropDownOptions = findByBoundaryType(
+ TempHierarchy?.[0]?.boundaryType,
+ Object.values(boundaryData)?.[0]?.hierarchicalData
+ ).map((data, index) => ({
+ name: data,
+ code: data,
+ boundaryType: TempHierarchy?.[0]?.boundaryType,
+ parentBoundaryType: undefined,
+ }));
+ } else TempHierarchy[i].dropDownOptions = [];
+ }
+ } else {
+ const currentHierarchy = findCurrentFilteredHierarchy(Object.values(boundaryData)?.[0]?.hierarchicalData, boundarySelections, TempHierarchy);
+ let currentDropdownIndex = 0;
+ hierarchy.forEach((e, index) => {
+ if (e && e?.boundaryType == changedBoundaryType) {
+ // && boundarySelections && boundarySelections[e.boundaryType] && boundarySelections[e.boundaryType].length !== 0) {
+ currentDropdownIndex = index;
+ }
+ });
+ Object.entries(boundarySelections)?.forEach(([key, value]) => {
+ let currentindex = hierarchy.findIndex((e) => e?.boundaryType === key);
+ if (currentDropdownIndex !== currentindex) return;
+ let childIndex = hierarchy.findIndex((e) => e?.parentBoundaryType === key);
+ if (childIndex == -1) return;
+ if (TempHierarchy?.[childIndex]) {
+ let newDropDownValuesForChild = [];
+ for (const element of value) {
+ let tempStore = Object.values(findChildren([element.name], currentHierarchy)).map((value) => ({
+ name: value?.name,
+ code: value?.name,
+ parent: element,
+ boundaryType: TempHierarchy[childIndex]?.boundaryType,
+ parentBoundaryType: TempHierarchy[childIndex]?.parentBoundaryType,
+ }));
+ if (tempStore) newDropDownValuesForChild.push(...tempStore);
+ }
+ // if (TempHierarchy[childIndex].dropDownOptions)
+ // TempHierarchy[childIndex].dropDownOptions = [...TempHierarchy[childIndex].dropDownOptions, ...newDropDownValuesForChild];
+ TempHierarchy[childIndex].dropDownOptions = newDropDownValuesForChild;
+ }
+ });
+ }
+ return TempHierarchy;
+};
+
+const findByBoundaryType = (boundaryType, hierarchy) => {
+ for (let [key, value] of Object.entries(hierarchy)) {
+ if (value?.boundaryType === boundaryType) return Object.keys(hierarchy).filter(Boolean);
+ if (value?.children) return findByBoundaryType(boundaryType, value?.children);
+ return [];
+ }
+ return [];
+};
+
+// makes a tree with the boundary selections as there might be duplicates in different branches that are not yet selected
+const findCurrentFilteredHierarchy = (hierarchyTree, boundarySelections, hierarchy) => {
+ const newtree = constructNewHierarchyTree(hierarchy, hierarchyTree, boundarySelections);
+ return newtree;
+};
+
+const constructNewHierarchyTree = (hierarchy, oldTree, boundarySelection, level = 0) => {
+ // let newTree = { ...oldTree }; // Initialize a new hierarchy tree
+ let newTree = {}; // Initialize a new hierarchy tree
+ if (!hierarchy?.[level]) return;
+ const levelName = hierarchy[level].boundaryType;
+
+ // Get the selections for this level from the boundary selection object
+ const selections = boundarySelection[levelName] || [];
+ // If there are selections for this level
+ if (selections.length > 0) {
+ // Construct the new hierarchy tree based on selections
+ for (const selection of selections) {
+ const { name } = selection;
+ // If the selection exists in the existing hierarchy tree
+ if (oldTree[name]) {
+ // Add the selected division to the new hierarchy tree
+ newTree[name] = { ...oldTree[name] };
+ // If there are children, recursively construct the children
+ if (oldTree[name].children) {
+ oldTree[name].children;
+ const nonNullObject = Object.entries(oldTree[name].children).reduce((acc, [key, value]) => {
+ if (value.name !== null) {
+ acc[key] = value;
+ }
+ return acc;
+ }, {});
+ newTree[name].children = constructNewHierarchyTree(hierarchy, nonNullObject, boundarySelection, level + 1);
+ }
+ }
+ }
+ } else {
+ const nonNullObject = Object.entries(oldTree).reduce((acc, [key, value]) => {
+ if (value.name !== null) {
+ acc[key] = value;
+ }
+ return acc;
+ }, {});
+ newTree = nonNullObject;
+ }
+
+ return newTree;
+};
+
+// Recursively calculates aggregate values for numerical properties within the `data` objects of each node in a hierarchical tree structure.
+// Updates the `properties` object within the `feature` object of each node with the aggregate values, if present.
+export const calculateAggregateForTree = (tree) => {
+ try {
+ function calculateAggregate(node) {
+ if (!node.children || Object.keys(node.children).length === 0) {
+ // if the node has no children, return a new node with its own data
+ return { ...node, data: { ...node.data } };
+ }
+
+ // Recursively calculate aggregate values for each child
+ const newChildren = {};
+
+ for (const childKey in node.children) {
+ const child = node.children[childKey];
+ const newChild = calculateAggregate(child);
+ newChildren[childKey] = newChild;
+ }
+
+ // Aggregate numerical values dynamically
+ const aggregate = {};
+ for (const childKey in newChildren) {
+ const child = newChildren[childKey];
+ for (const prop in child.data) {
+ if (typeof child.data[prop] === "number") {
+ aggregate[prop] = (aggregate[prop] || 0) + child.data[prop];
+ }
+ }
+ }
+
+ // Create a new node with updated data
+ const newNode = {
+ ...node,
+ data: { ...node.data, ...aggregate },
+ children: newChildren,
+ };
+
+ // Update properties in the feature object
+ if (newNode.data.feature) {
+ newNode.data.feature.properties = { ...newNode.data.feature.properties, ...aggregate };
+ }
+
+ return newNode;
+ }
+
+ const newTree = {};
+
+ // Iterate over each node object
+ for (const nodeKey in tree) {
+ const node = tree[nodeKey];
+ // Calculate aggregate values for the current node
+ const newNode = calculateAggregate(node);
+ // Add the updated node to the new tree
+ newTree[nodeKey] = newNode;
+ }
+
+ return newTree;
+ } catch (error) {
+ console.error("Failed to calculate treenode aggregates");
+ return {};
+ }
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
new file mode 100644
index 00000000000..9af362cbf62
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
@@ -0,0 +1,484 @@
+import { Request } from "@egovernments/digit-ui-libraries";
+import { parseXlsxToJsonMultipleSheetsForSessionUtil } from "../utils/exceltojson";
+import JSZip from "jszip";
+import * as XLSX from "xlsx";
+import axios from "axios";
+import shp from "shpjs";
+import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn } from "../configs/constants";
+import { addBoundaryData, fetchBoundaryData, filterBoundaries } from "./createTemplate";
+import { handleExcelFile } from "./uploadUtils";
+
+function handleExcelArrayBuffer(arrayBuffer, file) {
+ return new Promise((resolve, reject) => {
+ try {
+ // Read the response as an array buffer
+ // const arrayBuffer = response.arrayBuffer();
+
+ // Convert the array buffer to binary string
+ const data = new Uint8Array(arrayBuffer);
+ const binaryString = String.fromCharCode.apply(null, data);
+
+ // Parse the binary string into a workbook
+ const workbook = XLSX.read(binaryString, { type: "binary" });
+
+ // Assuming there's only one sheet in the workbook
+ const sheetName = workbook.SheetNames[0];
+ const sheet = workbook.Sheets[sheetName];
+
+ // Convert the sheet to JSON object
+ const jsonData = XLSX.utils.sheet_to_json(sheet);
+
+ resolve(jsonData);
+ } catch (error) {
+ reject(error);
+ }
+ });
+}
+
+function shpToGeoJSON(shpBuffer, file) {
+ return new Promise((resolve, reject) => {
+ try {
+ shp(shpBuffer)
+ .then((geojson) => {
+ resolve({ jsonData: geojson, file });
+ })
+ .catch((error) => reject(error));
+ } catch (error) {
+ reject(error);
+ }
+ });
+}
+
+function parseGeoJSONResponse(arrayBuffer, file) {
+ return new Promise((resolve, reject) => {
+ try {
+ const decoder = new TextDecoder("utf-8");
+ const jsonString = decoder.decode(arrayBuffer);
+ const jsonData = JSON.parse(jsonString);
+ resolve({ jsonData, file });
+ } catch (error) {
+ reject(error);
+ }
+ });
+}
+
+// Function to read blob data and parse it into JSON
+function parseBlobToJSON(blob, file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+
+ reader.onload = function (event) {
+ const data = new Uint8Array(event.target.result);
+ const workbook = XLSX.read(data, { type: "array" });
+ const jsonData = {};
+
+ workbook.SheetNames.forEach((sheetName) => {
+ const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]);
+ jsonData[sheetName] = sheetData;
+ });
+
+ resolve({ jsonData, file });
+ };
+
+ reader.onerror = function () {
+ reject(new Error("Error reading the blob data"));
+ };
+
+ reader.readAsArrayBuffer(blob);
+ });
+}
+
+export const updateSessionUtils = {
+ computeSessionObject: async (row, state, additionalProps) => {
+ const sessionObj = {};
+ const setCurrentPage = () => {
+ sessionObj.currentPage = {
+ id: 0,
+ name: "MICROPLAN_DETAILS",
+ component: "MicroplanDetails",
+ checkForCompleteness: true,
+ };
+ };
+
+ //currently hardcoded
+ const setMicroplanStatus = () => {
+ sessionObj.status = {
+ MICROPLAN_DETAILS: true,
+ UPLOAD_DATA: true,
+ HYPOTHESIS: true,
+ FORMULA_CONFIGURATION: true,
+ };
+ };
+
+ const setMicroplanDetails = () => {
+ if (row.name) {
+ sessionObj.microplanDetails = {
+ name: row?.name,
+ };
+ }
+ };
+
+ const setMicroplanHypothesis = () => {
+ if (row.assumptions.length > 0) {
+ sessionObj.hypothesis = row.assumptions?.filter((item) => item?.active);
+ }
+ };
+
+ const sortRules = (rules) => {
+ // Step 1: Identify all unique rule outputs
+ const allOutputs = [...new Set(rules.map((rule) => rule.output))];
+
+ // Step 2: Build input-output relationships
+ const inputOutputMap = new Map(); // Map to store input -> output relationship
+ rules.forEach((rule) => {
+ const { input, output } = rule;
+ if (!inputOutputMap.has(input)) {
+ inputOutputMap.set(input, []);
+ }
+ inputOutputMap.get(input).push(output);
+ });
+
+ // Step 3: Sort the output list based on dependencies
+ const sortedOutputList = [];
+ const visited = new Set();
+
+ const dfs = (output) => {
+ if (!visited.has(output)) {
+ visited.add(output);
+ if (inputOutputMap.has(output)) {
+ inputOutputMap.get(output).forEach((input) => {
+ dfs(input);
+ });
+ }
+ sortedOutputList.push(output);
+ }
+ };
+
+ // Sort outputs based on dependencies
+ allOutputs.forEach((output) => {
+ dfs(output);
+ });
+
+ // Reverse to get outputs in the correct order (outputs first)
+ sortedOutputList.reverse();
+
+ // Step 4: Arrange rules based on sorted output list
+ const sortedRules = [];
+ const ruleMap = new Map(rules.map((rule) => [rule.id, rule]));
+
+ sortedOutputList.forEach((output) => {
+ rules
+ .filter((rule) => rule.output === output)
+ .forEach((rule) => {
+ sortedRules.push(rule);
+ });
+ });
+
+ return sortedRules;
+ };
+
+ const setMicroplanRuleEngine = () => {
+ const rulesList = state?.RuleConfigureOperators || [];
+ const sortedRules = sortRules(row.operations);
+ if (row.operations.length > 0) {
+ sessionObj.ruleEngine = sortedRules?.map((item) => {
+ return {
+ ...item,
+ operator: rulesList.filter((rule) => rule.code === item.operator)?.[0]?.name,
+ };
+ });
+ }
+ };
+
+ const setDraftValues = () => {
+ sessionObj.planConfigurationId = row?.id;
+ sessionObj.auditDetails = row.auditDetails;
+ };
+
+ const fetchBoundaryDataWrapper = async (schemaData) => {
+ const boundaryDataAgainstBoundaryCode = {};
+ // if (!schemaData?.doHierarchyCheckInUploadedData) {
+ try {
+ const rootBoundary = additionalProps.campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable
+ const sessionData = Digit.SessionStorage.get("microplanHelperData") || {};
+ let boundaryData = sessionData.filteredBoundaries;
+ let filteredBoundaries;
+ if (!boundaryData) {
+ // Only fetch boundary data if not present in session storage
+ boundaryData = await fetchBoundaryData(
+ await Digit.ULBService.getCurrentTenantId(),
+ additionalProps.campaignData?.hierarchyType,
+ rootBoundary?.[0]?.code
+ );
+ filteredBoundaries = await filterBoundaries(boundaryData, additionalProps.campaignData?.boundaries);
+
+ // Update the session storage with the new filtered boundaries
+ Digit.SessionStorage.set("microplanHelperData", {
+ ...sessionData,
+ filteredBoundaries: filteredBoundaries,
+ });
+ } else {
+ filteredBoundaries = boundaryData;
+ }
+ const xlsxData = addBoundaryData([], filteredBoundaries, additionalProps.campaignData?.hierarchyType)?.[0]?.data;
+ xlsxData.forEach((item, i) => {
+ if (i === 0) return;
+ let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn);
+ if (boundaryCodeIndex >= item.length) {
+ // If boundaryCodeIndex is out of bounds, return the item as is
+ boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(additionalProps.t);
+ } else {
+ // Otherwise, remove the element at boundaryCodeIndex
+ boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item
+ .slice(0, boundaryCodeIndex)
+ .concat(item.slice(boundaryCodeIndex + 1))
+ .map(additionalProps.t);
+ }
+ });
+ } catch (error) {
+ console.error(error?.message);
+ }
+ // }
+ return boundaryDataAgainstBoundaryCode;
+ };
+
+ const handleGeoJson = async (file, result, upload, translatedData, active, processedData, shapefileOrigin = false) => {
+ if (!file) {
+ console.error(`${shapefileOrigin ? "Shapefile" : "Geojson"} file is undefined`);
+ return upload;
+ }
+
+ const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {};
+ let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, shapefileOrigin ? ".zip" : ".geojson", active);
+
+ const schema = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType);
+ if (!schema) {
+ console.error("Schema got undefined while handling geojson at handleGeoJson");
+ return [...upload, uploadObject];
+ }
+
+ await handleGeoJsonSpecific(schema, uploadObject, templateIdentifier, result, translatedData, filestoreId, processedData);
+ upload.push(uploadObject);
+ return upload;
+ };
+
+ const handleExcel = (file, result, upload, translatedData, active) => {
+ if (!file) {
+ console.error("Excel file is undefined");
+ return upload;
+ }
+
+ const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {};
+ let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, ".xlsx", active),
+ schema = findSchema(inputFileType, templateIdentifier, additionalProps.campaignType);
+ if (!schema) {
+ console.error("Schema got undefined while handling excel at handleExcel");
+ return [...upload, uploadObject];
+ }
+
+ uploadObject.data = result; //resultAfterMapping?.tempFileDataToStore;
+ upload.push(uploadObject);
+ return upload;
+ };
+
+ const createUploadObject = (templateIdentifier, inputFileType, fileId, filestoreId, extension, active) => ({
+ id: fileId,
+ templateIdentifier,
+ section: templateIdentifier,
+ fileName: `${templateIdentifier}${extension}`,
+ fileType: inputFileType,
+ file: null,
+ fileId: fileId,
+ filestoreId: filestoreId,
+ error: null,
+ resourceMapping: row?.resourceMapping?.filter((resourse) => resourse.filestoreId === filestoreId).map((item) => ({ ...item, filestoreId })),
+ data: {},
+ active,
+ });
+
+ const findSchema = (inputFileType, templateIdentifier, campaignType) => {
+ return state?.Schemas?.find(
+ (schema) =>
+ schema.type === inputFileType && schema.section === templateIdentifier && (!schema.campaignType || schema.campaignType === campaignType)
+ );
+ };
+
+ const handleGeoJsonSpecific = async (schema, upload, templateIdentifier, result, translatedData, filestoreId, processedData) => {
+ let schemaKeys;
+ if (schema?.schema?.["Properties"]) {
+ schemaKeys = additionalProps.hierarchyData?.concat(Object.keys(schema.schema["Properties"]));
+ }
+ upload.data = result;
+ if (processedData) return;
+ const mappedToList = upload?.resourceMapping.map((item) => item.mappedTo);
+ let sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, upload?.resourceMapping);
+ const newFeatures = result["features"].map((item) => {
+ let newProperties = {};
+ sortedSecondList
+ ?.filter((resourse) => resourse.filestoreId === filestoreId)
+ .forEach((e) => {
+ newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]];
+ });
+ item["properties"] = newProperties;
+ return item;
+ });
+ upload.data.features = newFeatures;
+ if (
+ additionalProps.hierarchyData?.every(
+ (item) =>
+ !mappedToList.includes(`${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`)
+ )
+ ) {
+ const boundaryDataAgainstBoundaryCode = await fetchBoundaryDataWrapper(schema);
+ upload.data.features.forEach((feature) => {
+ const boundaryCode = feature.properties.boundaryCode;
+ const additionalDetails = {};
+ for (let i = 0; i < additionalProps.hierarchyData?.length; i++) {
+ if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") {
+ additionalDetails[additionalProps.hierarchyData?.[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i];
+ } else {
+ additionalDetails[additionalProps.hierarchyData?.[i]] = "";
+ }
+ }
+ feature.properties = { ...additionalDetails, ...feature.properties };
+ });
+ }
+ };
+
+ const fetchFiles = async () => {
+ const files = row?.files;
+ if (!files || files.length === 0) {
+ return [];
+ }
+
+ const promises = [];
+ let storedData = [];
+ for (const { filestoreId, inputFileType, templateIdentifier, id, active } of files) {
+ if (!active) continue;
+ const schemaData = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType);
+ if (!schemaData) {
+ console.error("Schema got undefined while handling geojson at handleGeoJson");
+ return [...upload, uploadObject];
+ }
+ const boundaryDataAgainstBoundaryCode = {};
+ let fileData = {
+ filestoreId,
+ inputFileType,
+ templateIdentifier,
+ id,
+ };
+ let dataInSsn = Digit.SessionStorage.get("microplanData")?.upload?.find((item) => item.active && item.id === id);
+ if (dataInSsn && dataInSsn.filestoreId === filestoreId) {
+ storedData.push({ file: fileData, jsonData: dataInSsn?.data, processedData: true, translatedData: false, active });
+ } else {
+ const promiseToAttach = axios
+ .get("/filestore/v1/files/id", {
+ responseType: "arraybuffer",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: ACCEPT_HEADERS[inputFileType],
+ "auth-token": Digit.UserService.getUser()?.["access_token"],
+ },
+ params: {
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ fileStoreId: filestoreId,
+ },
+ })
+ .then(async (res) => {
+ if (inputFileType === EXCEL) {
+ try {
+ const file = new Blob([res.data], { type: ACCEPT_HEADERS[inputFileType] });
+ const response = await handleExcelFile(
+ file,
+ schemaData,
+ additionalProps.hierarchyData,
+ { id: inputFileType },
+ boundaryDataAgainstBoundaryCode,
+ () => {},
+ additionalProps.t,
+ additionalProps.campaignData,
+ additionalProps.readMeSheetName
+ );
+ let fileData = {
+ filestoreId,
+ inputFileType,
+ templateIdentifier,
+ id,
+ };
+
+ return { jsonData: response.fileDataToStore, file: fileData, translatedData: true, active };
+ } catch (error) {
+ console.error(error);
+ }
+ } else if (inputFileType === GEOJSON) {
+ let response = await parseGeoJSONResponse(res.data, {
+ filestoreId,
+ inputFileType,
+ templateIdentifier,
+ id,
+ });
+ return { ...response, translatedData: true, active };
+ } else if (inputFileType === SHAPEFILE) {
+ const geoJson = await shpToGeoJSON(res.data, {
+ filestoreId,
+ inputFileType,
+ templateIdentifier,
+ id,
+ });
+ return { ...geoJson, translatedData: true, active };
+ }
+ });
+ promises.push(promiseToAttach);
+ }
+ }
+
+ const resolvedPromises = await Promise.all(promises);
+ let result = storedData;
+ if (resolvedPromises) result = [...storedData, ...resolvedPromises];
+ return result;
+ };
+ const setMicroplanUpload = async (filesResponse) => {
+ //here based on files response set data in session
+ if (filesResponse.length === 0) {
+ return {};
+ }
+ //populate this object based on the files and return
+ let upload = [];
+
+ await filesResponse.forEach(async ({ jsonData, file, translatedData, active, processedData }, idx) => {
+ switch (file?.inputFileType) {
+ case "Shapefile":
+ upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData, true);
+ break;
+ case "Excel":
+ upload = handleExcel(file, jsonData, upload, translatedData, active);
+ break;
+ case "GeoJSON":
+ upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData);
+ break;
+ default:
+ break;
+ }
+ });
+ //here basically parse the files data from filestore parse it and populate upload object based on file type -> excel,shape,geojson
+ return upload;
+ };
+
+ try {
+ setCurrentPage();
+ setMicroplanStatus();
+ setMicroplanDetails();
+ setMicroplanHypothesis();
+ setMicroplanRuleEngine();
+ setDraftValues();
+ // calling fucntion to cache filtered boundary data
+ await fetchBoundaryDataWrapper({});
+ const filesResponse = await fetchFiles();
+ const upload = await setMicroplanUpload(filesResponse);
+ sessionObj.upload = upload;
+ return sessionObj;
+ } catch (error) {
+ console.error(error.message);
+ }
+ },
+};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js
new file mode 100644
index 00000000000..32935edba93
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js
@@ -0,0 +1,1030 @@
+import ExcelJS from "exceljs";
+import {
+ freezeSheetValues,
+ freezeWorkbookValues,
+ hideUniqueIdentifierColumn,
+ performUnfreezeCells,
+ unfreezeColumnsByHeader,
+ updateFontNameToRoboto,
+} from "../utils/excelUtils";
+import { addBoundaryData, createTemplate, fetchBoundaryData, filterBoundaries } from "../utils/createTemplate";
+import {
+ BOUNDARY_DATA_SHEET,
+ EXCEL,
+ FACILITY_DATA_SHEET,
+ SCHEMA_PROPERTIES_PREFIX,
+ SHEET_COLUMN_WIDTH,
+ UPLOADED_DATA_ACTIVE_STATUS,
+ commonColumn,
+} from "../configs/constants";
+import shp from "shpjs";
+import JSZip from "jszip";
+import { checkForErrorInUploadedFileExcel } from "../utils/excelValidations";
+import { convertJsonToXlsx } from "../utils/jsonToExcelBlob";
+import { parseXlsxToJsonMultipleSheets } from "../utils/exceltojson";
+import { geojsonValidations } from "../utils/geojsonValidations";
+
+// Function for checking the uploaded file for nameing conventions
+export const validateNamingConvention = (file, namingConvention, setToast, t) => {
+ try {
+ let processedConvention = namingConvention.replace("$", ".[^.]*$");
+ const regx = new RegExp(processedConvention);
+
+ if (regx && !regx.test(file.name)) {
+ setToast({
+ state: "error",
+ message: t("ERROR_NAMING_CONVENSION"),
+ });
+ return false;
+ }
+ return true;
+ } catch (error) {
+ console.error(error.message);
+ setToast({
+ state: "error",
+ message: t("ERROR_UNKNOWN"),
+ });
+ }
+};
+
+// Function for reading ancd checking geojson data
+export const readGeojson = async (file, t) => {
+ return new Promise((resolve, reject) => {
+ if (!file) return resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } });
+
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ try {
+ const geoJSONData = JSON.parse(e.target.result);
+ const trimmedGeoJSONData = trimJSON(geoJSONData);
+ resolve({ valid: true, geojsonData: trimmedGeoJSONData });
+ } catch (error) {
+ resolve({ valid: false, toast: { state: "error", message: t("ERROR_INCORRECT_FORMAT") } });
+ }
+ };
+ reader.onerror = (error) => {
+ resolve({ valid: false, toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") } });
+ };
+
+ reader.readAsText(file);
+ });
+};
+
+// Function to recursively trim leading and trailing spaces from string values in a JSON object
+export const trimJSON = (jsonObject) => {
+ if (typeof jsonObject !== "object") {
+ return jsonObject; // If not an object, return as is
+ }
+
+ if (Array.isArray(jsonObject)) {
+ return jsonObject.map((item) => trimJSON(item)); // If it's an array, recursively trim each item
+ }
+
+ const trimmedObject = {};
+ for (const key in jsonObject) {
+ if (Object.hasOwn(jsonObject, key)) {
+ const value = jsonObject[key];
+ // Trim string values, recursively trim objects
+ trimmedObject[key.trim()] = typeof value === "string" ? value.trim() : typeof value === "object" ? trimJSON(value) : value;
+ }
+ }
+ return trimmedObject;
+};
+// Function for reading and validating shape file data
+export const readAndValidateShapeFiles = async (file, t, namingConvention) => {
+ return new Promise((resolve, reject) => {
+ const readAndValidate = async () => {
+ if (!file) {
+ resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } });
+ }
+ const fileRegex = new RegExp(namingConvention.replace("$", ".*$"));
+ // File Size Check
+ const fileSizeInBytes = file.size;
+ const maxSizeInBytes = 2 * 1024 * 1024 * 1024; // 2 GB
+
+ // Check if file size is within limit
+ if (fileSizeInBytes > maxSizeInBytes)
+ resolve({ valid: false, message: t("ERROR_FILE_SIZE"), toast: { state: "error", message: t("ERROR_FILE_SIZE") } });
+
+ try {
+ const zip = await JSZip.loadAsync(file);
+ const isEPSG4326 = await checkProjection(zip);
+ if (!isEPSG4326) {
+ resolve({ valid: false, message: t("ERROR_WRONG_PRJ"), toast: { state: "error", message: t("ERROR_WRONG_PRJ") } });
+ }
+ const files = Object.keys(zip.files);
+ const allFilesMatchRegex = files.every((fl) => {
+ return fileRegex.test(fl);
+ });
+ let regx = new RegExp(namingConvention.replace("$", "\\.shp$"));
+ const shpFile = zip.file(regx)[0];
+ regx = new RegExp(namingConvention.replace("$", "\\.shx$"));
+ const shxFile = zip.file(regx)[0];
+ regx = new RegExp(namingConvention.replace("$", "\\.dbf$"));
+ const dbfFile = zip.file(regx)[0];
+
+ let geojson;
+ if (shpFile && dbfFile) {
+ const shpArrayBuffer = await shpFile.async("arraybuffer");
+ const dbfArrayBuffer = await dbfFile.async("arraybuffer");
+
+ geojson = shp.combine([shp.parseShp(shpArrayBuffer), shp.parseDbf(dbfArrayBuffer)]);
+ }
+ if (shpFile && dbfFile && shxFile && allFilesMatchRegex) resolve({ valid: true, data: geojson });
+ else if (!allFilesMatchRegex)
+ resolve({
+ valid: false,
+ message: [t("ERROR_CONTENT_NAMING_CONVENSION")],
+ toast: { state: "error", data: geojson, message: t("ERROR_CONTENT_NAMING_CONVENSION") },
+ });
+ else if (!shpFile)
+ resolve({ valid: false, message: [t("ERROR_SHP_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHP_MISSING") } });
+ else if (!dbfFile)
+ resolve({ valid: false, message: [t("ERROR_DBF_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_DBF_MISSING") } });
+ else if (!shxFile)
+ resolve({ valid: false, message: [t("ERROR_SHX_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHX_MISSING") } });
+ } catch (error) {
+ resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } });
+ }
+ };
+ readAndValidate();
+ });
+};
+
+// Function for projections check in case of shapefile data
+export const checkProjection = async (zip) => {
+ const prjFile = zip.file(/.prj$/i)[0];
+ if (!prjFile) {
+ return "absent";
+ }
+
+ const prjText = await prjFile.async("text");
+
+ if (prjText.includes("GEOGCS") && prjText.includes("WGS_1984") && prjText.includes("DATUM") && prjText.includes("D_WGS_1984")) {
+ return "EPSG:4326";
+ }
+ return false;
+};
+
+// find readMe as per campaign, template identifier and file type
+export const findReadMe = (readMeCollection, campaignType, type, section) => {
+ if (!readMeCollection) return readMeCollection;
+ return (
+ readMeCollection.find(
+ (readMe) => readMe.fileType === type && readMe.templateIdentifier === section && (!readMe.campaignType || readMe.campaignType === campaignType)
+ ) || {}
+ );
+};
+
+// Function to handle the template download
+export const downloadTemplate = async ({
+ campaignType,
+ type,
+ section,
+ setToast,
+ campaignData,
+ hierarchyType,
+ Schemas,
+ HierarchyConfigurations,
+ setLoader,
+ hierarchy,
+ readMeData,
+ readMeSheetName,
+ t,
+}) => {
+ try {
+ setLoader("LOADING");
+ await delay(100);
+ // Find the template based on the provided parameters
+ const schema = getSchema(campaignType, type, section, Schemas);
+ const hierarchyLevelName = HierarchyConfigurations?.find((item) => item.name === "devideBoundaryDataBy")?.value;
+ const filteredReadMeData = findReadMe(readMeData, campaignType, type, section);
+ let template = await createTemplate({
+ hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets,
+ hierarchyLevelName,
+ addFacilityData: schema?.template?.includeFacilityData,
+ schema,
+ boundaries: campaignData?.boundaries,
+ tenantId: Digit.ULBService.getCurrentTenantId(),
+ hierarchyType,
+ readMeData: filteredReadMeData,
+ readMeSheetName,
+ t,
+ });
+ const translatedTemplate = translateTemplate(template, t);
+
+ // Create a new workbook
+ const workbook = new ExcelJS.Workbook();
+
+ formatTemplate(translatedTemplate, workbook, t);
+
+ // Color headers
+ colorHeaders(
+ workbook,
+ [...hierarchy.map((item) => t(item)), t(commonColumn)],
+ schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [],
+ []
+ );
+
+ formatAndColorReadMeFile(
+ workbook,
+ (filteredReadMeData?.data || [])?.map((item) => t(item?.header)),
+ t(readMeSheetName)
+ );
+
+ // protextData
+ await protectData({
+ workbook,
+ hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets,
+ addFacilityData: schema?.template?.includeFacilityData,
+ schema,
+ readMeSheetName: t(readMeSheetName),
+ t,
+ });
+
+ // Write the workbook to a buffer
+ workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => {
+ // Create a Blob from the buffer
+ const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
+ // Create a URL for the Blob
+ const url = URL.createObjectURL(blob);
+ // Create a link element and simulate click to trigger download
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = `${t(section)}.xlsx`;
+ link.click();
+ // Revoke the URL to release the Blob
+ URL.revokeObjectURL(url);
+ setLoader(false);
+ });
+ } catch (error) {
+ setLoader(false);
+ console.error(error?.message);
+ setToast({ state: "error", message: t("ERROR_DOWNLOADING_TEMPLATE") });
+ }
+};
+
+export const formatAndColorReadMeFile = (workbook, headerSet, readMeSheetName) => {
+ const readMeSheet = workbook.getWorksheet(readMeSheetName);
+ if (!readMeSheet) return;
+ setAndFormatHeaders(readMeSheet);
+ formatWorksheet(readMeSheet, headerSet);
+};
+
+export function setAndFormatHeaders(worksheet) {
+ const row = worksheet.getRow(1);
+ // Color the header cell
+ row.eachCell((cell) => {
+ cell.fill = {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "f25449" }, // Header cell color
+ };
+ cell.alignment = { vertical: "middle", horizontal: "center", wrapText: true }; // Center align and wrap text
+ // cell.font = { bold: true };
+ });
+}
+export function formatWorksheet(worksheet, headerSet) {
+ // Add the data rows with text wrapping
+ const lineHeight = 17; // Set an approximate line height
+ const maxCharactersPerLine = 100; // Set a maximum number of characters per line for wrapping
+
+ worksheet.eachRow((row, index) => {
+ if (index === 1) return;
+ row.eachCell({ includeEmpty: true }, (cell) => {
+ cell.alignment = { vertical: "middle", horizontal: "left", wrapText: true }; // Apply text wrapping
+ // Calculate the required row height based on content length
+ const numberOfLines = Math.ceil(cell?.value.length / maxCharactersPerLine);
+ row.height = numberOfLines * lineHeight;
+
+ // Make the header text bold
+ if (headerSet?.includes(cell.value)) {
+ cell.font = { bold: true };
+ }
+ });
+ });
+ worksheet.getColumn(1).width = 130;
+ updateFontNameToRoboto(worksheet);
+}
+
+const freezeHierarchySheets = async ({ workbook, readMeSheetName, t }) => {
+ await freezeSheetValues(workbook, readMeSheetName);
+};
+
+const processFacilityData = async ({ workbook, schema, t }) => {
+ await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET));
+ await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET));
+ if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) {
+ const tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item)));
+ await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide);
+ }
+ // Further processing based on facilitySchemaApiMapping can be done here if needed
+};
+
+const processBoundaryData = async ({ workbook, schema, t }) => {
+ await freezeWorkbookValues(workbook);
+ await unfreezeColumnsByHeader(
+ workbook,
+ schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : []
+ );
+};
+
+export const protectData = async ({ workbook, hierarchyLevelWiseSheets = true, addFacilityData = false, schema, readMeSheetName, t }) => {
+ await freezeHierarchySheets({ workbook, readMeSheetName, t });
+ if (hierarchyLevelWiseSheets) {
+ if (addFacilityData) {
+ await processFacilityData({ workbook, schema, t });
+ } else {
+ await processBoundaryData({ workbook, schema, t });
+ }
+ } else {
+ if (addFacilityData) {
+ await processFacilityData({ workbook, schema, t });
+ } else {
+ await processBoundaryData({ workbook, schema, t });
+ }
+ }
+};
+
+export const colorHeaders = async (workbook, headerList1, headerList2, headerList3) => {
+ try {
+ // Iterate through each sheet
+ workbook.eachSheet((sheet, sheetId) => {
+ // Get the first row
+ const firstRow = sheet.getRow(1);
+
+ // Iterate through each cell in the first row
+ firstRow.eachCell((cell, colNumber) => {
+ const cellValue = cell.value.toString();
+
+ // Check conditions and set colors
+ if (headerList1?.includes(cellValue)) {
+ cell.fill = {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "ff9248" },
+ };
+ } else if (headerList2?.includes(cellValue)) {
+ cell.fill = {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "93C47D" },
+ };
+ } else if (headerList3?.includes(cellValue)) {
+ cell.fill = {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "CCCC00" },
+ };
+ }
+ });
+ });
+ } catch (error) {
+ console.error("Error coloring headers:", error);
+ }
+};
+
+export const formatTemplate = (template, workbook, t) => {
+ template.forEach(({ sheetName, data }) => {
+ // Create a new worksheet with properties
+ const worksheet = workbook.addWorksheet(sheetName);
+ let commonColumnIndex = -1;
+ data?.forEach((row, index) => {
+ const worksheetRow = worksheet.addRow(row);
+
+ // Apply fill color to each cell in the first row and make cells bold
+ if (index === 0) {
+ worksheetRow.eachCell((cell, colNumber) => {
+ // Set font to bold
+ cell.font = { bold: true };
+
+ // Enable text wrapping
+ cell.alignment = { vertical: "middle", horizontal: "center", wrapText: true };
+ // Update column width based on the length of the cell's text
+ // const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width
+ // const newWidth = Math.min(currentWidth, cell.value.toString().length + 2); // Add padding
+ if (cell.value === t(commonColumn) || cell.value === t(generateLocalisationKeyForSchemaProperties(commonColumn))) {
+ commonColumnIndex = colNumber;
+ worksheet.getColumn(colNumber).width = SHEET_COLUMN_WIDTH + 10;
+ } else {
+ worksheet.getColumn(colNumber).width = SHEET_COLUMN_WIDTH;
+ }
+ });
+ }
+ worksheetRow.eachCell({ includeEmpty: true }, (cell, colNumber) => {
+ cell.alignment = { vertical: "middle", wrapText: colNumber !== commonColumnIndex }; // Apply text wrapping
+ });
+ });
+
+ updateFontNameToRoboto(worksheet);
+ });
+};
+
+export const translateTemplate = (template, t) => {
+ // Initialize an array to hold the transformed result
+ const transformedResult = [];
+
+ // Iterate over each sheet in the divided data
+ for (const sheet of template) {
+ const sheetData = sheet.data;
+
+ // Find the index of the boundaryCode column in the header row
+ const boundaryCodeIndex = sheetData[0].indexOf(commonColumn);
+
+ const sheetName = t(sheet.sheetName);
+ const transformedSheet = {
+ sheetName: sheetName.length > 31 ? sheetName.slice(0, 31) : sheetName,
+ data: [],
+ };
+
+ // Iterate over each row in the sheet data
+ for (const [rowIndex, row] of sheetData.entries()) {
+ // Transform each entity in the row using the transformFunction
+ const transformedRow = row.map((entity, index) => {
+ // Skip transformation for the boundaryCode column
+ if ((index === boundaryCodeIndex && rowIndex !== 0) || typeof entity === "number") {
+ return entity;
+ }
+ return t(entity);
+ });
+ transformedSheet.data.push(transformedRow);
+ }
+
+ // Add the transformed sheet to the transformed result
+ transformedResult.push(transformedSheet);
+ }
+
+ return transformedResult;
+};
+
+// get schema for validation
+export const getSchema = (campaignType, type, section, schemas) => {
+ return schemas.find((schema) => {
+ if (!schema.campaignType) {
+ return schema.type === type && schema.section === section;
+ }
+ return schema.campaignType === campaignType && schema.type === type && schema.section === section;
+ });
+};
+
+// Performs resource mapping and data filtering for Excel files based on provided schema data, hierarchy, and file data.
+export const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t) => {
+ const resourceMappingData = [];
+ const newFileData = {};
+ if (selectedFileType.id === EXCEL && fileDataToStore) {
+ // Extract all unique column names from fileDataToStore and then doing thir resource mapping
+ const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || []));
+ if (schemaData?.schema?.["Properties"]) {
+ const schemaKeys = Object.keys(schemaData.schema["Properties"])
+ .map((item) => generateLocalisationKeyForSchemaProperties(item))
+ .concat([...hierarchy, commonColumn]);
+ schemaKeys.forEach((item) => {
+ if (columnForMapping.has(t(item))) {
+ resourceMappingData.push({
+ mappedFrom: t(item),
+ mappedTo: revertLocalisationKey(item),
+ });
+ }
+ });
+ }
+
+ // Filtering the columns with respect to the resource mapping and removing the columns that are not needed
+ Object.entries(fileDataToStore).forEach(([key, value]) => {
+ const data = [];
+ const headers = [];
+ const toRemove = [];
+ if (value && value.length > 0) {
+ value[0].forEach((item, index) => {
+ const mappedTo = resourceMappingData.find((e) => e.mappedFrom === item)?.mappedTo;
+ if (!mappedTo) {
+ toRemove.push(index);
+ return;
+ }
+ headers.push(mappedTo);
+ return;
+ });
+ for (let i = 1; i < value?.length; i++) {
+ let temp = [];
+ for (let j = 0; j < value[i].length; j++) {
+ if (!toRemove.includes(j)) {
+ temp.push(value[i][j]);
+ }
+ }
+ data.push(temp);
+ }
+ }
+ newFileData[key] = [headers, ...data];
+ });
+ }
+ return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData };
+};
+export const revertLocalisationKey = (localisedCode) => {
+ if (!localisedCode || !localisedCode.startsWith(SCHEMA_PROPERTIES_PREFIX + "_")) {
+ return localisedCode;
+ }
+ return localisedCode.substring(SCHEMA_PROPERTIES_PREFIX.length + 1);
+};
+// Function to process each dataset within the data object
+const processData = (data, schemaCols, errors, hierarchy, sectionIdList, readMeSheetName, t) => {
+ const processedData = {};
+ for (const sheet of data) {
+ const dataset = [...sheet.data];
+ dataset[0] = dataset[0].map((item) => {
+ if (item !== commonColumn && schemaCols.includes(item)) {
+ return t(generateLocalisationKeyForSchemaProperties(item));
+ }
+ return t(item);
+ });
+
+ if (sheet.sheetName !== t(BOUNDARY_DATA_SHEET) && sheet.sheetName !== t(readMeSheetName)) {
+ processSheetErrors(dataset, sheet.sheetName, errors, t);
+ }
+
+ if (sheet.sheetName === t(FACILITY_DATA_SHEET) || sectionIdList.includes(sheet.sheetName)) {
+ dataset[0] = dataset[0].map((item) => {
+ if (item === t(commonColumn)) {
+ return t(generateLocalisationKeyForSchemaProperties(commonColumn));
+ }
+ return item;
+ });
+
+ if (hierarchy.every((item) => dataset[0].includes(item))) {
+ for (let i = 0; i < dataset.length; i++) {
+ dataset[i] = dataset[i].slice(hierarchy.length);
+ }
+ }
+ }
+
+ processedData[sheet.sheetName] = dataset;
+ }
+ return processedData;
+};
+
+// Function to process errors for a sheet
+const processSheetErrors = (dataset, sheetName, errors, t) => {
+ const headerCount = dataset[0].length;
+ dataset[0].push(t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN"));
+
+ for (let i = 1; i < dataset.length; i++) {
+ const row = dataset[i];
+ if (headerCount > row.length) {
+ row.push(...Array(headerCount - row.length).fill(""));
+ }
+
+ const errorInfo = errors?.[sheetName]?.[i - 1];
+ if (errorInfo) {
+ const rowDataAddOn = Object.entries(errorInfo)
+ .map(([key, value]) => {
+ return `${t(key)}: ${value.map((item) => t(item)).join(", ")}`;
+ })
+ .join(". ");
+ row.push(t("MICROPLAN_ERROR_STATUS_INVALID"), rowDataAddOn);
+ } else {
+ row.push("");
+ }
+ }
+};
+
+// Function to style the workbook
+const styleWorkbook = (workbook, hierarchy, commonColumn, schema, t) => {
+ const style = {
+ font: { color: { argb: "B91900" } },
+ border: {
+ top: { style: "thin", color: { argb: "B91900" } },
+ left: { style: "thin", color: { argb: "B91900" } },
+ bottom: { style: "thin", color: { argb: "B91900" } },
+ right: { style: "thin", color: { argb: "B91900" } },
+ },
+ };
+
+ const header1 = [...hierarchy.map((item) => t(item)), t(commonColumn)];
+ const header2 = schema?.schema?.Properties
+ ? [
+ ...Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))),
+ t(generateLocalisationKeyForSchemaProperties(commonColumn)),
+ ]
+ : [];
+
+ colorHeaders(workbook, header1, header2, [t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")]);
+};
+
+// Function to protect the workbook data
+const protectWorkbookData = async (workbook, schema, t) => {
+ await protectData({
+ workbook,
+ hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets,
+ addFacilityData: schema?.template?.includeFacilityData,
+ schema,
+ t,
+ });
+};
+
+export const prepareExcelFileBlobWithErrors = async (dataInput, errors, schema, hierarchy, readMeData, readMeSheetName, sectionIdList, t) => {
+ const data = _.cloneDeep(dataInput);
+ const schemaCols = schema?.schema?.Properties ? Object.keys(schema.schema.Properties) : [];
+ const processedData = processData(data, schemaCols, errors, hierarchy, sectionIdList, readMeSheetName, t);
+
+ const workbook = await convertToWorkBook(
+ processedData,
+ {
+ errorColumns: [t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")],
+ style: {
+ font: { color: { argb: "B91900" } },
+ border: {
+ top: { style: "thin", color: { argb: "B91900" } },
+ left: { style: "thin", color: { argb: "B91900" } },
+ bottom: { style: "thin", color: { argb: "B91900" } },
+ right: { style: "thin", color: { argb: "B91900" } },
+ },
+ },
+ },
+ t
+ );
+
+ styleWorkbook(workbook, hierarchy, commonColumn, schema, t);
+
+ formatAndColorReadMeFile(
+ workbook,
+ readMeData?.map((item) => t(item?.header)),
+ t(readMeSheetName)
+ );
+
+ await protectWorkbookData(workbook, schema, t);
+
+ return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => {
+ return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
+ });
+};
+
+export const convertToWorkBook = async (jsonData, columnWithStyle, t) => {
+ const workbook = new ExcelJS.Workbook();
+
+ // Iterate over each sheet in jsonData
+ for (const [sheetName, data] of Object.entries(jsonData)) {
+ // Create a new worksheet
+ const worksheet = workbook.addWorksheet(sheetName);
+
+ let index = 0;
+ let commonColumnIndex = -1;
+
+ // Convert data to worksheet
+ for (const row of data) {
+ const newRow = worksheet.addRow(row);
+
+ const rowHasData = row?.filter((item) => item !== "").length !== 0;
+ // Apply red font color to the errorColumn if it exists
+ if (rowHasData && columnWithStyle?.errorColumns) {
+ for (const errorColumn of columnWithStyle?.errorColumns) {
+ const errorColumnIndex = data[0].indexOf(errorColumn);
+ if (errorColumnIndex !== -1) {
+ const columnIndex = errorColumnIndex + 1;
+ if (columnIndex > 0) {
+ const newCell = newRow.getCell(columnIndex);
+ if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key];
+ }
+ }
+ }
+ }
+ if (index === 0) {
+ newRow.eachCell((cell, colNumber) => {
+ // Set font to bold
+ cell.font = { bold: true };
+
+ // Enable text wrapping
+ cell.alignment = { vertical: "middle", horizontal: "center", wrapText: true };
+ // Update column width based on the length of the cell's text
+ // const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width
+ // const newWidth = Math.min(currentWidth, cell.value.toString().length + 2); // Add padding
+ if (cell.value === t(commonColumn) || cell.value === t(generateLocalisationKeyForSchemaProperties(commonColumn))) {
+ commonColumnIndex = colNumber;
+ worksheet.getColumn(colNumber).width = SHEET_COLUMN_WIDTH + 10;
+ } else {
+ worksheet.getColumn(colNumber).width = SHEET_COLUMN_WIDTH;
+ }
+ });
+ }
+ newRow.eachCell({ includeEmpty: true }, (cell, colNumber) => {
+ cell.alignment = { vertical: "middle", wrapText: colNumber !== commonColumnIndex }; // Apply text wrapping
+ });
+ index++;
+ }
+
+ // Make the first row bold
+ if (worksheet.getRow(1)) {
+ worksheet.getRow(1).font = { bold: true };
+ }
+
+ // Set column widths
+ // const columnCount = data?.[0]?.length || 0;
+ // const wscols = Array(columnCount).fill({ width: 30 });
+ // wscols.forEach((col, colIndex) => {
+ // worksheet.getColumn(colIndex + 1).width = col.width;
+ // });
+ }
+ return workbook;
+};
+export const boundaryDataGeneration = async (schemaData, campaignData, t) => {
+ const boundaryDataAgainstBoundaryCode = {};
+ if (schemaData && !schemaData.doHierarchyCheckInUploadedData) {
+ try {
+ const rootBoundary = campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable
+ const sessionData = Digit.SessionStorage.get("microplanHelperData") || {};
+ let boundaryData = sessionData.filteredBoundaries;
+ let filteredBoundaries;
+ if (!boundaryData) {
+ // Only fetch boundary data if not present in session storage
+ boundaryData = await fetchBoundaryData(Digit.ULBService.getCurrentTenantId(), campaignData?.hierarchyType, rootBoundary?.[0]?.code);
+ filteredBoundaries = filterBoundaries(boundaryData, campaignData?.boundaries);
+
+ // Update the session storage with the new filtered boundaries
+ Digit.SessionStorage.set("microplanHelperData", {
+ ...sessionData,
+ filteredBoundaries: filteredBoundaries,
+ });
+ } else {
+ filteredBoundaries = boundaryData;
+ }
+ const xlsxData = addBoundaryData([], filteredBoundaries, campaignData?.hierarchyType)?.[0]?.data;
+ xlsxData.forEach((item, i) => {
+ if (i === 0) return;
+ let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn);
+ if (boundaryCodeIndex >= item.length) {
+ // If boundaryCodeIndex is out of bounds, return the item as is
+ boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(t);
+ } else {
+ // Otherwise, remove the element at boundaryCodeIndex
+ boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item
+ .slice(0, boundaryCodeIndex)
+ .concat(item.slice(boundaryCodeIndex + 1))
+ .map(t);
+ }
+ });
+ return boundaryDataAgainstBoundaryCode;
+ } catch (error) {
+ console.error(error?.message);
+ }
+ }
+};
+
+const filterDataWithActiveInactiveStatus = (result, activeInactiveField, dataInObject, t) => {
+ const facilityDataSheetKey = t(FACILITY_DATA_SHEET);
+ const uploadedDataActiveStatus = t(UPLOADED_DATA_ACTIVE_STATUS);
+
+ if (!result?.[facilityDataSheetKey]) {
+ return result;
+ }
+
+ const facilityDataSheet = result[facilityDataSheetKey];
+
+ const filterDataInObject = () => {
+ return facilityDataSheet.filter((item) => item?.[activeInactiveField] === uploadedDataActiveStatus);
+ };
+
+ const filterDataInArray = () => {
+ const activeInactiveFieldIndex = facilityDataSheet[0]?.findIndex((item) => item === activeInactiveField);
+
+ if (activeInactiveFieldIndex === -1) {
+ return facilityDataSheet;
+ }
+
+ return facilityDataSheet.filter((item, index) => {
+ if (index === 0) {
+ return true; // Include header
+ }
+ return item?.[activeInactiveFieldIndex] === uploadedDataActiveStatus;
+ });
+ };
+
+ const filteredData = dataInObject ? filterDataInObject() : filterDataInArray();
+
+ return { [facilityDataSheetKey]: filteredData };
+};
+
+export const handleExcelFile = async (
+ file,
+ schemaData,
+ hierarchy,
+ selectedFileType,
+ boundaryDataAgainstBoundaryCode,
+ setUploadedFileError,
+ t,
+ campaignData,
+ readMeSheetName
+) => {
+ try {
+ // Converting the file to preserve the sequence of columns so that it can be stored
+ let fileDataToStore = await parseXlsxToJsonMultipleSheets(file, { header: 0 });
+ const additionalSheets = [];
+ if (fileDataToStore[t(BOUNDARY_DATA_SHEET)]) {
+ additionalSheets.push({ sheetName: t(BOUNDARY_DATA_SHEET), data: fileDataToStore[t(BOUNDARY_DATA_SHEET)], position: -1 });
+ delete fileDataToStore[t(BOUNDARY_DATA_SHEET)];
+ }
+ if (fileDataToStore[t(readMeSheetName)]) {
+ additionalSheets.push({ sheetName: t(readMeSheetName), data: fileDataToStore[t(readMeSheetName)], position: 0 });
+ delete fileDataToStore[t(readMeSheetName)];
+ } else {
+ return {
+ check: false,
+ interruptUpload: true,
+ fileDataToStore: {},
+ toast: { state: "error", message: t("ERROR_READ_ME_MISSING") },
+ };
+ }
+ let { tempResourceMappingData, tempFileDataToStore } = resourceMappingAndDataFilteringForExcelFiles(
+ schemaData,
+ hierarchy,
+ selectedFileType,
+ fileDataToStore,
+ t
+ );
+ fileDataToStore = await convertJsonToXlsx(tempFileDataToStore);
+ // Converting the input file to json format
+ let result = await parseXlsxToJsonMultipleSheets(fileDataToStore, { header: 1 });
+ if (result) {
+ const validSheets = {};
+ const resultSheetNames = Object.keys(result);
+ Object.keys(tempFileDataToStore).forEach((item) => {
+ if (resultSheetNames.includes(item)) {
+ validSheets[item] = tempFileDataToStore[item];
+ }
+ });
+ tempFileDataToStore = validSheets;
+ }
+ if (result?.error) {
+ return {
+ check: false,
+ interruptUpload: true,
+ error: result.error,
+ fileDataToStore: {},
+ toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") },
+ };
+ }
+ let extraColumns = [commonColumn];
+ // checking if the hierarchy and common column is present the uploaded data
+ extraColumns = [...hierarchy, commonColumn];
+ let data = Object.values(tempFileDataToStore);
+ let errorMsg;
+ let errors; // object containing the location and type of error
+ let toast;
+ let hierarchyDataPresent = true;
+ let latLngColumns =
+ Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => {
+ if (value?.isLocationDataColumns) {
+ acc.push(key);
+ }
+ return acc;
+ }, []) || [];
+ data.forEach((item) => {
+ const keys = item[0];
+ if (keys?.length !== 0) {
+ if (!extraColumns?.every((e) => keys.includes(e))) {
+ if (schemaData && !schemaData.doHierarchyCheckInUploadedData) {
+ hierarchyDataPresent = false;
+ } else {
+ errorMsg = {
+ check: false,
+ interruptUpload: true,
+ error: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT"),
+ fileDataToStore: {},
+ toast: { state: "error", message: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT") },
+ };
+ }
+ }
+ if (!latLngColumns?.every((e) => keys.includes(e))) {
+ toast = { state: "warning", message: t("ERROR_UPLOAD_EXCEL_LOCATION_DATA_MISSING") };
+ }
+ }
+ });
+ if (errorMsg && !errorMsg?.check) return errorMsg;
+ if (
+ schemaData?.activeInactiveField &&
+ schemaData?.schema?.Properties &&
+ Object.keys(schemaData.schema.Properties).includes(schemaData.activeInactiveField)
+ ) {
+ result = filterDataWithActiveInactiveStatus(result, schemaData.activeInactiveField, true, t);
+ tempFileDataToStore = filterDataWithActiveInactiveStatus(tempFileDataToStore, schemaData.activeInactiveField, false, t);
+ }
+ // Running Validations for uploaded file
+ let response = await checkForErrorInUploadedFileExcel(result, schemaData.schema, t);
+ if (!response.valid) setUploadedFileError(response.message);
+ errorMsg = response.message;
+ errors = response.errors;
+ const missingProperties = response.missingProperties;
+ let check = response.valid;
+ try {
+ if (
+ schemaData &&
+ !schemaData.doHierarchyCheckInUploadedData &&
+ !hierarchyDataPresent &&
+ boundaryDataAgainstBoundaryCode &&
+ (!missingProperties || [...missingProperties]?.includes(commonColumn))
+ ) {
+ let tempBoundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {};
+ for (const sheet in tempFileDataToStore) {
+ const commonColumnIndex = tempFileDataToStore[sheet]?.[0]?.indexOf(commonColumn);
+ if (commonColumnIndex !== -1) {
+ const dataCollector = [];
+ for (let index = 0; index < tempFileDataToStore[sheet].length; index++) {
+ let row = tempFileDataToStore[sheet][index];
+ const commonColumnValues = row[commonColumnIndex]?.split(",").map((item) => item.trim());
+ if (!commonColumnValues) {
+ dataCollector.push([...new Array(hierarchy.length).fill(""), ...row]);
+ continue;
+ }
+ for (const value of commonColumnValues) {
+ const newRowData = [...row];
+ newRowData[commonColumnIndex] = value;
+ dataCollector.push([
+ ...(tempBoundaryDataAgainstBoundaryCode[value]
+ ? tempBoundaryDataAgainstBoundaryCode[value]
+ : index !== 0
+ ? new Array(hierarchy.length).fill("")
+ : []),
+ ...newRowData,
+ ]);
+ }
+ }
+ tempFileDataToStore[sheet] = dataCollector;
+ }
+
+ tempFileDataToStore[sheet][0] = [...hierarchy, ...tempFileDataToStore[sheet][0]];
+ }
+ }
+ } catch (error) {
+ console.error("Error in boundary adding operaiton: ", error);
+ }
+ tempFileDataToStore = addMissingPropertiesToFileData(tempFileDataToStore, missingProperties);
+ return { check, errors, errorMsg, fileDataToStore: tempFileDataToStore, tempResourceMappingData, toast, additionalSheets };
+ } catch (error) {
+ console.error("Error in handling Excel file:", error.message);
+ }
+};
+export const addMissingPropertiesToFileData = (data, missingProperties) => {
+ if (!data || !missingProperties) return data;
+ let tempData = {};
+ Object.entries(data).forEach(([key, value], index) => {
+ const filteredMissingProperties = [...missingProperties]?.reduce((acc, item) => {
+ if (!value?.[0]?.includes(item)) {
+ acc.push(item);
+ }
+ return acc;
+ }, []);
+ const newTempHeaders = value?.[0].length !== 0 ? [...value[0], ...filteredMissingProperties] : [...filteredMissingProperties];
+ tempData[key] = [newTempHeaders, ...value.slice(1)];
+ });
+ return tempData;
+};
+
+export const handleGeojsonFile = async (file, schemaData, setUploadedFileError, t) => {
+ // Reading and checking geojson data
+ const data = await readGeojson(file, t);
+ if (!data.valid) {
+ return { check: false, stopUpload: true, toast: data.toast };
+ }
+
+ // Running geojson validaiton on uploaded file
+ let response = geojsonValidations(data.geojsonData, schemaData.schema, t);
+ if (!response.valid) setUploadedFileError(response.message);
+ let check = response.valid;
+ let error = response.message;
+ let fileDataToStore = data.geojsonData;
+ return { check, error, fileDataToStore };
+};
+
+const generateLocalisationKeyForSchemaProperties = (code) => {
+ if (!code) return code;
+ return `${SCHEMA_PROPERTIES_PREFIX}_${code}`;
+};
+export const handleShapefiles = async (file, schemaData, setUploadedFileError, selectedFileType, setToast, t) => {
+ // Reading and validating the uploaded geojson file
+ let response = await readAndValidateShapeFiles(file, t, selectedFileType["namingConvention"]);
+ if (!response.valid) {
+ setUploadedFileError(response.message);
+ setToast(response.toast);
+ }
+ let check = response.valid;
+ let error = response.message;
+ let fileDataToStore = response.data;
+ return { check, error, fileDataToStore };
+};
+
+export const convertToSheetArray = (data) => {
+ if (!data) return [];
+ const convertedSheetData = [];
+ for (const [key, value] of Object.entries(data)) {
+ convertedSheetData.push({ sheetName: key, data: value });
+ }
+ return convertedSheetData;
+};
+
+//find guideline
+export const findGuideLine = (campaignType, type, section, guidelineArray) => {
+ if (!guidelineArray) return guidelineArray;
+ return guidelineArray.find(
+ (guideline) =>
+ guideline.fileType === type && guideline.templateIdentifier === section && (!guideline.campaignType || guideline.campaignType === campaignType)
+ )?.guidelines;
+};
+
+// Utility function to introduce a delay
+export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/create.sh b/health/micro-ui/web/micro-ui-internals/scripts/create.sh
old mode 100755
new mode 100644
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/deploy.sh b/health/micro-ui/web/micro-ui-internals/scripts/deploy.sh
old mode 100755
new mode 100644
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/jenkins.sh b/health/micro-ui/web/micro-ui-internals/scripts/jenkins.sh
old mode 100755
new mode 100644
diff --git a/health/micro-ui/web/micro-ui-internals/scripts/run.sh b/health/micro-ui/web/micro-ui-internals/scripts/run.sh
old mode 100755
new mode 100644
diff --git a/health/micro-ui/web/microplan/App.js b/health/micro-ui/web/microplan/App.js
new file mode 100644
index 00000000000..afcd26669c6
--- /dev/null
+++ b/health/micro-ui/web/microplan/App.js
@@ -0,0 +1,61 @@
+import React from "react";
+import { initLibraries } from "@egovernments/digit-ui-libraries";
+
+import { DigitUI } from "@egovernments/digit-ui-module-core";
+
+import { UICustomizations } from "./Customisations/UICustomizations";
+import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning";
+
+
+window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
+
+const enabledModules = [
+ "DSS",
+ "NDSS",
+ "Utilities",
+ "HRMS",
+ "Engagement",
+ "Workbench",
+ "Microplanning"
+];
+
+const moduleReducers = (initData) => ({
+ initData,
+});
+
+const initDigitUI = () => {
+ window.Digit.ComponentRegistryService.setupRegistry({
+
+ });
+
+
+ initMicroplanningComponents()
+ window.Digit.Customizations = {
+ PGR: {},
+ commonUiConfig: UICustomizations,
+ };
+};
+
+initLibraries().then(() => {
+ initDigitUI();
+});
+
+function App() {
+ window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH");
+ const stateCode =
+ window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") ||
+ process.env.REACT_APP_STATE_LEVEL_TENANT_ID;
+ if (!stateCode) {
+ return stateCode is not defined
;
+ }
+ return (
+
+ );
+}
+
+export default App;
diff --git a/health/micro-ui/web/microplan/Dockerfile b/health/micro-ui/web/microplan/Dockerfile
new file mode 100644
index 00000000000..56388b8e2d7
--- /dev/null
+++ b/health/micro-ui/web/microplan/Dockerfile
@@ -0,0 +1,30 @@
+FROM egovio/alpine-node-builder-14:yarn AS build
+#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build
+RUN apk update && apk upgrade
+RUN apk add --no-cache git>2.30.0
+ARG WORK_DIR
+WORKDIR /app
+ENV NODE_OPTIONS "--max-old-space-size=4792"
+
+COPY ${WORK_DIR} .
+RUN ls -lah
+
+#RUN node web/envs.js
+RUN cd web/ \
+ && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \
+ && node -e 'console.log("core only")' \
+ && cd microplan/ \
+ && chmod +x ./install-deps.sh \
+ && ./install-deps.sh \
+ && cd ../ \
+ && yarn install \
+ && yarn build:webpack
+
+FROM nginx:mainline-alpine
+#FROM ghcr.io/egovernments/nginx:mainline-alpine
+ENV WORK_DIR=/var/web/microplan-ui
+
+RUN mkdir -p ${WORK_DIR}
+
+COPY --from=build /app/web/build ${WORK_DIR}/
+COPY --from=build /app/web/microplan/nginx.conf /etc/nginx/conf.d/default.conf
diff --git a/health/micro-ui/web/microplan/install-deps.sh b/health/micro-ui/web/microplan/install-deps.sh
new file mode 100644
index 00000000000..b090c8d6f04
--- /dev/null
+++ b/health/micro-ui/web/microplan/install-deps.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+BRANCH="$(git branch --show-current)"
+
+echo "Main Branch: $BRANCH"
+
+INTERNALS="micro-ui-internals"
+cd ..
+
+cp microplan/App.js src
+cp microplan/package.json package.json
+cp microplan/webpack.config.js webpack.config.js
+cp microplan/inter-package.json $INTERNALS/package.json
+
+cp $INTERNALS/example/src/UICustomizations.js src/Customisations
+
+echo "UI :: microplan " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages"
+
diff --git a/health/micro-ui/web/microplan/inter-package.json b/health/micro-ui/web/microplan/inter-package.json
new file mode 100644
index 00000000000..635c9cc954b
--- /dev/null
+++ b/health/micro-ui/web/microplan/inter-package.json
@@ -0,0 +1,61 @@
+{
+ "name": "egovernments",
+ "version": "1.0.0",
+ "main": "index.js",
+ "workspaces": [
+ "example",
+ "packages/css",
+ "packages/modules/*"
+ ],
+ "author": "JaganKumar ",
+ "license": "MIT",
+ "private": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "scripts": {
+ "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev",
+ "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script",
+ "start:dev": "run-p dev:**",
+ "start:script": "./scripts/create.sh",
+ "dev:css": "cd packages/css && yarn start",
+ "publish:css": "cd packages/css && yarn publish --access public",
+ "dev:example": "cd example && yarn start",
+ "dev:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn start",
+ "build": "run-p build:**",
+ "build:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn build",
+ "deploy:jenkins": "./scripts/jenkins.sh",
+ "clean": "rm -rf node_modules"
+ },
+ "resolutions": {
+ "**/@babel/runtime": "7.20.1",
+ "**/babel-preset-react-app": "10.0.0",
+ "**/babel-loader": "8.2.2",
+ "**/@babel/core": "7.14.0",
+ "**/@babel/preset-env": "7.14.0",
+ "**/@babel/plugin-transform-modules-commonjs": "7.14.0",
+ "**/polished":"4.2.2",
+ "fast-uri":"2.1.0"
+ },
+ "devDependencies": {
+ "husky": "7.0.4",
+ "lint-staged": "12.3.7",
+ "npm-run-all": "4.1.5",
+ "prettier": "2.1.2"
+ },
+ "husky": {},
+ "lint-staged": {
+ "*.{js,css,md}": "prettier --write"
+ },
+ "dependencies": {
+ "lodash": "4.17.21",
+ "microbundle-crl": "0.13.11",
+ "@egovernments/digit-ui-react-components": "1.8.1-beta.2",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0"
+ }
+}
diff --git a/health/micro-ui/web/microplan/nginx.conf b/health/micro-ui/web/microplan/nginx.conf
new file mode 100644
index 00000000000..9c84c01c4be
--- /dev/null
+++ b/health/micro-ui/web/microplan/nginx.conf
@@ -0,0 +1,12 @@
+server
+{
+ listen 80;
+ underscores_in_headers on;
+
+ location /microplan-ui
+ {
+ root /var/web;
+ index index.html index.htm;
+ try_files $uri $uri/ /microplan-ui/index.html;
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/microplan/package.json b/health/micro-ui/web/microplan/package.json
new file mode 100644
index 00000000000..dff749d1780
--- /dev/null
+++ b/health/micro-ui/web/microplan/package.json
@@ -0,0 +1,80 @@
+{
+ "name": "micro-ui",
+ "version": "1.0.0",
+ "author": "Jagankumar ",
+ "license": "MIT",
+ "private": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "workspaces": [
+ "micro-ui-internals/packages/modules/*"
+ ],
+ "homepage": "/microplan-ui",
+ "dependencies": {
+ "@egovernments/digit-ui-libraries": "1.8.2-beta.1",
+ "@egovernments/digit-ui-module-core": "1.8.2-beta.1",
+ "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.1",
+ "@egovernments/digit-ui-module-hcmmicroplanning":"0.0.1",
+ "@egovernments/digit-ui-components": "0.0.2-beta.2",
+ "babel-loader": "8.1.0",
+ "clean-webpack-plugin": "4.0.0",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "jsonpath": "^1.1.1",
+ "react-router-dom": "5.3.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "1.1.2",
+ "terser-brunch": "^4.1.0",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "css-loader": "5.2.6",
+ "style-loader": "2.0.0",
+ "webpack-cli": "4.10.0"
+ },
+ "devDependencies": {
+ "@babel/plugin-proposal-private-property-in-object": "7.21.0",
+ "file-loader": "^6.2.0",
+ "http-proxy-middleware": "1.3.1",
+ "lodash": "4.17.21",
+ "microbundle-crl": "0.13.11",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-hook-form": "6.15.8",
+ "react-i18next": "11.16.2",
+ "react-query": "3.6.1",
+ "react-router-dom": "5.3.0",
+ "husky": "7.0.4",
+ "lint-staged": "12.3.7",
+ "npm-run-all": "4.1.5",
+ "prettier": "2.1.2"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build",
+ "build:prepare": "./build.sh",
+ "build:libraries": "cd micro-ui-internals && yarn build",
+ "build:prod": "webpack --mode production",
+ "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod",
+ "clean": "rm -rf node_modules"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/health/micro-ui/web/microplan/webpack.config.js b/health/micro-ui/web/microplan/webpack.config.js
new file mode 100644
index 00000000000..c8036364605
--- /dev/null
+++ b/health/micro-ui/web/microplan/webpack.config.js
@@ -0,0 +1,52 @@
+const path = require("path");
+const HtmlWebpackPlugin = require("html-webpack-plugin");
+const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
+
+module.exports = {
+ // mode: 'development',
+ entry: "./src/index.js",
+ devtool: "none",
+ module: {
+ rules: [
+ {
+ test: /\.(js)$/,
+ exclude: /node_modules/,
+ use: ["babel-loader"],
+ },
+ {
+ test: /\.css$/i,
+ use: ["style-loader", "css-loader"],
+ },
+ {
+ test: /\.(png|jpe?g|gif)$/i,
+ use: [
+ {
+ loader: 'file-loader',
+ },
+ ],
+ },
+ ],
+ },
+ output: {
+ filename: "[name].bundle.js",
+ path: path.resolve(__dirname, "build"),
+ publicPath: "/microplan-ui/",
+ },
+ optimization: {
+ splitChunks: {
+ chunks: 'all',
+ minSize:20000,
+ maxSize:50000,
+ enforceSizeThreshold:50000,
+ minChunks:1,
+ maxAsyncRequests:30,
+ maxInitialRequests:30
+ },
+ },
+ plugins: [
+ new CleanWebpackPlugin(),
+ // new BundleAnalyzerPlugin(),
+ new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }),
+ ],
+};
\ No newline at end of file
diff --git a/health/micro-ui/web/package.json b/health/micro-ui/web/package.json
index 59ebb7ece05..e90ab5a52ba 100644
--- a/health/micro-ui/web/package.json
+++ b/health/micro-ui/web/package.json
@@ -1,6 +1,6 @@
{
"name": "micro-ui",
- "version": "1.0.0",
+ "version": "0.1.0",
"author": "Jagankumar ",
"license": "MIT",
"private": true,
diff --git a/health/micro-ui/web/public/index.html b/health/micro-ui/web/public/index.html
index 9da00f7e1de..feeeffb4b09 100644
--- a/health/micro-ui/web/public/index.html
+++ b/health/micro-ui/web/public/index.html
@@ -12,6 +12,7 @@
+
DIGIT
diff --git a/health/micro-ui/web/workbench/install-deps.sh b/health/micro-ui/web/workbench/install-deps.sh
old mode 100755
new mode 100644
diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity
new file mode 100644
index 00000000000..7e20d0946e2
--- /dev/null
+++ b/node_modules/.yarn-integrity
@@ -0,0 +1,12 @@
+{
+ "systemParams": "win32-x64-83",
+ "modulesFolders": [
+ "node_modules"
+ ],
+ "flags": [],
+ "linkedModules": [],
+ "topLevelPatterns": [],
+ "lockfileEntries": {},
+ "files": [],
+ "artifacts": {}
+}
\ No newline at end of file
From 94114732723f2ebef087907e39c6b436dd81e5bc Mon Sep 17 00:00:00 2001
From: siddhant-nawale-egov
<162107530+siddhant-nawale-egov@users.noreply.github.com>
Date: Thu, 27 Jun 2024 09:46:24 +0530
Subject: [PATCH 10/83] Trimmed microplan name. Open Saved microplan with
navigation for all steps unlocked (#967)
* Trimmed microplan name. Open Saved microplan with navigation for all steps unlocked
* Update SavedMicroplans.js
---
.../hcm-microplanning/src/components/MicroplanDetails.js | 8 ++++----
.../src/pages/employee/SavedMicroplans.js | 5 +++++
.../hcm-microplanning/src/utils/updateSessionUtils.js | 1 +
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js
index a54b7419ed8..c8156ee812a 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js
@@ -97,7 +97,7 @@ const MicroplanDetails = ({
setMicroplanData((previous) => ({
...previous,
microplanDetails: {
- name: microplan,
+ name: microplan?.trim(),
},
}));
}, [microplan]);
@@ -129,7 +129,7 @@ const MicroplanDetails = ({
setLoader("LOADING");
const body = {
PlanConfigurationSearchCriteria: {
- name: microplan,
+ name: microplan?.trim(),
tenantId: Digit.ULBService.getCurrentTenantId(),
},
};
@@ -171,7 +171,7 @@ const MicroplanDetails = ({
setMicroplanData((previous) => ({
...previous,
microplanDetails: {
- name: microplan,
+ name: microplan?.trim(),
},
}));
if (!["", null, undefined].includes(microplan)) {
@@ -292,4 +292,4 @@ const MicroplanDetails = ({
);
};
-export default MicroplanDetails;
+export default MicroplanDetails;
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js
index 39c26661891..497febf037c 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js
@@ -4,6 +4,7 @@ import { Header, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-re
import { useHistory } from "react-router-dom";
import { updateSessionUtils } from "../../utils/updateSessionUtils";
import { useMyContext } from "../../utils/context";
+import { timeLineOptions } from "../../configs/timeLineOptions.json";
const configs = {
label: "SAVED_MICROPLANS",
@@ -165,6 +166,10 @@ const SavedMicroplans = () => {
// Compute the session object based on the row?.original data and then re-route
const computedSession = await updateSessionUtils.computeSessionObject(row.original, state, additionalProps);
Digit.SessionStorage.set("microplanData", computedSession);
+ Digit.SessionStorage.set("microplanHelperData", {
+ ...Digit.SessionStorage.get("microplanHelperData"),
+ activeSteps: timeLineOptions.length - 1,
+ });
setShowLoader(false);
history.push(`/${window.contextPath}/employee/microplanning/edit-saved-microplan?id=${row?.original?.executionPlanId}`);
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
index 9af362cbf62..38f1dcbfc8b 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
@@ -106,6 +106,7 @@ export const updateSessionUtils = {
MICROPLAN_DETAILS: true,
UPLOAD_DATA: true,
HYPOTHESIS: true,
+ MAPPING: true,
FORMULA_CONFIGURATION: true,
};
};
From ef3963fe82b267e1062d2aef9ea4c5b5b4b1ad59 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Thu, 27 Jun 2024 09:54:50 +0530
Subject: [PATCH 11/83] Update build-config.yml for microplan build issue
---
build/build-config.yml | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/build/build-config.yml b/build/build-config.yml
index 7fcfd624e35..6bb79e8a0d1 100644
--- a/build/build-config.yml
+++ b/build/build-config.yml
@@ -19,16 +19,22 @@
config:
# frontend
- - name: builds/Digit-Frontend/workbench-ui
+ - name: builds/Digit-Frontend/workbench-ui-core
build:
- work-dir: micro-ui/
dockerfile: micro-ui/web/workbench/Dockerfile
image-name: workbench-ui
+ - name: builds/Digit-Frontend/workbench-ui
+ build:
+ - work-dir: health/micro-ui/
+ dockerfile: health/micro-ui/web/workbench/Dockerfile
+ image-name: workbench-ui
+
- name: builds/Digit-Frontend/microplan-ui
build:
- - work-dir: micro-ui/
- dockerfile: micro-ui/web/microplan/Dockerfile
+ - work-dir: health/micro-ui/
+ dockerfile: health/micro-ui/web/microplan/Dockerfile
image-name: microplan-ui
- name: builds/Digit-Frontend/storybook-svg
From f5f2f8108f7e2dfdb9d94f28933b98822cac90d9 Mon Sep 17 00:00:00 2001
From: siddhant-nawale-egov
<162107530+siddhant-nawale-egov@users.noreply.github.com>
Date: Thu, 27 Jun 2024 12:14:48 +0530
Subject: [PATCH 12/83] adding map height css changes, geojson active inactive
status change
---
.../example/public/index.html | 2 +-
.../src/utils/updateSessionUtils.js | 32 +++++++++++++------
health/micro-ui/web/public/index.html | 2 +-
3 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/health/micro-ui/web/micro-ui-internals/example/public/index.html b/health/micro-ui/web/micro-ui-internals/example/public/index.html
index 6c5bb32010c..789bd4b6f8a 100644
--- a/health/micro-ui/web/micro-ui-internals/example/public/index.html
+++ b/health/micro-ui/web/micro-ui-internals/example/public/index.html
@@ -17,7 +17,7 @@
-
+
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
index 38f1dcbfc8b..95c5d429e4b 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js
@@ -4,7 +4,7 @@ import JSZip from "jszip";
import * as XLSX from "xlsx";
import axios from "axios";
import shp from "shpjs";
-import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn } from "../configs/constants";
+import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn, UPLOADED_DATA_ACTIVE_STATUS } from "../configs/constants";
import { addBoundaryData, fetchBoundaryData, filterBoundaries } from "./createTemplate";
import { handleExcelFile } from "./uploadUtils";
@@ -313,17 +313,29 @@ export const updateSessionUtils = {
if (processedData) return;
const mappedToList = upload?.resourceMapping.map((item) => item.mappedTo);
let sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, upload?.resourceMapping);
- const newFeatures = result["features"].map((item) => {
+ const newFeatures = [];
+ for (const item of result["features"]) {
let newProperties = {};
- sortedSecondList
- ?.filter((resourse) => resourse.filestoreId === filestoreId)
- .forEach((e) => {
- newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]];
- });
+
+ sortedSecondList.forEach((e) => {
+ newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]];
+ });
item["properties"] = newProperties;
- return item;
- });
- upload.data.features = newFeatures;
+ newFeatures.push(item);
+ }
+ let filteredFeature = [];
+ for (const item of newFeatures) {
+ if (
+ schema?.activeInactiveField &&
+ schema?.schema?.Properties &&
+ Object.keys(schema.schema.Properties).includes(schema.activeInactiveField) &&
+ item?.properties?.[schema.activeInactiveField] !== additionalProps.t(UPLOADED_DATA_ACTIVE_STATUS)
+ ) {
+ continue;
+ }
+ filteredFeature.push(item);
+ }
+ upload.data.features = filteredFeature;
if (
additionalProps.hierarchyData?.every(
(item) =>
diff --git a/health/micro-ui/web/public/index.html b/health/micro-ui/web/public/index.html
index feeeffb4b09..4095a21541c 100644
--- a/health/micro-ui/web/public/index.html
+++ b/health/micro-ui/web/public/index.html
@@ -12,7 +12,7 @@
-
+
DIGIT
From e6d4a8e92cebd418998196b9b18f9722439ba515 Mon Sep 17 00:00:00 2001
From: siddhant-nawale-egov
<162107530+siddhant-nawale-egov@users.noreply.github.com>
Date: Fri, 28 Jun 2024 10:09:39 +0530
Subject: [PATCH 13/83] Adding handling of same name sheets (#975)
* Adding handling of same name sheets
* Update Upload.js
* upgrading css pkg for microplan
---
.../micro-ui-internals/example/public/index.html | 2 +-
.../MicroplanPreviewHelperCompoenents.js | 2 +-
.../hcm-microplanning/src/components/Upload.js | 6 +++---
.../src/utils/microplanPreviewUtils.js | 2 +-
.../hcm-microplanning/src/utils/uploadUtils.js | 15 +++++++++++++--
5 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/health/micro-ui/web/micro-ui-internals/example/public/index.html b/health/micro-ui/web/micro-ui-internals/example/public/index.html
index 789bd4b6f8a..fb156eecacf 100644
--- a/health/micro-ui/web/micro-ui-internals/example/public/index.html
+++ b/health/micro-ui/web/micro-ui-internals/example/public/index.html
@@ -17,7 +17,7 @@
-
+
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js
index e92335d6581..43d945e19f4 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js
@@ -18,7 +18,7 @@ export const HypothesisValues = memo(({ boundarySelections, hypothesisAssumption
setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") });
return;
}
- if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0))
+ if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.some((item) => item?.length !== 0))
return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") });
setHypothesisAssumptionsList(tempHypothesisList);
};
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js
index 9e0ed13d39b..2977de6d1f0 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js
@@ -707,12 +707,12 @@ const Upload = ({
const boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {};
const mappedToList = resourceMappingData.map((item) => item.mappedTo);
- if (hierarchy.every((item) => !mappedToList.includes(t(item)))) {
+ if (!schemaData.doHierarchyCheckInUploadedData && hierarchy.some((item) => !mappedToList.includes(t(item)))) {
data.features.forEach((feature) => {
- const boundaryCode = feature.properties.boundaryCode;
+ const boundaryCode = feature?.properties?.boundaryCode;
const additionalDetails = {};
for (let i = 0; i < hierarchy.length; i++) {
- if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") {
+ if (boundaryDataAgainstBoundaryCode?.[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode?.[boundaryCode]?.[i] === "") {
additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i];
} else {
additionalDetails[hierarchy[i]] = "";
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js
index ff5cd55208f..6b659e7e2a6 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js
@@ -136,7 +136,7 @@ export const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) =>
// Handles the change in hypothesis value
const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => {
// Checks it the boundary filters at at root level ( given constraints )
- if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0))
+ if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.some((item) => item?.length !== 0))
return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") });
// validating user input
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js
index 32935edba93..c1f158b3283 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js
@@ -384,10 +384,21 @@ export const colorHeaders = async (workbook, headerList1, headerList2, headerLis
}
};
+const addUniqueWorksheet = (workbook, sheetName) => {
+ let uniqueSheetName = sheetName;
+ let counter = 1;
+ while (workbook.getWorksheet(uniqueSheetName)) {
+ uniqueSheetName = `${sheetName} (${counter})`;
+ counter++;
+ }
+ return workbook.addWorksheet(uniqueSheetName);
+};
+
export const formatTemplate = (template, workbook, t) => {
template.forEach(({ sheetName, data }) => {
- // Create a new worksheet with properties
- const worksheet = workbook.addWorksheet(sheetName);
+ // Create a new worksheet with properties and unique name
+ const worksheet = addUniqueWorksheet(workbook, sheetName);
+
let commonColumnIndex = -1;
data?.forEach((row, index) => {
const worksheetRow = worksheet.addRow(row);
From dbdff07e1095640a9dbe541af483cb68afdeb760 Mon Sep 17 00:00:00 2001
From: siddhant-nawale-egov
<162107530+siddhant-nawale-egov@users.noreply.github.com>
Date: Fri, 28 Jun 2024 10:43:26 +0530
Subject: [PATCH 14/83] Microplan handling same sheet name (#979)
* Adding handling of same name sheets
* Update Upload.js
* upgrading css pkg for microplan
* adding optional changing for microplanPreview AggregatesList
---
.../hcm-microplanning/src/components/MicroplanPreview.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js
index 3ca2d08b160..5772033c0a7 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js
@@ -133,7 +133,7 @@ const MicroplanPreview = ({
const schemas = state?.Schemas;
let resourcelist = state?.Resources;
let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates;
- microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data;
+ microplanPreviewAggregatesList = microplanPreviewAggregatesList?.find((item) => item.campaignType === campaignType)?.data;
if (schemas) setValidationSchemas(schemas);
resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data;
if (resourcelist) setResources(resourcelist);
From d0c3c88cb8d60b56c4f3f67fa75bdedd56b2a5b7 Mon Sep 17 00:00:00 2001
From: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com>
Date: Tue, 2 Jul 2024 16:18:01 +0530
Subject: [PATCH 15/83] added changes in the master for draft boundary (#1002)
* added changes in the master for draft boundary
* added dss card changes
---------
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
---
.../micro-ui-internals/example/package.json | 2 +-
.../web/micro-ui-internals/package.json | 2 +-
.../modules/campaign-manager/package.json | 2 +-
.../modules/campaign-manager/src/Module.js | 2 +
.../src/components/DSSCard.js | 209 ++++++++++++++++++
.../src/components/SelectingBoundaries.js | 56 ++++-
.../src/pages/employee/MyCampaign.js | 2 +-
.../src/pages/employee/SetupCampaign.js | 36 +--
health/micro-ui/web/package.json | 2 +-
health/micro-ui/web/workbench/package.json | 2 +-
10 files changed, 291 insertions(+), 24 deletions(-)
create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js
diff --git a/health/micro-ui/web/micro-ui-internals/example/package.json b/health/micro-ui/web/micro-ui-internals/example/package.json
index 2d8c8857b45..e1bd379be46 100644
--- a/health/micro-ui/web/micro-ui-internals/example/package.json
+++ b/health/micro-ui/web/micro-ui-internals/example/package.json
@@ -14,7 +14,7 @@
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"@egovernments/digit-ui-module-core": "1.8.2-beta.2",
"@egovernments/digit-ui-module-utilities": "1.0.1-beta.30",
- "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
"@egovernments/digit-ui-module-campaign-manager": "0.0.1",
"@egovernments/digit-ui-module-hcmmicroplanning": "0.0.1",
diff --git a/health/micro-ui/web/micro-ui-internals/package.json b/health/micro-ui/web/micro-ui-internals/package.json
index d15c627d3ab..9c291afc34b 100644
--- a/health/micro-ui/web/micro-ui-internals/package.json
+++ b/health/micro-ui/web/micro-ui-internals/package.json
@@ -47,7 +47,7 @@
"ajv": "8.12.0",
"lodash": "4.17.21",
"microbundle-crl": "0.13.11",
- "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"react": "17.0.2",
"react-dom": "17.0.2",
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json
index 41e43fdb6fd..6bf03a8c422 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json
@@ -18,7 +18,7 @@
"react-router-dom": "5.3.0"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"@rjsf/core": "5.10.0",
"@rjsf/utils": "5.10.0",
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js
index cc2f33443d4..049aa1dbe03 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js
@@ -24,6 +24,7 @@ import AddProductField from "./components/AddProductField";
import CycleDataPreview from "./components/CycleDataPreview";
import { ErrorBoundary } from "@egovernments/digit-ui-components";
import CampaignResourceDocuments from "./components/CampaignResourceDocuments";
+import { DSSCard } from "./components/DSSCard";
/**
* The CampaignModule function fetches store data based on state code, module code, and language, and
@@ -82,6 +83,7 @@ const componentsToRegister = {
AddProductField,
CycleDataPreview,
CampaignResourceDocuments,
+ DSSCard
};
const overrideHooks = () => {
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js
new file mode 100644
index 00000000000..97ee3a85608
--- /dev/null
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js
@@ -0,0 +1,209 @@
+import { EmployeeModuleCard, ModuleCardFullWidth, DSSIcon } from "@egovernments/digit-ui-react-components";
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+const nationalScreenURLs = {
+ overview: { key: "national-overview", stateKey: "overview", label: "NURT_OVERVIEW", active: true, nActive: true },
+ propertytax: { key: "national-propertytax", stateKey: "propertytax", label: "NURT_PROPERTY_TAX", active: true, nActive: true },
+ tradelicense: { key: "national-tradelicense", stateKey: "tradelicense", label: "NURT_TRADE_LICENCE", active: true, nActive: true },
+ pgr: { key: "national-pgr", stateKey: "pgr", label: "NURT_COMPLAINS", active: true, nActive: true },
+ fsm: { key: "fsm", stateKey: "fsm", label: "CS_HOME_FSM_SERVICES", active: true, nActive: false },
+ mCollect: { key: "national-mcollect", stateKey: "mCollect", label: "NURT_MCOLLECT", active: true, nActive: true },
+ ws: { key: "national-ws", stateKey: "ws", label: "NURT_WATER_SEWERAGE", active: true, nActive: true },
+ obps: { key: "nss-obps", stateKey: "obps", label: "DSS_BUILDING_PERMISSION", active: true, nActive: true },
+ noc: { key: "national-firenoc", stateKey: "noc", label: "NURT_FIRENOC", active: true, nActive: true },
+ bnd: { key: "nss-birth-death", stateKey: "birth-death", label: "BIRTH_AND_DEATH", active: true, nActive: true },
+ faqs: { key: "national-faqs", stateKey: "national-faqs", label: "DSS_FAQS", active: false, nActive: true, others: true },
+ finance: { key: "national-finance", stateKey: "finance", label: "DSS_FINANCE", active: true, nActive: false },
+ about: { key: "national-about", stateKey: "national-about", label: "DSS_ABOUT_DASHBOARD", active: false, nActive: true, others: true },
+};
+
+const healthDSSURLs = {
+ about: { key: "about", stateKey: "about", label: "DSS_ABOUT", active: true },
+ faqs: { key: "faqs", stateKey: "faqs", label: "DSS_FAQS", active: true },
+ calculations: { key: "calculations", stateKey: "calculations", label: "DSS_CALCULATIONS", active: true }
+};
+
+export const checkCurrentScreen = () => {
+ const moduleName = Digit.Utils.dss.getCurrentModuleName();
+ const nationalURLS = Object.keys(nationalScreenURLs).map((key) => nationalScreenURLs[key].key);
+ return nationalURLS.filter(ele=>ele!=="fsm").some((e) => moduleName?.includes(e));
+};
+
+const NDSSCard = () => {
+ const NATADMIN = Digit.UserService.hasAccess("NATADMIN");
+ const { t } = useTranslation();
+
+ if (!NATADMIN) {
+ return null;
+ }
+
+ let links = Object.values(nationalScreenURLs)
+ .filter((ele) => ele["nActive"] === true)
+ .map((obj) => ({
+ label: t(obj?.label),
+ link: `/digit-ui/employee/dss/dashboard/${obj?.key}`,
+ link: obj?.others?`/digit-ui/employee/dss/${obj?.key}`:`/digit-ui/employee/dss/dashboard/${obj?.key}`,
+ }));
+
+ const propsForModuleCard = {
+ headerStyle: { border: "none", height: "48px" },
+ moduleName: t("ACTION_TEST_NATDASHBOARD"),
+ subHeader: t("ACTION_TEST_NATDASHBOARD"),
+ subHeaderLink: `/digit-ui/employee/dss/landing/NURT_DASHBOARD`,
+ className: "employeeCard customEmployeeCard card-home full-width-card full-employee-card-height",
+ links: [...links],
+ };
+ return ;
+};
+
+const DSSCard = () => {
+ const STADMIN = Digit.UserService.hasAccess("STADMIN");
+ const { t } = useTranslation();
+
+ const { data: tenantData } = Digit.Hooks.dss.useMDMS(Digit.ULBService.getStateId(), "tenant", ["tenants"], {
+ select: (data) => {
+ const tenantData = data?.["tenant"]?.["tenants"]?.[0];
+ return tenantData;
+ },
+ enabled: true,
+ });
+
+ const shouldInvokeProjectService = tenantData?.integrateProjectService || false;
+ if (shouldInvokeProjectService) {
+ return ;
+ }
+
+ if (!STADMIN) {
+ return null;
+ }
+
+ let links = Object.values(nationalScreenURLs)
+ .filter((ele) => ele["active"] === true)
+ .map((obj) => ({
+ label: t(obj?.label),
+ link: obj.active ? `/digit-ui/employee/dss/dashboard/${obj?.stateKey}` : `/employee/integration/dss/${obj?.stateKey}`,
+ }));
+
+ const propsForModuleCard = {
+ headerStyle: { border: "none", height: "48px" },
+ moduleName: t("ES_TITLE_DSS"),
+ subHeader: t("ACTION_TEST_SURE_DASHBOARD"),
+ subHeaderLink: `/digit-ui/employee/dss/landing/home`,
+ className: "employeeCard card-home customEmployeeCard full-width-card full-employee-card-height",
+ links: [...links],
+ };
+ return ;
+};
+
+const DynamicDSSCard = () => {
+ const { t } = useTranslation();
+
+ const isNationalSupervisor = Digit.UserService.hasAccess(["NATIONAL_SUPERVISOR"]);
+ const isProvincialSupervisor = Digit.UserService.hasAccess(["PROVINCIAL_SUPERVISOR"]);
+ const isDistrictSupervisor = Digit.UserService.hasAccess(["DISTRICT_SUPERVISOR"]);
+ const isHealthFacilitySupervisor = Digit.UserService.hasAccess(["HEALTH_FACILITY_SUPERVISOR"]);
+ const isCommunitySupervisor = Digit.UserService.hasAccess(["COMMUNITY_SUPERVISOR"]);
+
+ const projectTypes = Digit.SessionStorage.get("projectTypes");
+ const campaignData = Digit.SessionStorage.get("campaigns-info");
+
+ if(!isCommunitySupervisor && !isHealthFacilitySupervisor){
+ if (!campaignData || !projectTypes) {
+ return null;
+ }
+ }
+ const generateLinks = (location, code) => {
+ let links = [];
+ Object.keys(campaignData)?.map((key) => {
+ if (key === "LLIN-Default") {
+ const campaignType = campaignData[key];
+ campaignType.forEach((data) => {
+ const locationParam = data.boundaries?.[location]?.[0];
+ const url = projectTypes?.filter(project => project?.code === "LLIN-Default")[0]?.dashboardUrls?.[code]
+ links.push({
+ label: `${t(key)} - ${Digit.Utils.locale.getTitleHeading(locationParam)}`,
+ link: location === "province" ? `${url}?province=${locationParam}` : `${url}`,
+ });
+ })
+ }
+ });
+ return links;
+ };
+
+ let links = [];
+
+ // if (isNationalSupervisor) {
+ // links = Object.keys(campaignData)?.map((key) => {
+ // return {
+ // label: `${t(`${key}`)} - Mozambique`,
+ // link: projectTypes?.filter(project => project?.code === key)[0]?.dashboardUrls?.["NATIONAL_SUPERVISOR"]
+ // };
+ // });
+ // } else if (isProvincialSupervisor) {
+ // links = generateLinks("province","PROVINCIAL_SUPERVISOR");
+ // } else if (isDistrictSupervisor) {
+ // links = generateLinks("district","DISTRICT_SUPERVISOR");
+ // }
+ // links.push(...Object.values(healthDSSURLs)
+ // .filter((ele) => ele["active"] === true)
+ // .map((obj) => ({
+ // label: t(obj?.label),
+ // link: `/digit-ui/employee/dss/${obj?.stateKey}`
+ // })));
+
+ if (isNationalSupervisor) {
+ links.push({
+ label: t("NATIONAL_DASHBOARD"),
+ link: "/digit-ui/employee/utilities/iframe/elastic/national"
+ });
+ // TODO: To remove these hardcoded urls and generate all of this from mdms config
+ links.push({
+ label: t("NDSS_DASHBOARD"),
+ link: "/digit-ui/employee/dss/landing/national-health-dashboard"
+ })
+ } else if (isProvincialSupervisor) {
+ links.push({
+ label: t("PROVINCIAL_DASHBOARD"),
+ link: "/digit-ui/employee/utilities/iframe/elastic/province?query=true"
+ })
+ links = [...links, ...generateLinks("province","PROVINCIAL_SUPERVISOR")]
+ } else if (isDistrictSupervisor) {
+ links.push({
+ label: t("DISTRICT_DASHBOARD"),
+ link: "/digit-ui/employee/utilities/iframe/elastic/district?query=true"
+ })
+ links = [...links, ...generateLinks("district","DISTRICT_SUPERVISOR")]
+ console.log(links)
+ }
+ else if(isHealthFacilitySupervisor){
+ links.push({
+ label: t("REFERRAL_DASHBOARD"),
+ link: "/digit-ui/employee/utilities/iframe/elastic/hf?query=true"
+ })
+ }
+
+ // if(isNationalSupervisor || isProvincialSupervisor || isDistrictSupervisor){
+ // links.push({
+ // label: t('CUSTOM_REPORTS_LINK'),
+ // link: Digit.SessionStorage.get("initData")?.stateInfo?.customReportsDriveLink,
+ // external: true
+ // })
+
+ // links.push({
+ // label: t('FEEDBACK_LINK'),
+ // link: Digit.SessionStorage.get("initData")?.stateInfo?.feedbackLink,
+ // external: true
+ // })
+ // }
+
+ const propsForModuleCard = {
+ Icon: ,
+ moduleName: t("DSS_CARD_HEADER_DASHBOARD"),
+ links: [...links],
+ };
+
+ return ;
+};
+
+export { DSSCard, NDSSCard };
\ No newline at end of file
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js
index 239cf948ee0..95f90030602 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js
@@ -47,6 +47,60 @@ function SelectingBoundaries({ onSelect, formData, ...props }) {
const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item) => item.parentBoundaryType === lowestHierarchy)?.[0]?.boundaryType;
const searchParams = new URLSearchParams(location.search);
const isDraft = searchParams.get("draft");
+ const draftBoundary = searchParams.get("draftBoundary");
+
+ function updateUrlParams(params) {
+ const url = new URL(window.location.href);
+ Object.entries(params).forEach(([key, value]) => {
+ url.searchParams.set(key, value);
+ });
+ window.history.replaceState({}, "", url);
+ }
+
+ const fetchOptions = async ()=>{
+ setLoaderEnabled(true);
+ const draftSelected = props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData;
+ for (const item of draftSelected) {
+ const code = item?.code;
+ const parent = item?.parent;
+ const boundary = item?.type;
+
+ const childBoundary = props?.props?.dataParams?.hierarchy?.boundaryHierarchy.filter((item) => item.parentBoundaryType === boundary)?.[0]?.boundaryType;
+ const reqCriteriaBoundaryTypeSearch = await Digit.CustomService.getResponse({
+ url: "/boundary-service/boundary-relationships/_search",
+ params: {
+ tenantId: tenantId,
+ hierarchyType: props?.props?.dataParams?.hierarchyType,
+ boundaryType: childBoundary,
+ parent: code,
+ },
+ body: {},
+ });
+ const boundaryTypeData = reqCriteriaBoundaryTypeSearch;
+
+ setBoundaryData((prevBoundaryData) => {
+ const existingData = prevBoundaryData[childBoundary] || [];
+
+ // Check if the entry already exists
+ const updatedData = {
+ ...prevBoundaryData,
+ [childBoundary]: [...existingData.filter((entry) => entry.parentCode !== code), { parentCode: code, boundaryTypeData }],
+ };
+ return updatedData;
+ });
+ }
+ updateUrlParams({ draftBoundary: false });
+ setLoaderEnabled(false);
+ }
+
+ useEffect(()=>{
+ if(isDraft == "true" && props?.props?.dataParams?.hierarchy &&
+ props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData?.length > 0 &&
+ draftBoundary === "true"
+ ){
+ fetchOptions();
+ }
+ },[isDraft,draftBoundary,props?.props?.dataParams?.hierarchy , props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData])
useEffect(() => {
if (!updateBoundary) {
@@ -333,7 +387,7 @@ function SelectingBoundaries({ onSelect, formData, ...props }) {
} else {
// transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType)
const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType);
- if (filteredData.length === 0) {
+ if (filteredData.length === 0 || filteredData.length !== res.length) {
// If no selected data for the particular boundary type, run the transformation logic
transformedRes = res?.map((item) => ({
code: item.code,
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js
index 4e72d9f98e1..d6565de7d04 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js
@@ -47,7 +47,7 @@ const MyCampaign = () => {
history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`);
break;
case "CAMPAIGN_DRAFTS":
- history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&draft=${true}&fetchBoundary=${true}`);
+ history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&draft=${true}&fetchBoundary=${true}&draftBoundary=${true}`);
break;
case "CAMPAIGN_FAILED":
history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`);
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js
index 0dc19dab4d7..847d58ec364 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js
@@ -189,26 +189,28 @@ function groupByTypeRemap(data) {
data.forEach((item) => {
const type = item?.type;
const boundaryType = item?.type;
- const parentCode = item?.parent;
- const obj = {
- parentCode,
- boundaryTypeData: {
- TenantBoundary: [
- {
- boundary: [{ ...item, boundaryType }],
- },
- ],
- },
- };
+ const parentCode = item?.parent !== undefined ? item.parent : null;
- if (result[type]) {
- result[type][0].boundaryTypeData.TenantBoundary[0].boundary.push(item);
- } else {
- result[type] = [obj];
+ if (!result[type]) {
+ result[type] = {};
+ }
+
+ if (!result[type][parentCode]) {
+ result[type][parentCode] = {
+ parentCode,
+ boundaryTypeData: {
+ TenantBoundary: [
+ {
+ boundary: [],
+ },
+ ],
+ },
+ };
}
- });
- return result;
+ const targetBoundaryArray = result[type][parentCode].boundaryTypeData.TenantBoundary[0].boundary;
+ targetBoundaryArray.push({ ...item, boundaryType });
+ });
}
// Example usage:
diff --git a/health/micro-ui/web/package.json b/health/micro-ui/web/package.json
index e90ab5a52ba..7336d39215c 100644
--- a/health/micro-ui/web/package.json
+++ b/health/micro-ui/web/package.json
@@ -18,7 +18,7 @@
"@egovernments/digit-ui-module-workbench": "1.0.1-beta.16",
"@egovernments/digit-ui-module-core": "1.8.2-beta.2",
"@egovernments/digit-ui-module-hrms": "1.8.0-beta.2",
- "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"@egovernments/digit-ui-module-dss": "1.8.0-beta",
"@egovernments/digit-ui-module-common": "1.8.0-beta",
diff --git a/health/micro-ui/web/workbench/package.json b/health/micro-ui/web/workbench/package.json
index 7cc60ef7bff..e849ea199f4 100644
--- a/health/micro-ui/web/workbench/package.json
+++ b/health/micro-ui/web/workbench/package.json
@@ -17,7 +17,7 @@
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"@egovernments/digit-ui-module-core": "1.8.2-beta.2",
"@egovernments/digit-ui-module-utilities": "1.0.1-beta.30",
- "@egovernments/digit-ui-react-components": "1.8.2-beta.6",
+ "@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
"@egovernments/digit-ui-module-campaign-manager": "0.0.1",
"babel-loader": "8.1.0",
From 1f02a1724b9db8dd98df18124d2cde9fc46109f2 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Tue, 2 Jul 2024 16:46:48 +0530
Subject: [PATCH 16/83] updated docker file
---
health/micro-ui/web/docker/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/docker/Dockerfile b/health/micro-ui/web/docker/Dockerfile
index 8e9b173bb85..933f759cb11 100644
--- a/health/micro-ui/web/docker/Dockerfile
+++ b/health/micro-ui/web/docker/Dockerfile
@@ -11,7 +11,7 @@ RUN ls -lah
#RUN node web/envs.js
RUN cd web/ \
- && ./install-deps.sh \
+ && chmod +x install-deps.sh \
&& yarn install \
&& yarn build:webpack
From ddecfa9e46eee176b394b25a0fb74313a71bd407 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Tue, 2 Jul 2024 16:56:24 +0530
Subject: [PATCH 17/83] updated workbench docker
---
health/micro-ui/web/workbench/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/workbench/Dockerfile b/health/micro-ui/web/workbench/Dockerfile
index 31b3912759b..62a665d09fd 100644
--- a/health/micro-ui/web/workbench/Dockerfile
+++ b/health/micro-ui/web/workbench/Dockerfile
@@ -14,7 +14,7 @@ RUN cd web/ \
&& node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \
&& node -e 'console.log("core only")' \
&& cd workbench/ \
- && ./install-deps.sh \
+ && chmod +x ./install-deps.sh \
&& cd ../ \
&& yarn install \
&& yarn build:webpack
From f48f0440928e16d7fead59e93f2f4922ffb907da Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Tue, 2 Jul 2024 19:00:17 +0530
Subject: [PATCH 18/83] updated the workspace
---
health/micro-ui/web/workbench/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/workbench/package.json b/health/micro-ui/web/workbench/package.json
index e849ea199f4..74ae5211b23 100644
--- a/health/micro-ui/web/workbench/package.json
+++ b/health/micro-ui/web/workbench/package.json
@@ -8,7 +8,7 @@
"node": ">=14"
},
"workspaces": [
- "micro-ui-internals/packages/modules/*"
+ "micro-ui-internals/packages/modules/campaign-manager"
],
"homepage": "/workbench-ui",
"dependencies": {
From 05aa759ec8a61e73d0a8ae1c2c4648db1972cd10 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Wed, 3 Jul 2024 13:40:08 +0530
Subject: [PATCH 19/83] Update webpack.config.js
---
micro-ui/web/webpack.config.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/micro-ui/web/webpack.config.js b/micro-ui/web/webpack.config.js
index 5f3dc46967a..c19e631fe01 100644
--- a/micro-ui/web/webpack.config.js
+++ b/micro-ui/web/webpack.config.js
@@ -11,6 +11,7 @@ module.exports = {
rules: [
{
test: /\.(js)$/,
+ exclude: /node_modules/,
use: ["babel-loader"],
},
{
@@ -22,7 +23,7 @@ module.exports = {
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "build"),
- publicPath: "/digit-ui/",
+ publicPath: "/workbench-ui/",
},
optimization: {
splitChunks: {
From 43e2f4095be69961d9bf89e8c1a5151cc74f2535 Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Wed, 3 Jul 2024 14:27:39 +0530
Subject: [PATCH 20/83] Update buildWorkbenchUI.yml
---
.github/workflows/buildWorkbenchUI.yml | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/buildWorkbenchUI.yml b/.github/workflows/buildWorkbenchUI.yml
index 53ad39bacf7..e6142e9d80f 100644
--- a/.github/workflows/buildWorkbenchUI.yml
+++ b/.github/workflows/buildWorkbenchUI.yml
@@ -1,13 +1,9 @@
name: Digit Admin Console Build workflow
on:
push:
- branches:
- - campaign
+ branches: [ 'develop','campaign' ,'microplan','master']
paths:
- 'health/micro-ui/web/micro-ui-internals/**'
- pull_request:
- branches:
- - campaign
workflow_dispatch:
jobs:
docker_image-build:
@@ -61,4 +57,4 @@ jobs:
docker build -t workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} -f web/workbench/Dockerfile .
docker tag workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }}
docker push egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }}
- working-directory: micro-ui
+ working-directory: health/micro-ui
From 22ad147d049df471dc3f3e1d5bb135f06342eb4f Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Wed, 3 Jul 2024 14:28:13 +0530
Subject: [PATCH 21/83] Update package.json
---
health/micro-ui/web/micro-ui-internals/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/micro-ui-internals/package.json b/health/micro-ui/web/micro-ui-internals/package.json
index 9c291afc34b..87102afe2ff 100644
--- a/health/micro-ui/web/micro-ui-internals/package.json
+++ b/health/micro-ui/web/micro-ui-internals/package.json
@@ -1,6 +1,6 @@
{
"name": "egovernments",
- "version": "1.0.0",
+ "version": "0.1.0",
"main": "index.js",
"workspaces": [
"example",
From cbf898e948e7721e4212652d58908c94ffcded1a Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Wed, 3 Jul 2024 14:35:44 +0530
Subject: [PATCH 22/83] updated the log
---
health/micro-ui/web/workbench/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/workbench/Dockerfile b/health/micro-ui/web/workbench/Dockerfile
index 62a665d09fd..00e14cd19b1 100644
--- a/health/micro-ui/web/workbench/Dockerfile
+++ b/health/micro-ui/web/workbench/Dockerfile
@@ -12,7 +12,7 @@ RUN ls -lah
#RUN node web/envs.js
RUN cd web/ \
&& node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \
- && node -e 'console.log("core only")' \
+ && node -e 'console.log("health-workbench only")' \
&& cd workbench/ \
&& chmod +x ./install-deps.sh \
&& cd ../ \
From 0828c3cbd040077e7aeb3f4c443d7625843c88ab Mon Sep 17 00:00:00 2001
From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
Date: Wed, 3 Jul 2024 14:43:11 +0530
Subject: [PATCH 23/83] Update Dockerfile
---
health/micro-ui/web/workbench/Dockerfile | 1 +
1 file changed, 1 insertion(+)
diff --git a/health/micro-ui/web/workbench/Dockerfile b/health/micro-ui/web/workbench/Dockerfile
index 00e14cd19b1..e71bf99a826 100644
--- a/health/micro-ui/web/workbench/Dockerfile
+++ b/health/micro-ui/web/workbench/Dockerfile
@@ -15,6 +15,7 @@ RUN cd web/ \
&& node -e 'console.log("health-workbench only")' \
&& cd workbench/ \
&& chmod +x ./install-deps.sh \
+ && ./install-deps.sh \
&& cd ../ \
&& yarn install \
&& yarn build:webpack
From 49952744601b172212ffa8c951d4f6291b0f4969 Mon Sep 17 00:00:00 2001
From: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com>
Date: Wed, 3 Jul 2024 18:48:23 +0530
Subject: [PATCH 24/83] Added Dashboard Icon & Commented harcoded check (#1010)
Co-authored-by: nabeelmd-eGov
---
.../campaign-manager/src/components/DSSCard.js | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js
index 97ee3a85608..a099d4a18ce 100644
--- a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js
+++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DSSCard.js
@@ -1,4 +1,4 @@
-import { EmployeeModuleCard, ModuleCardFullWidth, DSSIcon } from "@egovernments/digit-ui-react-components";
+import { EmployeeModuleCard, ModuleCardFullWidth, SVG } from "@egovernments/digit-ui-react-components";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -108,11 +108,12 @@ const DynamicDSSCard = () => {
const projectTypes = Digit.SessionStorage.get("projectTypes");
const campaignData = Digit.SessionStorage.get("campaigns-info");
- if(!isCommunitySupervisor && !isHealthFacilitySupervisor){
- if (!campaignData || !projectTypes) {
- return null;
- }
- }
+ // if (!isCommunitySupervisor && !isHealthFacilitySupervisor) {
+ // if (!campaignData || !projectTypes) {
+ // return null;
+ // }
+ // }
+
const generateLinks = (location, code) => {
let links = [];
Object.keys(campaignData)?.map((key) => {
@@ -198,7 +199,7 @@ const DynamicDSSCard = () => {
// }
const propsForModuleCard = {
- Icon: ,
+ Icon: ,
moduleName: t("DSS_CARD_HEADER_DASHBOARD"),
links: [...links],
};
From dc7b6d2bc222dc9a833a3d65473d0f1fcb52189c Mon Sep 17 00:00:00 2001
From: Nipun Arora
Date: Tue, 9 Jul 2024 14:56:29 +0530
Subject: [PATCH 25/83] Updated the Utilites package updated for Kibana
dashboard integration (#1020)
---
health/micro-ui/web/workbench/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/workbench/package.json b/health/micro-ui/web/workbench/package.json
index 74ae5211b23..06ca9a82dd4 100644
--- a/health/micro-ui/web/workbench/package.json
+++ b/health/micro-ui/web/workbench/package.json
@@ -16,7 +16,7 @@
"@egovernments/digit-ui-module-workbench": "1.0.2-beta.3",
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"@egovernments/digit-ui-module-core": "1.8.2-beta.2",
- "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30",
+ "@egovernments/digit-ui-module-utilities": "1.0.1-beta.33",
"@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
"@egovernments/digit-ui-module-campaign-manager": "0.0.1",
From 6c6676347251f2d807872b70c27786f85211b2ec Mon Sep 17 00:00:00 2001
From: Nipun Arora
Date: Tue, 9 Jul 2024 16:23:07 +0530
Subject: [PATCH 26/83] Update package.json (#1023)
---
health/micro-ui/web/workbench/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/workbench/package.json b/health/micro-ui/web/workbench/package.json
index 06ca9a82dd4..17220047a59 100644
--- a/health/micro-ui/web/workbench/package.json
+++ b/health/micro-ui/web/workbench/package.json
@@ -16,7 +16,7 @@
"@egovernments/digit-ui-module-workbench": "1.0.2-beta.3",
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"@egovernments/digit-ui-module-core": "1.8.2-beta.2",
- "@egovernments/digit-ui-module-utilities": "1.0.1-beta.33",
+ "@egovernments/digit-ui-module-utilities": "1.0.1-beta.34",
"@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
"@egovernments/digit-ui-module-campaign-manager": "0.0.1",
From 11a65fc21731ecf2679e32dfa063d23fb11ecaaa Mon Sep 17 00:00:00 2001
From: Nipun Arora
Date: Tue, 9 Jul 2024 17:05:20 +0530
Subject: [PATCH 27/83] Update package.json (#1025)
---
health/micro-ui/web/workbench/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/health/micro-ui/web/workbench/package.json b/health/micro-ui/web/workbench/package.json
index 17220047a59..2c5a8d264e9 100644
--- a/health/micro-ui/web/workbench/package.json
+++ b/health/micro-ui/web/workbench/package.json
@@ -16,7 +16,7 @@
"@egovernments/digit-ui-module-workbench": "1.0.2-beta.3",
"@egovernments/digit-ui-components": "0.0.2-beta.1",
"@egovernments/digit-ui-module-core": "1.8.2-beta.2",
- "@egovernments/digit-ui-module-utilities": "1.0.1-beta.34",
+ "@egovernments/digit-ui-module-utilities": "1.0.1-beta.35",
"@egovernments/digit-ui-react-components": "1.8.2-beta.10",
"@egovernments/digit-ui-module-hcmworkbench":"0.0.38",
"@egovernments/digit-ui-module-campaign-manager": "0.0.1",
From 0b95620678d14b208b655d1f68138caf7b1e7171 Mon Sep 17 00:00:00 2001
From: aaradhya-egov <137176709+aaradhya-egov@users.noreply.github.com>
Date: Wed, 10 Jul 2024 12:31:50 +0530
Subject: [PATCH 28/83] Added Environment support to use mdms v1 or v2 based on
config and Workbench to have schema code in action url (#1035)
* added logic to handle mdms-v2 api
* Update urls.js
* Update package.json
---------
Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com>
---
.../web/micro-ui-internals/example/package.json | 4 ++--
micro-ui/web/micro-ui-internals/package.json | 1 -
.../packages/libraries/README.md | 1 +
.../packages/libraries/package.json | 2 +-
.../src/services/atoms/ApiCacheService.js | 11 +++++++++++
.../packages/libraries/src/services/atoms/urls.js | 5 ++++-
.../packages/modules/workbench/README.md | 1 +
.../packages/modules/workbench/package.json | 2 +-
.../modules/workbench/src/hooks/workbench.js | 6 +++++-
.../workbench/src/pages/employee/MDMSAddV2.js | 2 +-
.../workbench/src/pages/employee/MDMSEdit.js | 2 +-
.../packages/modules/workbench/src/utils/index.js | 14 +++++++++++++-
micro-ui/web/package.json | 4 ++--
13 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/micro-ui/web/micro-ui-internals/example/package.json b/micro-ui/web/micro-ui-internals/example/package.json
index f8b03e3697b..78ab7f1db18 100644
--- a/micro-ui/web/micro-ui-internals/example/package.json
+++ b/micro-ui/web/micro-ui-internals/example/package.json
@@ -9,8 +9,8 @@
"start": "react-scripts start"
},
"devDependencies": {
- "@egovernments/digit-ui-libraries": "1.8.1",
- "@egovernments/digit-ui-module-workbench": "1.0.1",
+ "@egovernments/digit-ui-libraries": "1.8.2",
+ "@egovernments/digit-ui-module-workbench": "1.0.2",
"@egovernments/digit-ui-module-dss": "1.8.0",
"@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-common": "1.8.0",
diff --git a/micro-ui/web/micro-ui-internals/package.json b/micro-ui/web/micro-ui-internals/package.json
index a21133ca9b0..3ae6d073f40 100644
--- a/micro-ui/web/micro-ui-internals/package.json
+++ b/micro-ui/web/micro-ui-internals/package.json
@@ -51,7 +51,6 @@
"resolutions": {
"**/@babel/runtime": "7.20.1",
"**/babel-preset-react-app": "10.0.0",
- "**/ajv": "8.11.2",
"fast-uri":"2.1.0"
},
"devDependencies": {
diff --git a/micro-ui/web/micro-ui-internals/packages/libraries/README.md b/micro-ui/web/micro-ui-internals/packages/libraries/README.md
index 45dd849b233..28506d91de7 100644
--- a/micro-ui/web/micro-ui-internals/packages/libraries/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/libraries/README.md
@@ -55,6 +55,7 @@ export default App;
### Changelog
```bash
+1.8.2 Added mdms-v2 url & mdms v1 globalconfig MDMS_V1_CONTEXT_PATH to support both v1 and v2
1.8.1 Added logoutRedirectURL for mgramseva workbench
1.8.0 Released as part of workbench v1.0
```
diff --git a/micro-ui/web/micro-ui-internals/packages/libraries/package.json b/micro-ui/web/micro-ui-internals/packages/libraries/package.json
index a8da4ae0bd5..78d052c08b7 100644
--- a/micro-ui/web/micro-ui-internals/packages/libraries/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/libraries/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-libraries",
- "version": "1.8.1",
+ "version": "1.8.2",
"main": "dist/index.js",
"module": "dist/index.modern.js",
"source": "src/index.js",
diff --git a/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/ApiCacheService.js b/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/ApiCacheService.js
index 31bbe25c694..96613e9b6ba 100644
--- a/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/ApiCacheService.js
+++ b/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/ApiCacheService.js
@@ -24,6 +24,17 @@ const defaultApiCachingSettings = [
},
],
},
+ {
+ serviceName: "mdms-v2",
+ cacheTimeInSecs: 3600,
+ debounceTimeInMS: 100,
+ moduleSettings: [
+ {
+ moduleName: "FSM",
+ cacheTimeInSecs: 7200,
+ },
+ ],
+ },
];
const storageKey = "cachingService";
diff --git a/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/urls.js b/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/urls.js
index 8f48cc54f81..474f4a5fc17 100644
--- a/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/urls.js
+++ b/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/urls.js
@@ -1,5 +1,8 @@
+const mdmsV1Path = window?.globalConfigs?.getConfig("MDMS_V1_CONTEXT_PATH") || "egov-mdms-service";
+const mdmsV2Path = window?.globalConfigs?.getConfig("MDMS_V2_CONTEXT_PATH") || "mdms-v2";
const Urls = {
- MDMS: `/egov-mdms-service/v1/_search`,
+ MDMS_V2:`/${mdmsV2Path}/v1/_search`,
+ MDMS: `/${mdmsV1Path}/v1/_search`,
WorkFlow: `/egov-workflow-v2/egov-wf/businessservice/_search`,
WorkFlowProcessSearch: `/egov-workflow-v2/egov-wf/process/_search`,
localization: `/localization/messages/v1/_search`,
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md b/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
index e802d4b0c47..6df0870f723 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
@@ -110,6 +110,7 @@ https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd5
### Changelog
```bash
+1.0.2 If you dont want to use modulename and mastername in mdms-v2 data create and update api use {MDMS_SCHEMACODE_INACTION} this constant in global config and set it as false
1.0.1 Fixes related to the limits
1.0.0 Workbench v1.0 release
1.0.0-beta workbench base version beta release
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
index ffdf9dd35a7..2da8381be23 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-module-workbench",
- "version": "1.0.1",
+ "version": "1.0.2",
"description": "Workbench",
"main": "dist/index.js",
"module": "dist/index.modern.js",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js
index cab3ec1ad0b..5ff5a1ac5fa 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js
@@ -71,4 +71,8 @@ const getMDMSContextPath = () => {
return window?.globalConfigs?.getConfig("MDMS_CONTEXT_PATH") || "mdms-v2";
};
-export { UICreateConfigGenerator, getMDMSContextPath };
+const isSchemaCodeInMDMSAction = () => {
+ return window?.globalConfigs?.getConfig("MDMS_SCHEMACODE_INACTION") || "true";
+};
+
+export { UICreateConfigGenerator, getMDMSContextPath,isSchemaCodeInMDMSAction };
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js
index 0b89efd0b94..3fc6d8703a7 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js
@@ -76,7 +76,7 @@ const MDMSAdd = ({ defaultFormData, updatesToUISchema, screenType = "add", onVie
},
};
const reqCriteriaAdd = {
- url: api ? api?.url : `/${Digit.Hooks.workbench.getMDMSContextPath()}/v2/_create/${moduleName}.${masterName}`,
+ url: api ? api?.url : Digit.Utils.workbench.getMDMSActionURL(moduleName,masterName,"create"),
params: {},
body: { ...body },
config: {
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js
index 4f334245eaa..12c5b8b4dba 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js
@@ -70,7 +70,7 @@ const MDMSEdit = ({...props}) => {
const reqCriteriaUpdate = {
- url: `/${Digit.Hooks.workbench.getMDMSContextPath()}/v2/_update/${moduleName}.${masterName}`,
+ url: Digit.Utils.workbench.getMDMSActionURL(moduleName,masterName,"update"),
params: {},
body: {
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/utils/index.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/utils/index.js
index 24a0ff92a27..c6603f9f749 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/utils/index.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/utils/index.js
@@ -268,4 +268,16 @@ const postProcessData = (data = {}, schema = {}) => {
return { ...data };
};
-export default { getConfig, getMDMSLabel, getFormattedData, getUpdatedPath, updateTitleToLocalisationCodeForObject, preProcessData, postProcessData };
+
+const getMDMSActionURL = (moduleName, masterName, action) => {
+ let url = `/${Digit.Hooks.workbench.getMDMSContextPath()}/v2/_${action}`;
+ if (Digit.Hooks.workbench.isSchemaCodeInMDMSAction()) {
+ url += `/${moduleName}.${masterName}`;
+ }
+ return url;
+}
+
+
+
+
+export default { getConfig, getMDMSLabel, getFormattedData, getUpdatedPath, updateTitleToLocalisationCodeForObject, preProcessData, postProcessData,getMDMSActionURL };
diff --git a/micro-ui/web/package.json b/micro-ui/web/package.json
index 211c97047b6..34de6d31efb 100644
--- a/micro-ui/web/package.json
+++ b/micro-ui/web/package.json
@@ -14,8 +14,8 @@
],
"homepage": "/digit-ui",
"dependencies": {
- "@egovernments/digit-ui-libraries": "1.8.1",
- "@egovernments/digit-ui-module-workbench": "1.0.1",
+ "@egovernments/digit-ui-libraries": "1.8.2",
+ "@egovernments/digit-ui-module-workbench": "1.0.2",
"@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-hrms": "1.8.0",
"@egovernments/digit-ui-react-components": "1.8.1",
From b5829d4ce7b947665fe44b5d158725ffa6d1fd97 Mon Sep 17 00:00:00 2001
From: aaradhya-egov <137176709+aaradhya-egov@users.noreply.github.com>
Date: Wed, 10 Jul 2024 12:41:40 +0530
Subject: [PATCH 29/83] changed version of workbench and libraries (#1036)
---
micro-ui/web/core/package.json | 4 ++--
micro-ui/web/workbench/package.json | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/micro-ui/web/core/package.json b/micro-ui/web/core/package.json
index 52eabb1f64c..aa5589bd3c9 100644
--- a/micro-ui/web/core/package.json
+++ b/micro-ui/web/core/package.json
@@ -14,8 +14,8 @@
],
"homepage": "/core-ui",
"dependencies": {
- "@egovernments/digit-ui-libraries": "1.8.1",
- "@egovernments/digit-ui-module-workbench": "1.0.1",
+ "@egovernments/digit-ui-libraries": "1.8.2",
+ "@egovernments/digit-ui-module-workbench": "1.0.2",
"@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-pgr": "1.8.0",
"@egovernments/digit-ui-react-components": "1.8.1",
diff --git a/micro-ui/web/workbench/package.json b/micro-ui/web/workbench/package.json
index fa62e0594ee..af19c3578e6 100644
--- a/micro-ui/web/workbench/package.json
+++ b/micro-ui/web/workbench/package.json
@@ -14,8 +14,8 @@
],
"homepage": "/workbench-ui",
"dependencies": {
- "@egovernments/digit-ui-libraries": "1.8.1",
- "@egovernments/digit-ui-module-workbench": "1.0.1",
+ "@egovernments/digit-ui-libraries": "1.8.2",
+ "@egovernments/digit-ui-module-workbench": "1.0.2",
"@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-react-components": "1.8.1",
"@egovernments/digit-ui-module-utilities": "1.0.0",
From 96e6dce10ad9527bcd502a2ad2b5ca2359a2c486 Mon Sep 17 00:00:00 2001
From: aaradhya-egov <137176709+aaradhya-egov@users.noreply.github.com>
Date: Wed, 10 Jul 2024 15:10:45 +0530
Subject: [PATCH 30/83] changed version and fix config issue (#1039)
---
micro-ui/web/micro-ui-internals/example/package.json | 2 +-
.../packages/modules/workbench/README.md | 1 +
.../packages/modules/workbench/package.json | 2 +-
.../packages/modules/workbench/src/hooks/index.js | 7 +++----
.../packages/modules/workbench/src/hooks/workbench.js | 2 +-
.../modules/workbench/src/pages/employee/MDMSEdit.js | 2 +-
.../modules/workbench/src/pages/employee/MDMSView.js | 4 ++--
7 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/micro-ui/web/micro-ui-internals/example/package.json b/micro-ui/web/micro-ui-internals/example/package.json
index 78ab7f1db18..bd701f18956 100644
--- a/micro-ui/web/micro-ui-internals/example/package.json
+++ b/micro-ui/web/micro-ui-internals/example/package.json
@@ -10,7 +10,7 @@
},
"devDependencies": {
"@egovernments/digit-ui-libraries": "1.8.2",
- "@egovernments/digit-ui-module-workbench": "1.0.2",
+ "@egovernments/digit-ui-module-workbench": "1.0.3",
"@egovernments/digit-ui-module-dss": "1.8.0",
"@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-common": "1.8.0",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md b/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
index 6df0870f723..7933cf66cd2 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
@@ -110,6 +110,7 @@ https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd5
### Changelog
```bash
+1.0.3 Changed url in view and edit screen of workbench and fix some bug
1.0.2 If you dont want to use modulename and mastername in mdms-v2 data create and update api use {MDMS_SCHEMACODE_INACTION} this constant in global config and set it as false
1.0.1 Fixes related to the limits
1.0.0 Workbench v1.0 release
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
index 2da8381be23..75a097c5ee8 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-module-workbench",
- "version": "1.0.2",
+ "version": "1.0.3",
"description": "Workbench",
"main": "dist/index.js",
"module": "dist/index.modern.js",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/index.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/index.js
index 1431e683687..38ef7213968 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/index.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/index.js
@@ -1,5 +1,5 @@
import { logoutV1 } from "./logout";
-import { UICreateConfigGenerator , getMDMSContextPath } from "./workbench";
+import { UICreateConfigGenerator , getMDMSContextPath, isSchemaCodeInMDMSAction} from "./workbench";
import utils from "../utils";
import useLocalisationSearch from "./useLocalisationSearch";
@@ -8,9 +8,8 @@ const UserService = {
};
const workbench = {
- UICreateConfigGenerator,
- useLocalisationSearch,
- getMDMSContextPath
+ UICreateConfigGenerator , getMDMSContextPath, isSchemaCodeInMDMSAction,
+ useLocalisationSearch
};
const contracts = {};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js
index 5ff5a1ac5fa..31891af2e5f 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/hooks/workbench.js
@@ -72,7 +72,7 @@ const getMDMSContextPath = () => {
};
const isSchemaCodeInMDMSAction = () => {
- return window?.globalConfigs?.getConfig("MDMS_SCHEMACODE_INACTION") || "true";
+ return window?.globalConfigs?.getConfig("MDMS_SCHEMACODE_INACTION")===false?false : true;
};
export { UICreateConfigGenerator, getMDMSContextPath,isSchemaCodeInMDMSAction };
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js
index 12c5b8b4dba..a6bb74bb6a3 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSEdit.js
@@ -104,7 +104,7 @@ const MDMSEdit = ({...props}) => {
mutation.mutate(
{
- url:`/${Digit.Hooks.workbench.getMDMSContextPath()}/v2/_update/${moduleName}.${masterName}`,
+ url:reqCriteriaUpdate?.url,
params: {},
body: {
Mdms:{
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSView.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSView.js
index c29a48c8d00..08eba3476a2 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSView.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSView.js
@@ -60,7 +60,7 @@ const MDMSView = ({...props}) => {
const { isLoading, data, isFetching,refetch,revalidate } = Digit.Hooks.useCustomAPIHook(reqCriteria);
const reqCriteriaUpdate = {
- url: `/${Digit.Hooks.workbench.getMDMSContextPath()}/v2/_update/${moduleName}.${masterName}`,
+ url: Digit.Utils.workbench.getMDMSActionURL(moduleName,masterName,"update"),
params: {},
body: {
@@ -94,7 +94,7 @@ const MDMSView = ({...props}) => {
mutation.mutate(
{
- url:`/${Digit.Hooks.workbench.getMDMSContextPath()}/v2/_update/${moduleName}.${masterName}`,
+ url:reqCriteriaUpdate?.url,
params: {},
body: {
Mdms:{
From 5ce4b595112fb7be41060d97136e808abd2baf3b Mon Sep 17 00:00:00 2001
From: Swathi-eGov <137176788+Swathi-eGov@users.noreply.github.com>
Date: Fri, 12 Jul 2024 11:55:30 +0530
Subject: [PATCH 31/83] Workbench Enahancement to have referenced dropdown as
popup where data is large added search feature changes (#1052)
* added search feature changes
* updated css readme
* updated versions
---
micro-ui/web/core/inter-package.json | 2 +-
micro-ui/web/core/package.json | 4 +-
.../micro-ui-internals/example/package.json | 4 +-
micro-ui/web/micro-ui-internals/package.json | 2 +-
.../micro-ui-internals/packages/css/README.md | 1 +
.../packages/css/package.json | 2 +-
.../src/digitv2/pages/employee/workbench.scss | 427 ++++++++++++++++++
.../packages/modules/core/package.json | 2 +-
.../packages/modules/dss/package.json | 2 +-
.../packages/modules/pgr/package.json | 2 +-
.../packages/modules/utilities/package.json | 2 +-
.../packages/modules/workbench/README.md | 1 +
.../packages/modules/workbench/package.json | 4 +-
.../workbench/src/components/DigitJSONForm.js | 28 +-
.../workbench/src/components/MultiSelect.js | 246 +++++++++-
.../workbench/src/components/MultiSelectV2.js | 77 ++++
.../workbench/src/configs/UICustomizations.js | 151 ++++++-
.../src/configs/searchMDMSConfigPopup.js | 139 ++++++
.../src/pages/employee/MDMSSearchv2Popup.js | 221 +++++++++
.../packages/react-components/README.md | 1 +
.../packages/react-components/package.json | 2 +-
.../src/atoms/SearchComponent.js | 47 +-
micro-ui/web/package.json | 4 +-
micro-ui/web/public/index.html | 2 +-
micro-ui/web/workbench/inter-package.json | 2 +-
micro-ui/web/workbench/package.json | 4 +-
26 files changed, 1302 insertions(+), 77 deletions(-)
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelectV2.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/searchMDMSConfigPopup.js
create mode 100644 micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSSearchv2Popup.js
diff --git a/micro-ui/web/core/inter-package.json b/micro-ui/web/core/inter-package.json
index 6d73a849610..319769d675e 100644
--- a/micro-ui/web/core/inter-package.json
+++ b/micro-ui/web/core/inter-package.json
@@ -65,7 +65,7 @@
"dependencies": {
"lodash": "4.17.21",
"microbundle-crl": "0.13.11",
- "@egovernments/digit-ui-react-components": "1.8.1",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-hook-form": "6.15.8",
diff --git a/micro-ui/web/core/package.json b/micro-ui/web/core/package.json
index aa5589bd3c9..d605cffcf13 100644
--- a/micro-ui/web/core/package.json
+++ b/micro-ui/web/core/package.json
@@ -15,10 +15,10 @@
"homepage": "/core-ui",
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.2",
- "@egovernments/digit-ui-module-workbench": "1.0.2",
+ "@egovernments/digit-ui-module-workbench": "1.0.4",
"@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-pgr": "1.8.0",
- "@egovernments/digit-ui-react-components": "1.8.1",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"babel-loader": "8.1.0",
"clean-webpack-plugin": "4.0.0",
diff --git a/micro-ui/web/micro-ui-internals/example/package.json b/micro-ui/web/micro-ui-internals/example/package.json
index bd701f18956..dd1046da212 100644
--- a/micro-ui/web/micro-ui-internals/example/package.json
+++ b/micro-ui/web/micro-ui-internals/example/package.json
@@ -10,7 +10,7 @@
},
"devDependencies": {
"@egovernments/digit-ui-libraries": "1.8.2",
- "@egovernments/digit-ui-module-workbench": "1.0.3",
+ "@egovernments/digit-ui-module-workbench": "1.0.4",
"@egovernments/digit-ui-module-dss": "1.8.0",
"@egovernments/digit-ui-module-core": "1.8.2",
"@egovernments/digit-ui-module-common": "1.8.0",
@@ -18,7 +18,7 @@
"@egovernments/digit-ui-module-hrms": "1.8.0",
"@egovernments/digit-ui-module-utilities": "1.0.0",
"@egovernments/digit-ui-module-engagement": "1.8.0",
- "@egovernments/digit-ui-react-components": "1.8.1",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"http-proxy-middleware": "^1.0.5",
"react": "17.0.2",
"react-dom": "17.0.2",
diff --git a/micro-ui/web/micro-ui-internals/package.json b/micro-ui/web/micro-ui-internals/package.json
index 3ae6d073f40..b67548f679d 100644
--- a/micro-ui/web/micro-ui-internals/package.json
+++ b/micro-ui/web/micro-ui-internals/package.json
@@ -66,7 +66,7 @@
"dependencies": {
"lodash": "4.17.21",
"microbundle-crl": "0.13.11",
- "@egovernments/digit-ui-react-components": "1.8.1",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-hook-form": "6.15.8",
diff --git a/micro-ui/web/micro-ui-internals/packages/css/README.md b/micro-ui/web/micro-ui-internals/packages/css/README.md
index 777caa2bbfd..763e35085c0 100644
--- a/micro-ui/web/micro-ui-internals/packages/css/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/css/README.md
@@ -42,6 +42,7 @@ frontend/micro-ui/web/public/index.html
### Changelog
```bash
+1.8.1 added workbench releated css for popup
1.8.0 Workbench v1.0
1.8.0-beta.13 fixed the login text styling issue
1.8.0-beta.1 styles for login dropdown and homepage dropdowns
diff --git a/micro-ui/web/micro-ui-internals/packages/css/package.json b/micro-ui/web/micro-ui-internals/packages/css/package.json
index 6156df88825..76e9ccaaad4 100644
--- a/micro-ui/web/micro-ui-internals/packages/css/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/css/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-css",
- "version": "1.8.0",
+ "version": "1.8.1",
"license": "MIT",
"main": "dist/index.css",
"author": "Jagankumar ",
diff --git a/micro-ui/web/micro-ui-internals/packages/css/src/digitv2/pages/employee/workbench.scss b/micro-ui/web/micro-ui-internals/packages/css/src/digitv2/pages/employee/workbench.scss
index 2e6f685f512..fd08bcac8aa 100644
--- a/micro-ui/web/micro-ui-internals/packages/css/src/digitv2/pages/employee/workbench.scss
+++ b/micro-ui/web/micro-ui-internals/packages/css/src/digitv2/pages/employee/workbench.scss
@@ -613,3 +613,430 @@ button:hover {
.popup-header-fix {
margin-top: -0.5rem !important;
}
+
+
+.option-details {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 999;
+ border: 1px solid #D6D5D4;
+ /* Border color and width */
+ background-color: #fff;
+ padding: 2em;
+ border-radius: 5px;
+ display: flex;
+ flex-direction: column;
+ width: 40%;
+ min-width: 300px;
+
+
+ .detail-container {
+ margin-top: 20px;
+ overflow-y: auto;
+ max-height: 50vh;
+
+ .detail-item {
+ margin: 10px 0;
+ display: flex;
+ align-items: center;
+
+ .key {
+ flex-basis: 30%;
+ margin-right: 10px;
+ font-weight: bold;
+ text-align: start !important;
+ }
+
+
+
+ .value {
+ flex-basis: 70%;
+ text-align: start !important;
+ }
+
+ }
+
+
+
+ .separator {
+ margin: 10px 0;
+ border: none;
+ border-bottom: 1px solid #ccc;
+ }
+
+
+
+ .view-more {
+ display: flex;
+ justify-content: flex-start;
+ margin-top: 1.5em;
+ }
+
+
+
+ .select {
+ display: flex;
+ justify-content: flex-start;
+ margin-top: 1.5em;
+ }
+
+ }
+
+}
+
+
+.close-button {
+ align-self: flex-end;
+ cursor: pointer;
+ font-weight: bold;
+ position: absolute;
+ padding: 7px;
+ top: 0;
+ right: 0;
+ border: 1px solid black;
+ margin-bottom: 20px;
+}
+
+
+
+
+
+
+
+.option-details-dropdown {
+ position: absolute;
+ z-index: 999;
+ border: #D6D5D4 1px solid;
+ background-color: #fff;
+ padding: 10px;
+ border-radius: 5px;
+ width: 250px;
+ margin-left: -250px;
+}
+
+
+.modal-wrapper {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 9999;
+ overflow: auto;
+ /* Enable scrolling if content exceeds the viewport */
+}
+
+
+.modal-content {
+ background-color: #fff;
+ padding: 20px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ max-width: 80%;
+ /* Adjust the maximum width as needed */
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ max-height: 80vh;
+ /* Limit the maximum height to 80% of the viewport height */
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
+.modal-inner {
+ overflow-y: auto;
+ /* Enable scrolling within the modal */
+}
+
+.modal-content .employee-select-wrap .select input {
+ width: calc(100% - 32px);
+ background-color: initial;
+ position: relative !important;
+ z-index: 10;
+ width: 100%;
+ height: 100%;
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+ padding-left: 8px;
+}
+
+
+
+.modal-content .employee-select-wrap .select-active {
+ position: absolute;
+ display: block;
+ width: 100%;
+ height: 2.5rem;
+ --border-opacity: 1;
+ border: 1px solid #f47738;
+ border-color: rgba(244, 119, 56, var(--border-opacity));
+}
+
+
+
+.modal-content .label-field-pair {
+ display: -ms-flexbox;
+ display: block !important;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+
+.modal-content .employee-select-wrap {
+ margin-bottom: 24px;
+}
+
+.inbox-search-wrapper {
+ .add-new-container {
+ width: 100%;
+ display: flex;
+ flex-direction: row-reverse;
+ .add-new {
+ position: relative;
+ color: #F47738;
+ cursor: pointer;
+ margin-right: 1em;
+ font-weight: bolder;
+ font-size: 23px;
+ }
+ }
+}
+
+
+
+.multiselect {
+ display: flex;
+ align-items: center;
+
+ @media (max-width: 588px) {
+ .info-icon-container {
+ position: absolute;
+ right: 2px;
+ margin-right: 0px !important;
+ margin-left: 0px !important;
+ display: flex;
+ justify-content: center;
+ margin-bottom: 0.7em;
+ }
+ }
+
+
+
+ .info-icon-container {
+ margin-left: 0.7em;
+ margin-right: -2em;
+ display: flex;
+ justify-content: center;
+ margin-bottom: 0.7em;
+ }
+
+
+
+ .info-icon-container .info-icon {
+ cursor: pointer;
+ }
+
+}
+
+
+
+.link-container {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ padding: 10px;
+ background-color: #bdc5d1;
+
+
+
+ .view-all-link {
+ background-color: #bdc5d1;
+ color: #f47738;
+ font-size: 16px;
+ text-decoration: underline;
+ cursor: pointer;
+ }
+
+}
+
+
+
+.action-bar {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+
+
+ .action-bar-button {
+ margin-right: 0.5em;
+ }
+}
+
+
+
+.progressBarContainer {
+ position: fixed;
+ bottom: 20px;
+ right: 20px;
+ background-color: #fff;
+ padding: 45px 45px 20px 20px;
+ border-radius: 8px;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ z-index: 9999;
+ width: 25vw;
+
+
+ @media (max-width: 768px) {
+ width: 70vw;
+ position: fixed;
+ bottom: 20px;
+ right: auto;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+
+
+ .progressBar {
+ display: flex;
+ flex-direction: row;
+ border-radius: 4px;
+ overflow: hidden;
+ border: 1px solid #ccc;
+ height: 20px;
+ background-color: #4CAF50;
+ }
+
+
+
+ .progressHeading {
+ margin: 8px 0;
+ font-size: 16px;
+
+
+
+ .success-container {
+ display: flex;
+ flex-direction: row;
+ background-color: #00703C;
+ color: #fff;
+ padding: 5px 10px;
+ border-radius: 5px;
+ width: fit-content;
+ align-items: center;
+
+
+
+ .success-count {
+ background-color: #fff;
+ color: #00703C;
+ padding: 3px 5px;
+ border-radius: 3px;
+ margin-left: 5px;
+ }
+
+ }
+
+ }
+
+
+
+ .closeButton {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ cursor: pointer;
+ padding: 2px;
+ border: 1px solid #ccc;
+ border-radius: 1px;
+ }
+
+
+
+ .no-uploads {
+ margin-top: 1em;
+ }
+
+}
+
+
+
+.results-container-orange {
+ max-height: 50vh;
+ overflow: auto;
+ margin-top: 1em;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ padding: 1em;
+ background-color: #ea8a3b !important;
+
+
+
+ .no-errors {
+ background-color: #ea8a3b !important;
+ }
+
+}
+
+
+
+.results-container {
+ max-height: 50vh;
+ overflow: auto;
+ margin-top: 1em;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ padding: 1em;
+
+
+
+ .results-list-item {
+ border-bottom: 1px solid #ddd;
+ padding: 0.5em;
+ cursor: pointer;
+
+
+ &:hover {
+ background-color: #D4351C;
+ color: white;
+ /* Yellowish color on hover */
+ }
+
+ }
+
+
+
+ .results-details {
+ white-space: pre-wrap;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ padding: 1em;
+ }
+}
+
+
+
+.overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.3);
+ z-index: 9998;
+}
+
+.CloseLevelButton {
+ font-size: 1rem;
+ margin-bottom: 24px;
+ /* margin-left: 24px; */
+ position: relative;
+ right: auto;
+ border: none;
+
+}
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/core/package.json b/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
index 65e1ef85169..58bcbbd5439 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/core/package.json
@@ -14,7 +14,7 @@
"prepublish": "yarn build"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.1",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-i18next": "11.16.2",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/dss/package.json b/micro-ui/web/micro-ui-internals/packages/modules/dss/package.json
index 21baf439f2b..a8cd18293a0 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/dss/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/dss/package.json
@@ -18,7 +18,7 @@
"react-router-dom": "5.3.0"
},
"dependencies": {
-"@egovernments/digit-ui-react-components": "1.8.0",
+"@egovernments/digit-ui-react-components": "1.8.2",
"jsonpath": "^1.1.1",
"react": "17.0.2",
"react-date-range": "1.3.0",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json b/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
index 4e8082e21e9..c1541d800ec 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/pgr/package.json
@@ -18,7 +18,7 @@
"react-router-dom": "5.3.0"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.1",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"lodash.merge": "^4.6.2",
"react": "17.0.2",
"react-dom": "17.0.2",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/utilities/package.json b/micro-ui/web/micro-ui-internals/packages/modules/utilities/package.json
index a4742414c3e..89633d4258e 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/utilities/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/utilities/package.json
@@ -18,7 +18,7 @@
"react-router-dom": "5.3.0"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.0",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"react": "17.0.2",
"react-date-range": "^1.4.0",
"react-dom": "17.0.2",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md b/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
index 7933cf66cd2..8bc71aa1c57 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/README.md
@@ -110,6 +110,7 @@ https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd5
### Changelog
```bash
+1.0.4 Added Search feature changes
1.0.3 Changed url in view and edit screen of workbench and fix some bug
1.0.2 If you dont want to use modulename and mastername in mdms-v2 data create and update api use {MDMS_SCHEMACODE_INACTION} this constant in global config and set it as false
1.0.1 Fixes related to the limits
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
index 75a097c5ee8..b4b45b59428 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-module-workbench",
- "version": "1.0.3",
+ "version": "1.0.4",
"description": "Workbench",
"main": "dist/index.js",
"module": "dist/index.modern.js",
@@ -18,7 +18,7 @@
"react-router-dom": "5.3.0"
},
"dependencies": {
- "@egovernments/digit-ui-react-components": "1.8.1",
+ "@egovernments/digit-ui-react-components": "1.8.2",
"@rjsf/core": "5.10.0",
"@rjsf/utils": "5.10.0",
"@rjsf/validator-ajv8": "5.10.0",
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/DigitJSONForm.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/DigitJSONForm.js
index 4cf868e6751..8890e308c91 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/DigitJSONForm.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/DigitJSONForm.js
@@ -1,5 +1,4 @@
import {
- Loader,
Header,
Toast,
Card,
@@ -20,6 +19,7 @@ import validator from "@rjsf/validator-ajv8";
// import { UiSchema } from '@rjsf/utils';
import { titleId } from "@rjsf/utils";
import CustomDropdown from "./MultiSelect";
+import CustomDropdownV2 from "./MultiSelectV2";
import CustomCheckbox from "./Checbox";
/*
@@ -82,7 +82,7 @@ const getArrayWrapperClassName = (type) => {
default:
return "jk-array-of-non-objects";
}
-};
+}
function ArrayFieldItemTemplate(props) {
const { t } = useTranslation();
@@ -122,9 +122,10 @@ function ArrayFieldItemTemplate(props) {
isDisabled={disabled}
/>
+
)
)}
-
+
);
}
@@ -252,20 +253,22 @@ const DigitJSONForm = ({
disabled = false,
setShowToast,
setShowErrorToast,
+ v2 = true
}) => {
const { t } = useTranslation();
useEffect(() => {
onFormChange({ formData: Digit.Utils.workbench.postProcessData(formData, inputUiSchema) });
}, []);
- const onSubmitV2 = async({ formData }) => {
- const updatedData=await Digit.Utils.workbench.preProcessData(formData, inputUiSchema);
+ const onSubmitV2 = async ({ formData }) => {
+ const updatedData = await Digit.Utils.workbench.preProcessData(formData, inputUiSchema);
onSubmit(updatedData);
};
- const customWidgets = { SelectWidget: CustomDropdown, CheckboxWidget: CustomCheckbox };
+ const customWidgets = { SelectWidget: v2 ? CustomDropdown : CustomDropdownV2, CheckboxWidget: CustomCheckbox };
const [displayMenu, setDisplayMenu] = useState(false);
const [liveValidate, setLiveValidate] = useState(false);
+
const onError = (errors) => {
setLiveValidate(true);
onFormError(errors);
@@ -309,11 +312,14 @@ const DigitJSONForm = ({
// focusOnFirstError={true}
/* added logic to show live validations after form submit is clicked */
liveValidate={liveValidate}
- // liveValidate={formData && Object.keys(formData) && Object.keys(formData)?.length > 0}
+ // liveValidate={formData && Object.keys(formData) && Object.keys(formData)?.length > 0}
>
{(screenType === "add" || screenType === "edit") && (
-
-
+
+
{/* */}
)}
@@ -344,8 +350,8 @@ const DigitJSONForm = ({
isDleteBtn={true}
>
)}
-
+
);
};
-export default DigitJSONForm;
+export default DigitJSONForm;
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelect.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelect.js
index 4cd1e203a39..2d045b655bd 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelect.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelect.js
@@ -1,7 +1,9 @@
-import React from "react";
-import Select from "react-select";
+import React, { useState, useEffect } from "react";
+import Select, { components } from "react-select";
import { useTranslation } from "react-i18next";
-import { Loader } from "@egovernments/digit-ui-react-components";
+import { useHistory } from "react-router-dom";
+import { Loader, InfoBannerIcon, Button, Close } from "@egovernments/digit-ui-react-components";
+import MDMSSearchv2Popup from "../pages/employee/MDMSSearchv2Popup";
const customStyles = {
control: (provided, state) => ({
@@ -12,11 +14,20 @@ const customStyles = {
borderColor: "#f47738",
},
}),
+ option: (provided, state) => ({
+ ...provided,
+ backgroundColor: state.isSelected ? "#f47738" : "white", // Background color for selected options
+ color: state.isSelected ? "white" : "black", // Text color for selected options
+ "&:hover": {
+ backgroundColor: "#ffe6cc", // Very light orange background color on hover
+ },
+ }),
};
/* Multiple support not added TODO jagan to fix this issue */
const CustomSelectWidget = (props) => {
const { t } = useTranslation();
+ const history = useHistory();
const { moduleName, masterName } = Digit.Hooks.useQueryParams();
const {
options,
@@ -31,7 +42,10 @@ const CustomSelectWidget = (props) => {
schema = { schemaCode: "", fieldPath: "" },
} = props;
const { schemaCode = `${moduleName}.${masterName}`, tenantId, fieldPath } = schema;
- const handleChange = (selectedValue) => onChange(multiple ? selectedValue?.value : selectedValue?.value);
+ const [showTooltipFlag, setShowTooltipFlag] = useState(false);
+
+ const [mainData, setMainData] = useState([]);
+
/*
logic added to fetch data of schemas in each component itself
*/
@@ -42,8 +56,8 @@ const CustomSelectWidget = (props) => {
MdmsCriteria: {
tenantId: tenantId,
schemaCode: schemaCode,
- limit: 200,
- offset: 0
+ limit: 100,
+ offset: 0,
},
},
config: {
@@ -58,39 +72,223 @@ const CustomSelectWidget = (props) => {
respData?.map((e) => e.value)
);
}
+ setMainData(data?.mdms);
return respData;
},
},
changeQueryName: `data-${schemaCode}`,
};
-
const { isLoading, data } = Digit.Hooks.useCustomAPIHook(reqCriteriaForData);
const optionsList = data || options?.enumOptions || options || [];
-
+ const optionsLimit = 10;
const formattedOptions = React.useMemo(
() => optionsList.map((e) => ({ label: t(Digit.Utils.locale.getTransformedLocale(`${schemaCode}_${e?.label}`)), value: e.value })),
[optionsList, schemaCode, data]
);
+ const [limitedOptions, setLimitedOptions] = useState([]);
+ const [selectedDetails, setSelectedDetails] = useState(null);
+ const [showDetails, setShowDetails] = useState(null);
+ const [isSelect, setIsSelect] = useState(false);
+ const [showModal, setShowModal] = useState(false);
+ const [isSeeAll, setIsSeeAll] = useState(false);
+ const handleSeeAll = () => {
+ setShowModal(true);
+ };
+ const handleCloseModal = () => {
+ setShowModal(false);
+ };
+ const SelectMenuButton = (props) => {
+ return (
+
+ );
+ };
const selectedOption = formattedOptions?.filter((obj) => (multiple ? value?.includes(obj.value) : obj.value == value));
+ const handleChange = (selectedValue) => {
+ setShowTooltipFlag(true);
+ setIsSelect(true);
+ setShowDetails(
+ mainData?.filter((obj) => (multiple ? selectedValue.value?.includes(obj.uniqueIdentifier) : obj.uniqueIdentifier == selectedValue.value))
+ );
+ };
+ const handleSelect = (detail) => {
+ setShowTooltipFlag(false);
+ setIsSelect(false);
+ onChange(data ? detail.uniqueIdentifier : detail.value);
+ setSelectedDetails([detail]);
+ };
+
+ useEffect(() => {
+ setLimitedOptions(formattedOptions.slice(0, optionsLimit));
+ if (optionsLimit < formattedOptions.length) {
+ setIsSeeAll(true);
+ }
+ setSelectedDetails(mainData?.filter((obj) => (multiple ? value?.includes(obj.uniqueIdentifier) : obj.uniqueIdentifier == value)));
+ }, [formattedOptions, optionsLimit]);
+ const onClickSelect = (selectedValue) => {
+ selectedValue = { ...selectedValue, value: selectedValue.uniqueIdentifier, label: selectedValue.description };
+ onChange(selectedValue.uniqueIdentifier);
+ setSelectedDetails(
+ mainData?.filter((obj) => (multiple ? selectedValue.value?.includes(obj.uniqueIdentifier) : obj.uniqueIdentifier == selectedValue.value))
+ );
+ setShowModal(false);
+ };
+ const handleViewMoreClick = (detail) => {
+ const schemaCode = detail?.schemaCode;
+ const [moduleName, masterName] = schemaCode.split(".");
+ const uniqueIdentifier = detail?.uniqueIdentifier;
+ history.push(
+ `/${window.contextPath}/employee/workbench/mdms-view?moduleName=${moduleName}&masterName=${masterName}&uniqueIdentifier=${uniqueIdentifier}`
+ );
+ };
+ const OptionWithInfo = (props) => {
+ const { data } = props;
+
+ // Find the index of the selected option within limitedOptions
+ const index = limitedOptions.findIndex((option) => option.value === data.value);
+
+ const handleInfoBannerClick = () => {
+ // Create a singleton array with the selected detail
+ const selectedDetail = mainData[index];
+ setSelectedDetails([selectedDetail]);
+ setShowTooltipFlag(true);
+ };
+
+ return (
+
+
+ {data.label}
+ {/*
+
+ */}
+
+
+ );
+ };
+
if (isLoading) {
return ;
}
return (
-
+
+
+
+
+
{
+ setShowTooltipFlag(true);
+ }}
+ >
+ {selectedDetails && selectedDetails.length > 0 && data && (
+
+
+
+ )}
+
+
+ {showTooltipFlag && (
+
+ {isSelect && (
+
+ {showDetails?.map((detail) => (
+
+
+ {Object.keys(detail.data).map((key) => {
+ const value = detail.data[key];
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
+ return (
+
+
{t(Digit.Utils.locale.getTransformedLocale(`${schemaCode}_${key}`))}
+
{String(value)}
+
+ );
+ }
+ return null;
+ })}
+
+
+ handleSelect(detail)} />
+
+
+ ))}
+
+ )}
+ {!isSelect && (
+
+ {selectedDetails?.map((detail) => (
+
+
+ {Object.keys(detail.data).map((key) => {
+ const value = detail.data[key];
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
+ return (
+
+
{t(Digit.Utils.locale.getTransformedLocale(`${schemaCode}_${key}`))}
+
{String(value)}
+
+ );
+ }
+ return null;
+ })}
+
+
+ handleViewMoreClick(detail)} />
+
+
+ ))}
+
+ )}
+
{
+ setShowTooltipFlag(false);
+ setIsSelect(false);
+ }}
+ >
+
+
+
+ )}
+
+ {
+ showModal && (
+
+ )
+ }
+
);
};
-export default CustomSelectWidget;
+export default CustomSelectWidget;
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelectV2.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelectV2.js
new file mode 100644
index 00000000000..9abd18b344d
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/components/MultiSelectV2.js
@@ -0,0 +1,77 @@
+import React, { useEffect, useState } from "react";
+import Select from "react-select";
+import { useTranslation } from "react-i18next";
+import { Loader } from "@egovernments/digit-ui-react-components";
+import _ from "lodash";
+
+const customStyles = {
+ control: (provided, state) => ({
+ ...provided,
+ borderColor: state.isFocused ? "#f47738" : "#505a5f",
+ borderRadius: "unset",
+ "&:hover": {
+ borderColor: "#f47738",
+ },
+ }),
+};
+
+/* Multiple support not added TODO jagan to fix this issue */
+const CustomSelectWidget = (props) => {
+ const { t } = useTranslation();
+ const { moduleName, masterName } = Digit.Hooks.useQueryParams();
+ const {
+ options,
+ value,
+ disabled,
+ readonly,
+ onChange,
+ onBlur,
+ onFocus,
+ placeholder,
+ multiple = false,
+ schema = { schemaCode: "", fieldPath: "" },
+ } = props;
+ const { schemaCode = `${moduleName}.${masterName}`, tenantId, fieldPath } = schema;
+ const [prefix, setPrefix] = useState(schemaCode);
+ const { configs, updateConfigs, updateSchema, schema: formSchema, formData } = Digit.Hooks.workbench.useWorkbenchFormContext();
+useEffect(()=>{
+ const customConfig = configs?.customUiConfigs?.custom?.filter((data) => data?.fieldPath == fieldPath)?.[0] || {};
+ const newPrefix = customConfig?.prefix || prefix;
+ const suffix = customConfig?.suffix;
+
+ newPrefix != prefix && setPrefix(newPrefix);
+},[configs]);
+ const handleChange = (selectedValue) => onChange(multiple ? selectedValue?.value : selectedValue?.value);
+ /*
+ logic added to fetch data of schemas in each component itself
+ */
+ const { isLoading, data } = Digit.Hooks.useCustomAPIHook(Digit.Utils.workbench.getCriteriaForSelectData(props) );
+ const optionsList = data || options?.enumOptions || options || [];
+ const formattedOptions = React.useMemo(
+ () => optionsList.map((e) => ({ label: t(Digit.Utils.locale.getTransformedLocale(prefix?.trim?.()!=""?`${prefix}_${e?.label}`:e?.label)), value: e?.value })),
+ [optionsList, prefix, data]
+ );
+ const selectedOption = formattedOptions?.filter((obj) => (multiple ? value?.includes(obj.value) : obj.value == value));
+ if (isLoading) {
+ return ;
+ }
+
+ return (
+
+ );
+};
+export default CustomSelectWidget;
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/UICustomizations.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/UICustomizations.js
index 2bcaf06a94a..8015bf312cc 100644
--- a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/UICustomizations.js
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/UICustomizations.js
@@ -1,6 +1,7 @@
import { Link,useHistory } from "react-router-dom";
import _ from "lodash";
import React from 'react';
+import { Button } from "@egovernments/digit-ui-react-components";
//create functions here based on module name set in mdms(eg->SearchProjectConfig)
//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName]
@@ -615,5 +616,153 @@ export const UICustomizations = {
return defaultData
}
- }
+ },
+ SearchMDMSConfigPopup: {
+ customValidationCheck: (data) => {
+ //checking both to and from date are present
+ const { createdFrom, createdTo, field, value } = data;
+ if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === ""))
+ return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" };
+
+ if ((field && !value) || (!field && value)) {
+ return { warning: true, label: "WBH_MDMS_SEARCH_VALIDATION_FIELD_VALUE_PAIR" };
+ }
+
+ return false;
+ },
+ preProcess: (data, additionalDetails) => {
+ const tenantId = Digit.ULBService.getCurrentTenantId();
+ data.body.MdmsCriteria.tenantId = tenantId
+ const filters = {}
+ const custom = data.body.MdmsCriteria.custom
+ const { field, value, isActive } = custom || {}
+ filters[field?.code] = value
+ if (isActive) {
+ if (isActive.value === "all") delete data.body.MdmsCriteria.isActive
+ else data.body.MdmsCriteria.isActive = isActive?.value
+ } else {
+ delete data.body.MdmsCriteria.isActive
+ }
+ data.body.MdmsCriteria.filters = filters
+ data.body.MdmsCriteria.isActive = true;
+ data.body.MdmsCriteria.schemaCode = additionalDetails?.currentSchemaCode
+ delete data.body.MdmsCriteria.custom
+
+
+ // const {field,value} = data.body.MdmsCriteria.moduleDetails[0].masterDetails[0].custom || {}
+
+ // const tenantId = Digit.ULBService.getCurrentTenantId()
+ // data.body.MdmsCriteria.tenantId = tenantId
+
+ // //generate filter
+ // const filter = `[?(@.${field?.code}=='${value}')]`
+
+
+ // data.body.MdmsCriteria.moduleDetails[0].masterDetails[0].filter = filter
+ // delete data.body.MdmsCriteria.moduleDetails[0].masterDetails[0].custom
+ //we simply
+ // data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() };
+
+ // let requestBody = { ...data.body.Individual };
+ // const pathConfig = {
+ // name: "name.givenName",
+ // };
+ // const dateConfig = {
+ // createdFrom: "daystart",
+ // createdTo: "dayend",
+ // };
+ // const selectConfig = {
+ // wardCode: "wardCode[0].code",
+ // socialCategory: "socialCategory.code",
+ // };
+ // const textConfig = ["name", "individualId"];
+ // let Individual = Object.keys(requestBody)
+ // .map((key) => {
+ // if (selectConfig[key]) {
+ // requestBody[key] = _.get(requestBody, selectConfig[key], null);
+ // } else if (typeof requestBody[key] == "object") {
+ // requestBody[key] = requestBody[key]?.code;
+ // } else if (textConfig?.includes(key)) {
+ // requestBody[key] = requestBody[key]?.trim();
+ // }
+ // return key;
+ // })
+ // .filter((key) => requestBody[key])
+ // .reduce((acc, curr) => {
+ // if (pathConfig[curr]) {
+ // _.set(acc, pathConfig[curr], requestBody[curr]);
+ // } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) {
+ // _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr]));
+ // } else {
+ // _.set(acc, curr, requestBody[curr]);
+ // }
+ // return acc;
+ // }, {});
+
+ // data.body.Individual = { ...Individual };
+ return data;
+ },
+ additionalCustomizations: (row, key, column, value, t, searchResult) => {
+ //here we can add multiple conditions
+ //like if a cell is link then we return link
+ //first we can identify which column it belongs to then we can return relevant result
+ switch (key) {
+ case " ":
+ return (
+ {
+ e.stopPropagation();
+ column.onClick(row);
+ }}
+ />
+ );
+ case "WBH_UNIQUE_IDENTIFIER":
+ const [moduleName, masterName] = row.schemaCode.split(".")
+ return (
+
+
+ {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))}
+
+
+ );
+ case "MASTERS_SOCIAL_CATEGORY":
+ return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA");
+
+ case "CORE_COMMON_PROFILE_CITY":
+ return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA");
+
+ case "MASTERS_WARD":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+
+ case "MASTERS_LOCALITY":
+ return value ? (
+ {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))}
+ ) : (
+ t("ES_COMMON_NA")
+ );
+ case "WBH_ISACTIVE":
+ return value ? {t("WBH_COMMON_YES")} : {t("WBH_COMMON_NO")}
+ default:
+ return t("ES_COMMON_NA");
+ }
+ },
+ MobileDetailsOnClick: (row, tenantId) => {
+ let link;
+ Object.keys(row).map((key) => {
+ if (key === "MASTERS_WAGESEEKER_ID")
+ link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`;
+ });
+ return link;
+ },
+ additionalValidations: (type, data, keys) => {
+ if (type === "date") {
+ return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true;
+ }
+ }
+ },
};
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/searchMDMSConfigPopup.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/searchMDMSConfigPopup.js
new file mode 100644
index 00000000000..d434cd75f68
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/configs/searchMDMSConfigPopup.js
@@ -0,0 +1,139 @@
+export const Config = {
+ label: "WBH_SEARCH_MDMS",
+ type: "search",
+ actionLabel: "WBH_ADD_MDMS",
+ actionRole: "MDMS_ADMIN",
+ actionLink: "workbench/mdms-add-v2",
+ apiDetails: {
+ serviceName: `/mdms-v2/v2/_search`,
+ requestParam: {},
+ requestBody: {
+ MdmsCriteria: {
+ },
+ },
+ minParametersForSearchForm: 0,
+ masterName: "commonUiConfig",
+ moduleName: "SearchMDMSConfigPopup",
+ tableFormJsonPath: "requestBody.MdmsCriteria",
+ filterFormJsonPath: "requestBody.MdmsCriteria.custom",
+ searchFormJsonPath: "requestBody.MdmsCriteria.custom"
+ },
+ sections: {
+ search: {
+ uiConfig: {
+ searchWrapperStyles: {
+ paddingTop: "0.5rem",
+ alignItems: "center",
+ justifyContent: "end",
+ },
+ // submitContainerStyles: {
+ // flexDirection: "column-reverse",
+ // marginTop: "2rem",
+ // alignItems: "center",
+ // justifyContent: "end"
+ // },
+ headerStyle: null,
+ formClassName: "", //"custom-both-clear-search",
+ primaryLabel: "ES_COMMON_SEARCH",
+ secondaryLabel: "ES_COMMON_CLEAR_SEARCH",
+ minReqFields: 0,
+ isPopUp: true,
+ defaultValues: {
+ value: "",
+ field: "",
+ isActive: {
+ code: "WBH_COMMON_ALL",
+ value: "all",
+ }
+ // createdFrom: "",
+ // createdTo: "",
+ },
+ fields: [
+ {
+ label: "WBH_FIELD",
+ type: "dropdown",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "field",
+ optionsKey: "i18nKey",
+ optionsCustomStyle: { top: "2.3rem" },
+ options: [
+ {
+ code: "code",
+ name: "code",
+ },
+ {
+ code: "name",
+ name: "name",
+ },
+ {
+ code: "description",
+ name: "description",
+ },
+ ],
+ },
+ },
+ {
+ label: "WBH_FIELD_VALUE",
+ type: "text",
+ isMandatory: false,
+ disable: false,
+ populators: {
+ name: "value",
+ validation: { pattern: {}, maxlength: 140 },
+ },
+ }
+ // {
+ // label: "CREATED_FROM_DATE",
+ // type: "date",
+ // isMandatory: false,
+ // disable: false,
+ // key: "createdFrom",
+ // preProcess: {
+ // updateDependent: ["populators.max"],
+ // },
+ // populators: { name: "createdFrom", max: "currentDate" },
+ // },
+ // {
+ // label: "CREATED_TO_DATE",
+ // type: "date",
+ // isMandatory: false,
+ // disable: false,
+ // key: "createdTo",
+ // preProcess: {
+ // updateDependent: ["populators.max"],
+ // },
+ // populators: {
+ // name: "createdTo",
+ // error: "DATE_VALIDATION_MSG",
+ // max: "currentDate",
+ // },
+ // additionalValidation: {
+ // type: "date",
+ // keys: { start: "createdFrom", end: "createdTo" },
+ // },
+ // },
+ ],
+ },
+ label: "",
+ children: {},
+ show: true,
+ },
+ searchResult: {
+ label: "",
+ uiConfig: {
+ columns: [
+ ],
+ enableGlobalSearch: false,
+ enableColumnSort: true,
+ resultsJsonPath: "mdms",
+ rowClassName: "table-row-mdms table-row-mdms-hover",
+ noColumnBorder: true
+ },
+ children: {},
+ show: true,
+ },
+ },
+ additionalSections: {},
+};
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSSearchv2Popup.js b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSSearchv2Popup.js
new file mode 100644
index 00000000000..e53a6936a07
--- /dev/null
+++ b/micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSSearchv2Popup.js
@@ -0,0 +1,221 @@
+import { AddFilled, Button, Header, InboxSearchComposer, Loader, Dropdown, SubmitBar, ActionBar, Close } from "@egovernments/digit-ui-react-components";
+import React, { useState, useEffect, useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import { useHistory, useParams } from "react-router-dom";
+import { Config as Configg } from "../../configs/searchMDMSConfigPopup";
+import _, { drop } from "lodash";
+
+const toDropdownObj = (master = "", mod = "") => {
+ return {
+ name: mod || master,
+ code: Digit.Utils.locale.getTransformedLocale(mod ? `WBH_MDMS_${master}_${mod}` : `WBH_MDMS_MASTER_${master}`),
+ };
+};
+
+
+const MDMSSearchv2Popup = ({ masterNameInherited, moduleNameInherited, onClickSelect }) => {
+ let Config = _.clone(Configg)
+ const { t } = useTranslation();
+ const history = useHistory();
+
+ let { masterName: modulee, moduleName: master, tenantId } = Digit.Hooks.useQueryParams()
+ master = masterNameInherited;
+ modulee = moduleNameInherited;
+
+ const [availableSchemas, setAvailableSchemas] = useState([]);
+ const [currentSchema, setCurrentSchema] = useState(null);
+ const [masterName, setMasterName] = useState(null); //for dropdown
+ const [moduleName, setModuleName] = useState(null); //for dropdown
+ const [masterOptions, setMasterOptions] = useState([])
+ const [moduleOptions, setModuleOptions] = useState([])
+ const [updatedConfig, setUpdatedConfig] = useState(null)
+ const [showDetails, setShowDetails] = useState(false);
+ const [selectedRowData, setSelectedRowData] = useState(null);
+ tenantId = tenantId || Digit.ULBService.getCurrentTenantId();
+ const SchemaDefCriteria = {
+ tenantId: tenantId,
+ limit: 50
+ }
+ const handleRowClick = (selectedValue) => {
+ setShowDetails(true);
+ setSelectedRowData(selectedValue);
+ };
+
+ const handleCloseDetails = () => {
+ setShowDetails(false);
+ setSelectedRowData(null);
+ };
+
+ const handleSelect = () => {
+ onClickSelect(selectedRowData.original);
+ handleCloseDetails();
+ }
+ const handleSelectForRow = (rowValue) => {
+ onClickSelect(rowValue);
+ handleCloseDetails();
+ }
+
+ if (master && modulee) {
+ SchemaDefCriteria.codes = [`${modulee}.${master}`]
+ }
+ const { isLoading, data: dropdownData } = Digit.Hooks.useCustomAPIHook({
+ url: `/${Digit.Hooks.workbench.getMDMSContextPath()}/schema/v1/_search`,
+ params: {
+
+ },
+ body: {
+ SchemaDefCriteria
+ },
+ config: {
+ select: (data) => {
+
+ function onlyUnique(value, index, array) {
+ return array.indexOf(value) === index;
+ }
+
+ //when api is working fine change here(thsese are all schemas available in a tenant)
+ // const schemas = sampleSchemaResponse.SchemaDefinitions;
+ const schemas = data?.SchemaDefinitions
+ setAvailableSchemas(schemas);
+ if (schemas?.length === 1) setCurrentSchema(schemas?.[0])
+ //now extract moduleNames and master names from this schema
+ const obj = {
+ mastersAvailable: [],
+ };
+ schemas.forEach((schema, idx) => {
+ const { code } = schema;
+ const splittedString = code.split(".");
+ const [master, mod] = splittedString;
+ obj[master] = obj[master]?.length > 0 ? [...obj[master], toDropdownObj(master, mod)] : [toDropdownObj(master, mod)];
+ obj.mastersAvailable.push(master);
+ });
+ obj.mastersAvailable = obj.mastersAvailable.filter(onlyUnique);
+ obj.mastersAvailable = obj.mastersAvailable.map((mas) => toDropdownObj(mas));
+
+ return obj;
+ },
+ },
+ });
+
+ useEffect(() => {
+ setModuleOptions(dropdownData?.[masterName?.name])
+ setMasterOptions(dropdownData?.mastersAvailable)
+ if (masterName?.name && moduleName?.name) {
+ setCurrentSchema(availableSchemas.filter(schema => schema.code === `${masterName?.name}.${moduleName?.name}`)?.[0])
+ }
+ }, [masterName, dropdownData, moduleName])
+
+ useEffect(() => {
+ if (currentSchema) {
+ const dropDownOptions = [];
+ const {
+ definition: { properties },
+ } = currentSchema;
+
+ Object.keys(properties)?.forEach((key) => {
+ if (properties[key].type === "string" && !properties[key].format) {
+ dropDownOptions.push({
+ // name: key,
+ name: key,
+ code: key,
+ i18nKey: Digit.Utils.locale.getTransformedLocale(`${currentSchema.code}_${key}`)
+ });
+ }
+ });
+ Config.sections.search.uiConfig.fields[0].populators.options = dropDownOptions;
+ Config.actionLink = Config.actionLink + `?moduleName=${masterName?.name}&masterName=${moduleName?.name}`;
+ // Config.apiDetails.serviceName = `/mdms-v2/v2/_search/${currentSchema.code}`
+
+
+ Config.additionalDetails = {
+ currentSchemaCode: currentSchema.code
+ }
+
+ Config.sections.searchResult.uiConfig.columns = [...dropDownOptions.map(option => {
+ return {
+ label: option.i18nKey,
+ i18nKey: option.i18nKey,
+ jsonPath: `data.${option.code}`,
+ dontShowNA: true
+ }
+ }), {
+ label: "WBH_ISACTIVE",
+ i18nKey: "WBH_ISACTIVE",
+ jsonPath: `isActive`,
+ additionalCustomization: true
+ // dontShowNA:true
+ }, {
+ label: " ",
+ i18nKey: " ",
+ jsonPath: '',
+ additionalCustomization: true,
+ dontShowNA: true,
+ onClick: handleSelectForRow
+ }]
+ Config.apiDetails.serviceName = `/${Digit.Hooks.workbench.getMDMSContextPath()}/v2/_search`;
+ setUpdatedConfig(Config)
+ }
+ }, [currentSchema]);
+
+ const handleAddNewClick = () => {
+ const isConfirmed = window.confirm(t("WORKBENCH_MDMS_SEARCH_REDIRECTION"));
+
+ if (isConfirmed) {
+ history.push(
+ `/${window?.contextPath}/employee/workbench/${"mdms-add-v2"}?moduleName=${modulee}&masterName=${master}`
+ );
+ }
+ };
+
+ if (isLoading) return ;
+ return (
+
+ {updatedConfig && (
+
+ {/*
+
+ + Add New
+
+
*/}
+
+
+ )}
+
+ {showDetails && (
+
+
+
+
+
+
+ {Object.keys(selectedRowData?.original?.data).map((key) => {
+ const value = selectedRowData?.original?.data[key]
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
+ return (
+
+
{t(Digit.Utils.locale.getTransformedLocale(`${modulee}.${master}_${key}`))}
+
{String(value)}
+
+ );
+ }
+ return null;
+ })}
+
+
+
+
+
+
+ )}
+
+ );
+};
+
+export default MDMSSearchv2Popup;
\ No newline at end of file
diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/README.md b/micro-ui/web/micro-ui-internals/packages/react-components/README.md
index c74129fb3de..a4101a0b156 100644
--- a/micro-ui/web/micro-ui-internals/packages/react-components/README.md
+++ b/micro-ui/web/micro-ui-internals/packages/react-components/README.md
@@ -88,6 +88,7 @@ Syntax for the FormComposersV2
### Changelog
```bash
+1.8.2 updated serachcomponent for serachscreen inside popup
1.8.1 build issue fix due to ajv library
1.8.0 workbench v1.0 release
1.8.0-beta workbench base version beta release
diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/package.json b/micro-ui/web/micro-ui-internals/packages/react-components/package.json
index 3448a46eaa1..3692589dea0 100644
--- a/micro-ui/web/micro-ui-internals/packages/react-components/package.json
+++ b/micro-ui/web/micro-ui-internals/packages/react-components/package.json
@@ -1,6 +1,6 @@
{
"name": "@egovernments/digit-ui-react-components",
- "version": "1.8.1",
+ "version": "1.8.2",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.modern.js",
diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SearchComponent.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SearchComponent.js
index 1b10c02ab7b..6e1ec61070e 100644
--- a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SearchComponent.js
+++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SearchComponent.js
@@ -18,7 +18,7 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon
if (fullConfig?.postProcessResult){
//conditions can be added while calling postprocess function to pass different params
- Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.postProcess(data, uiConfig)
+ Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.postProcess(data, uiConfig)
}
const {
@@ -50,18 +50,19 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon
updatedFields = Object.values(formState?.dirtyFields)
}, [formState])
- const onSubmit = (data) => {
-
+ const onSubmit = (data, e) => {
+
+ e?.preventDefault?.();
//here -> added a custom validator function, if required add in UICustomizations
- const isAnyError = Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.customValidationCheck ? Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.customValidationCheck(data) : false
- if(isAnyError) {
+ const isAnyError = Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.customValidationCheck ? Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.customValidationCheck(data) : false
+ if (isAnyError) {
setShowToast(isAnyError)
- setTimeout(closeToast,3000)
+ setTimeout(closeToast, 3000)
return
}
- if(updatedFields.length >= uiConfig?.minReqFields) {
- // here based on screenType call respective dispatch fn
+ if (updatedFields.length >= uiConfig?.minReqFields) {
+ // here based on screenType call respective dispatch fn
dispatch({
type: uiConfig?.type === "filter" ? "filterForm" : "searchForm",
state: {
@@ -82,10 +83,10 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon
//need to pass form with empty strings
})
dispatch({
- type:"clearTableForm"
+ type: "clearTableForm"
})
}
-
+
const closeToast = () => {
setShowToast(null);
}
@@ -100,8 +101,8 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon
}
const renderHeader = () => {
- switch(uiConfig?.type) {
- case "filter" : {
+ switch (uiConfig?.type) {
+ case "filter": {
return (
@@ -110,7 +111,7 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon
)
}
- default : {
+ default: {
return
}
}
@@ -123,10 +124,10 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon