From 1eea6a1e885825a3d7b9e4e75c7fa83867d40aa2 Mon Sep 17 00:00:00 2001 From: nabeelmd-eGov Date: Wed, 8 Jan 2025 12:43:27 +0530 Subject: [PATCH] HCMPRE-1766: App Configuration Screen Setup (#2117) * HCMPRE-1766: Added AppScreenConfiguration Feature screen * added enhancement in app configuration * added app configuration link * added tag component in mapping * package upgrade --------- Co-authored-by: NabeelAyubee --- .../example/public/index.html | 4 +- .../packages/css/package.json | 2 +- .../css/src/pages/employee/campaign.scss | 82 ++++-- .../modules/campaign-manager/src/Module.js | 4 +- .../src/components/CampaignCard.js | 8 +- .../src/components/SidePanel.js | 223 ++++++++++++++ .../campaign-manager/src/components/Switch.js | 62 ++++ .../components/UploadDataMappingWrapper.js | 17 +- .../pages/employee/AppConfigurationWrapper.js | 217 ++++++++++++++ .../src/pages/employee/AppFieldComposer.js | 274 ++++++++++++++++++ .../pages/employee/AppFieldScreenWrapper.js | 215 ++++++++++++++ .../src/pages/employee/DrawerFieldComposer.js | 189 ++++++++++++ .../src/pages/employee/SidePanel.js | 241 +++++++++++++++ .../src/pages/employee/index.js | 4 +- .../src/components/OldCampaignCard.js | 8 +- health/micro-ui/web/public/index.html | 2 +- 16 files changed, 1514 insertions(+), 38 deletions(-) create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SidePanel.js create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/Switch.js create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppConfigurationWrapper.js create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldComposer.js create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldScreenWrapper.js create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/DrawerFieldComposer.js create mode 100644 health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SidePanel.js 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 e27792f67b3..89f01158877 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 @@ -11,8 +11,8 @@ DIGIT - - + + 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 index f5f09e35c1e..6e08896c2d9 100644 --- a/health/micro-ui/web/micro-ui-internals/packages/css/package.json +++ b/health/micro-ui/web/micro-ui-internals/packages/css/package.json @@ -1,6 +1,6 @@ { "name": "@egovernments/digit-ui-health-css", - "version": "0.2.34", + "version": "0.2.35", "license": "MIT", "main": "dist/index.css", "author": "Jagankumar ", 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 index 5c924cb0e55..b636d64d928 100644 --- 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 @@ -67,9 +67,9 @@ border-width: 0rem 1.5rem; tbody { tr:hover { - td{ + td { background: rgba(#f47738, 0.12); - cursor: pointer; + cursor: pointer; } } } @@ -111,46 +111,46 @@ justify-content: space-between; align-items: center; } -.setup-campaign{ - .digit-success{ - z-index: 1000; +.setup-campaign { + .digit-success { + z-index: 1000; } } -.digit-error{ +.digit-error { z-index: 900; } -.timeline-user{ +.timeline-user { display: flex; justify-content: space-between; } -.upcoming-timeline{ - .timeline-label{ +.upcoming-timeline { + .timeline-label { color: #b1b4b6; } } -.container{ +.container { display: flex; flex-direction: row; gap: 1.5rem; align-items: stretch; } -.stepper-card{ - height: 37rem; +.stepper-card { + height: 39rem; margin-bottom: 1.5rem !important; padding-top: 0rem; } -.stepper-subheader{ +.stepper-subheader { color: theme(digitv2.lightTheme.header-sidenav); } -.container-full{ +.container-full { display: flex; flex-direction: row; gap: 1.5rem; align-items: stretch; height: 100%; } -.name-container-label{ - .label-field-wrapper{ +.name-container-label { + .label-field-wrapper { width: -webkit-fill-available; } } @@ -186,31 +186,37 @@ .hierarchy-boundary-heading { font-size: 2.5rem; font-weight: 700; - font-family: 'Roboto Condensed', sans-serif; + font-family: "Roboto Condensed", sans-serif; } .hierarchy-boundary-sub-heading { width: 20rem; margin-top: 0.6rem; font-weight: 600; - font-family: 'Roboto', sans-serif; + font-family: "Roboto", sans-serif; } .hierarchy-boundary-sub-heading2 { - font-size: 1.2rem; + font-size: 1.2rem; font-weight: 600; - font-family: 'Roboto', sans-serif; + font-family: "Roboto", sans-serif; } -.campaign-preview{ +.campaign-preview { display: flex; align-items: center; gap: 0.5rem; } -.card-container1{ +.card-container1 { width: 100%; } -.campaign-tag{ +.campaign-tag { + border: 0.5px solid #0b4b66; margin-bottom: 1rem; + height: 3.3rem; + .digit-tag-text { + font-size: 1.5rem; + font-weight: 700; + } } .digit-popup-wrapper.dataMapping { .digit-popup-children-wrap { @@ -231,4 +237,32 @@ > div:nth-of-type(1) { width: 69%; } -} \ No newline at end of file +} + +.appConfiglabelField { + padding: 3rem 1rem; + background-color: #eee; + border: 1px solid #d6d5d4; + border-radius: 0.5rem; +} +.appConfiglabelField.selected { + background-color: #f477381a; + border: 1px solid #c84c0e; +} +.appConfig-flow-stepper { + margin-top: 2rem; +} +.app-config-add-section { + margin-inline: auto; + margin-top: 2rem; + margin-bottom: 5rem; +} +.appConfigScreenCard { + margin-bottom: 2rem; +} +.appConfiglabelField-label { + width: 25rem; +} +.app-config-actionBar { + z-index: 9999; +} 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 aa986b565db..26f16633c2b 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 @@ -57,6 +57,7 @@ import MapView from "./components/MapView"; import NoResultsFound from "./components/NoResultsFound"; import UploadDataMappingWrapper from "./components/UploadDataMappingWrapper"; import DataUploadWrapper from "./components/DataUploadWrapper"; +import AppConfigurationWrapper from "./pages/employee/AppConfigurationWrapper"; /** * MDMS Module name @@ -91,7 +92,7 @@ const CampaignModule = ({ stateCode, userType, tenants }) => { const hierarchyData = Digit.Hooks.campaign.useBoundaryRelationshipSearch({ BOUNDARY_HIERARCHY_TYPE, tenantId }); const modulePrefix = "hcm"; - const moduleCode = BOUNDARY_HIERARCHY_TYPE ? [`boundary-${BOUNDARY_HIERARCHY_TYPE}`] : ["campaignmanager", "schema", "admin-schemas", "checklist"]; + const moduleCode = BOUNDARY_HIERARCHY_TYPE ? [`boundary-${BOUNDARY_HIERARCHY_TYPE}`] : ["campaignmanager", "schema", "admin-schemas", "checklist", "appconfiguration"]; const { path, url } = useRouteMatch(); const language = Digit.StoreData.getCurrentLanguage(); @@ -175,6 +176,7 @@ const componentsToRegister = { NoResultsFound, UploadDataMappingWrapper, DataUploadWrapper, + AppConfigurationWrapper, }; const overrideHooks = () => { 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 index 7b000d81dc6..cfc87a259f1 100644 --- 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 @@ -63,7 +63,13 @@ const CampaignCard = () => { link: `/${window?.contextPath}/employee/campaign/boundary/home`, roles: ROLES.BOUNDARY_MANAGER, // count: isLoading?"-":data - } + }, + { + label: t("ACTION_TEST_APP_CONFIGURATION"), + link: `/workbench-ui/employee/campaign/app-configuration`, + roles: ROLES.CAMPAIGN_MANAGER, + // count: isLoading?"-":data + }, ]; links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true)); diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SidePanel.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SidePanel.js new file mode 100644 index 00000000000..92c9bb49b59 --- /dev/null +++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SidePanel.js @@ -0,0 +1,223 @@ +import React, { useEffect, useState, useRef } from "react"; +import PropTypes from "prop-types"; +import { SVG } from "./SVG"; +import { Colors } from "../constants/colors/colorconstants"; +import { Spacers } from "../constants/spacers/spacers"; + +const SidePanel = ({ + className = "", + styles = {}, + type = "static", + position = "right", + children, + header, + footer, + bgActive = false, + isOverlay = false, + isDraggable = false, + hideArrow, + hideScrollIcon, + sections = [], + defaultOpenWidth, + defaultClosedWidth, + addClose, + closedContents, + closedSections, + closedHeader, + closedFooter, + transitionDuration +}) => { + const [isOpen, setIsOpen] = useState(true); + const sliderRef = useRef(null); + const [sliderWidth, setSliderWidth] = useState(defaultOpenWidth || 300); + const isDragging = useRef(false); + + const iconColor = Colors.lightTheme.text.primary; + const iconSize = Spacers.spacer8; + + const toggleSlider = () => { + if (type === "static") return; + if (isOpen) { + setIsOpen(false); + setSliderWidth(defaultClosedWidth || 64); + return; + } + setIsOpen((prevState) => !prevState); + if (!isOpen) { + setSliderWidth(defaultOpenWidth); + } + }; + + const handleClose = () => { + setIsOpen(false); + }; + + const handleMouseDown = (e) => { + if (isDraggable && type === "dynamic" && isOpen) { + isDragging.current = true; + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); + } + }; + + const handleMouseMove = (e) => { + if (isDragging.current && sliderRef.current && isOpen) { + const newWidth = + position === "right" ? window.innerWidth - e.clientX : e.clientX; + setSliderWidth( + newWidth > (defaultClosedWidth || 64) + ? newWidth + : defaultClosedWidth || 64 + ); + } + }; + + const handleMouseUp = () => { + isDragging.current = false; + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + }; + + useEffect(() => { + return () => { + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + }; + }, []); + + useEffect(() => {}, [isOpen]); + + return ( + <> + {!bgActive &&
} +
+ {type === "dynamic" && ( +
+ {!hideScrollIcon &&
} + {!hideArrow && ( +
+ +
+ )} +
+ )} +
+ {header && isOpen && ( +
+ {addClose && isOpen && ( +
+ +
+ )} + {header} +
+ )} + { + closedHeader && !isOpen && ( +
+ {closedHeader} +
+ ) + } +
0 ? "with-sections" : "" + }`} + > + {isOpen + ? sections && sections?.length > 0 + ? sections?.map((section, index) => ( +
+
+ {section} +
+ {index < sections.length - 1 && ( +
+ )} +
+ )) + : children + : sections && sections?.length > 0 + ? closedSections?.map((section, index) => ( +
+
+ {section} +
+ {index < sections.length - 1 && ( +
+ )} +
+ )) + : closedContents} +
+ + {footer && isOpen &&
{footer}
} + {closedFooter && !isOpen &&
{closedFooter}
} +
+
+ + ); +}; + +SidePanel.propTypes = { + className: PropTypes.string, + styles: PropTypes.object, + type: PropTypes.oneOf(["static", "dynamic"]), + position: PropTypes.oneOf(["left", "right"]), + children: PropTypes.node, + header: PropTypes.node, + footer: PropTypes.node, + addClose: PropTypes.bool, + closedContents: PropTypes.node, + closedSections: PropTypes.arrayOf(PropTypes.node), + closedHeader: PropTypes.node, + closedFooter: PropTypes.node, + transitionDuration: PropTypes.number, + bgActive: PropTypes.bool, + isOverlay: PropTypes.bool, + isDraggable: PropTypes.bool, + sections: PropTypes.arrayOf(PropTypes.node), + hideArrow: PropTypes.bool, + hideScrollIcon: PropTypes.bool, + defaultOpenWidth: PropTypes.number, + defaultClosedWidth: PropTypes.number, +}; + +export default SidePanel; diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/Switch.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/Switch.js new file mode 100644 index 00000000000..a04e20f47bb --- /dev/null +++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/Switch.js @@ -0,0 +1,62 @@ +import React, { useEffect, useState } from "react"; +import PropTypes from "prop-types"; + +const Switch = ({ + isLabelFirst = false, + label = "", + shapeOnOff = false, + isCheckedInitially = false, + onToggle = () => {}, + className, + style, + disable = false, + switchStyle, +}) => { + const [isChecked, setIsChecked] = useState(isCheckedInitially); + useEffect(() => { + setIsChecked(isCheckedInitially); + }, [isCheckedInitially]); + + const handleToggle = () => { + if (!disable) { + setIsChecked(!isChecked); + onToggle(!isChecked); + } + }; + + return ( +
+ {isLabelFirst && {label}} +
{ + if (e.key === "Enter" || e.key === " ") { + handleToggle(); + } + }} + > + {shapeOnOff && isChecked &&
} +
+ {shapeOnOff && !isChecked &&
} +
+ {!isLabelFirst && {label}} +
+ ); +}; + +export default Switch; + +Switch.propTypes = { + isLabelFirst: PropTypes.bool, + label: PropTypes.string, + shapeOnOff: PropTypes.bool, + isCheckedInitially: PropTypes.bool, + onToggle: PropTypes.func, + className: PropTypes.string, + style: PropTypes.object, + switchStyle: PropTypes.object, + disable: PropTypes.bool, +}; diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadDataMappingWrapper.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadDataMappingWrapper.js index 89af558e9a4..2ab249f807e 100644 --- a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadDataMappingWrapper.js +++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadDataMappingWrapper.js @@ -2,6 +2,7 @@ import { Card, CardHeader, Switch, Toast, ToggleSwitch } from "@egovernments/dig import React, { createContext, Fragment, useContext, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import UploadDataMapping from "./UploadDataMapping"; +import TagComponent from "./TagComponent"; const UploadDataMappingContext = createContext("UploadDataMappingContext"); @@ -11,18 +12,22 @@ export const useUploadDataMappingContext = () => { function UploadDataMappingWrapper({ props: customProps, formData, currentCategories, onSelect }) { const { t } = useTranslation(); const searchParams = new URLSearchParams(window.location.search); + const campaignName = customProps?.sessionData?.HCM_CAMPAIGN_NAME?.campaignName || searchParams.get("campaignName"); const tenantId = Digit.ULBService.getCurrentTenantId(); const [showToast, setShowToast] = useState(null); const { id, draft, key, ...queryParams } = Digit.Hooks.useQueryParams(); return ( - - {t(`UPLOAD_DATA_MAPPING`)} -
- -
-
+
+ + + {t(`UPLOAD_DATA_MAPPING`)} +
+ +
+
+
{showToast && ( { + return useContext(AppConfigContext); +}; + +const reducer = (state = initialState, action) => { + switch (action.type) { + case "MASTER_DATA": + return { + ...state, + MASTER_DATA: { ...action.state }, + screenData: action.state?.AppScreenConfigTemplateSchema, + }; + case "ADD_SECTION": + return { + ...state, + screenData: state?.screenData?.map((item, index) => { + if (item?.name === action?.payload?.currentScreen?.name) { + return { + ...item, + cards: [ + ...item?.cards, + { + fields: [], + header: "Header", + description: "Desc", + headerFields: [ + { + type: "text", + label: "SCREEN_HEADING", + active: true, + jsonPath: "ScreenHeading", + metaData: {}, + required: true, + }, + { + type: "text", + label: "SCREEN_DESCRIPTION", + active: true, + jsonPath: "Description", + metaData: {}, + required: true, + }, + ], + }, + ], + }; + } + return item; + }), + }; + case "ADD_FIELD": + return { + ...state, + screenData: state?.screenData?.map((item, index) => { + if (item?.name === action?.payload?.currentScreen?.name) { + return { + ...item, + cards: item?.cards?.map((j, k) => { + if (j.header === action.payload.currentCard?.header) { + return { + ...j, + fields: [ + ...j.fields, + { + id: crypto.randomUUID(), + type: "text", + label: "LABEL", + active: true, + }, + ], + }; + } + return j; + }), + }; + } + return item; + }), + }; + case "DELETE_FIELD": + return { + ...state, + screenData: state?.screenData?.map((item, index) => { + if (item?.name === action?.payload?.currentScreen?.name) { + return { + ...item, + cards: item?.cards?.map((j, k) => { + if (j.header === action.payload.currentCard?.header) { + return { + ...j, + fields: j.fields?.filter((k) => k.id !== action.payload.currentField.id), + }; + } + return j; + }), + }; + } + return item; + }), + }; + case "SELECT_DRAWER_FIELD": + return { + ...state, + currentScreen: action?.payload?.currentScreen, + currentCard: action?.payload?.currentCard, + drawerField: action?.payload?.drawerField, + }; + case "UNSELECT_DRAWER_FIELD": + return { + ...state, + drawerField: null, + }; + case "UPDATE_DRAWER_FIELD": + return { + ...state, + screenData: state?.screenData?.map((item, index) => { + if (item?.name === state?.currentScreen?.name) { + return { + ...item, + cards: item?.cards?.map((j, k) => { + if (j.header === state.currentCard?.header) { + return { + ...j, + fields: j.fields.map((k) => { + if (k.id === state.drawerField.id) { + return { + ...action.payload.updatedState, + }; + } + return k; + }), + }; + } + return j; + }), + }; + } + return item; + }), + }; + default: + return state; + } +}; + +const MODULE_CONSTANTS = "HCM-ADMIN-CONSOLE"; +function AppConfigurationWrapper() { + const [state, dispatch] = useReducer(reducer, initialState); + const { t } = useTranslation(); + const { isLoading: isLoadingAppConfigMdmsData, data: AppConfigMdmsData } = Digit.Hooks.useCustomMDMS( + Digit.ULBService.getCurrentTenantId(), + MODULE_CONSTANTS, + [{ name: "AppScreenConfigTemplateSchema" }, { name: "AppFieldType" }, { name: "DrawerPanelConfig" }, { name: "AppScreenLocalisationConfig" }], + { + cacheTime: Infinity, + staleTime: Infinity, + select: (data) => { + dispatch({ + type: "MASTER_DATA", + state: { + ...data?.["HCM-ADMIN-CONSOLE"], + }, + }); + }, + }, + { schemaCode: "BASE_APP_MASTER_DATA" } //mdmsv2 + ); + + if (isLoadingAppConfigMdmsData) { + return ; + } + + return ( + + + {state?.drawerField && ( + ]} + closedHeader={[]} + closedSections={[]} + defaultClosedWidth="" + defaultOpenWidth="" + footer={[]} + header={[ +
+ Header +
, + ]} + hideScrollIcon + isDraggable={false} + position="right" + sections={[]} + styles={{}} + type="static" + > + +
+ )} +
+ ); +} + +export default AppConfigurationWrapper; diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldComposer.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldComposer.js new file mode 100644 index 00000000000..b050ca5681e --- /dev/null +++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldComposer.js @@ -0,0 +1,274 @@ +import { LabelFieldPair, TextInput, Dropdown, CheckBox } from "@egovernments/digit-ui-components"; +import React, { Fragment, useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { PRIMARY_COLOR } from "../../utils"; +import { DustbinIcon } from "../../components/icons/DustbinIcon"; +import { useAppConfigContext } from "./AppConfigurationWrapper"; + +const CheckBoxes = ({ t, option, optionKey, isLabelFirst }) => { + return ( +
+ {option?.map((item, index) => ( + {}} value={""} label={t(`${item?.[optionKey]}`)} isLabelFirst={isLabelFirst} /> + ))} +
+ ); +}; + +function AppFieldComposer({ + headerFields = false, + type, + label, + value, + required, + isDelete = false, + onDelete, + onSelectField = () => {}, + dropDownOptions = [], + config, +}) { + const { t } = useTranslation(); + const { state, dispatch } = useAppConfigContext(); + const componentRef = useRef(null); + + const Field = () => { + switch (type) { + case "text": + case "textInput": + return ( + //
{ + // onSelectField(); + // }} + // > + +
+ {`${t(label)}`} + {required && *} +
+ {}} /> + {isDelete && ( +
{ + // e.stopPropagation(); + onDelete(); + }} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + +
+ )} +
+ //
+ ); + break; + case "dropDown": + return ( + //
{ + // onSelectField(); + // }} + // > + +
+ {`${t(label)}`} + {required && *} +
+ {}} + /> + {isDelete && ( +
{ + // e.stopPropagation(); + onDelete(); + }} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + +
+ )} +
+ //
+ ); + break; + case "dobPicker": + case "datePicker": + return ( + +
+ {`${t(label)}`} + {required && *} +
+ {}} /> + {isDelete && ( +
{ + // e.stopPropagation(); + onDelete(); + }} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + +
+ )} +
+ ); + break; + case "counter": + return ( + +
+ {`${t(label)}`} + {required && *} +
+ {}} /> + {isDelete && ( +
{ + // e.stopPropagation(); + onDelete(); + }} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + +
+ )} +
+ ); + break; + case "number": + return ( + +
+ {`${t(label)}`} + {required && *} +
+ {}} /> + {isDelete && ( +
{ + // e.stopPropagation(); + onDelete(); + }} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + +
+ )} +
+ ); + case "checkbox": + return ( + +
+ {`${t(label)}`} + {required && *} +
+ + {isDelete && ( +
{ + // e.stopPropagation(); + onDelete(); + }} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + +
+ )} +
+ ); + default: + return null; + break; + } + }; + + return ( +
{ + if (config?.id !== state?.drawerField?.id) { + onSelectField(); + } + // e.stopPropagation(); + // onSelectField(); + }} + className="app-config-field-wrapper" + style={{ width: "50%" }} + > + +
+ ); +} + +export default AppFieldComposer; diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldScreenWrapper.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldScreenWrapper.js new file mode 100644 index 00000000000..e9717cf4afe --- /dev/null +++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AppFieldScreenWrapper.js @@ -0,0 +1,215 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { useAppConfigContext } from "./AppConfigurationWrapper"; +import { useTranslation } from "react-i18next"; +import { Button, Card, CardHeader, Divider, Stepper, Tab, ActionBar } from "@egovernments/digit-ui-components"; +import AppFieldComposer from "./AppFieldComposer"; +import _ from "lodash"; + +const Tabs = ({ numberTabs, onTabChange }) => { + const { state, dispatch } = useAppConfigContext(); + const { t } = useTranslation(); + return ( +
+ {numberTabs.map((_, index) => ( + + ))} +
+ ); +}; + +function AppFieldScreenWrapper() { + const { state, dispatch } = useAppConfigContext(); + const { t } = useTranslation(); + // const appTemplate = state?.["MASTER_DATA"]?.AppScreenConfigTemplateSchema; + const appTemplate = state?.screenData; + const [numberTabs, setNumberTabs] = useState( + [...new Set(appTemplate?.map((i) => i?.parent))].map((i, index) => { + return { parent: i, active: index === 0 ? true : false, code: index + 1 }; + }) + ); + + const [stepper, setStepper] = useState( + appTemplate + ?.filter((i) => i.parent === numberTabs.find((j) => j.active)?.parent) + .sort((a, b) => a.order - b.order) + ?.map((k, j, t) => ({ + name: k.name, + isLast: j === t.length - 1 ? true : false, + isFirst: j === 0 ? true : false, + active: j === 0 ? true : false, + })) + ); + + const [currentStep, setCurrentStep] = useState(1); + + useEffect(() => { + // if (currentStep) { + setStepper((prev) => { + return prev.map((i, c) => { + if (c === currentStep - 1) { + return { + ...i, + active: true, + }; + } + return { + ...i, + active: false, + }; + }); + }); + dispatch({ + type: "UNSELECT_DRAWER_FIELD", + }); + // } + }, [currentStep]); + + const currentCard = useMemo(() => { + return state?.screenData + ?.filter((i) => i.parent === numberTabs.find((j) => j.active)?.parent) + ?.sort((a, b) => a.order - b.order) + ?.filter((k) => k.name === stepper.find((l) => l.active)?.name)?.[0]; + }, [state?.screenData, numberTabs, stepper, currentStep]); + + return ( + + { + setNumberTabs((prev) => { + return prev.map((j) => { + if (j.parent === tab.parent) { + return { + ...j, + active: true, + }; + } + return { + ...j, + active: false, + }; + }); + }); + }} + /> + i.name)]} + currentStep={currentStep} + onStepClick={() => {}} + activeSteps={0} + className={"appConfig-flow-stepper"} + /> + {currentCard?.cards?.map(({ fields, description, header, headerFields }, index, card) => { + return ( + + {headerFields?.map(({ type, label, active, required }) => ( + + ))} + + {fields?.map(({ type, label, active, required, dropDownOptions, deleteFlag }, i, c) => ( + { + dispatch({ + type: "DELETE_FIELD", + payload: { + currentScreen: currentCard, + currentCard: card[index], + currentField: c[i], + }, + }); + // return; + }} + onSelectField={() => { + dispatch({ + type: "SELECT_DRAWER_FIELD", + payload: { + currentScreen: currentCard, + currentCard: card[index], + drawerField: c[i], + }, + }); + // return; + }} + config={c[i]} + /> + ))} + {currentCard?.config?.enableFieldAddition && ( +
+ )} + + ); +} + +export default DrawerFieldComposer; diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SidePanel.js b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SidePanel.js new file mode 100644 index 00000000000..05be4199ea9 --- /dev/null +++ b/health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SidePanel.js @@ -0,0 +1,241 @@ +import React, { useEffect, useState, useRef, Fragment } from "react"; +import PropTypes from "prop-types"; +import { SVG } from "@egovernments/digit-ui-components"; + +const Colors = { + lightTheme: { + primary: { + 1: "#C84C0E", + 2: "#0B4B66", + bg: "#FBEEE8", + }, + text: { + primary: "#363636", + secondary: "#787878", + disabled: "#C5C5C5", + }, + alert: { + error: "#B91900", + errorbg: "#FFF5F4", + success: "#00703C", + successbg: "#F1FFF8", + warning: "#9E5F00", + warningbg: "#FFF9F0", + info: "#0057BD", + infobg: "#DEEFFF", + }, + generic: { + background: "#EEEEEE", + divider: "#D6D5D4", + inputBorder: "#505A5F", + }, + paper: { + primary: "#FFFFFF", + secondary: "#FAFAFA", + }, + }, +}; +const Spacers = { + spacer0: "0rem", + spacer1: "0.25rem", + spacer2: "0.5rem", + spacer3: "0.75rem", + spacer4: "1rem", + spacer5: "1.25rem", + spacer6: "1.5rem", + spacer7: "1.75rem", + spacer8: "2rem", + spacer9: "2.25rem", + spacer10: "2.5rem", + spacer11: "2.75rem", + spacer12: "3rem", +}; + +const SidePanel = ({ + className = "", + styles = {}, + type = "static", + position = "right", + children, + header, + footer, + bgActive = false, + isOverlay = false, + isDraggable = false, + hideArrow, + hideScrollIcon, + sections = [], + defaultOpenWidth, + defaultClosedWidth, + addClose, + closedContents, + closedSections, + closedHeader, + closedFooter, + transitionDuration, +}) => { + const [isOpen, setIsOpen] = useState(true); + const sliderRef = useRef(null); + const [sliderWidth, setSliderWidth] = useState(defaultOpenWidth || 300); + const isDragging = useRef(false); + + const iconColor = Colors.lightTheme.text.primary; + const iconSize = Spacers.spacer8; + + const toggleSlider = () => { + if (type === "static") return; + if (isOpen) { + setIsOpen(false); + setSliderWidth(defaultClosedWidth || 64); + return; + } + setIsOpen((prevState) => !prevState); + if (!isOpen) { + setSliderWidth(defaultOpenWidth); + } + }; + + const handleClose = () => { + setIsOpen(false); + }; + + const handleMouseDown = (e) => { + if (isDraggable && type === "dynamic" && isOpen) { + isDragging.current = true; + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); + } + }; + + const handleMouseMove = (e) => { + if (isDragging.current && sliderRef.current && isOpen) { + const newWidth = position === "right" ? window.innerWidth - e.clientX : e.clientX; + setSliderWidth(newWidth > (defaultClosedWidth || 64) ? newWidth : defaultClosedWidth || 64); + } + }; + + const handleMouseUp = () => { + isDragging.current = false; + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + }; + + useEffect(() => { + return () => { + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + }; + }, []); + + useEffect(() => {}, [isOpen]); + + return ( + <> + {!bgActive &&
} +
+ {type === "dynamic" && ( +
+ {!hideScrollIcon &&
} + {!hideArrow && ( +
+ +
+ )} +
+ )} +
+ {header && isOpen && ( +
+ {addClose && isOpen && ( +
+ +
+ )} + {header} +
+ )} + {closedHeader && !isOpen &&
{closedHeader}
} +
0 ? "with-sections" : ""}`}> + {isOpen + ? sections && sections?.length > 0 + ? sections?.map((section, index) => ( +
+
+ {section} +
+ {index < sections.length - 1 &&
} +
+ )) + : children + : sections && sections?.length > 0 + ? closedSections?.map((section, index) => ( +
+
+ {section} +
+ {index < sections.length - 1 &&
} +
+ )) + : closedContents} +
+ + {footer && isOpen &&
{footer}
} + {closedFooter && !isOpen &&
{closedFooter}
} +
+
+ + ); +}; + +SidePanel.propTypes = { + className: PropTypes.string, + styles: PropTypes.object, + type: PropTypes.oneOf(["static", "dynamic"]), + position: PropTypes.oneOf(["left", "right"]), + children: PropTypes.node, + header: PropTypes.node, + footer: PropTypes.node, + addClose: PropTypes.bool, + closedContents: PropTypes.node, + closedSections: PropTypes.arrayOf(PropTypes.node), + closedHeader: PropTypes.node, + closedFooter: PropTypes.node, + transitionDuration: PropTypes.number, + bgActive: PropTypes.bool, + isOverlay: PropTypes.bool, + isDraggable: PropTypes.bool, + sections: PropTypes.arrayOf(PropTypes.node), + hideArrow: PropTypes.bool, + hideScrollIcon: PropTypes.bool, + defaultOpenWidth: PropTypes.number, + defaultClosedWidth: PropTypes.number, +}; + +export default SidePanel; 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 index 122578edc9c..b30b177ce60 100644 --- 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 @@ -104,7 +104,8 @@ const App = ({ path, BOUNDARY_HIERARCHY_TYPE, hierarchyData }) => { const Response = Digit?.ComponentRegistryService?.getComponent("Response"); const AddProduct = Digit?.ComponentRegistryService?.getComponent("AddProduct"); const UpdateDatesWithBoundaries = Digit?.ComponentRegistryService?.getComponent("UpdateDatesWithBoundaries"); - + const AppConfigurationWrapper = Digit?.ComponentRegistryService?.getComponent("AppConfigurationWrapper"); + useEffect(() => { if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); @@ -154,6 +155,7 @@ const App = ({ path, BOUNDARY_HIERARCHY_TYPE, hierarchyData }) => { } /> } /> } /> + } /> diff --git a/health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/OldCampaignCard.js b/health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/OldCampaignCard.js index 2e0ab2386a8..84534615904 100644 --- a/health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/OldCampaignCard.js +++ b/health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/OldCampaignCard.js @@ -54,7 +54,13 @@ const CampaignCard = () => { link: `/workbench-ui/employee/campaign/boundary/home`, roles: ROLES.BOUNDARY_MANAGER, // count: isLoading?"-":data - } + }, + { + label: t("ACTION_TEST_APP_CONFIGURATION"), + link: `/workbench-ui/employee/campaign/app-configuration`, + roles: ROLES.CAMPAIGN_MANAGER, + // count: isLoading?"-":data + }, ]; links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true)); diff --git a/health/micro-ui/web/public/index.html b/health/micro-ui/web/public/index.html index 909c37fa2ea..54d966c5765 100644 --- a/health/micro-ui/web/public/index.html +++ b/health/micro-ui/web/public/index.html @@ -10,7 +10,7 @@ - + DIGIT HCM