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 0719d6ca091..e956e0f86c2 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-beta.2: Enhanced `useCustomMdms` hook to support version 2 of MDMS API calls. 1.8.1-beta.1 Republished after merging with Master due to version issues. 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 374d1185336..5ee80d755cf 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-beta.1", + "version": "1.8.1-beta.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/hooks/useCustomMDMS.js b/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomMDMS.js index 523bcf41593..292be88c2bf 100644 --- a/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomMDMS.js +++ b/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomMDMS.js @@ -1,6 +1,8 @@ import { useQuery } from "react-query"; import { MdmsService } from "../services/elements/MDMS"; - +import useCustomAPIHook from "./useCustomAPIHook"; +import Urls from "../services/atoms/urls"; +import _ from "lodash"; /** * Custom hook which can be used to * make a single hook a module to get multiple masterdetails with/without filter @@ -25,7 +27,42 @@ import { MdmsService } from "../services/elements/MDMS"; * * @returns {Object} Returns the object of the useQuery from react-query. */ -const useCustomMDMS = (tenantId, moduleName, masterDetails = [], config = {}) => { +const useCustomMDMS = (tenantId, moduleName, masterDetails = [], config = {},mdmsv2=false,) => { + if(mdmsv2) { + //here call the mdmsv2 api and return the options array + return useCustomAPIHook({ + url: Urls.mdms_v2.search, + params:{}, + changeQueryName:`mdms-v2-dropdowns${mdmsv2?.schemaCode}`, + body:{ + MdmsCriteria:{ + // tenantId, //changing here to send user's tenantId always whether stateId or city + tenantId:Digit.ULBService.getCurrentTenantId(), + schemaCode:mdmsv2?.schemaCode, + isActive:true, + limit: 100, + } + }, + config:{ + enabled:mdmsv2 ? true : false , + select: (response) => { + //mdms will be an array of master data + const {mdms} = response + //first filter with isActive + //then make a data array with actual data + //refer the "code" key in data(for now) and set options array , also set i18nKey in each object to show in UI + const options = mdms?.filter(row => row?.isActive)?.map(row => { + return { + i18nKey:Digit.Utils.locale.getTransformedLocale(`${row?.schemaCode}_${row?.data?.code}`), + ...row.data, + } + }) + return options; + } + } + + }); + } return useQuery([tenantId, moduleName, masterDetails], () => MdmsService.getMultipleTypesWithFilter(tenantId, moduleName, masterDetails), config); }; 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 b18f0dd26a9..e1a2f009eee 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 @@ -137,6 +137,7 @@ To use the InboxSearchComposer component for managing multiple tabs, follow thes ### Changelog ```bash +1.8.1-beta.10: Introduced `InboxSearchComposerV2` component with browser session integration, removable tags for search/inbox screens on mobile, and a unified configuration for both mobile and desktop screens. 1.8.1-beta.9 Fixed Loader with gap 1.8.1-beta.8 Added Close button and Loader 1.8.1-beta.7 Viewcomposer enhancement for cardheader action 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 18fabb3868d..a84be992148 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-beta.9", + "version": "1.8.1-beta.10", "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/CheckBox.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/CheckBox.js index 99c7b780e9c..a1db224cd47 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/CheckBox.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/CheckBox.js @@ -1,11 +1,8 @@ -import React ,{Fragment}from "react"; +import React,{Fragment} from "react"; import { CheckSvg } from "./svgindex"; import PropTypes from "prop-types"; -import BreakLine from "./BreakLine"; import { useTranslation } from "react-i18next"; - - -const CheckBox = ({ onChange, label, value, disable, ref, checked, inputRef, pageType, style, index, isLabelFirst, customLabelMarkup, ...props }) => { +const CheckBox = ({ onChange, label, value, disable, ref, checked, inputRef, pageType, style, index, isLabelFirst,customLabelMarkup, ...props }) => { const { t } = useTranslation() const userType = pageType || Digit.SessionStorage.get("userType"); let wrkflwStyle = props.styles; @@ -13,7 +10,7 @@ const CheckBox = ({ onChange, label, value, disable, ref, checked, inputRef, pag return (

{index+1}.

-

+

{label}

@@ -50,14 +47,13 @@ const CheckBox = ({ onChange, label, value, disable, ref, checked, inputRef, pag // {(checked ? (checked = { checked }) : null)} checked={checked} /> -

+

{/* */}

-

- - {customLabelMarkup ? +

+ {customLabelMarkup ? <>

{t("COMMON_CERTIFY_ONE")}


diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/HorizontalNavV2.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/HorizontalNavV2.js new file mode 100644 index 00000000000..303b83c360d --- /dev/null +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/HorizontalNavV2.js @@ -0,0 +1,56 @@ +import React, {useState} from 'react' +import { useTranslation } from 'react-i18next' +import BreakLine from './BreakLine' +const HorizontalNavV2 = ({ configNavItems, activeLink, setActiveLink, showNav = false, children, customStyle = {}, customClassName = "", inFormComposer = true, navClassName = "", navStyles = {},fromSearchComp=false,horizontalLine=false }) => { + const { t } = useTranslation() + const setActive = (item) => { + setActiveLink(item) + } + + const MenuItem = ({ item }) => { + let itemComponent = item.code; + + const Item = () => ( + +
{t(itemComponent)}
+
+ ); + + return ( + + ); + }; + + if(fromSearchComp) { + return ( +
+ {showNav &&
+ {configNavItems?.map((item, index) => ( +
setActive(item)}> + +
+ ))} +
+ } + {/* Commenting out for now due to horizontal line coming in every inbox as well */} + {horizontalLine && } + {children} +
+ ) + } + return ( +
+ {showNav &&
+ {configNavItems?.map((item, index) => ( +
setActive(item)}> + +
+ ))} +
+ } + {children} +
+ ) +} + +export default HorizontalNavV2 \ No newline at end of file diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/InboxSearchLinks.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/InboxSearchLinks.js index 9d340be0190..a21e99396f1 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/InboxSearchLinks.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/InboxSearchLinks.js @@ -1,7 +1,6 @@ import React, { useState, useEffect } from "react" import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; -import { PropertyHouse, BioMetricIcon,WorksMgmtIcon} from "./svgindex"; const getIconComponent = (iconName="")=>{ return require("@egovernments/digit-ui-react-components")?.[iconName]; diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/MultiSelectDropdown.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/MultiSelectDropdown.js index 9ed5e1c52b1..ab6f9890694 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/MultiSelectDropdown.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/MultiSelectDropdown.js @@ -1,8 +1,8 @@ import React, { useEffect, useReducer, useRef, useState } from "react"; import { ArrowDown, CheckSvg } from "./svgindex"; import { useTranslation } from "react-i18next"; -import RemoveableTag from "./RemoveableTag"; -const MultiSelectDropdown = ({ options, optionsKey, selected = [], onSelect, defaultLabel = "", defaultUnit = "",BlockNumber=1,isOBPSMultiple=false,props={},isPropsNeeded=false,ServerStyle={}, config}) => { + +const MultiSelectDropdown = ({ options, optionsKey, selected = [], onSelect, defaultLabel = "", defaultUnit = "",BlockNumber=1,isOBPSMultiple=false,props={},isPropsNeeded=false,ServerStyle={}, isSurvey=false,placeholder, disable=false,config}) => { const [active, setActive] = useState(false); const [searchQuery, setSearchQuery] = useState(); const [optionIndex, setOptionIndex] = useState(-1); @@ -14,11 +14,9 @@ const MultiSelectDropdown = ({ options, optionsKey, selected = [], onSelect, def case "ADD_TO_SELECTED_EVENT_QUEUE": return [...state, {[optionsKey]: action.payload?.[1]?.[optionsKey], propsData: action.payload} ] case "REMOVE_FROM_SELECTED_EVENT_QUEUE": - const newState = state.filter( - (e) => e?.[optionsKey] !== action.payload?.[1]?.[optionsKey] - ); - onSelect(newState.map((e) => e.propsData), props); // Update the form state here - return newState; + const newState = state.filter( e => e?.[optionsKey] !== action.payload?.[1]?.[optionsKey]) + onSelect(newState.map((e) => e.propsData), props); + return newState case "REPLACE_COMPLETE_STATE": return action.payload default: @@ -28,7 +26,7 @@ const MultiSelectDropdown = ({ options, optionsKey, selected = [], onSelect, def useEffect(() => { dispatch({type: "REPLACE_COMPLETE_STATE", payload: fnToSelectOptionThroughProvidedSelection(selected) }) - },[selected?.length]) + },[selected?.length, selected?.[0]?.code]) function fnToSelectOptionThroughProvidedSelection(selected){ return selected?.map( e => ({[optionsKey]: e?.[optionsKey], propsData: [null, e]})) @@ -84,16 +82,17 @@ const MultiSelectDropdown = ({ options, optionsKey, selected = [], onSelect, def } const MenuItem = ({ option, index }) => ( -
+
selectedOption[optionsKey] === option[optionsKey]) ? true : false} onChange={(e) => isPropsNeeded?onSelectToAddToQueue(e, option,props):isOBPSMultiple?onSelectToAddToQueue(e, option,BlockNumber):onSelectToAddToQueue(e, option)} style={{minWidth: "24px", width: "100%"}} + disabled={option.isDisabled || false} />
- +

-

-
- setActive(true)} value={searchQuery} onChange={onSearch} /> +
+
+ setActive(true)} value={searchQuery} onChange={onSearch} placeholder={t(placeholder)} />
-

{alreadyQueuedSelectedState.length > 0 ? `${alreadyQueuedSelectedState.length} ${defaultUnit}` : defaultLabel}

- +

{alreadyQueuedSelectedState.length > 0 ? `${isSurvey? alreadyQueuedSelectedState?.filter((ob) => ob?.i18nKey !== undefined).length : alreadyQueuedSelectedState.length} ${defaultUnit}` : defaultLabel}

+
{active ? ( @@ -123,7 +122,7 @@ const MultiSelectDropdown = ({ options, optionsKey, selected = [], onSelect, def
) : null} - +
{config?.isDropdownWithChip ?
{alreadyQueuedSelectedState.length > 0 && diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/RemovableTagNew.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/RemovableTagNew.js new file mode 100644 index 00000000000..ce5e4415a40 --- /dev/null +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/RemovableTagNew.js @@ -0,0 +1,14 @@ +import React from "react"; +import { Close } from "./svgindex"; + +const RemoveableTagNew = ({ text={}, onClick, extraStyles,disabled = false }) => ( +
+ {`${text?.label} :`} + {text?.value} + + + +
+); + +export default RemoveableTagNew; 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 19ae3054570..b3e273df0b5 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 @@ -1,5 +1,5 @@ -import React, { useContext, useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; +import React, { useContext, useEffect, useState,useMemo } from "react"; +import { useForm,useWatch} from "react-hook-form"; import { useTranslation } from "react-i18next"; import { InboxContext } from "../hoc/InboxSearchComposerContext"; import RenderFormFields from "../molecules/RenderFormFields"; @@ -8,20 +8,36 @@ import LinkLabel from '../atoms/LinkLabel'; import SubmitBar from "../atoms/SubmitBar"; import Toast from "../atoms/Toast"; import { FilterIcon, RefreshIcon } from "./svgindex"; +import HorizontalNavV2 from "./HorizontalNavV2"; -const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullConfig, data, showTab, tabData, onTabChange }) => { +const setUIConf = (uiConfig) => { + if(uiConfig.additionalTabs) + return [{...uiConfig},...uiConfig?.additionalTabs] + return [{uiConfig}] +} + +const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullConfig, data,activeLink,setActiveLink,browserSession,showTab}) => { + + //whenever activeLink changes we'll change uiConfig + // const [activeLink,setActiveLink] = useState(uiConfig?.configNavItems?.filter(row=>row.activeByDefault)?.[0]?.name) + const [navConfig,setNavConfig] = useState(uiConfig?.configNavItems) + const [allUiConfigs,setAllUiConfigs] = useState(setUIConf(uiConfig)) const { t } = useTranslation(); const { state, dispatch } = useContext(InboxContext) - const [showToast, setShowToast] = useState(null) + const [showToast,setShowToast] = useState(null) let updatedFields = []; - const { apiDetails } = fullConfig + const {apiDetails} = fullConfig const customDefaultPagination = fullConfig?.sections?.searchResult?.uiConfig?.customDefaultPagination || null - - if (fullConfig?.postProcessResult) { + const [session,setSession,clearSession] = browserSession || [] + + 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 defValuesFromSession = uiConfig?.type === "search" ? session?.searchForm : session?.filterForm + + const { register, handleSubmit, @@ -38,8 +54,12 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon unregister, } = useForm({ defaultValues: uiConfig?.defaultValues, + // defaultValues: {...uiConfig?.defaultValues,...defValuesFromSession} + // defaultValues:defaultValuesFromSession }); + const formData = watch(); + const checkKeyDown = (e) => { const keyCode = e.keyCode ? e.keyCode : e.key ? e.key : e.which; if (keyCode === 13) { @@ -51,25 +71,33 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon updatedFields = Object.values(formState?.dirtyFields) }, [formState]) - const onSubmit = (data, e) => { - - e?.preventDefault?.(); + useEffect(() => { + clearSearch() + }, [activeLink]) + + const onSubmit = (data) => { + //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 >= (activeLink ? allUiConfigs?.filter(uiConf => activeLink?.name === uiConf.uiConfig.navLink)?.[0]?.uiConfig?.minReqFields : uiConfig?.minReqFields)) { + // here based on screenType call respective dispatch fn dispatch({ type: uiConfig?.type === "filter" ? "filterForm" : "searchForm", state: { ...data } }) + //here reset tableForm as well when search + dispatch({ + type: "tableForm", + state: { limit:10,offset:0 } + }) } else { setShowToast({ warning: true, label: t("ES_COMMON_MIN_SEARCH_CRITERIA_MSG") }) setTimeout(closeToast, 3000); @@ -77,17 +105,32 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon } const clearSearch = () => { + reset(uiConfig?.defaultValues) dispatch({ - type: "clearSearchForm", + type: uiConfig?.type === "filter"?"clearFilterForm" :"clearSearchForm", state: { ...uiConfig?.defaultValues } //need to pass form with empty strings }) + //here reset tableForm as well dispatch({ - type: "clearTableForm" + type: "tableForm", + state: { limit:10,offset:0 } + //need to pass form with empty strings }) } + //call this fn whenever session gets updated + const setDefaultValues = () => { + reset({...uiConfig?.defaultValues,...defValuesFromSession}) + } + + //adding this effect because simply setting session to default values is not working + useEffect(() => { + setDefaultValues() + }, [session]) + + const closeToast = () => { setShowToast(null); } @@ -102,8 +145,8 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon } const renderHeader = () => { - switch (uiConfig?.type) { - case "filter": { + switch(uiConfig?.type) { + case "filter" : { return (
@@ -112,38 +155,81 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon
) } - default: { + default : { return
{t(header)}
} } } - - return ( - - {showTab &&
-
- {tabData?.map((i,num) => ( - - ))} + if(showTab){ + return + {showTab &&
+
+ {tabData?.map((i,num) => ( + + ))} +
+
+ } +
+ {header && renderHeader()} +
checkKeyDown(e)}> +
+ {uiConfig?.showFormInstruction &&

{t(uiConfig?.showFormInstruction)}

} +
+ +
+ {uiConfig?.secondaryLabel && {t(uiConfig?.secondaryLabel)}} + {uiConfig?.isPopUp && uiConfig?.primaryLabel && { + handleSubmit(onSubmit)(e); + // onSubmit(formData, e) + }} disabled={false} />} + {!uiConfig?.isPopUp && uiConfig?.primaryLabel && }
- } +
+
+ {showToast && + } +
+
+ } + return ( + 0 ? navConfig : []} showNav={navConfig?.length > 0 ? true : false} activeLink={activeLink} setActiveLink={setActiveLink} fromSearchComp={true} horizontalLine={uiConfig?.horizontalLine}>
{header && renderHeader()}
checkKeyDown(e)}>
{uiConfig?.showFormInstruction &&

{t(uiConfig?.showFormInstruction)}

} -
- + activeLink?.name === uiConf.uiConfig.navLink)?.[0]?.uiConfig?.fields : uiConfig?.fields} + control={control} formData={formData} errors={errors} register={register} @@ -151,22 +237,18 @@ const SearchComponent = ({ uiConfig, header = "", screenType = "search", fullCon getValues={getValues} setError={setError} clearErrors={clearErrors} - labelStyle={{ fontSize: "16px" }} + labelStyle={{fontSize: "16px"}} apiDetails={apiDetails} data={data} - /> -
- {uiConfig?.secondaryLabel && {t(uiConfig?.secondaryLabel)}} - {uiConfig?.isPopUp && uiConfig?.primaryLabel && { - handleSubmit(onSubmit)(e); - // onSubmit(formData, e) - }} disabled={false} />} - {!uiConfig?.isPopUp && uiConfig?.primaryLabel && } + /> +
+ { uiConfig?.secondaryLabel && {t(uiConfig?.secondaryLabel)} } + { uiConfig?.primaryLabel && }
-
+
- {showToast && }
- +
) } diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SubmitBar.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SubmitBar.js index bef3395df49..6bc5cb3c699 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SubmitBar.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/SubmitBar.js @@ -12,7 +12,7 @@ const SubmitBar = forwardRef((props, ref) => { onClick={props.onSubmit} {... props.form ? {form: props.form} : {}} > -
{props.label}
+
{props.label}
); }); diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Table.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Table.js index 280abc942ba..c183efe44ac 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Table.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Table.js @@ -278,4 +278,4 @@ const Table = ({ ); }; -export default Table; +export default Table; \ No newline at end of file diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/UploadFile.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/UploadFile.js index 9267e90982f..a251c89e3eb 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/UploadFile.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/UploadFile.js @@ -80,30 +80,30 @@ const getCitizenStyles = (value) => { }, tagContainerStyles: { margin: "0px", - padding: "0px" + padding: "0px", + width: "46%" }, tagStyles: { height: "auto", - padding: "5px", + padding: "8px", margin: 0, width: "100%", margin: "5px" }, textStyles: { - wordBreak: "break-all", + wordBreak: "break-word", height: "auto", lineHeight: "16px", overflow: "hidden", // minHeight: "35px", - maxHeight: "34px", - maxWidth: "100%" + maxHeight: "34px" }, inputStyles: { - width: "42%", + width: "43%", minHeight: "42px", maxHeight: "42px", - top: "12px", - left: "12px" + top: "5px", + left: "5px" }, buttonStyles: { height: "auto", @@ -134,6 +134,9 @@ const getCitizenStyles = (value) => { }; const UploadFile = (props) => { + if(props.enableButton){ + props.disabled = !props.enableButton + } const { t } = useTranslation(); const inpRef = useRef(); const [hasFile, setHasFile] = useState(false); @@ -150,7 +153,6 @@ const UploadFile = (props) => { // for common aligmnent issues added common styles extraStyles = getCitizenStyles("OBPS"); - // if (window.location.href.includes("/obps") || window.location.href.includes("/noc")) { // extraStyles = getCitizenStyles("OBPS"); @@ -195,12 +197,12 @@ const UploadFile = (props) => { return ( {showHint &&

{t(props?.hintText)}

} -
+
@@ -210,11 +212,25 @@ const UploadFile = (props) => { props?.removeTargetedFile(fileDetailsData, e)} />
})} - {props?.uploadedFiles.length === 0 &&

{props.message}

} + {props?.uploadedFiles.length === 0 &&

{props?.message}

} + {!hasFile || props.error ? ( +

{props.message}

+ ) : ( +
+
+ + {(typeof inpRef.current.files[0]?.name !== "undefined") && !(props?.file) ? inpRef.current.files[0]?.name : props.file?.name} + + handleDelete()} style={extraStyles ? extraStyles?.closeIconStyles : null}> + + +
+
+ )}
{ disabled={props.disabled} onChange={(e) => props.onUpload(e)} onClick ={ event => { - if (!props?.enableButton) { + if (props?.disabled) { event.preventDefault() - } else { - const { target = {} } = event || {}; - target.value = ""; + return } + const { target = {} } = event || {}; + target.value = ""; }} />
{props.iserror &&

{props.iserror}

} - {props?.showHintBelow &&

{t(props?.hintText)}

} + {props?.showHintBelow &&

{t(props?.hintText)}

}
); }; diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/FormComposerV2.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/FormComposerV2.js index 4823fed3e57..7033adc6ed3 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/FormComposerV2.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/FormComposerV2.js @@ -33,7 +33,6 @@ import ApiDropdown from "../molecules/ApiDropdown"; import Header from "../atoms/Header"; import Button from "../atoms/Button" - import { yupResolver } from '@hookform/resolvers/yup'; // import { validateResolver } from "./validateResolver"; import { buildYupConfig } from "./formUtils"; @@ -881,7 +880,7 @@ export const FormComposer = (props) => { {props.secondaryLabel && props.showSecondaryLabel && ( -
-
+
- { showToast && - } + {showToast && ( + + )}
- ) + ); }; export default MobileSearchComponent; \ No newline at end of file diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/MobileView/MobileSearchResultsv1.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/MobileView/MobileSearchResultsv1.js new file mode 100644 index 00000000000..01719c2782e --- /dev/null +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/MobileView/MobileSearchResultsv1.js @@ -0,0 +1,106 @@ +import React, { useMemo, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import DetailsCard from '../../molecules/DetailsCard'; +import { Link } from 'react-router-dom'; +import NoResultsFound from '../../atoms/NoResultsFound'; +import { Loader } from '../../atoms/Loader'; +import _ from 'lodash'; +import { useHistory } from 'react-router-dom'; + +// const sampleSearchResult = [ +// { +// businessObject:{ +// testId:"AW28929", +// treatmentProcess:"KA - 25235", +// stage:"Jagadamba Cleaners", +// outputType:"KA - 25235", +// pendingDate:"12/02/2013", +// status:"Pending results", +// sla:12 +// } +// } +// ] + +const convertRowToDetailCardData = (row,config,t,apiDetails,searchResult) => { + const resultantObj = { + apiResponse:{...row,hidden:true} + } + + config.columns.map((column,idx) => { + resultantObj[t(column.label)] = column.additionalCustomization ? Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.additionalCustomizations(row,column?.label,column, _.get(row,column.jsonPath,""),t, searchResult) : String(_.get(row,column.jsonPath,"") ? column.translate? t(Digit.Utils.locale.getTransformedLocale(column.prefix?`${column.prefix}${_.get(row,column.jsonPath,"")}`:_.get(row,column.jsonPath,""))) : _.get(row,column.jsonPath,"") : t("ES_COMMON_NA")); + }) + + return resultantObj +} + +const convertDataForDetailsCard = (config,searchResult,t,apiDetails) => { +//map over columns and generate data accordingly + + const result = searchResult?.map((row,idx) => { + return convertRowToDetailCardData(row,config,t,apiDetails,searchResult) + } ) + + return result +} + +const MobileSearchResultsv1 = ({ + config, + data, + isLoading, + isFetching, + fullConfig, +}) => { + const { t } = useTranslation(); + const history = useHistory() + const { apiDetails } = fullConfig; + const resultsKey = config.resultsJsonPath; + + let searchResult = _.get(data, resultsKey, []); + + //for sample result + // let searchResult = _.get(sampleSearchResult, resultsKey, []); + + searchResult = searchResult?.length > 0 ? searchResult : []; + // searchResult = searchResult?.reverse(); + + const tenantId = Digit.ULBService.getCurrentTenantId(); + + const RenderResult = () => { + const dataForDetailsCard = convertDataForDetailsCard(config,searchResult,t,apiDetails) + const propsForDetailsCard = { + t, + data:dataForDetailsCard, + showActionBar:config?.showActionBarMobileCard, // to show action button on detail card + submitButtonLabel:config?.actionButtonLabelMobileCard, + handleDetailCardClick:(obj)=>{ //fn when action button on card is clicked + const linkToPushTo = Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.onCardActionClick(obj) + history.push(linkToPushTo) + }, + handleSelect:(obj)=>{ + const linkToPushTo = Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.onCardClick(obj) + history.push(linkToPushTo) + // Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.onCardActionClick(obj) + }, //fn when card container is clicked + mode:"tqm", + apiDetails, + } + + return + } + + if (isLoading || isFetching) { + return ; + } + + if (searchResult?.length === 0) { + return ( ); + } + + return ( + + + + ); +}; + +export default MobileSearchResultsv1; diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/RemovableTags.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/RemovableTags.js new file mode 100644 index 00000000000..c6d525a66d5 --- /dev/null +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/RemovableTags.js @@ -0,0 +1,186 @@ +import React, { useState, useEffect, useContext } from 'react'; +import RemoveableTagNew from '../atoms/RemovableTagNew'; +import { useTranslation } from 'react-i18next'; +import { Loader } from '../atoms/Loader'; +import { InboxContext } from './InboxSearchComposerContext'; +import _ from "lodash"; + +const generateTagsFromFields = (fields, sessionData, t,data) => { + //filetering the fields + + const fieldsToShow = fields + ?.filter((row) => row?.removableTagConf) + ?.map((row) => row?.removableTagConf); + + const crumbs = []; + fieldsToShow?.forEach((field, idx) => { + //one field can have multiple crumbs + // we need to fill + + //setting the text + const value = _.get(sessionData, field.sessionJsonPath, ''); + if (!value || value?.length === 0) { + return; + } + + //convert this to switch case and write a separate fn for it + switch (field?.type) { + case 'multi': + value?.forEach((val) => { + crumbs?.push({ + label: t(field.label) || '', + value: `${t( + Digit.Utils.locale.getTransformedLocale( + _.get(val, field.valueJsonPath, '') + ) + )}`, + removableTagConf: { + ...field, + value: val, + }, + }); + }); + break; + case 'single': + if(_.get(value, field.valueJsonPath, '')){ + crumbs?.push({ + label: t(field.label) || '', + value: `${t( + Digit.Utils.locale.getTransformedLocale( + _.get(value, field.valueJsonPath, '') + ) + )}`, + removableTagConf: { ...field, value }, + }); + }else if(typeof value === "string" && value){ + crumbs?.push({ + label: t(field.label) || '', + value: `${t( + Digit.Utils.locale.getTransformedLocale( + value + ) + )}`, + removableTagConf: { ...field, value }, + }); + } + break; + case 'dateRange': + if(_.get(value, field.valueJsonPath, '')){ + crumbs?.push({ + label: t(field.label) || '', + value: _.get(value, field.valueJsonPath, ''), + removableTagConf: { ...field, value }, + }); + } + break; + case 'workflowStatusFilter': + if(!data || !value || Object?.keys(value)?.length===0){ + return + } + const statusIds = Object?.keys(value)?.map(key => value[key] ? key : false)?.filter(val => val) + const statusObj = data?.statusMap?.map(status => { + if(statusIds?.includes(status?.statusid)){ + return { + ...status + } + }else { + return false + } + })?.filter(val => val) + statusObj?.forEach(obj => { + crumbs?.push({ + label: t(field.label) || '', + value: field?.valuePrefix ? t(Digit.Utils.locale.getTransformedLocale(`${field.valuePrefix}${obj?.applicationstatus}`)):t(Digit.Utils.locale.getTransformedLocale(obj?.applicationstatus)) , + removableTagConf: { ...field, dynamicId:obj.statusid }, + }); + }) + break; + default: + break; + } + + // if (field?.type === 'multi') { + // value?.forEach((val) => { + // crumbs?.push({ + // label: t(field.label) || '', + // value: `${t( + // Digit.Utils.locale.getTransformedLocale( + // _.get(val, field.valueJsonPath, '') + // ) + // )}`, + // removableTagConf:{ + // ...field, + // value:val + // } + // }); + // }); + // } else if (field?.type === 'single') { + // crumbs?.push({ + // label: t(field.label) || '', + // value: `${t( + // Digit.Utils.locale.getTransformedLocale( + // _.get(val, field.valueJsonPath, '') + // ) + // )}`, + // removableTagConf:{...field,value:val} + // }); + // } + }); + + return crumbs; +}; + +const RemovableTags = ({ config, browserSession, fields,data, ...props }) => { + const { t } = useTranslation(); + const [sessionData, setSessionData, clearSessionData] = browserSession; + + const [removableTags, setRemovableTags] = useState([]); + const { state, dispatch } = useContext(InboxContext); + + //sessionData will be the single source of truth for showing removable tags + //on click of tags we'll call dispatch and update the state which in turns updates the browser session + + // On onclick of removable tag you need to update the state accordingly so that browser session gets updated accordingly + // map over fields in search and filter section + // for each field, refer field.removableTagConf + + //an effect for generating selected filter tags + useEffect(() => { + setRemovableTags(generateTagsFromFields(fields, sessionData, t,data)); + return () => {}; + }, [fields, sessionData,data]); + + + // function to handle deletion of tags + //flow -> onClick -> Update state(dispatch with jsonPath) -> session gets updated automatically due to effect in parent + const handleCrumbDeletion = (tag) => { + dispatch( + { + type:"jsonPath", + tag + } + ) + }; + + if (removableTags?.length === 0) { + return null; + } + + return ( +
+ {removableTags?.map((tag, index) => { + return ( + { + handleCrumbDeletion(tag); + }} + /> + ); + })} +
+ ); +}; + +export default RemovableTags; diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/ResultsTable.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/ResultsTable.js index 0aff5f793cd..61533b4c535 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/ResultsTable.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/ResultsTable.js @@ -1,21 +1,20 @@ import React, { useMemo, useCallback, useState, useEffect, Fragment,useContext } from 'react' import { useTranslation } from 'react-i18next'; -import DetailsCard from '../molecules/DetailsCard' import Table from '../atoms/Table' import TextInput from '../atoms/TextInput' import { useForm, Controller } from "react-hook-form"; import _ from "lodash"; import { InboxContext } from './InboxSearchComposerContext'; -import { Link } from "react-router-dom"; import { Loader } from '../atoms/Loader'; import NoResultsFound from '../atoms/NoResultsFound'; import { InfoIcon,EditIcon } from "../atoms/svgindex"; -const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fullConfig,revalidate,additionalConfig }) => { +const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fullConfig,revalidate,type,activeLink,browserSession,additionalConfig }) => { const {apiDetails} = fullConfig const { t } = useTranslation(); const resultsKey = config.resultsJsonPath - + const [showResultsTable,setShowResultsTable] = useState(true) + const [session,setSession,clearSession] = browserSession || [] // let searchResult = data?.[resultsKey]?.length>0 ? data?.[resultsKey] : [] let searchResult = _.get(data,resultsKey,[]) searchResult = searchResult?.length>0 ? searchResult : [] @@ -41,10 +40,24 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu const {state,dispatch} = useContext(InboxContext) + //here I am just checking state.searchForm has all empty keys or not(when clicked on clear search) + useEffect(() => { + if(apiDetails?.minParametersForSearchForm !== 0 && Object.keys(state.searchForm).length > 0 && !Object.keys(state.searchForm).some(key => state.searchForm[key]!=="") && type==="search" && activeLink?.minParametersForSearchForm !== 0){ + setShowResultsTable(false) + } + // else{ + // setShowResultsTable(true) + // } + return ()=>{ + setShowResultsTable(true) + } + }, [state]) + + + const tableColumns = useMemo(() => { //test if accessor can take jsonPath value only and then check sort and global search work properly return config?.columns?.map(column => { - if(column?.svg) { // const icon = Digit.ComponentRegistryService.getComponent(column.svg); return { @@ -55,12 +68,12 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu } } } - if (column.additionalCustomization){ return { Header: t(column?.label) || t("ES_COMMON_NA"), accessor:column.jsonPath, headerAlign: column?.headerAlign, + disableSortBy:column?.disableSortBy ? column?.disableSortBy :false, Cell: ({ value, col, row }) => { return Digit?.Customizations?.[apiDetails?.masterName]?.[apiDetails?.moduleName]?.additionalCustomizations(row.original,column?.label,column, value,t, searchResult); } @@ -70,13 +83,16 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu Header: t(column?.label) || t("ES_COMMON_NA"), accessor: column.jsonPath, headerAlign: column?.headerAlign, + disableSortBy:column?.disableSortBy ? column?.disableSortBy :false, Cell: ({ value, col, row }) => { - return String(value ? column.translate? t(column.prefix?`${column.prefix}${value}`:value) : value : column?.dontShowNA ? " " : t("ES_COMMON_NA")); + return String(value ? column.translate? t(Digit.Utils.locale.getTransformedLocale(column.prefix?`${column.prefix}${value}`:value)) : value : t("ES_COMMON_NA")); } } }) }, [config, searchResult]) - const defaultValuesFromSession = config?.customDefaultPagination ? config?.customDefaultPagination : {limit:10,offset:0} + + const defaultValuesFromSession = config?.customDefaultPagination ? config?.customDefaultPagination : (session?.tableForm ? {...session?.tableForm} : {limit:10,offset:0}) + const { register, handleSubmit, @@ -95,6 +111,16 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu defaultValues: defaultValuesFromSession }); + //call this fn whenever session gets updated + const setDefaultValues = () => { + reset(defaultValuesFromSession) + } + + //adding this effect because simply setting session to default values is not working + useEffect(() => { + setDefaultValues() + }, [session]) + const isMobile = window.Digit.Utils.browser.isMobile(); const [searchQuery, onSearch] = useState(""); @@ -122,15 +148,14 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu }, []); useEffect(() => { - register("offset", config?.customDefaultPagination?.offset || 0); - register("limit", config?.customDefaultPagination?.limit || 10); + register("offset",session?.tableForm?.offset || config?.customDefaultPagination?.offset|| 0); + register("limit",session?.tableForm?.limit || config?.customDefaultPagination?.limit || 10); }, [register]); useEffect(() => { - setValue("offset",state.tableForm.offset) - setValue("limit",state.tableForm.limit) - }) - + setValue("offset",state.tableForm.offset) + setValue("limit",state.tableForm.limit) + }) function onPageSizeChange(e) { setValue("limit", Number(e.target.value)); @@ -162,6 +187,7 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu if (isLoading || isFetching ) return if(!data) return <> + if(!showResultsTable) return <> if (searchResult?.length === 0) return return (
@@ -177,24 +203,23 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu {searchResult?.length > 0 && { return { style: { @@ -205,9 +230,7 @@ const ResultsTable = ({ tableContainerClass, config,data,isLoading,isFetching,fu }; }} onClickRow={additionalConfig?.resultsTable?.onClickRow} - rowClassName={config.rowClassName} - noColumnBorder={config?.noColumnBorder} - customPageSizesArray={config?.customPageSizesArray || null} + manualPagination={config.manualPagination} />} ) diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/index.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/index.js index 822fcddf48a..5d387e3f1c5 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/index.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/index.js @@ -271,6 +271,7 @@ import HorizontalNav from "./atoms/HorizontalNav"; import NoResultsFound from "./atoms/NoResultsFound"; import { ViewImages } from "./atoms/ViewImages"; import InboxSearchComposer from "./hoc/InboxSearchComposer"; +import InboxSearchComposerV2 from "./hoc/InboxSearchComposerV2"; import MobileSearchResults from "./hoc/MobileView/MobileSearchResults"; import MobileSearchComponent from "./hoc/MobileView/MobileSearchComponent"; import ResultsTable from "./hoc/ResultsTable"; @@ -486,6 +487,7 @@ export { Details, InboxComposer, InboxSearchComposer, + InboxSearchComposerV2, MobileSearchResults, MobileSearchComponent, ResultsTable, diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/ApiCheckboxes.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/ApiCheckboxes.js new file mode 100644 index 00000000000..1fc776cfdeb --- /dev/null +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/ApiCheckboxes.js @@ -0,0 +1,46 @@ +import React, { Fragment, useState, useEffect } from "react"; +import { Loader } from "../atoms/Loader"; +import { useTranslation } from "react-i18next"; +import _ from "lodash"; +import CheckBox from "../atoms/CheckBox"; +import CardLabel from "../atoms/CardLabel"; + +const ApiCheckboxes = ({ populators, formData, props }) => { + //based on the reqCriteria and populators we will render options in checkboxes + + const [options, setOptions] = useState([]); + const { t } = useTranslation(); + + const reqCriteria = Digit?.Customizations?.[populators?.masterName]?.[populators?.moduleName]?.[populators?.customfn](populators) + + const { isLoading: isApiLoading, data: apiData, revalidate, isFetching: isApiFetching } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + useEffect(() => { + setOptions(apiData); + }, [apiData]); + + if (isApiLoading) return ; + + return ( + <> + {options?.map((row,idx) => { + return ( + { + const obj = { + ...props.value, + [e.target.value]: e.target.checked, + }; + props.onChange(obj); + }} + value={row?.[populators?.optionsKey]} + checked={formData?.[populators.name]?.[row?.[populators?.optionsKey]]} + label={t(row?.[populators?.labelKey])} + /> + ); + })} + + ); +}; + +export default ApiCheckboxes; diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/ApiDropdown.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/ApiDropdown.js index 46bc815e704..30a95d638df 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/ApiDropdown.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/ApiDropdown.js @@ -13,9 +13,8 @@ const ApiDropdown = ({ populators, formData, props, inputRef, errors }) => { const { t } = useTranslation(); - - const reqCriteria = Digit?.Customizations?.[populators?.masterName]?.[populators?.moduleName]?.[populators?.customfn]() - + const reqCriteria = Digit?.Customizations?.[populators?.masterName]?.[populators?.moduleName]?.[populators?.customfn](populators) + const { isLoading: isApiLoading, data: apiData, revalidate, isFetching: isApiFetching } = Digit.Hooks.useCustomAPIHook(reqCriteria); useEffect(() => { @@ -43,9 +42,10 @@ const ApiDropdown = ({ populators, formData, props, inputRef, errors }) => { ); }} selected={props?.value} - defaultLabel={t(populators?.defaultText)} - defaultUnit={t(populators?.selectedText)} + defaultLabel={t(populators?.defaultText) } + defaultUnit={t(populators?.selectedText) || t("COMMON_SELECTED")} config={populators} + /> )} diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/CustomDropdown.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/CustomDropdown.js index 17b6f383708..6b7de351205 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/CustomDropdown.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/CustomDropdown.js @@ -1,8 +1,9 @@ import _ from "lodash"; -import React from "react"; +import React, { useEffect, useState } from "react"; import { Loader } from "../atoms/Loader"; import RadioButtons from "../atoms/RadioButtons"; import Dropdown from "../atoms/Dropdown"; +import MultiSelectDropdown from "../atoms/MultiSelectDropdown"; /** * Custom Dropdown / Radio Button component can be used mostly via formcomposer @@ -62,22 +63,22 @@ or }, * */ -const CustomDropdown = ({ t, config, inputRef, label, onChange, value, errorStyle, disable, type, additionalWrapperClass = "" }) => { +const CustomDropdown = ({ t, config, inputRef, label, onChange, value, errorStyle, disable, type, additionalWrapperClass = "",mdmsv2=false,props}) => { const master = { name: config?.mdmsConfig?.masterName }; if (config?.mdmsConfig?.filter) { master["filter"] = config?.mdmsConfig?.filter; } const { isLoading, data } = Digit.Hooks.useCustomMDMS(Digit.ULBService.getStateId(), config?.mdmsConfig?.moduleName, [master], { - select: config?.mdmsConfig?.select - ? Digit.Utils.createFunction(config?.mdmsConfig?.select) - : (data) => { - const optionsData = _.get(data, `${config?.mdmsConfig?.moduleName}.${config?.mdmsConfig?.masterName}`, []); - return optionsData - .filter((opt) => (opt?.hasOwnProperty("active") ? opt.active : true)) - .map((opt) => ({ ...opt, name: `${config?.mdmsConfig?.localePrefix}_${Digit.Utils.locale.getTransformedLocale(opt.code)}` })); - }, - enabled: config?.mdmsConfig ? true : false, - }); + select: config?.mdmsConfig?.select + ? Digit.Utils.createFunction(config?.mdmsConfig?.select) + : (data) => { + const optionsData = _.get(data, `${config?.mdmsConfig?.moduleName}.${config?.mdmsConfig?.masterName}`, []); + return optionsData + .filter((opt) => (opt?.hasOwnProperty("active") ? opt.active : true)) + .map((opt) => ({ ...opt, name: `${config?.mdmsConfig?.localePrefix}_${Digit.Utils.locale.getTransformedLocale(opt.code)}` })); + }, + enabled: (config?.mdmsConfig || config?.mdmsv2) ? true : false, + },mdmsv2); if (isLoading) { return ; } @@ -91,6 +92,11 @@ const CustomDropdown = ({ t, config, inputRef, label, onChange, value, errorStyl // } // return selectedValue // } + + if(config?.optionsDisable && config?.options && config?.defaultOptions){ + config?.options?.forEach(obj1 => obj1.isDisabled = config?.defaultOptions.some(obj2 => obj2.type === obj1.code)); + } + return ( {/* @@ -98,7 +104,39 @@ const CustomDropdown = ({ t, config, inputRef, label, onChange, value, errorStyl {t(label)} {config.required ? " * " : null} */} - {type === "radio" ? ( + + { (config.allowMultiSelect && type==="dropdown") ? +
+ { + props?.onChange + ? props.onChange( + e + ?.map((row) => { + return row?.[1] ? row[1] : null; + }) + .filter((e) => e) + ) + : onChange( + e + ?.map((row) => { + return row?.[1] ? row[1] : null; + }) + .filter((e) => e) + ); + }} + selected={props?.value || value} + defaultLabel={t(config?.defaultText) } + defaultUnit={t(config?.selectedText) || t("COMMON_SELECTED")} + config={config} + disable={disable} + optionsDisable={config?.optionsDisable} + /> +
: type === "radio" ? ( - )} - {/*
*/} + ) + }
); }; diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DateRangeNew.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DateRangeNew.js index 98c5a07a1c5..fa3a52173be 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DateRangeNew.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DateRangeNew.js @@ -14,13 +14,13 @@ function isStartDateFocused(focusNumber) { return focusNumber === 0; } -const DateRangeNew = ({ values, onFilterChange, t, labelClass, label, customStyles, inputRef}) => { +const DateRangeNew = ({populators, values, onFilterChange, t, labelClass, label, customStyles, inputRef}) => { const [isModalOpen, setIsModalOpen] = useState(false); const [focusedRange, setFocusedRange] = useState([0, 0]); const [selectionRange, setSelectionRange] = useState({ ...values, - startDate: values?.startDate, - endDate: values?.endDate + startDate: typeof values?.startDate === "string" ? new Date(values?.startDate) : values?.startDate, + endDate: typeof values?.endDate === "string" ? new Date(values?.endDate) : values?.endDate }); const wrapperRef = useRef(inputRef); @@ -41,7 +41,7 @@ const DateRangeNew = ({ values, onFilterChange, t, labelClass, label, customStyl const startDate = selectionRange?.startDate; const endDate = selectionRange?.endDate; const duration = getDuration(selectionRange?.startDate, selectionRange?.endDate); - const title = `${format(selectionRange?.startDate, "MMM d, yy")} - ${format(selectionRange?.endDate, "MMM d, yy")}`; + const title = `${format(selectionRange?.startDate, 'dd/MM/yyyy')} - ${format(selectionRange?.endDate, 'dd/MM/yyyy')}`; onFilterChange({ range: { startDate, endDate, duration, title }, requestDate: { startDate, endDate, duration, title } }); } }, [selectionRange, isModalOpen]); @@ -143,12 +143,12 @@ const DateRangeNew = ({ values, onFilterChange, t, labelClass, label, customStyl setIsModalOpen((prevState) => !prevState)} /> {isModalOpen && ( -
+
)} diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DetailsCard.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DetailsCard.js index 9b402db6ebc..74288931595 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DetailsCard.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/DetailsCard.js @@ -4,6 +4,7 @@ import { Link } from "react-router-dom"; import CitizenInfoLabel from "../atoms/CitizenInfoLabel"; import ActionBar from "../atoms/ActionBar"; import SubmitBar from "../atoms/SubmitBar"; +import Button from "../atoms/Button"; export const Details = ({ label, name, onClick}) => { return (
@@ -15,7 +16,7 @@ export const Details = ({ label, name, onClick}) => { ); }; -const DetailsCard = ({ data, serviceRequestIdKey, linkPrefix, handleSelect, selectedItems, keyForSelected, handleDetailCardClick, isTwoDynamicPrefix = false, getRedirectionLink, handleClickEnabled = true, t, showActionBar = true, showCitizenInfoLabel = false,submitButtonLabel }) => { +const DetailsCard = ({ data, serviceRequestIdKey, linkPrefix, handleSelect, selectedItems, keyForSelected, handleDetailCardClick, isTwoDynamicPrefix = false, getRedirectionLink, handleClickEnabled = true, t, showActionBar = true, showCitizenInfoLabel = false,submitButtonLabel,mode="default",apiDetails }) => { if (linkPrefix && serviceRequestIdKey) { return (
@@ -57,23 +58,73 @@ const DetailsCard = ({ data, serviceRequestIdKey, linkPrefix, handleSelect, sele return (
handleClickEnabled && handleSelect(object)} + onClick={(e) =>{ + e.stopPropagation() + handleClickEnabled && handleSelect(object) + }} > - {Object.keys(object).filter(rowEle => !(typeof object[rowEle] == "object" && object[rowEle]?.hidden == true)).map((name, index) => { - return
handleClickEnabled && handleDetailCardClick(object)} />; - })} - {showCitizenInfoLabel ?:null} - {showActionBar ? - handleDetailCardClick(object)} label={submitButtonLabel} /> - :null} + {Object.keys(object) + .filter( + (rowEle) => + !( + typeof object[rowEle] == 'object' && + object[rowEle]?.hidden == true + ) + ) + .map((name, index) => { + return ( +
{ + e.stopPropagation() + handleClickEnabled && handleSelect(object) + } + } + /> + ); + })} + {showCitizenInfoLabel ? ( + + ) : null} + {showActionBar && mode==="default" ? ( + handleDetailCardClick(object)} + label={submitButtonLabel} + /> + ) : null} + {showActionBar && mode==="tqm" && ( +
); })} diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/FilterAction.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/FilterAction.js index a2d38b83606..9dcb49b05ff 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/FilterAction.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/FilterAction.js @@ -1,11 +1,11 @@ import React from "react"; -import { FilterSvg } from "../atoms/svgindex"; +import { FilterSvg,FilterIcon,SortSvg } from "../atoms/svgindex"; import RoundedLabel from "../atoms/RoundedLabel"; const FilterAction = ({ text, handleActionClick, ...props }) => (
- {text} + {text}
); diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/MultiUploadWrapper.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/MultiUploadWrapper.js index a5d27397003..d0a4323de69 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/MultiUploadWrapper.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/MultiUploadWrapper.js @@ -4,7 +4,7 @@ import UploadFile from "../atoms/UploadFile" const displayError = ({ t, error, name }, customErrorMsg) => (
{customErrorMsg ? t(customErrorMsg) : t(error)}
-
{customErrorMsg ? '' : `${t('ES_COMMON_DOC_FILENAME')} : ${name} ...`}
+
{customErrorMsg ? '' : `${t('ES_COMMON_DOC_FILENAME')} : ${name} ...`}
) @@ -130,11 +130,10 @@ const MultiUploadWrapper = ({ t, module = "PGR", tenantId = Digit.ULBService.get setFileErrors([]) }} accept={acceptFiles} - message={t(`WORKS_NO_FILE_SELECTED`)} customClass={customClass} enableButton={enableButton} /> - + {fileErrors.length ? fileErrors.map(({ valid, name, type, size, error }) => ( valid ? null : displayError({ t, error, name }, customErrorMsg) )) : null} diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/RenderFormFields.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/RenderFormFields.js index 7449cb69a8c..ac0027321b7 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/RenderFormFields.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/RenderFormFields.js @@ -14,8 +14,8 @@ import MultiSelectDropdown from '../atoms/MultiSelectDropdown'; import LocationDropdownWrapper from './LocationDropdownWrapper'; import WorkflowStatusFilter from './WorkflowStatusFilter'; import ApiDropdown from './ApiDropdown'; +import ApiCheckboxes from './ApiCheckboxes'; const RenderFormFields = ({data,...props}) => { - const { t } = useTranslation(); const { fields, control, formData, errors, register, setValue, getValues, setError, clearErrors, apiDetails} = props @@ -42,7 +42,7 @@ const RenderFormFields = ({data,...props}) => { errorStyle={errors?.[populators.name]} max={populators.max} disable={disable} - style={type === "date" ? { paddingRight: "3px" } : ""} + style={type === "date" ? { paddingRight: "3px" } : populators?.style ? {...populators?.style} : {}} maxlength={populators?.validation?.maxlength} minlength={populators?.validation?.minlength} /> @@ -160,6 +160,8 @@ const RenderFormFields = ({data,...props}) => { config={populators} disable={config?.disable} errorStyle={errors?.[populators.name]} + mdmsv2={populators.mdmsv2 ? populators.mdmsv2 : false } + props={props} /> )} rules={{ required: isMandatory, ...populators.validation }} @@ -198,7 +200,7 @@ const RenderFormFields = ({data,...props}) => { /> ); - case "locationdropdown": + case "locationdropdown": return ( { /> ); - + case "apicheckboxes": + return ( + { + return ( +
+ +
+ ); + }} + /> + ); case "workflowstatesfilter": return ( { + populators={populators} + /> )} rules={{ required: isMandatory, ...populators.validation }} defaultValue={formData?.[populators.name]} @@ -309,6 +346,7 @@ const RenderFormFields = ({data,...props}) => { control={control} getValues={getValues} responseData={data} + populators={populators} /> )} name={config?.key} @@ -325,7 +363,7 @@ const RenderFormFields = ({data,...props}) => { {fields?.map((item, index) => { return ( - + { item.label && ( {t(item.label)}{ item?.isMandatory ? " * " : null } diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/SearchAction.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/SearchAction.js index 76cf79eb347..b11f8b8993b 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/SearchAction.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/SearchAction.js @@ -1,9 +1,9 @@ import React from "react"; -import { SearchIconSvg } from "../atoms/svgindex"; +import { SearchIconSvg,FilterSvg,FilterIcon } from "../atoms/svgindex"; const SearchAction = ({ text, handleActionClick }) => (
- {text} + {text}
); diff --git a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/WorkflowStatusFilter.js b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/WorkflowStatusFilter.js index 481e9ad4ade..f202f721bc6 100644 --- a/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/WorkflowStatusFilter.js +++ b/micro-ui/web/micro-ui-internals/packages/react-components/src/molecules/WorkflowStatusFilter.js @@ -1,39 +1,39 @@ -import React, { Fragment,useEffect,useState } from "react"; +import React, { Fragment, useEffect, useState } from "react"; import CheckBox from "../atoms/CheckBox"; import { Loader } from "../atoms/Loader"; import CardLabel from "../atoms/CardLabel"; -const WorkflowStatusFilter = ({ props, t, populators, formData,inboxResponse }) => { -//from inbox response get the statusMap and show the relevant statuses +const WorkflowStatusFilter = ({ props, t, populators, formData, inboxResponse }) => { + //from inbox response get the statusMap and show the relevant statuses //here need to filter these options based on logged in user(and test based on single roles in every inbox)(new requirement from vasanth) - - const [statusMap,setStatusMap] = useState(null) - + const [statusMap, setStatusMap] = useState(null); useEffect(() => { - if(inboxResponse) { - setStatusMap(inboxResponse.statusMap?.map(row => { - return { - uuid:row.statusid, - state: row.state || row.applicationstatus, - businessService:row?.businessservice - } - })) + if (inboxResponse) { + setStatusMap( + inboxResponse.statusMap?.map((row) => { + return { + uuid: row.statusid, + state: row.state || row.applicationstatus, + businessService: row?.businessservice, + count: row?.count, + }; + }) + ); } - }, [inboxResponse]) - + }, [inboxResponse]); if (!statusMap && !inboxResponse) return ; return ( <> - -{ statusMap&&statusMap.length>0&&populators?.componentLabel && ( - - {t(populators?.componentLabel)}{ populators?.isMandatory ? " * " : null } - ) - } - {statusMap?.map((row) => { + {statusMap && statusMap.length > 0 && populators?.componentLabel && ( + + {t(populators?.componentLabel)} + {populators?.isMandatory ? " * " : null} + + )} + {statusMap?.map((row) => { return ( { @@ -42,15 +42,16 @@ const WorkflowStatusFilter = ({ props, t, populators, formData,inboxResponse }) [e.target.value]: e.target.checked, }; props.onChange(obj); + // TODO:: set formData in such a way that it's an array of objects instead of array of ids so that we are able to show removable crumbs for this }} value={row.uuid} - checked={formData?.[populators.name]?.[row.uuid]} - label={t(Digit.Utils.locale.getTransformedLocale(`${populators.labelPrefix}${row?.businessService}_STATE_${row?.state}`))} + checked={formData?.[populators.name]?.[row.uuid] ? true : false} + label={`${t(Digit.Utils.locale.getTransformedLocale(`${populators.labelPrefix}${row?.businessService}_STATE_${row?.state}`))} (${row?.count || 0})`} /> ); })} - ) + ); }; export default WorkflowStatusFilter;