diff --git a/frontend/mgramseva/lib/screeens/household_register/household_list.dart b/frontend/mgramseva/lib/screeens/household_register/household_list.dart index cbe32cebb..0fb9c72ab 100644 --- a/frontend/mgramseva/lib/screeens/household_register/household_list.dart +++ b/frontend/mgramseva/lib/screeens/household_register/household_list.dart @@ -73,8 +73,8 @@ class _HouseholdListState extends State { leftColumnWidth: width, rightColumnWidth: width * (householdProvider.collectionHeaderList.length - 1), - height: 58 + (52.0 * tableData.length + 1), - scrollPhysics: NeverScrollableScrollPhysics(), + height: 58 + (52.0 * (tableData.length < 10 ? tableData.length : 10 ) + 1), + scrollPhysics: BouncingScrollPhysics(), ); }); } diff --git a/frontend/mgramseva/lib/screeens/household_register/household_register.dart b/frontend/mgramseva/lib/screeens/household_register/household_register.dart index e3bb41715..68ff68255 100644 --- a/frontend/mgramseva/lib/screeens/household_register/household_register.dart +++ b/frontend/mgramseva/lib/screeens/household_register/household_register.dart @@ -74,7 +74,9 @@ class _HouseholdRegister extends State color: Color.fromRGBO(238, 238, 238, 1), padding: EdgeInsets.only(left: 8, right: 8), height: constraints.maxHeight - 50, - child: CustomScrollView(slivers: [ + child: CustomScrollView( + primary: false, + slivers: [ SliverList( delegate: SliverChildListDelegate([ SizedBox( @@ -99,6 +101,7 @@ class _HouseholdRegister extends State ), Container(key: key, child: HouseholdCard()), ])), + SliverToBoxAdapter(child: HouseholdSearch()) ])), Align( diff --git a/frontend/mgramseva/lib/screeens/household_register/household_search.dart b/frontend/mgramseva/lib/screeens/household_register/household_search.dart index ed443c460..6189120f0 100644 --- a/frontend/mgramseva/lib/screeens/household_register/household_search.dart +++ b/frontend/mgramseva/lib/screeens/household_register/household_search.dart @@ -68,10 +68,12 @@ class _HouseholdSearchState extends State Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: SingleChildScrollView( + primary: false, scrollDirection: Axis.horizontal, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: List.generate( + tabList.length, (index) => Padding( padding: EdgeInsets.only( diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js index 07152552d..981a9b5e1 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js @@ -583,12 +583,12 @@ export const UICustomizations = { config: { enabled: true, select: (data) => { - const result = data?.MdmsRes?.tenant?.tenants?.filter(row => row?.divisionCode && row?.divisionName)?.map(row => { - return { - ...row, - updatedCode:`${row.divisionName} - ${row?.name}` - } - }); + const result = data?.MdmsRes?.tenant?.tenants?.filter( + (row) => row?.divisionCode && row?.divisionName + )?.map((row) => ({ + ...row, + updatedCode: `${row.divisionName} - ${row?.name}`, + })); return result; }, }, diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/iframe.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/iframe.scss index 1f3b992c7..484172d6b 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/iframe.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/iframe.scss @@ -47,14 +47,16 @@ body { } .app-iframe-wrapper{ - left: 64px; - border-width: 0; - position: fixed; - top: 80px; + + left: 3.8em; + border-width: 0; + position: fixed; + top: 5.5em; } .app-iframe{ - width: 97%; - height: calc(100vh - 90px); + + width: calc(100vw-4.1em); + height: calc(100vh - 5.7em); border-width: 0; position: fixed; } diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss index 839c86b07..78b670224 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss @@ -41,6 +41,8 @@ } } + + .links-wrapper { @apply pl-md py-sm text-text-btn; .link { @@ -51,6 +53,16 @@ } } } + + .category-header{ + font-weight: 500 !important; + margin-top: 0.5rem !important; + } + + .category-item{ + margin-left: 1rem !important; + margin-top: 0.25rem !important; + } } .MobilePopupHeadingWrapper { diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/custom-css/example/index.css b/frontend/micro-ui/web/micro-ui-internals/packages/custom-css/example/index.css index b3e1be6e0..7cfbab3c6 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/custom-css/example/index.css +++ b/frontend/micro-ui/web/micro-ui-internals/packages/custom-css/example/index.css @@ -1884,7 +1884,7 @@ img, video { margin-bottom: 24px; margin-left: 0; } .employee .card-home { - width: 270px; + width: 300px; margin-right: 10px; margin-bottom: 10px; } .employee .card-home-hrms { diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/dss/useMDMS.js b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/dss/useMDMS.js index 2b420c260..bb0e6e2ac 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/dss/useMDMS.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/dss/useMDMS.js @@ -5,6 +5,7 @@ const useDssMDMS = (tenantId, moduleCode, type, config) => { const useDssDashboard = () => { return useQuery("DSS_DASHBOARD", () => MdmsService.getDssDashboard(tenantId, moduleCode), config); }; + const _default = () => { return useQuery([tenantId, moduleCode, type], () => MdmsService.getMultipleTypes(tenantId, moduleCode, type), config); }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/EmployeeModuleCard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/EmployeeModuleCard.js index 3b71938f5..646c12a2c 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/EmployeeModuleCard.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/EmployeeModuleCard.js @@ -17,7 +17,7 @@ const EmployeeModuleCard = ({ ); - + return (
@@ -44,10 +44,72 @@ const EmployeeModuleCard = ({ ))}
)} -
- {links.map(({ count, label, link }, index) => ( + + +
+ + + {links.reduce((acc, { count, label, link, category }, index) => { + const currentCategory = category; + + // Check if category has changed or is the first item + if (!acc.currentCategory || acc.currentCategory !== currentCategory) { + acc.currentCategory = currentCategory; + acc.links.push({ category, items: [] }); // Create new category object + } + + // Add link details to the current category + acc.links[acc.links.length - 1].items.push({ count, label, link }); + + return acc; + }, { currentCategory: null, links: [] }) // Initial accumulator state + .links.filter(({ items }) => items.length > 0) // Filter out categories with no items + .map(({ category, items }, index) => ( + <> + {category && ( // Display category header if category exists +
{category}
+ )} +
+ {items.map((item, subIndex) => ( +
+ + { item.link && item.link?.includes("https") ? ( + item.label.includes("Dashboard")? + + + {item.label} + : + + {item.label} + + ) : ( + {item.label} + )} + + {item.count ? ( + <> + {FsmHideCount ? null : ( + {item.count || "-"} + )} + + + + + ) : null} +
+ ))} +
+ + ))} +
+ + + + + {/*
+ {links.map(({ count, label, link,category }, index) => ( - {link && link?.includes("https") ? ( + { link && link?.includes("https") ? ( label.includes("Dashboard")? {label} : @@ -67,7 +129,7 @@ const EmployeeModuleCard = ({ ) : null} ))} -
+
*/}
diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserForm.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserForm.js index 5fddd2542..2ac58f8a5 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserForm.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserForm.js @@ -2,7 +2,10 @@ import { Loader, Header, Dropdown, LabelFieldPair, CardLabel, LinkLabel, SubmitB import React, { useState, useMemo, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { Controller, useForm, useWatch } from "react-hook-form"; -import MultiSelectDropdown from "./MultiSelectDropdown"; +import MultiSelectDropdown from "../components/pageComponents/Multiselect"; + +const XLSX = require("xlsx"); + function filterKeys(data, keys) { return data.map((item) => { const filteredItem = {}; @@ -79,7 +82,7 @@ function buildTree(data, hierarchy) { return tree; } -const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles }) => { +const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles, employeeData }) => { const { t } = useTranslation(); const [showToast, setShowToast] = useState(null); const [hierarchy, setHierarchy] = useState([ @@ -92,7 +95,9 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles { level: "code", value: 7, optionsKey: "name", isMandatory: false }, ]); const [tree, setTree] = useState(null); - const [rolesOptions, setRolesOptions] = useState(null) + const [rolesOptions, setRolesOptions] = useState(null); + const [isShowAllClicked, setIsShowAllClicked] = useState(false); + // const [zones,setZones] = useState([]) // const [circles,setCircles] = useState([]) // const [divisions,setDivisions] = useState([]) @@ -123,7 +128,7 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles name: "WSServiceRoles", }, ], - } + }, ], }, }, @@ -150,11 +155,13 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles const filteredResult = filterKeys(result, requiredKeys); const resultInTree = buildTree(filteredResult, hierarchy); const excludeCodes = ["HRMS_ADMIN", "LOC_ADMIN", "MDMS_ADMIN", "EMPLOYEE", "SYSTEM"]; - setRolesOptions(data?.MdmsRes?.["ws-services-masters"]?.["WSServiceRoles"]?.filter(row => !excludeCodes.includes(row?.code) - && - (row?.name === "Secretary" || row?.name === "Sarpanch" || row?.name === "Revenue Collector" || row?.name === "DIVISION ADMIN") - )) - + setRolesOptions( + data?.MdmsRes?.["ws-services-masters"]?.["WSServiceRoles"]?.filter( + (row) => + !excludeCodes.includes(row?.code) && + (row?.name === "Secretary" || row?.name === "Sarpanch" || row?.name === "Revenue Collector" || row?.name === "DIVISION ADMIN") + ) + ); //updating to state roles as requested // setRolesOptions([ // // { @@ -208,13 +215,13 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles unregister, } = useForm({ defaultValues: { - "zoneCode": "", - "circleCode": "", - "divisionCode": "", - "subDivisionCode": "", - "sectionCode": "", - "code": "", - "roles": [] + zoneCode: "", + circleCode: "", + divisionCode: "", + subDivisionCode: "", + sectionCode: "", + code: "", + roles: [], }, }); @@ -222,13 +229,13 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles const clearSearch = () => { reset({ - "zoneCode": "", - "circleCode": "", - "divisionCode": "", - "subDivisionCode": "", - "sectionCode": "", - "code": "", - "roles": [] + zoneCode: "", + circleCode: "", + divisionCode: "", + subDivisionCode: "", + sectionCode: "", + code: "", + roles: [], }); setUniqueRoles(null); setUniqueTenants(null); @@ -246,6 +253,44 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles // }) }; + useEffect(() => { + if (isShowAllClicked && employeeData) { + jsonToExcel(employeeData, "employees.xlsx"); + setIsShowAllClicked(false); + } + }, [employeeData]); + + function jsonToExcel(employeeData, fileName) { + const employees = employeeData.map((employee) => ({ + "User Id": employee.code, + Name: employee.user.name, + "Type of User": employee?.assignments[0]?.department, + Designation: t(employee?.assignments[0]?.designation), + Username: employee?.user?.mobileNumber, + Status: employee?.isActive ? "Active" : "Inactive", + Tenant: t(employee?.tenantId), + })); + + try { + const wb = XLSX.utils.book_new(); + const ws = XLSX.utils.json_to_sheet(employees); + + XLSX.utils.book_append_sheet(wb, ws, "Employees"); + + XLSX.writeFile(wb, fileName); + } catch (error) { + console.log("Error occurred", error); + } + } + + const showAllData = () => { + clearSearch(); + setIsShowAllClicked(true); + const listOfUniqueTenants = getUniqueLeafCodes(tree); + + setUniqueTenants(() => listOfUniqueTenants); + setUniqueRoles(() => rolesOptions?.filter((row) => row.code)?.map((role) => role.code)); + }; const onSubmit = (data) => { //assuming atleast one hierarchy is entered @@ -302,7 +347,7 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles //this is the list of tenants under the current subtree const listOfUniqueTenants = getUniqueLeafCodes(currentLevel); setUniqueTenants(() => listOfUniqueTenants); - setUniqueRoles(() => data?.roles?.filter(row => row.code)?.map(role => role.code)); + setUniqueRoles(() => data?.roles?.filter((row) => row.code)?.map((role) => role.code)); }; const optionsForHierarchy = (level, value) => { @@ -330,8 +375,9 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles const renderHierarchyFields = useMemo(() => { return hierarchy.map(({ level, optionsKey, isMandatory, ...rest }, idx) => ( - {`${t(Digit.Utils.locale.getTransformedLocale(`HR_SU_${level}`))} ${isMandatory ? "*" : "" - }`} + {`${t(Digit.Utils.locale.getTransformedLocale(`HR_SU_${level}`))} ${ + isMandatory ? "*" : "" + }`} ( { + rolesOptions?.forEach((option) => { + option.i18text = "ACCESSCONTROL_ROLES_ROLES_" + option?.code; + }); + }, [rolesOptions]); + if (isLoading || !setTree) { return ; } @@ -384,7 +436,7 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles
{ @@ -394,19 +446,19 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles return row?.[1] ? row[1] : null; }) .filter((e) => e) - ) + ); }} selected={props?.value || []} defaultLabel={t("HR_SU_SELECT_ROLES")} defaultUnit={t("COMMON_ROLES_SELECTED")} showSelectAll={true} t={t} - // config={config} - // disable={false} - // optionsDisable={config?.optionsDisable} + // config={config} + // disable={false} + // optionsDisable={config?.optionsDisable} />
- ) + ); }} rules={{}} defaultValue={[]} @@ -424,6 +476,14 @@ const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles {t("HR_SU_CLEAR_SEARCH")} + { + showAllData(); + }} + > + {t("HR_SHOW_ALL_DATA")} + diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js index 7561dd21f..4c40da348 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js @@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next"; import EmployeeModuleCard from "./EmployeeModuleCard"; const HRMSCard = () => { - const ADMIN = Digit.Utils.hrmsAccess(); const STATE_ADMIN = Digit.UserService.hasAccess(["STATE_ADMIN"]); const DIV_ADMIN = Digit.UserService.hasAccess(["DIV_ADMIN"]); @@ -18,46 +17,43 @@ const HRMSCard = () => { let roles = STATE_ADMIN ? { roles: "DIV_ADMIN", isStateLevelSearch: true } : { - roles: "SYSTEM, GP_ADMIN, COLLECTION_OPERATOR, PROFILE_UPDATE, DASHBOAD_VIEWER, SARPANCH, REVENUE_COLLECTOR, SECRETARY", - isStateLevelSearch: false, - }; + roles: "SYSTEM, GP_ADMIN, COLLECTION_OPERATOR, PROFILE_UPDATE, DASHBOAD_VIEWER, SARPANCH, REVENUE_COLLECTOR, SECRETARY", + isStateLevelSearch: false, + }; const { isLoading, isError, error, data, ...rest } = Digit.Hooks.hrms.useHRMSCount(tenantId, roles); const moduleForSomeDIVAdmin = - DIV_ADMIN && MDMS_ADMIN ? [ - { - label: t("WORK_BENCH_URL_MASTER_DATA"), - link: `${window?.location?.origin}/workbench-ui/employee/workbench/mdms-search-v2?moduleName=ws-services-calculation&masterName=WCBillingSlab`, - }, - // { - // label: t("WORK_BENCH_URL_LOCALIZATION"), - // link: `${window?.location?.origin}/workbench-ui/employee/workbench/localisation-search`, - // }, - ] + { + label: t("WORK_BENCH_URL_MASTER_DATA"), + link: `${window?.location?.origin}/workbench-ui/employee/workbench/mdms-search-v2?moduleName=ws-services-calculation&masterName=WCBillingSlab`, + category: t("HR_EDIT_MASTER"), + }, + ] : []; const moduleForSomeSTATEUser = STATE_ADMIN && MDMS_ADMIN ? [ - { - label: t("WORK_BENCH_URL_VILLAGE_MASTER_DATA"), - link: `${window?.location?.origin}/workbench-ui/employee/workbench/mdms-search-v2?moduleName=tenant&masterName=tenants`, - }, - ] + { + label: t("WORK_BENCH_URL_VILLAGE_MASTER_DATA"), + link: `${window?.location?.origin}/workbench-ui/employee/workbench/mdms-search-v2?moduleName=tenant&masterName=tenants`, + category: t("HR_EDIT_MASTER"), + }, + ] : []; const moduleForDivisionUser = - DIV_ADMIN && MDMS_ADMIN ? - [ - { - label: t("WORK_BENCH_URL_PENALTY_MASTER_DATA"), - link: `${window?.location?.origin}/workbench-ui/employee/workbench/mdms-search-v2?moduleName=ws-services-calculation&masterName=Penalty`, - - }, - ] : []; - + DIV_ADMIN && MDMS_ADMIN + ? [ + { + label: t("WORK_BENCH_URL_PENALTY_MASTER_DATA"), + link: `${window?.location?.origin}/workbench-ui/employee/workbench/mdms-search-v2?moduleName=ws-services-calculation&masterName=Penalty`, + category: t("HR_EDIT_MASTER"), + }, + ] + : []; const propsForModuleCard = { Icon: , @@ -76,26 +72,33 @@ const HRMSCard = () => { ], links: [ { - label: t("HR_SEARCH_USER"), + label: STATE_ADMIN ? t("HR_COMMON_CREATE_DIVISION_EMPLOYEE_HEADER") : t("HR_COMMON_CREATE_EMPLOYEE_HEADER"), + link: `/${window?.contextPath}/employee/hrms/create`, + category: t("HR_CREATE_USER_HEADER"), + }, + { + label: STATE_ADMIN ? t("HR_DIVISION_SEARCH_USER") : t("HR_SEARCH_USER"), link: `/${window?.contextPath}/employee/hrms/search-user`, - roles: ["DIV_ADMIN", "STATE_ADMIN"] + roles: ["DIV_ADMIN", "STATE_ADMIN"], + category: t("SEARCH_USER_HEADER"), }, { label: t("HR_HOME_SEARCH_RESULTS_HEADING"), link: `/${window?.contextPath}/employee/hrms/inbox`, + category: t("SEARCH_USER_HEADER"), }, + + DIV_ADMIN + ? {} + : { + label: t("HR_STATE_ REPORTS"), + link: `/${window?.contextPath}/employee/hrms/dashboard?moduleName=dashboard&pageName=state`, + category: t("HR_DASHBOARD_HEADER"), + }, { - label: STATE_ADMIN ? t("HR_COMMON_CREATE_DIVISION_EMPLOYEE_HEADER") : t("HR_COMMON_CREATE_EMPLOYEE_HEADER"), - link: `/${window?.contextPath}/employee/hrms/create`, - }, - DIV_ADMIN ? {} : - { - label: t("HR_STATE_ REPORTS"), - link: "https://mgramseva-dwss.punjab.gov.in/kibana/app/r/s/JNF2x?auth_provider_hint=anonymous1", - }, - { label: t("HR_RATE_DASHBOARD"), - link: "https://mgramseva-dwss.punjab.gov.in/kibana/app/dashboards#/view/22ed8660-39cf-11ef-841e-251f7e3bc6c7?[…]!t,value:60000),time:(from:now-15m,to:now))", + link: `/${window?.contextPath}/employee/hrms/dashboard?moduleName=dashboard&pageName=rate-master`, + category: t("HR_DASHBOARD_HEADER"), }, ...moduleForSomeDIVAdmin, ...moduleForSomeSTATEUser, @@ -106,5 +109,4 @@ const HRMSCard = () => { return ; }; - export default HRMSCard; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/DesktopInbox.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/DesktopInbox.js index 5e432b1d2..35b42b9f4 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/DesktopInbox.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/DesktopInbox.js @@ -91,6 +91,22 @@ const DesktopInbox = ({ tableConfig, filterComponent, ...props }) => { // ); }, }, + { + Header: t("HR_USER_TYPE"), + disableSortBy: false, + accessor: "typeofuser", + Cell: ({ row }) => { + return GetCell(`${row.original?.assignments[0]?.department}`); + }, + }, + { + Header: t("HR_USER_DESIGNATION"), + disableSortBy: false, + accessor: "designation", + Cell: ({ row }) => { + return GetCell(`${row.original?.assignments[0]?.designation}`); + }, + }, { Header: t("HR_STATUS_LABEL"), disableSortBy: false, @@ -195,4 +211,4 @@ const DesktopInbox = ({ tableConfig, filterComponent, ...props }) => { ); }; -export default DesktopInbox; \ No newline at end of file +export default DesktopInbox; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js index 752bec612..730bc5d05 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js @@ -88,12 +88,10 @@ const MultiSelectDropdown = ({ }, [selected?.length]); function fnToSelectOptionThroughProvidedSelection(selected) { - return selected?.map((e) => ( - { - [optionsKey]: e?.i18text? e.i18text : `ACCESSCONTROL_ROLES_ROLES_${e.code}`, - propsData: [null, e] - } - )); + return selected?.map((e) => ({ + [optionsKey]: e?.i18text ? e.i18text : `ACCESSCONTROL_ROLES_ROLES_${e.code}`, + propsData: [null, e], + })); } const [alreadyQueuedSelectedState, dispatch] = useReducer(reducer, selected, fnToSelectOptionThroughProvidedSelection); @@ -107,16 +105,15 @@ const MultiSelectDropdown = ({ } }, [active]); - useEffect(()=>{ - if (alreadyQueuedSelectedState?.length === filteredOptions?.length){ - if(alreadyQueuedSelectedState?.length != 0 && filteredOptions?.length != 0){ - setIsSelected(true) - } - }else{ - setIsSelected(false) - + useEffect(() => { + if (alreadyQueuedSelectedState?.length === filteredOptions?.length) { + if (alreadyQueuedSelectedState?.length != 0 && filteredOptions?.length != 0) { + setIsSelected(true); + } + } else { + setIsSelected(false); } - },[alreadyQueuedSelectedState]) + }, [alreadyQueuedSelectedState]); function handleOutsideClickAndSubmitSimultaneously() { setActive(false); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js index 15ad7adbb..af19a5905 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js @@ -39,17 +39,17 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { !isEdit && sessionFormData?.Jurisdictions?.length > 0 ? makeDefaultValues(sessionFormData) : formData?.Jurisdictions || [ - { - id: undefined, - key: 1, - hierarchy: null, - boundaryType: null, - boundary: null, - division: {}, - divisionBoundary: [], - roles: [], - }, - ] + { + id: undefined, + key: 1, + hierarchy: null, + boundaryType: null, + boundary: null, + division: {}, + divisionBoundary: [], + roles: [], + }, + ] ); const [jurisdictionsData, setJuristictionsData] = useState([]); let hierarchylist = []; @@ -86,7 +86,6 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { return unique; }, []); - const uniqueDivisions = divisions?.reduce((unique, obj) => { const isDuplicate = unique.some((item) => item.id === obj.id && item.name === obj.name); if (!isDuplicate) { @@ -107,7 +106,6 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { ); if (uniqueSubDivisionsItems != null) { selectSubDivisionList(uniqueSubDivisionsItems); - } // selectSectionListList }, [data, userData]); @@ -197,7 +195,6 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { config.key, [...jurisdictionData, ...inactiveJurisdictions].filter((value) => Object.keys(value).length !== 0) ); - }, [jurisdictions, data?.MdmsRes]); const reviseIndexKeys = () => { @@ -235,7 +232,6 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { ]); setJuristictionsData((prev) => prev.map((unit, index) => ({ ...unit, key: index }))); } - } else { setjurisdictions((prev) => [ ...prev, @@ -250,31 +246,22 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { }, ]); setjurisdictions((prev) => prev.map((unit, index) => ({ ...unit, key: index }))); - } - - - }; function filterJurisdictions(unit, jurisdictions) { - const divisionBoundaryCodes = new Set(unit.divisionBoundary.map(item => item.code)); - return jurisdictions.filter(jurisdiction => { + const divisionBoundaryCodes = new Set(unit.divisionBoundary.map((item) => item.code)); + return jurisdictions.filter((jurisdiction) => { return !divisionBoundaryCodes.has(jurisdiction.boundary.code); }); } const handleRemoveUnit = (unit) => { if (STATE_ADMIN) { if (!isEdit) { - setjurisdictions(jurisdictions.filter( - (element) => element.key !== unit.key - )); + setjurisdictions(jurisdictions.filter((element) => element.key !== unit.key)); setjurisdictions((prev) => prev.map((unit, index) => ({ ...unit, key: index }))); - } - else { - setJuristictionsData(jurisdictionsData.filter( - (element) => element.key !== unit.key - )); + } else { + setJuristictionsData(jurisdictionsData.filter((element) => element.key !== unit.key)); let filterJurisdictionsItems = filterJurisdictions(unit, jurisdictions); setjurisdictions(filterJurisdictionsItems); setjurisdictions((prev) => prev.map((unit, index) => ({ ...unit, key: index }))); @@ -283,10 +270,7 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { clearErrors("Jurisdictions"); } reviseIndexKeys(); - } - - - else { + } else { if (unit.id) { let res = { id: unit?.id, @@ -315,15 +299,11 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { } reviseIndexKeys(); - } - }; let boundaryTypeoption = []; const [focusIndex, setFocusIndex] = useState(-1); - - function getroledata() { if (STATE_ADMIN) { // Specify the role codes you want to filter @@ -341,8 +321,9 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { const roleCodesToFilter = ["HRMS_ADMIN", "DIV_ADMIN", "MDMS_ADMIN", "LOC_ADMIN", "SYSTEM"]; // Use the filter method to extract roles with the specified codes return data?.MdmsRes?.["ws-services-masters"].WSServiceRoles?.filter((role) => { - return !roleCodesToFilter.includes(role.code) && - (role?.name === "Secretary" || role?.name === "Sarpanch" || role?.name === "Revenue Collector"); + return ( + !roleCodesToFilter.includes(role.code) && (role?.name === "Secretary" || role?.name === "Sarpanch" || role?.name === "Revenue Collector") + ); })?.map((role) => { return { code: role.code, name: role?.name ? role?.name : " ", i18text: "ACCESSCONTROL_ROLES_ROLES_" + role.code }; }); @@ -407,7 +388,7 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { // SUBDIVISION & SECTION subDivisionList={subDivisionList} sectionList={sectionList} - // SUBDIVISION & SECTION + // SUBDIVISION & SECTION /> )) )} @@ -457,9 +438,9 @@ function Jurisdiction({ if (ele.code === currentTenant) { defaultjurisdiction = ele; } - }) + }); return defaultjurisdiction; - } + }; useEffect(() => { setDivision( @@ -488,7 +469,6 @@ function Jurisdiction({ setjurisdictions((pre) => pre.map((item) => (item.key === jurisdiction.key ? { ...item, boundary: value } : item))); }; - const selectSubDivisionList = (value) => { setjurisdictions((pre) => pre.map((item) => (item.key === jurisdiction.key ? { ...item, subDivision: value } : item))); @@ -498,7 +478,7 @@ function Jurisdiction({ return { code: division.sectionCode, name: division.sectionName, - i18text: Digit.Utils.locale.getCityLocale(division.sectionCode) + i18text: Digit.Utils.locale.getCityLocale(division.sectionCode), }; }); const uniqueSections = sections?.reduce((unique, obj) => { @@ -771,9 +751,7 @@ function Jurisdiction({
0 && "50px", overflowY: "scroll" }}> {jurisdiction?.roles.length > 0 && jurisdiction?.roles.map((value, index) => { - return ( - onRemove(index, value)} /> - ) + return onRemove(index, value)} />; })}
diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/Dashboard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/Dashboard.js new file mode 100644 index 000000000..0f4a04983 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/Dashboard.js @@ -0,0 +1,25 @@ +import React, { useState, useEffect } from "react"; +import IFrameInterface from "../../../utilities/src/pages/employee/IFrameInterface/index"; + +const Dashboard = () => { + const queryString = window.location.search; + const params = new URLSearchParams(queryString); + const moduleName = params.get("moduleName"); + const pageName = params.get("pageName"); + const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb"; + + return ( +
+ +
+ ); +}; + +export default Dashboard; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/SearchUser.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/SearchUser.js index 68bcb3a5d..f61b924a6 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/SearchUser.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/SearchUser.js @@ -1,14 +1,15 @@ -import React, { useState, useEffect } from 'react' -import SearchUserForm from '../components/SearchUserForm' -import SearchUserResults from '../components/SearchUserResults'; -import { Header } from '@egovernments/digit-ui-react-components' +import React, { useState, useEffect } from "react"; +import SearchUserForm from "../components/SearchUserForm"; +import SearchUserResults from "../components/SearchUserResults"; +import { Header } from "@egovernments/digit-ui-react-components"; import { useTranslation } from "react-i18next"; - const SearchUser = () => { + const { t } = useTranslation() const [uniqueTenants, setUniqueTenants] = useState(null) const [roles, setUniqueRoles] = useState(null) + const STATE_ADMIN = Digit.UserService.hasAccess(["STATE_ADMIN"]); const requestCriteriaForEmployeeSearch = { url: "/egov-hrms/employees/_searchListOfEmployee", @@ -17,34 +18,37 @@ const SearchUser = () => { criteria: { tenantIds: uniqueTenants, roles: roles, - type: "EMPLOYEE" - } + type: "EMPLOYEE", + }, }, config: { enabled: !!uniqueTenants && !!roles, select: (data) => { - return data?.Employees + return data?.Employees; }, - }, - changeQueryName: { uniqueTenants, roles } + changeQueryName: { uniqueTenants, roles }, }; const { isLoading, data, revalidate, isFetching, error } = Digit.Hooks.useCustomAPIHook(requestCriteriaForEmployeeSearch); - - return (
-
{t("HR_SU")}
- +
{STATE_ADMIN ? t("HR_SDU") :t("HR_SU")}
+
- ) -} + ); +}; -export default SearchUser \ No newline at end of file +export default SearchUser; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js index 56279ed7e..84e8d5d86 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js @@ -1,8 +1,10 @@ import { PrivateRoute } from "@egovernments/digit-ui-react-components"; -import React,{ useEffect } from "react"; +import React, { useEffect } from "react"; import { useTranslation } from "react-i18next"; import { Link, Switch, useLocation, useHistory } from "react-router-dom"; import SearchUser from "./SearchUser"; +import Dashboard from "./Dashboard"; + // const {SixFtApart,Rotate360}=SVG; const EmployeeApp = ({ path, url, userType }) => { const { t } = useTranslation(); @@ -23,26 +25,32 @@ const EmployeeApp = ({ path, url, userType }) => { const EditEmpolyee = Digit?.ComponentRegistryService?.getComponent("HREditEmpolyee"); const employeeCreateSession = Digit.Hooks.useSessionStorage("NEW_EMPLOYEE_CREATE", {}); - const [sessionFormData,setSessionFormData, clearSessionFormData] = employeeCreateSession; + const [sessionFormData, setSessionFormData, clearSessionFormData] = employeeCreateSession; // remove session form data if user navigates away from the estimate create screen - useEffect(()=>{ + useEffect(() => { if (!window.location.href.includes("/hrms/create") && sessionFormData && Object.keys(sessionFormData) != 0) { - clearSessionFormData(); + clearSessionFormData(); } -},[location]); + }, [location]); return (

- + {t("HR_COMMON_BUTTON_HOME")} {" "} - / {location.pathname === `/${window?.contextPath}/employee/hrms/inbox` ? t("HR_COMMON_HEADER") : t("HR_COMMON_HEADER")} + / {location.pathname === `/${window?.contextPath}/employee/hrms/inbox` ? t("HR_COMMON_HEADER") : t("HR_COMMON_HEADER")}

-
history.goBack()}>

Back

+
history.goBack()}> + + + + +

Back

+
( @@ -54,6 +62,7 @@ const EmployeeApp = ({ path, url, userType }) => { } /> } /> } /> + } />
diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/UICustomizations.js index f9d91f8da..07d9858ff 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/UICustomizations.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/UICustomizations.js @@ -177,6 +177,11 @@ export const UICustomizations = { updatedCode:`${row.divisionName} - ${row?.name}` } }); + result.sort((a, b) => { + const nameA = (a.divisionName || "").toLowerCase().trim(); + const nameB = (b?.divisionName || "").toLowerCase().trim(); + return nameA.localeCompare(nameB); + }); return result; }, }, diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/README.md new file mode 100644 index 000000000..5ec6f55ab --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/README.md @@ -0,0 +1,152 @@ + + +# digit-ui-module-utilities + +## Install + +```bash +npm install --save digit-ui-module-utilities +``` + +## 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-utilities":"0.0.1", +``` + +then navigate to App.js + +```bash + frontend/micro-ui/web/src/App.js +``` + +```jsx +/** add this import **/ + +import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; + +/** inside enabledModules add this new module key **/ + +const enabledModules = ["Utilities"]; + +/** inside init Function call this function **/ + +const initDigitUI = () => { + initUtilitiesComponents(); +}; + +``` + +Add the Inbox /search config and use as mentioned below + +```jsx + import { InboxSearchComposer } from "@egovernments/digit-ui-module-utilities"; + + +
{t(updatedConfig?.label)}
+
+ +
+
+``` + + +In MDMS + +_Add this configuration to enable this module [MDMS Enabling Utilities Module](https://github.com/egovernments/works-mdms-data/blob/48461ecaf944ea243e24e1c1f9a5e2179d8091ac/data/pg/tenant/citymodule.json#L193)_ + +## List of Screens available in this versions were as follows + +1. Search or Inbox + Example Routes as follows + + ```bash + works-ui/employee/utilities/search/commonMuktaUiConfig/SearchIndividualConfig + + works-ui/employee/utilities/search/commonMuktaUiConfig/InboxMusterConfig + ``` + +2. Iframe + + ```bash + works-ui/employee/utilities/iframe/shg/home + ``` + +3. Workflow Test for any module + +Sample URL + +_Contract Module + +```bash + works-ui/employee/utilities/workflow?tenantId=pg.citya&applicationNo=WO/2023-24/000721&businessService=CONTRACT&moduleCode=contract +``` + +_Estimate Module + +```bash + works-ui/employee/utilities/workflow?tenantId=pg.citya&applicationNo=ES/2023-24/001606&businessService=ESTIMATE&moduleCode=estimate +``` + +_Attendance Module + +```bash + works-ui/employee/utilities/workflow?tenantId=pg.citya&applicationNo=MR/2023-24/05/31/000778&businessService=MR&moduleCode=muster%20roll +``` + +_Bill Module + +```bash + works-ui/employee/utilities/workflow?tenantId=pg.citya&applicationNo=PB/2023-24/000379&businessService=EXPENSE.PURCHASE&moduleCode=wages.purchase +``` + + + + +## Coming Soon + +1. Create Screen +2. View Screen + + +### Changelog + +```bash +1.0.0 Workbench v1.0 release +1.0.0-beta workbench base version beta release +0.0.8 fix response data for custom compnent in inbox composer +0.0.7 updated the readme content +0.0.6 fixed the module overriding issue +0.0.5 fixed the instablility issue with previous version +0.0.4 Updated the react-component library version +0.0.3 corrected the directory and added the preprocess function at inbox +0.0.2 added into the digit-core and integrated with core react components +0.0.1 base version +``` + +### Contributors + +[jagankumar-egov] + + +## 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) \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/package.json new file mode 100644 index 000000000..89633d425 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/package.json @@ -0,0 +1,39 @@ +{ + "name": "@egovernments/digit-ui-module-utilities", + "version": "1.0.0", + "description": "Utilities Module UI", + "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", + "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" + }, + "author": "Jagankumar ", + "license": "MIT", + "keywords": [ + "digit", + "egov", + "dpg", + "digit-ui", + "utilities" + ] +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/Module.js new file mode 100644 index 000000000..b9cb3f314 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/Module.js @@ -0,0 +1,33 @@ +import { Loader, InboxSearchComposer, FormComposerV2 } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useRouteMatch } from "react-router-dom"; +import { default as EmployeeApp } from "./pages/employee"; + +export const UtilitiesModule = ({ stateCode, userType, tenants }) => { + const { path, url } = useRouteMatch(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const moduleCode = ["utilities", "common-masters", tenantId]; + const language = Digit.StoreData.getCurrentLanguage(); + const { isLoading, data: store } = Digit.Services.useStore({ + stateCode, + moduleCode, + language, + }); + + if (isLoading) { + return ; + } + return ; +}; + +const componentsToRegister = { + UtilitiesModule +}; + +export const initUtilitiesComponents = () => { + Object.entries(componentsToRegister).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; + +export { InboxSearchComposer, FormComposerV2 }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/DynamicCreateComponent/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/DynamicCreateComponent/index.js new file mode 100644 index 000000000..2370108cd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/DynamicCreateComponent/index.js @@ -0,0 +1,51 @@ +import { Loader,FormComposerV2 as FormComposer } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +const CreateProject = () => { + const { t } = useTranslation(); + const stateTenant = Digit.ULBService.getStateId(); + const { moduleName, masterName } = useParams(); + + const { isLoading, data: configs } = Digit.Hooks.useCustomMDMS( + //change to data + stateTenant, + moduleName, + [ + { + name: masterName, + }, + ], + { + select: (data) => { + return data?.[moduleName]?.[masterName]?.[0]; + }, + } + ); + + if (isLoading) return ; + return ( + +
{t("CREATE")}
+ + { + return { + ...config, + body: config?.body.filter((a) => !a.hideInEmployee), + }; + })} + onSubmit={() => {}} + submitInForm={false} + fieldStyle={{ marginRight: 0 }} + inline={false} + className="form-no-margin" + defaultValues={{}} + cardClassName="mukta-header-card" + /> +
+ ); +}; + +export default CreateProject; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/DynamicSearchComponent/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/DynamicSearchComponent/index.js new file mode 100644 index 000000000..daa764edf --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/DynamicSearchComponent/index.js @@ -0,0 +1,62 @@ +import { AddFilled, Button, Header, InboxSearchComposer, Loader } 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"; + +// works-ui/employee/dss/search/commonMuktaUiConfig/SearchEstimateConfig +const DynamicSearchComponent = () => { + const { t } = useTranslation(); + const history = useHistory(); + const { moduleName, masterName } = useParams(); + const [pageConfig, setPageConfig] = useState(null); + const tenant = Digit.ULBService.getStateId(); + const { isLoading, data } = Digit.Hooks.useCustomMDMS( + tenant, + moduleName, + [ + { + name: masterName, + }, + ], + { + select: (data) => { + return data?.[moduleName]?.[masterName]?.[0]; + }, + } + ); + let configs = data || {}; + + const updatedConfig = useMemo(() => Digit.Utils.preProcessMDMSConfigInboxSearch(t, pageConfig, "sections.search.uiConfig.fields", {}), [ + data, + pageConfig, + ]); + + useEffect(() => { + setPageConfig(_.cloneDeep(configs)); + }, [data]); + + if (isLoading || !pageConfig) return ; + return ( + +
+
{t(updatedConfig?.label)}
+ {Digit.Utils.didEmployeeHasRole(updatedConfig?.actionRole) && ( +
+
+ +
+
+ ); +}; + +export default DynamicSearchComponent; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/IFrameInterface/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/IFrameInterface/index.js new file mode 100644 index 000000000..bdf2b4f09 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/utilities/src/pages/employee/IFrameInterface/index.js @@ -0,0 +1,274 @@ +import { Header, Loader } from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useLocation } from "react-router-dom"; +import { Toast } from "@egovernments/digit-ui-components"; +import axios from "axios"; + +// moduleName, pageName will be passed as props as defined in the uiCommonConstants to fetch URL. +const IFrameInterface = (props) => { + const { stateCode, moduleName, pageName, filters } = props; + const location = useLocation(); + const iframeRef = useRef(null); + const localStorageKey = "Employee.token"; + const [isAxiosLoading, setIsAxiosLoading] = useState(true); + const { t } = useTranslation(); + const [url, setUrl] = useState(""); + const [title, setTitle] = useState(""); + const [sendAuth, setSendAuth] = useState(true); + const [iframeLoaded, setIframeLoaded] = useState(false); + + const { data, isLoading } = Digit.Hooks.dss.useMDMS(stateCode, "common-masters", ["uiCommonConstants"], { + select: (data) => { + let formattedResponse = data?.["common-masters"]?.["uiCommonConstants"]?.[0] || {}; + return formattedResponse; + }, + enabled: true, + }); + + const injectCustomHttpInterceptors = (iframeWindow) => { + const injectCustomHttpInterceptor = () => { + try { + if (!iframeWindow) { + console.error("Failed to access iframe content window."); + return; + } + + const xhrOpen = iframeWindow.XMLHttpRequest.prototype.open; + iframeWindow.XMLHttpRequest.prototype.open = function (method, url, async, user, password) { + // Intercepting here + this.addEventListener("readystatechange", function () { + if (this.readyState === XMLHttpRequest.OPENED) { + const oidcToken = window.localStorage.getItem(localStorageKey); + if (oidcToken) { + const accessToken = oidcToken; + + if (sendAuth === "invalid") { + this.setRequestHeader("Authorization", "Bearer " + "authToken"); + } else { + this.setRequestHeader("Authorization", accessToken); + } + } + this.setRequestHeader("type-req", "xhr"); + } + }); + xhrOpen.apply(this, arguments); + }; + } catch (error) { + console.error("Error injecting custom HTTP interceptor:", error); + } + }; + + const injectCustomHttpInterceptorFetch = () => { + try { + if (!iframeWindow) { + console.error("Failed to access iframe content window."); + return; + } + + const originalFetch = iframeWindow.fetch; + iframeWindow.fetch = function (url, options = {}) { + options.headers = options.headers || {}; + const oidcToken = window.localStorage.getItem(localStorageKey); + if (oidcToken) { + const accessToken = oidcToken; + + if (sendAuth === "invalid") { + options.headers["Authorization"] = `Bearer authToken`; + } else { + options.headers["Authorization"] = `${accessToken}`; + } + } + options.headers["type-req"] = "fetch"; + return originalFetch(url, options) + .then((response) => { + return response; + }) + .catch((error) => { + console.error("Fetch error:", error); + throw error; + }); + }; + } catch (error) { + console.error("Error injecting custom HTTP interceptor:", error); + } + }; + + const injectCustomHttpInterceptorDocumentApi = () => { + try { + if (!iframeWindow) { + console.error("Failed to access iframe content window."); + return; + } + + if (typeof iframeWindow.document.api !== "function") { + console.error("document.api is not a function."); + return; + } + + const originalDocumentApi = iframeWindow.document.api; + iframeWindow.document.api = function (url, options = {}) { + options.headers = options.headers || {}; + const oidcToken = window.localStorage.getItem(localStorageKey); + if (oidcToken) { + const accessToken = oidcToken; + + if (sendAuth === "invalid") { + options.headers["Authorization"] = `Bearer authToken`; + } else { + options.headers["Authorization"] = `${accessToken}`; + } + } + options.headers["type-req"] = "document"; + return originalDocumentApi(url, options) + .then((response) => { + return response; + }) + .catch((error) => { + console.error("Document API error:", error); + throw error; + }); + }; + } catch (error) { + console.error("Error injecting custom HTTP interceptor for document.api:", error); + } + }; + + if (sendAuth) { + injectCustomHttpInterceptor(); + injectCustomHttpInterceptorFetch(); + injectCustomHttpInterceptorDocumentApi(); + } + }; + + useEffect(() => { + const iframeWindow = iframeRef?.current?.contentWindow || iframeRef?.current?.contentDocument; + if (iframeRef.current) { + injectCustomHttpInterceptors(iframeWindow); + } + }, [localStorageKey, sendAuth, location]); + + useEffect(() => { + const pageObject = data?.[moduleName]?.["iframe-routes"]?.[pageName] || {}; + if (pageObject?.Authorization) { + if (pageObject?.SendInvalidAuthorization) { + setSendAuth("invalid"); + } else { + setSendAuth(true); + } + } else { + setSendAuth(false); + } + + const isOrign = pageObject?.["isOrigin"] || false; + const domain = isOrign + ? process.env.NODE_ENV === "development" + ? "https://mgramseva-dwss.punjab.gov.in" + : document.location.origin + : pageObject?.["domain"]; + //checking if overwrite time is true then update the url as per filter time else return the url + + const contextPath = pageObject?.["routePath"] + ? pageObject?.["overwriteTimeFilter"] && filters?.range?.startDate && filters?.range?.endDate + ? pageObject["routePath"] + .replace("from:now-15m", `from:'${new Date(filters?.range?.startDate).toISOString()}'`) + .replace("to:now", `to:'${new Date(filters?.range?.endDate).toISOString()}'`) + : pageObject["routePath"] + : ""; + const title = pageObject?.["title"] || ""; + let url = `${domain}${contextPath}`; + + if (pageObject?.authToken && pageObject?.authToken?.enable) { + const authKey = pageObject?.authToken?.key || "auth-token"; + if (pageObject?.authToken?.customFun && Digit.Utils.createFunction(pageObject?.authToken?.customFun)) { + const customFun = Digit.Utils.createFunction(pageObject?.authToken?.customFun); + url = customFun(url, Digit.UserService.getUser()?.access_token, pageObject?.authToken); + } else { + url = `${url}&${authKey}=${Digit.UserService.getUser()?.access_token || ""}`; + } + } + setUrl(url); + + setTitle(title); + }, [data, moduleName, pageName, location, filters]); + + useEffect(() => { + const fetchData = async () => { + try { + const basePath = data?.[moduleName]?.["iframe-routes"]?.[pageName]?.["base-kibana-path"] || "/kibana/"; + const response = await axios.post( + `${window.location.origin}${basePath}internal/security/login`, + { + providerType: "anonymous", + providerName: "anonymous1", + currentURL: `${window.location.origin}${basePath}login`, + }, + { + headers: { + Accept: "*/*", + "Accept-Language": "en-US,en;q=0.9", + "Cache-Control": "no-cache", + Connection: "keep-alive", + "Content-Type": "application/json", + DNT: "1", + Origin: window.location.origin, + Pragma: "no-cache", + Referer: `${window.location.origin}${basePath}login?next=%2Fkibana%2F`, + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-origin", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", + "kbn-build-number": "68312", + "kbn-version": "8.11.3", + "sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Windows"', + "x-elastic-internal-origin": "Kibana", + "x-kbn-context": `{"type":"application","name":"security_login","url":"${basePath}login"}`, + }, + } + ); + const setCookie = response.headers["set-cookie"]; + if (setCookie) { + console.log("axios cookie set", setCookie); + document.cookie = setCookie; + } + } catch (error) { + console.log("axios resp err", error.message); + console.error("Error fetching data:", error); + } finally { + setIsAxiosLoading(false); + } + }; + + fetchData(); + }, []); + + if (isLoading || isAxiosLoading) { + return ; + } + + if (!url) { + return
No Iframe To Load
; + } + + return ( + +
{t(title)}
+
+