From 0121d6f4be40273bc8259a611e206068be946033 Mon Sep 17 00:00:00 2001 From: ailZhou <127151429+ailZhou@users.noreply.github.com> Date: Thu, 30 Jan 2025 11:06:25 -0500 Subject: [PATCH] Remove Index From AIF-HH & IU-HH (#2545) --- .../ui-src/src/measures/2021/AIFHH/data.ts | 60 +- .../ui-src/src/measures/2021/AIFHH/index.tsx | 89 -- .../src/measures/2021/AIFHH/validation.ts | 5 +- .../ui-src/src/measures/2021/IUHH/data.ts | 44 +- .../ui-src/src/measures/2021/IUHH/index.tsx | 89 -- .../src/measures/2021/IUHH/validation.ts | 5 +- services/ui-src/src/measures/2021/index.tsx | 10 +- .../src/measures/2021/measureTemplate.tsx | 6 + .../ui-src/src/measures/2022/AIFHH/data.ts | 60 +- .../src/measures/2022/AIFHH/index.test.tsx | 377 --------- .../ui-src/src/measures/2022/AIFHH/index.tsx | 89 -- .../src/measures/2022/AIFHH/validation.ts | 5 +- .../ui-src/src/measures/2022/IUHH/data.ts | 44 +- .../src/measures/2022/IUHH/index.test.tsx | 782 ------------------ .../ui-src/src/measures/2022/IUHH/index.tsx | 89 -- .../src/measures/2022/IUHH/validation.ts | 5 +- services/ui-src/src/measures/2022/index.tsx | 10 +- .../src/measures/2022/measureTemplate.tsx | 6 + .../src/measures/2022/measureTemplateData.tsx | 8 + .../ui-src/src/measures/2023/AIFHH/data.ts | 60 +- .../src/measures/2023/AIFHH/index.test.tsx | 382 --------- .../ui-src/src/measures/2023/AIFHH/index.tsx | 86 -- .../src/measures/2023/AIFHH/validation.ts | 5 +- .../ui-src/src/measures/2023/IUHH/data.ts | 44 +- .../src/measures/2023/IUHH/index.test.tsx | 782 ------------------ .../ui-src/src/measures/2023/IUHH/index.tsx | 86 -- .../src/measures/2023/IUHH/validation.ts | 5 +- services/ui-src/src/measures/2023/index.tsx | 10 +- .../src/measures/2023/measureTemplate.tsx | 4 + .../src/measures/2023/measureTemplateData.tsx | 8 + .../ui-src/src/measures/2024/AIFHH/data.ts | 60 +- .../src/measures/2024/AIFHH/index.test.tsx | 382 --------- .../ui-src/src/measures/2024/AIFHH/index.tsx | 86 -- .../src/measures/2024/AIFHH/validation.ts | 5 +- .../ui-src/src/measures/2024/IUHH/data.ts | 44 +- .../src/measures/2024/IUHH/index.test.tsx | 781 ----------------- .../ui-src/src/measures/2024/IUHH/index.tsx | 86 -- .../src/measures/2024/IUHH/validation.ts | 5 +- services/ui-src/src/measures/2024/index.tsx | 10 +- .../src/measures/2024/measureTemplate.tsx | 4 + .../src/measures/2024/measureTemplateData.tsx | 8 + .../ui-src/src/measures/2025/AIFHH/data.ts | 60 +- .../src/measures/2025/AIFHH/index.test.tsx | 379 --------- .../ui-src/src/measures/2025/AIFHH/index.tsx | 86 -- .../src/measures/2025/AIFHH/validation.ts | 5 +- .../ui-src/src/measures/2025/IUHH/data.ts | 45 +- .../src/measures/2025/IUHH/index.test.tsx | 781 ----------------- .../ui-src/src/measures/2025/IUHH/index.tsx | 86 -- .../src/measures/2025/IUHH/validation.ts | 5 +- services/ui-src/src/measures/2025/index.tsx | 10 +- .../src/measures/2025/measureTemplate.tsx | 4 + .../src/measures/2025/measureTemplateData.tsx | 8 + .../OptionalMeasureStrat/index.tsx | 10 +- .../src/shared/types/MeasureTemplate.tsx | 1 + 54 files changed, 445 insertions(+), 5761 deletions(-) delete mode 100644 services/ui-src/src/measures/2021/AIFHH/index.tsx delete mode 100644 services/ui-src/src/measures/2021/IUHH/index.tsx delete mode 100644 services/ui-src/src/measures/2022/AIFHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2022/AIFHH/index.tsx delete mode 100644 services/ui-src/src/measures/2022/IUHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2022/IUHH/index.tsx delete mode 100644 services/ui-src/src/measures/2023/AIFHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2023/AIFHH/index.tsx delete mode 100644 services/ui-src/src/measures/2023/IUHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2023/IUHH/index.tsx delete mode 100644 services/ui-src/src/measures/2024/AIFHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2024/AIFHH/index.tsx delete mode 100644 services/ui-src/src/measures/2024/IUHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2024/IUHH/index.tsx delete mode 100644 services/ui-src/src/measures/2025/AIFHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2025/AIFHH/index.tsx delete mode 100644 services/ui-src/src/measures/2025/IUHH/index.test.tsx delete mode 100644 services/ui-src/src/measures/2025/IUHH/index.tsx diff --git a/services/ui-src/src/measures/2021/AIFHH/data.ts b/services/ui-src/src/measures/2021/AIFHH/data.ts index ca76742f7..5dad6a5de 100644 --- a/services/ui-src/src/measures/2021/AIFHH/data.ts +++ b/services/ui-src/src/measures/2021/AIFHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { xNumbersYDecimals } from "utils"; export const { categories, qualifiers } = getCatQualLabels("AIF-HH"); -const measureName = "AIFHH"; - const inputFieldNames = [ { id: "Number of Enrollee Months", @@ -43,7 +43,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Short-Term Admissions per 1,000 Enrollee Months { @@ -68,22 +67,39 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - questionText: [ - "The number of admissions to an institutional facility among Health Home enrollees age 18 and older residing in the community for at least one month. The number of short-, medium-, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", - ], - questionListItems: [ - " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", - ], - questionListTitles: ["Short-Term Stay", "Medium-Term Stay", "Long-Term Stay"], - questionSubtext: [ - "The following three rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", - ], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + questionText: [ + "The number of admissions to an institutional facility among Health Home enrollees age 18 and older residing in the community for at least one month. The number of short-, medium-, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", + ], + questionListItems: [ + " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", + ], + questionListTitles: [ + "Short-Term Stay", + "Medium-Term Stay", + "Long-Term Stay", + ], + questionSubtext: [ + "The following three rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", + ], + categories, + qualifiers, + measureName: "AIFHH", + inputFieldNames, + ndrFormulas, + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "AIF", + }, }; diff --git a/services/ui-src/src/measures/2021/AIFHH/index.tsx b/services/ui-src/src/measures/2021/AIFHH/index.tsx deleted file mode 100644 index c88a9a83a..000000000 --- a/services/ui-src/src/measures/2021/AIFHH/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormDataLegacy as FormData } from "shared/types/FormData"; - -export const AIFHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2021/AIFHH/validation.ts b/services/ui-src/src/measures/2021/AIFHH/validation.ts index 0dcacdf0c..24de96004 100644 --- a/services/ui-src/src/measures/2021/AIFHH/validation.ts +++ b/services/ui-src/src/measures/2021/AIFHH/validation.ts @@ -42,7 +42,10 @@ const AIFHHValidation = (data: FormData) => { false ); const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2021/IUHH/data.ts b/services/ui-src/src/measures/2021/IUHH/data.ts index a0b4a1f91..9b5edb792 100644 --- a/services/ui-src/src/measures/2021/IUHH/data.ts +++ b/services/ui-src/src/measures/2021/IUHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { xNumbersYDecimals } from "utils"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { ComplexRate } from "components"; export const { categories, qualifiers } = getCatQualLabels("IU-HH"); -const measureName = "IUHH"; - const inputFieldNames = [ { id: "Number of Enrollee Months", @@ -30,7 +30,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Discharges per 1,000 Enrollee Months { @@ -55,16 +54,29 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - customPrompt: - "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", - questionText: [ - "Rate of acute inpatient care and services (total, maternity, mental and behavioral disorders, surgery, and medicine) per 1,000 enrollee months among Health Home enrollees.", - ], - questionListItems: [], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + customPrompt: + "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", + questionText: [ + "Rate of acute inpatient care and services (total, maternity, mental and behavioral disorders, surgery, and medicine) per 1,000 enrollee months among Health Home enrollees.", + ], + questionListItems: [], + categories, + qualifiers, + inputFieldNames, + ndrFormulas, + measureName: "IUHH", + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "IU", + }, }; diff --git a/services/ui-src/src/measures/2021/IUHH/index.tsx b/services/ui-src/src/measures/2021/IUHH/index.tsx deleted file mode 100644 index 2615b66b5..000000000 --- a/services/ui-src/src/measures/2021/IUHH/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormDataLegacy as FormData } from "shared/types/FormData"; - -export const IUHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2021/IUHH/validation.ts b/services/ui-src/src/measures/2021/IUHH/validation.ts index 9d53c41d0..54618e8ca 100644 --- a/services/ui-src/src/measures/2021/IUHH/validation.ts +++ b/services/ui-src/src/measures/2021/IUHH/validation.ts @@ -39,7 +39,10 @@ const IUHHValidation = (data: FormData) => { false ); const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2021/index.tsx b/services/ui-src/src/measures/2021/index.tsx index d44ee9275..fa8b1a836 100644 --- a/services/ui-src/src/measures/2021/index.tsx +++ b/services/ui-src/src/measures/2021/index.tsx @@ -10,18 +10,12 @@ the key should be the measure id as a string (with '-XX' included) const AMRAD = lazy(() => import("./AMRAD").then((module) => ({ default: module.AMRAD })) ); -const AIFHH = lazy(() => - import("./AIFHH").then((module) => ({ default: module.AIFHH })) -); const CPAAD = lazy(() => import("./CPAAD").then((module) => ({ default: module.CPAAD })) ); const CPCCH = lazy(() => import("./CPCCH").then((module) => ({ default: module.CPCCH })) ); -const IUHH = lazy(() => - import("./IUHH").then((module) => ({ default: module.IUHH })) -); const LBWCH = lazy(() => import("./LBWCH").then((module) => ({ default: module.LBWCH })) ); @@ -48,7 +42,7 @@ const SSHH = lazy(() => ); const twentyTwentyOneMeasures = { "ADD-CH": measureTemplate, - "AIF-HH": AIFHH, + "AIF-HH": measureTemplate, "AMB-CH": measureTemplate, "AMB-HH": measureTemplate, "AMM-AD": measureTemplate, @@ -88,7 +82,7 @@ const twentyTwentyOneMeasures = { "IET-AD": measureTemplate, "IET-HH": measureTemplate, "IMA-CH": measureTemplate, - "IU-HH": IUHH, + "IU-HH": measureTemplate, "LBW-CH": LBWCH, "LRCD-CH": LRCDCH, "MSC-AD": MSCAD, diff --git a/services/ui-src/src/measures/2021/measureTemplate.tsx b/services/ui-src/src/measures/2021/measureTemplate.tsx index d60567f2e..7cb7ac27d 100644 --- a/services/ui-src/src/measures/2021/measureTemplate.tsx +++ b/services/ui-src/src/measures/2021/measureTemplate.tsx @@ -78,11 +78,13 @@ export const measureTemplate = ({ showtextbox={custom?.showtextbox} hybridMeasure={hybridMeasure} rateReadOnly={custom?.rateReadOnly} + RateComponent={custom?.RateComponent} rateCalc={custom?.rateCalc} /> )} @@ -108,7 +110,11 @@ export const measureTemplate = ({ allowNumeratorGreaterThanDenominator={ custom?.allowNumeratorGreaterThanDenominator } + componentFlag={opm?.componentFlag} excludeOptions={opm?.excludeOptions} + inputFieldNames={performanceMeasure?.inputFieldNames} + ndrFormulas={performanceMeasure?.ndrFormulas} + measureName={performanceMeasure?.measureName} /> )} diff --git a/services/ui-src/src/measures/2022/AIFHH/data.ts b/services/ui-src/src/measures/2022/AIFHH/data.ts index e0a5caf48..541fad169 100644 --- a/services/ui-src/src/measures/2022/AIFHH/data.ts +++ b/services/ui-src/src/measures/2022/AIFHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { xNumbersYDecimals } from "utils"; export const { categories, qualifiers } = getCatQualLabels("AIF-HH"); -const measureName = "AIFHH"; - const inputFieldNames = [ { id: "Number of Enrollee Months", @@ -43,7 +43,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Short-Term Admissions per 1,000 Enrollee Months { @@ -68,22 +67,39 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - questionText: [ - "The number of admissions to an institutional facility among health home enrollees age 18 and older residing in the community for at least one month. The number of short-, medium-, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", - ], - questionListItems: [ - " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", - ], - questionListTitles: ["Short-Term Stay", "Medium-Term Stay", "Long-Term Stay"], - questionSubtext: [ - "The following three rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", - ], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + questionText: [ + "The number of admissions to an institutional facility among health home enrollees age 18 and older residing in the community for at least one month. The number of short-, medium-, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", + ], + questionListItems: [ + " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", + ], + questionListTitles: [ + "Short-Term Stay", + "Medium-Term Stay", + "Long-Term Stay", + ], + questionSubtext: [ + "The following three rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", + ], + categories, + qualifiers, + measureName: "AIFHH", + inputFieldNames, + ndrFormulas, + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "AIF", + }, }; diff --git a/services/ui-src/src/measures/2022/AIFHH/index.test.tsx b/services/ui-src/src/measures/2022/AIFHH/index.test.tsx deleted file mode 100644 index 12cad85f3..000000000 --- a/services/ui-src/src/measures/2022/AIFHH/index.test.tsx +++ /dev/null @@ -1,377 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "AIF-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2022; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - afterEach(() => { - screen.debug(); - }); - it.skip("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it.skip("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it.skip("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it.skip("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it.skip("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it.skip("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it.skip("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeviationFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - }); - - it.skip("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect( - V.ComplexValidateAtLeastOneNDRInDeviationOfMeasureSpec - ).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - }); - - it.skip("should pass a11y tests", async () => { - useApiMock(apiData); - renderWithHookForm(component); - await act(async () => { - const results = await axe(screen.getByTestId("measure-wrapper-form")); - expect(results).toHaveNoViolations(); - }); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - singleCategory: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 65 to 74", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 75 to 84", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Age 85 and older", - }, - { - fields: [ - { - value: "2", - label: "Number of Enrollee Months", - }, - { - value: 2, - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - isTotal: true, - label: "Total", - }, - ], - }, - }, - MeasurementSpecification: "CMS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2022/AIFHH/index.tsx b/services/ui-src/src/measures/2022/AIFHH/index.tsx deleted file mode 100644 index c88a9a83a..000000000 --- a/services/ui-src/src/measures/2022/AIFHH/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormDataLegacy as FormData } from "shared/types/FormData"; - -export const AIFHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2022/AIFHH/validation.ts b/services/ui-src/src/measures/2022/AIFHH/validation.ts index df6dbbffe..363b73ed6 100644 --- a/services/ui-src/src/measures/2022/AIFHH/validation.ts +++ b/services/ui-src/src/measures/2022/AIFHH/validation.ts @@ -42,7 +42,10 @@ const AIFHHValidation = (data: FormData) => { false ); const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2022/IUHH/data.ts b/services/ui-src/src/measures/2022/IUHH/data.ts index 12b844cd0..202c78b43 100644 --- a/services/ui-src/src/measures/2022/IUHH/data.ts +++ b/services/ui-src/src/measures/2022/IUHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { xNumbersYDecimals } from "utils"; export const { categories, qualifiers } = getCatQualLabels("IU-HH"); -const measureName = "IUHH"; - const inputFieldNames = [ { id: "Number of Enrollee Months", @@ -30,7 +30,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Discharges per 1,000 Enrollee Months { @@ -55,16 +54,29 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - customPrompt: - "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", - questionText: [ - "Rate of acute inpatient care and services (total, maternity, mental and behavioral disorders, surgery, and medicine) per 1,000 enrollee months among health home enrollees.", - ], - questionListItems: [], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + customPrompt: + "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", + questionText: [ + "Rate of acute inpatient care and services (total, maternity, mental and behavioral disorders, surgery, and medicine) per 1,000 enrollee months among health home enrollees.", + ], + questionListItems: [], + categories, + qualifiers, + inputFieldNames, + ndrFormulas, + measureName: "IUHH", + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "IU", + }, }; diff --git a/services/ui-src/src/measures/2022/IUHH/index.test.tsx b/services/ui-src/src/measures/2022/IUHH/index.test.tsx deleted file mode 100644 index e3257d1be..000000000 --- a/services/ui-src/src/measures/2022/IUHH/index.test.tsx +++ /dev/null @@ -1,782 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "IU-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2022; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -jest.mock("utils/getLabelText", () => ({ - ...jest.requireActual("utils/getLabelText"), - isLegacyLabel: () => true, -})); - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - - it("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeviationFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - }); - - it("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect( - V.ComplexValidateAtLeastOneNDRInDeviationOfMeasureSpec - ).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - }); - - it("should pass a11y tests", async () => { - useApiMock(apiData); - renderWithHookForm(component); - await act(async () => { - const results = await axe(screen.getByTestId("measure-wrapper-form")); - expect(results).toHaveNoViolations(); - }); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - Inpatient: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: 1, - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: 1, - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Maternity: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Medicine: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - MentalandBehavioralDisorders: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Surgery: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - }, - }, - MeasurementSpecification: "NCQA/HEDIS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2022/IUHH/index.tsx b/services/ui-src/src/measures/2022/IUHH/index.tsx deleted file mode 100644 index 2615b66b5..000000000 --- a/services/ui-src/src/measures/2022/IUHH/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormDataLegacy as FormData } from "shared/types/FormData"; - -export const IUHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2022/IUHH/validation.ts b/services/ui-src/src/measures/2022/IUHH/validation.ts index 4c91d0ed9..94f3d5ff2 100644 --- a/services/ui-src/src/measures/2022/IUHH/validation.ts +++ b/services/ui-src/src/measures/2022/IUHH/validation.ts @@ -39,7 +39,10 @@ const IUHHValidation = (data: FormData) => { false ); const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2022/index.tsx b/services/ui-src/src/measures/2022/index.tsx index cd76fbfa7..ee31d6673 100644 --- a/services/ui-src/src/measures/2022/index.tsx +++ b/services/ui-src/src/measures/2022/index.tsx @@ -3,9 +3,6 @@ import { measureTemplate } from "./measureTemplate"; import { Qualifier } from "shared/Qualifiers"; import { Data } from "labels/2022/qualifierFormsData"; -const AIFHH = lazy(() => - import("./AIFHH").then((module) => ({ default: module.AIFHH })) -); const AMRAD = lazy(() => import("./AMRAD").then((module) => ({ default: module.AMRAD })) ); @@ -15,9 +12,6 @@ const CPAAD = lazy(() => const CPCCH = lazy(() => import("./CPCCH").then((module) => ({ default: module.CPCCH })) ); -const IUHH = lazy(() => - import("./IUHH").then((module) => ({ default: module.IUHH })) -); const LBWCH = lazy(() => import("./LBWCH").then((module) => ({ default: module.LBWCH })) ); @@ -42,7 +36,7 @@ const SSHH = lazy(() => const twentyTwentyTwoMeasures = { "AAB-AD": measureTemplate, "ADD-CH": measureTemplate, - "AIF-HH": AIFHH, + "AIF-HH": measureTemplate, "AMB-CH": measureTemplate, "AMB-HH": measureTemplate, "AMM-AD": measureTemplate, @@ -86,7 +80,7 @@ const twentyTwentyTwoMeasures = { "IET-AD": measureTemplate, "IET-HH": measureTemplate, "IMA-CH": measureTemplate, - "IU-HH": IUHH, + "IU-HH": measureTemplate, "LBW-CH": LBWCH, "LRCD-CH": LRCDCH, "MSC-AD": MSCAD, diff --git a/services/ui-src/src/measures/2022/measureTemplate.tsx b/services/ui-src/src/measures/2022/measureTemplate.tsx index 28cf12cb0..e1829c4dc 100644 --- a/services/ui-src/src/measures/2022/measureTemplate.tsx +++ b/services/ui-src/src/measures/2022/measureTemplate.tsx @@ -77,11 +77,13 @@ export const measureTemplate = ({ showtextbox={custom?.showtextbox} hybridMeasure={hybridMeasure} rateReadOnly={custom?.rateReadOnly} + RateComponent={custom?.RateComponent} rateCalc={custom?.rateCalc} /> )} @@ -108,8 +110,12 @@ export const measureTemplate = ({ allowNumeratorGreaterThanDenominator={ custom?.allowNumeratorGreaterThanDenominator } + componentFlag={opm?.componentFlag} customPrompt={custom?.customPrompt} excludeOptions={opm?.excludeOptions} + inputFieldNames={performanceMeasure?.inputFieldNames} + ndrFormulas={performanceMeasure?.ndrFormulas} + measureName={performanceMeasure?.measureName} /> )} diff --git a/services/ui-src/src/measures/2022/measureTemplateData.tsx b/services/ui-src/src/measures/2022/measureTemplateData.tsx index ce6edf93b..b87c7c383 100644 --- a/services/ui-src/src/measures/2022/measureTemplateData.tsx +++ b/services/ui-src/src/measures/2022/measureTemplateData.tsx @@ -4,6 +4,9 @@ import { validationFunctions as AABAD_Validations } from "./AABAD/validation"; import { data as ADDCH_Data } from "./ADDCH/data"; import { validationFunctions as ADDCH_Validations } from "./ADDCH/validation"; +import { data as AIFHH_Data } from "./AIFHH/data"; +import { validationFunctions as AIFHH_Validations } from "./AIFHH/validation"; + import { data as AMBCH_Data } from "./AMBCH/data"; import { validationFunctions as AMBCH_Validations } from "./AMBCH/validation"; @@ -124,6 +127,9 @@ import { validationFunctions as IETHH_Validations } from "./IETHH/validation"; import { data as IMACH_Data } from "./IMACH/data"; import { validationFunctions as IMACH_Validations } from "./IMACH/validation"; +import { data as IUHH_Data } from "./IUHH/data"; +import { validationFunctions as IUHH_Validations } from "./IUHH/validation"; + import { data as OEVCH_Data } from "./OEVCH/data"; import { validationFunctions as OEVCH_Validations } from "./OEVCH/validation"; @@ -181,6 +187,7 @@ import { validationFunctions as WCVCH_Validations } from "./WCVCH/validation"; export const measureTemplateData: { [measure: string]: any } = { "AAB-AD": { data: AABAD_Data, validationFunctions: AABAD_Validations }, "ADD-CH": { data: ADDCH_Data, validationFunctions: ADDCH_Validations }, + "AIF-HH": { data: AIFHH_Data, validationFunctions: AIFHH_Validations }, "AMB-CH": { data: AMBCH_Data, validationFunctions: AMBCH_Validations }, "AMB-HH": { data: AMBHH_Data, validationFunctions: AMBHH_Validations }, "AMM-AD": { data: AMMAD_Data, validationFunctions: AMMAD_Validations }, @@ -221,6 +228,7 @@ export const measureTemplateData: { [measure: string]: any } = { "IET-AD": { data: IETAD_Data, validationFunctions: IETAD_Validations }, "IET-HH": { data: IETHH_Data, validationFunctions: IETHH_Validations }, "IMA-CH": { data: IMACH_Data, validationFunctions: IMACH_Validations }, + "IU-HH": { data: IUHH_Data, validationFunctions: IUHH_Validations }, "OEV-CH": { data: OEVCH_Data, validationFunctions: OEVCH_Validations }, "OHD-AD": { data: OHDAD_Data, validationFunctions: OHDAD_Validations }, "OUD-AD": { data: OUDAD_Data, validationFunctions: OUDAD_Validations }, diff --git a/services/ui-src/src/measures/2023/AIFHH/data.ts b/services/ui-src/src/measures/2023/AIFHH/data.ts index c968396db..de9362075 100644 --- a/services/ui-src/src/measures/2023/AIFHH/data.ts +++ b/services/ui-src/src/measures/2023/AIFHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { xNumbersYDecimals } from "utils"; export const { categories, qualifiers } = getCatQualLabels("AIF-HH"); -const measureName = "AIFHH"; - const inputFieldNames = [ { label: "Number of Enrollee Months", @@ -43,7 +43,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Short-Term Admissions per 1,000 Enrollee Months { @@ -68,22 +67,39 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - questionText: [ - "The number of admissions to a facility among enrollees age 18 and older residing in the community for at least one month. The number of short-term, medium-term, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", - ], - questionListItems: [ - " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", - ], - questionListTitles: ["Short-Term Stay", "Medium-Term Stay", "Long-Term Stay"], - questionSubtext: [ - "The following three performance rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", - ], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + questionText: [ + "The number of admissions to a facility among enrollees age 18 and older residing in the community for at least one month. The number of short-term, medium-term, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", + ], + questionListItems: [ + " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", + ], + questionListTitles: [ + "Short-Term Stay", + "Medium-Term Stay", + "Long-Term Stay", + ], + questionSubtext: [ + "The following three performance rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", + ], + categories, + qualifiers, + measureName: "AIFHH", + inputFieldNames, + ndrFormulas, + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "AIF", + }, }; diff --git a/services/ui-src/src/measures/2023/AIFHH/index.test.tsx b/services/ui-src/src/measures/2023/AIFHH/index.test.tsx deleted file mode 100644 index ee32c73f4..000000000 --- a/services/ui-src/src/measures/2023/AIFHH/index.test.tsx +++ /dev/null @@ -1,382 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "AIF-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2023; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - afterEach(() => { - screen.debug(); - }); - it.skip("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it.skip("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it.skip("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it.skip("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it.skip("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it.skip("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it.skip("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).not.toHaveBeenCalled(); - expect(V.validateDeviationTextFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).not.toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).not.toHaveBeenCalled(); - }); - - it.skip("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).toHaveBeenCalled(); - }); - - it.skip("should pass a11y tests", async () => { - useApiMock(apiData); - renderWithHookForm(component); - await act(async () => { - const results = await axe(screen.getByTestId("measure-wrapper-form")); - expect(results).toHaveNoViolations(); - }); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - singleCategory: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 65 to 74", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 75 to 84", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Age 85 and older", - }, - { - fields: [ - { - value: "2", - label: "Number of Enrollee Months", - }, - { - value: 2, - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - isTotal: true, - label: "Total (Age 18 and older)", - }, - ], - }, - }, - MeasurementSpecification: "CMS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2023/AIFHH/index.tsx b/services/ui-src/src/measures/2023/AIFHH/index.tsx deleted file mode 100644 index 724bcbd73..000000000 --- a/services/ui-src/src/measures/2023/AIFHH/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormData as FormData } from "shared/types/FormData"; - -export const AIFHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2023/AIFHH/validation.ts b/services/ui-src/src/measures/2023/AIFHH/validation.ts index 0db61ff06..34fce2c3c 100644 --- a/services/ui-src/src/measures/2023/AIFHH/validation.ts +++ b/services/ui-src/src/measures/2023/AIFHH/validation.ts @@ -38,7 +38,10 @@ const AIFHHValidation = (data: FormData) => { const definitionOfDenominator = data[DC.DEFINITION_OF_DENOMINATOR]; const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; const deviationReason = data[DC.DEVIATION_REASON]; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2023/IUHH/data.ts b/services/ui-src/src/measures/2023/IUHH/data.ts index 79dc46893..a3841ff49 100644 --- a/services/ui-src/src/measures/2023/IUHH/data.ts +++ b/services/ui-src/src/measures/2023/IUHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { xNumbersYDecimals } from "utils"; export const { categories, qualifiers } = getCatQualLabels("IU-HH"); -const measureName = "IUHH"; - const inputFieldNames = [ { label: "Number of Enrollee Months", @@ -30,7 +30,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Discharges per 1,000 Enrollee Months { @@ -55,16 +54,29 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - customPrompt: - "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", - questionText: [ - "Rate of acute inpatient care and services (total, mental and behavioral disorders, surgery, and medicine) per 1,000 enrollee months among health home enrollees.", - ], - questionListItems: [], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + customPrompt: + "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", + questionText: [ + "Rate of acute inpatient care and services (total, mental and behavioral disorders, surgery, and medicine) per 1,000 enrollee months among health home enrollees.", + ], + questionListItems: [], + categories, + qualifiers, + inputFieldNames, + ndrFormulas, + measureName: "IUHH", + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "IU", + }, }; diff --git a/services/ui-src/src/measures/2023/IUHH/index.test.tsx b/services/ui-src/src/measures/2023/IUHH/index.test.tsx deleted file mode 100644 index 0006a46dd..000000000 --- a/services/ui-src/src/measures/2023/IUHH/index.test.tsx +++ /dev/null @@ -1,782 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "IU-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2023; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - - it("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).not.toHaveBeenCalled(); - expect(V.validateDeviationTextFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).not.toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).not.toHaveBeenCalled(); - }); - - it("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).toHaveBeenCalled(); - }); - - it("should pass a11y tests", async () => { - useApiMock(apiData); - renderWithHookForm(component); - await act(async () => { - const results = await axe(screen.getByTestId("measure-wrapper-form")); - expect(results).toHaveNoViolations(); - }); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - Inpatient: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: 1, - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: 1, - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Maternity: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Medicine: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - MentalandBehavioralDisorders: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Surgery: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - }, - }, - MeasurementSpecification: "NCQA/HEDIS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2023/IUHH/index.tsx b/services/ui-src/src/measures/2023/IUHH/index.tsx deleted file mode 100644 index c440b2f00..000000000 --- a/services/ui-src/src/measures/2023/IUHH/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormData as FormData } from "shared/types/FormData"; - -export const IUHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2023/IUHH/validation.ts b/services/ui-src/src/measures/2023/IUHH/validation.ts index a1a121d23..49d0514c2 100644 --- a/services/ui-src/src/measures/2023/IUHH/validation.ts +++ b/services/ui-src/src/measures/2023/IUHH/validation.ts @@ -35,7 +35,10 @@ const IUHHValidation = (data: FormData) => { const definitionOfDenominator = data[DC.DEFINITION_OF_DENOMINATOR]; const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; const deviationReason = data[DC.DEVIATION_REASON]; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2023/index.tsx b/services/ui-src/src/measures/2023/index.tsx index 9a2928aae..d360bf68e 100644 --- a/services/ui-src/src/measures/2023/index.tsx +++ b/services/ui-src/src/measures/2023/index.tsx @@ -3,9 +3,6 @@ import { measureTemplate } from "./measureTemplate"; import { Qualifier } from "shared/Qualifiers"; import { Data } from "labels/2023/qualifierFormsData"; -const AIFHH = lazy(() => - import("./AIFHH").then((module) => ({ default: module.AIFHH })) -); const AMRAD = lazy(() => import("./AMRAD").then((module) => ({ default: module.AMRAD })) ); @@ -15,9 +12,6 @@ const CPAAD = lazy(() => const CPCCH = lazy(() => import("./CPCCH").then((module) => ({ default: module.CPCCH })) ); -const IUHH = lazy(() => - import("./IUHH").then((module) => ({ default: module.IUHH })) -); const LBWCH = lazy(() => import("./LBWCH").then((module) => ({ default: module.LBWCH })) ); @@ -43,7 +37,7 @@ const twentyTwentyThreeMeasures = { "AAB-AD": measureTemplate, "AAB-CH": measureTemplate, "ADD-CH": measureTemplate, - "AIF-HH": AIFHH, + "AIF-HH": measureTemplate, "AMB-CH": measureTemplate, "AMB-HH": measureTemplate, "AMM-AD": measureTemplate, @@ -88,7 +82,7 @@ const twentyTwentyThreeMeasures = { "IET-AD": measureTemplate, "IET-HH": measureTemplate, "IMA-CH": measureTemplate, - "IU-HH": IUHH, + "IU-HH": measureTemplate, "LBW-CH": LBWCH, "LRCD-CH": LRCDCH, "LSC-CH": measureTemplate, diff --git a/services/ui-src/src/measures/2023/measureTemplate.tsx b/services/ui-src/src/measures/2023/measureTemplate.tsx index 2c092e38a..22a3f0b9c 100644 --- a/services/ui-src/src/measures/2023/measureTemplate.tsx +++ b/services/ui-src/src/measures/2023/measureTemplate.tsx @@ -110,9 +110,13 @@ export const measureTemplate = ({ allowNumeratorGreaterThanDenominator={ custom?.allowNumeratorGreaterThanDenominator } + componentFlag={opm?.componentFlag} excludeOptions={opm?.excludeOptions} customPrompt={custom?.customPrompt} rateCalc={custom?.rateCalc} + inputFieldNames={performanceMeasure?.inputFieldNames} + ndrFormulas={performanceMeasure?.ndrFormulas} + measureName={performanceMeasure?.measureName} /> ))} diff --git a/services/ui-src/src/measures/2023/measureTemplateData.tsx b/services/ui-src/src/measures/2023/measureTemplateData.tsx index fb5757cdc..3d94539de 100644 --- a/services/ui-src/src/measures/2023/measureTemplateData.tsx +++ b/services/ui-src/src/measures/2023/measureTemplateData.tsx @@ -7,6 +7,9 @@ import { validationFunctions as AABCH_Validations } from "./AABCH/validation"; import { data as ADDCH_Data } from "./ADDCH/data"; import { validationFunctions as ADDCH_Validations } from "./ADDCH/validation"; +import { data as AIFHH_Data } from "./AIFHH/data"; +import { validationFunctions as AIFHH_Validations } from "./AIFHH/validation"; + import { data as AMBCH_Data } from "./AMBCH/data"; import { validationFunctions as AMBCH_Validations } from "./AMBCH/validation"; @@ -130,6 +133,9 @@ import { validationFunctions as IETHH_Validations } from "./IETHH/validation"; import { data as IMACH_Data } from "./IMACH/data"; import { validationFunctions as IMACH_Validations } from "./IMACH/validation"; +import { data as IUHH_Data } from "./IUHH/data"; +import { validationFunctions as IUHH_Validations } from "./IUHH/validation"; + import { data as LSCCH_Data } from "./LSCCH/data"; import { validationFunctions as LSCCH_Validations } from "./LSCCH/validation"; @@ -191,6 +197,7 @@ export const measureTemplateData: { [measure: string]: any } = { "AAB-AD": { data: AABAD_Data, validationFunctions: AABAD_Validations }, "AAB-CH": { data: AABCH_Data, validationFunctions: AABCH_Validations }, "ADD-CH": { data: ADDCH_Data, validationFunctions: ADDCH_Validations }, + "AIF-HH": { data: AIFHH_Data, validationFunctions: AIFHH_Validations }, "AMB-CH": { data: AMBCH_Data, validationFunctions: AMBCH_Validations }, "AMB-HH": { data: AMBHH_Data, validationFunctions: AMBHH_Validations }, "AMM-AD": { data: AMMAD_Data, validationFunctions: AMMAD_Validations }, @@ -232,6 +239,7 @@ export const measureTemplateData: { [measure: string]: any } = { "IET-AD": { data: IETAD_Data, validationFunctions: IETAD_Validations }, "IET-HH": { data: IETHH_Data, validationFunctions: IETHH_Validations }, "IMA-CH": { data: IMACH_Data, validationFunctions: IMACH_Validations }, + "IU-HH": { data: IUHH_Data, validationFunctions: IUHH_Validations }, "LSC-CH": { data: LSCCH_Data, validationFunctions: LSCCH_Validations }, "OEV-CH": { data: OEVCH_Data, validationFunctions: OEVCH_Validations }, "OHD-AD": { data: OHDAD_Data, validationFunctions: OHDAD_Validations }, diff --git a/services/ui-src/src/measures/2024/AIFHH/data.ts b/services/ui-src/src/measures/2024/AIFHH/data.ts index c968396db..de9362075 100644 --- a/services/ui-src/src/measures/2024/AIFHH/data.ts +++ b/services/ui-src/src/measures/2024/AIFHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { xNumbersYDecimals } from "utils"; export const { categories, qualifiers } = getCatQualLabels("AIF-HH"); -const measureName = "AIFHH"; - const inputFieldNames = [ { label: "Number of Enrollee Months", @@ -43,7 +43,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Short-Term Admissions per 1,000 Enrollee Months { @@ -68,22 +67,39 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - questionText: [ - "The number of admissions to a facility among enrollees age 18 and older residing in the community for at least one month. The number of short-term, medium-term, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", - ], - questionListItems: [ - " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", - ], - questionListTitles: ["Short-Term Stay", "Medium-Term Stay", "Long-Term Stay"], - questionSubtext: [ - "The following three performance rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", - ], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + questionText: [ + "The number of admissions to a facility among enrollees age 18 and older residing in the community for at least one month. The number of short-term, medium-term, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", + ], + questionListItems: [ + " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", + ], + questionListTitles: [ + "Short-Term Stay", + "Medium-Term Stay", + "Long-Term Stay", + ], + questionSubtext: [ + "The following three performance rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", + ], + categories, + qualifiers, + measureName: "AIFHH", + inputFieldNames, + ndrFormulas, + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "AIF", + }, }; diff --git a/services/ui-src/src/measures/2024/AIFHH/index.test.tsx b/services/ui-src/src/measures/2024/AIFHH/index.test.tsx deleted file mode 100644 index 64c36f98d..000000000 --- a/services/ui-src/src/measures/2024/AIFHH/index.test.tsx +++ /dev/null @@ -1,382 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "AIF-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2024; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - afterEach(() => { - screen.debug(); - }); - - it("should pass a11y tests", async () => { - useApiMock(apiData); - await act(async () => { - const { container } = renderWithHookForm(component); - expect(await axe(container)).toHaveNoViolations(); - }); - }); - - it("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).not.toHaveBeenCalled(); - expect(V.validateDeviationTextFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).not.toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).not.toHaveBeenCalled(); - }); - - it("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).toHaveBeenCalled(); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - singleCategory: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 65 to 74", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 75 to 84", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Age 85 and older", - }, - { - fields: [ - { - value: "2", - label: "Number of Enrollee Months", - }, - { - value: 2, - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - isTotal: true, - label: "Total (Age 18 and older)", - }, - ], - }, - }, - MeasurementSpecification: "CMS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2024/AIFHH/index.tsx b/services/ui-src/src/measures/2024/AIFHH/index.tsx deleted file mode 100644 index 724bcbd73..000000000 --- a/services/ui-src/src/measures/2024/AIFHH/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormData as FormData } from "shared/types/FormData"; - -export const AIFHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2024/AIFHH/validation.ts b/services/ui-src/src/measures/2024/AIFHH/validation.ts index 6d3d1c3fe..3e49f05f4 100644 --- a/services/ui-src/src/measures/2024/AIFHH/validation.ts +++ b/services/ui-src/src/measures/2024/AIFHH/validation.ts @@ -38,7 +38,10 @@ const AIFHHValidation = (data: FormData) => { const definitionOfDenominator = data[DC.DEFINITION_OF_DENOMINATOR]; const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; const deviationReason = data[DC.DEVIATION_REASON]; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2024/IUHH/data.ts b/services/ui-src/src/measures/2024/IUHH/data.ts index 0677497bf..1c7a56662 100644 --- a/services/ui-src/src/measures/2024/IUHH/data.ts +++ b/services/ui-src/src/measures/2024/IUHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { xNumbersYDecimals } from "utils"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; +import { ComplexRate } from "components"; export const { categories, qualifiers } = getCatQualLabels("IU-HH"); -const measureName = "IUHH"; - const inputFieldNames = [ { label: "Number of Enrollee Months", @@ -30,7 +30,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Discharges per 1,000 Enrollee Months { @@ -55,16 +54,29 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - customPrompt: - "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", - questionText: [ - "Rate of acute inpatient care and services (total and mental and behavioral disorders) per 1,000 enrollee months among health home enrollees.", - ], - questionListItems: [], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + customPrompt: + "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", + questionText: [ + "Rate of acute inpatient care and services (total and mental and behavioral disorders) per 1,000 enrollee months among health home enrollees.", + ], + questionListItems: [], + categories, + qualifiers, + inputFieldNames, + ndrFormulas, + measureName: "IUHH", + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "IU", + }, }; diff --git a/services/ui-src/src/measures/2024/IUHH/index.test.tsx b/services/ui-src/src/measures/2024/IUHH/index.test.tsx deleted file mode 100644 index ccbb0b094..000000000 --- a/services/ui-src/src/measures/2024/IUHH/index.test.tsx +++ /dev/null @@ -1,781 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "IU-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2024; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - - it("should pass a11y tests", async () => { - useApiMock(apiData); - await act(async () => { - const { container } = renderWithHookForm(component); - expect(await axe(container)).toHaveNoViolations(); - }); - }); - - it("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).not.toHaveBeenCalled(); - expect(V.validateDeviationTextFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).not.toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).not.toHaveBeenCalled(); - }); - - it("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).toHaveBeenCalled(); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - Inpatient: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: 1, - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: 1, - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Maternity: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Medicine: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - MentalandBehavioralDisorders: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Surgery: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - }, - }, - MeasurementSpecification: "NCQA/HEDIS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2024/IUHH/index.tsx b/services/ui-src/src/measures/2024/IUHH/index.tsx deleted file mode 100644 index c440b2f00..000000000 --- a/services/ui-src/src/measures/2024/IUHH/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormData as FormData } from "shared/types/FormData"; - -export const IUHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2024/IUHH/validation.ts b/services/ui-src/src/measures/2024/IUHH/validation.ts index f12e29bc7..2100bcdf9 100644 --- a/services/ui-src/src/measures/2024/IUHH/validation.ts +++ b/services/ui-src/src/measures/2024/IUHH/validation.ts @@ -35,7 +35,10 @@ const IUHHValidation = (data: FormData) => { const definitionOfDenominator = data[DC.DEFINITION_OF_DENOMINATOR]; const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; const deviationReason = data[DC.DEVIATION_REASON]; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2024/index.tsx b/services/ui-src/src/measures/2024/index.tsx index df9f28952..7cb6b4528 100644 --- a/services/ui-src/src/measures/2024/index.tsx +++ b/services/ui-src/src/measures/2024/index.tsx @@ -3,9 +3,6 @@ import { measureTemplate } from "./measureTemplate"; import { Qualifier } from "shared/Qualifiers"; import { Data } from "labels/2024/qualifierFormsData"; -const AIFHH = lazy(() => - import("./AIFHH").then((module) => ({ default: module.AIFHH })) -); const AMRAD = lazy(() => import("./AMRAD").then((module) => ({ default: module.AMRAD })) ); @@ -18,9 +15,6 @@ const CPCCH = lazy(() => const CPUAD = lazy(() => import("./CPUAD").then((module) => ({ default: module.CPUAD })) ); -const IUHH = lazy(() => - import("./IUHH").then((module) => ({ default: module.IUHH })) -); const LBWCH = lazy(() => import("./LBWCH").then((module) => ({ default: module.LBWCH })) ); @@ -46,7 +40,7 @@ const twentyTwentyFourMeasures = { "AAB-AD": measureTemplate, "AAB-CH": measureTemplate, "ADD-CH": measureTemplate, - "AIF-HH": AIFHH, + "AIF-HH": measureTemplate, "AMB-CH": measureTemplate, "AMB-HH": measureTemplate, "AMM-AD": measureTemplate, @@ -90,7 +84,7 @@ const twentyTwentyFourMeasures = { "IET-AD": measureTemplate, "IET-HH": measureTemplate, "IMA-CH": measureTemplate, - "IU-HH": IUHH, + "IU-HH": measureTemplate, "LBW-CH": LBWCH, "LRCD-CH": LRCDCH, "LSC-CH": measureTemplate, diff --git a/services/ui-src/src/measures/2024/measureTemplate.tsx b/services/ui-src/src/measures/2024/measureTemplate.tsx index eeeac7f04..f0d351103 100644 --- a/services/ui-src/src/measures/2024/measureTemplate.tsx +++ b/services/ui-src/src/measures/2024/measureTemplate.tsx @@ -109,9 +109,13 @@ export const measureTemplate = ({ allowNumeratorGreaterThanDenominator={ custom?.allowNumeratorGreaterThanDenominator } + componentFlag={opm?.componentFlag} excludeOptions={opm?.excludeOptions} customPrompt={custom?.customPrompt} rateCalc={custom?.rateCalc} + inputFieldNames={performanceMeasure?.inputFieldNames} + ndrFormulas={performanceMeasure?.ndrFormulas} + measureName={performanceMeasure?.measureName} /> ))} diff --git a/services/ui-src/src/measures/2024/measureTemplateData.tsx b/services/ui-src/src/measures/2024/measureTemplateData.tsx index bd2c5739f..3946fd20a 100644 --- a/services/ui-src/src/measures/2024/measureTemplateData.tsx +++ b/services/ui-src/src/measures/2024/measureTemplateData.tsx @@ -7,6 +7,9 @@ import { validationFunctions as AABCH_Validations } from "./AABCH/validation"; import { data as ADDCH_Data } from "./ADDCH/data"; import { validationFunctions as ADDCH_Validations } from "./ADDCH/validation"; +import { data as AIFHH_Data } from "./AIFHH/data"; +import { validationFunctions as AIFHH_Validations } from "./AIFHH/validation"; + import { data as AMBCH_Data } from "./AMBCH/data"; import { validationFunctions as AMBCH_Validations } from "./AMBCH/validation"; @@ -124,6 +127,9 @@ import { validationFunctions as IETHH_Validations } from "./IETHH/validation"; import { data as IMACH_Data } from "./IMACH/data"; import { validationFunctions as IMACH_Validations } from "./IMACH/validation"; +import { data as IUHH_Data } from "./IUHH/data"; +import { validationFunctions as IUHH_Validations } from "./IUHH/validation"; + import { data as LSCCH_Data } from "./LSCCH/data"; import { validationFunctions as LSCCH_Validations } from "./LSCCH/validation"; @@ -185,6 +191,7 @@ export const measureTemplateData: { [measure: string]: any } = { "AAB-AD": { data: AABAD_Data, validationFunctions: AABAD_Validations }, "AAB-CH": { data: AABCH_Data, validationFunctions: AABCH_Validations }, "ADD-CH": { data: ADDCH_Data, validationFunctions: ADDCH_Validations }, + "AIF-HH": { data: AIFHH_Data, validationFunctions: AIFHH_Validations }, "AMB-CH": { data: AMBCH_Data, validationFunctions: AMBCH_Validations }, "AMB-HH": { data: AMBHH_Data, validationFunctions: AMBHH_Validations }, "AMM-AD": { data: AMMAD_Data, validationFunctions: AMMAD_Validations }, @@ -224,6 +231,7 @@ export const measureTemplateData: { [measure: string]: any } = { "IET-AD": { data: IETAD_Data, validationFunctions: IETAD_Validations }, "IET-HH": { data: IETHH_Data, validationFunctions: IETHH_Validations }, "IMA-CH": { data: IMACH_Data, validationFunctions: IMACH_Validations }, + "IU-HH": { data: IUHH_Data, validationFunctions: IUHH_Validations }, "LSC-CH": { data: LSCCH_Data, validationFunctions: LSCCH_Validations }, "OEV-CH": { data: OEVCH_Data, validationFunctions: OEVCH_Validations }, "OHD-AD": { data: OHDAD_Data, validationFunctions: OHDAD_Validations }, diff --git a/services/ui-src/src/measures/2025/AIFHH/data.ts b/services/ui-src/src/measures/2025/AIFHH/data.ts index c968396db..40e9b4aa6 100644 --- a/services/ui-src/src/measures/2025/AIFHH/data.ts +++ b/services/ui-src/src/measures/2025/AIFHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; +import { xNumbersYDecimals } from "utils"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; export const { categories, qualifiers } = getCatQualLabels("AIF-HH"); -const measureName = "AIFHH"; - const inputFieldNames = [ { label: "Number of Enrollee Months", @@ -43,7 +43,6 @@ const inputFieldNames = [ }, ]; -// Rate structure by index in row const ndrFormulas = [ // Short-Term Admissions per 1,000 Enrollee Months { @@ -68,22 +67,39 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - questionText: [ - "The number of admissions to a facility among enrollees age 18 and older residing in the community for at least one month. The number of short-term, medium-term, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", - ], - questionListItems: [ - " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", - " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", - ], - questionListTitles: ["Short-Term Stay", "Medium-Term Stay", "Long-Term Stay"], - questionSubtext: [ - "The following three performance rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", - ], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + questionText: [ + "The number of admissions to a facility among enrollees age 18 and older residing in the community for at least one month. The number of short-term, medium-term, or long-term admissions is reported per 1,000 enrollee months. Enrollee months reflect the total number of months each enrollee is enrolled in the program and residing in the community for at least one day of the month.", + ], + questionListItems: [ + " The rate of admissions resulting in a short-term stay (1 to 20 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a medium-term stay (21 to 100 days) per 1,000 enrollee months.", + " The rate of admissions resulting in a long-term stay (greater than or equal to 101 days) per 1,000 enrollee months.", + ], + questionListTitles: [ + "Short-Term Stay", + "Medium-Term Stay", + "Long-Term Stay", + ], + questionSubtext: [ + "The following three performance rates are reported across four age groups (ages 18 to 64, ages 65 to 74, ages 75 to 84, and age 85 and older):", + ], + categories, + qualifiers, + measureName: "AIFHH", + inputFieldNames, + ndrFormulas, + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "AIF", + }, }; diff --git a/services/ui-src/src/measures/2025/AIFHH/index.test.tsx b/services/ui-src/src/measures/2025/AIFHH/index.test.tsx deleted file mode 100644 index e30583647..000000000 --- a/services/ui-src/src/measures/2025/AIFHH/index.test.tsx +++ /dev/null @@ -1,379 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "AIF-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2025; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - - it("should pass a11y tests", async () => { - useApiMock(apiData); - await act(async () => { - const { container } = renderWithHookForm(component); - expect(await axe(container)).toHaveNoViolations(); - }); - }); - - it("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).not.toHaveBeenCalled(); - expect(V.validateDeviationTextFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).not.toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).not.toHaveBeenCalled(); - }); - - it("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).toHaveBeenCalled(); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - singleCategory: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 65 to 74", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Ages 75 to 84", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Number of Short-Term Admissions", - }, - { - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Medium-Term Admissions", - }, - { - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - label: "Number of Long-Term Admissions", - }, - { - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - label: "Age 85 and older", - }, - { - fields: [ - { - value: "2", - label: "Number of Enrollee Months", - }, - { - value: 2, - label: "Number of Short-Term Admissions", - }, - { - value: "1000.0", - label: "Short-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Medium-Term Admissions", - }, - { - value: "1000.0", - label: "Medium-Term Admissions per 1,000 Enrollee Months", - }, - { - value: 2, - label: "Number of Long-Term Admissions", - }, - { - value: "1000.0", - label: "Long-Term Admissions per 1,000 Enrollee Months", - }, - ], - isTotal: true, - label: "Total (Age 18 and older)", - }, - ], - }, - }, - MeasurementSpecification: "CMS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2025/AIFHH/index.tsx b/services/ui-src/src/measures/2025/AIFHH/index.tsx deleted file mode 100644 index 724bcbd73..000000000 --- a/services/ui-src/src/measures/2025/AIFHH/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormData as FormData } from "shared/types/FormData"; - -export const AIFHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2025/AIFHH/validation.ts b/services/ui-src/src/measures/2025/AIFHH/validation.ts index fc60f4164..8117bafa9 100644 --- a/services/ui-src/src/measures/2025/AIFHH/validation.ts +++ b/services/ui-src/src/measures/2025/AIFHH/validation.ts @@ -38,7 +38,10 @@ const AIFHHValidation = (data: FormData) => { const definitionOfDenominator = data[DC.DEFINITION_OF_DENOMINATOR]; const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; const deviationReason = data[DC.DEVIATION_REASON]; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2025/IUHH/data.ts b/services/ui-src/src/measures/2025/IUHH/data.ts index 0677497bf..b31cbc8b8 100644 --- a/services/ui-src/src/measures/2025/IUHH/data.ts +++ b/services/ui-src/src/measures/2025/IUHH/data.ts @@ -1,10 +1,10 @@ -import { DataDrivenTypes } from "shared/types"; +import { ComplexRate } from "components"; +import { xNumbersYDecimals } from "utils"; import { getCatQualLabels } from "../rateLabelText"; +import { MeasureTemplateData } from "shared/types/MeasureTemplate"; export const { categories, qualifiers } = getCatQualLabels("IU-HH"); -const measureName = "IUHH"; - const inputFieldNames = [ { label: "Number of Enrollee Months", @@ -29,8 +29,6 @@ const inputFieldNames = [ id: "coDyWU", }, ]; - -// Rate structure by index in row const ndrFormulas = [ // Discharges per 1,000 Enrollee Months { @@ -55,16 +53,29 @@ const ndrFormulas = [ }, ]; -export const data: DataDrivenTypes.PerformanceMeasure = { - customPrompt: - "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", - questionText: [ - "Rate of acute inpatient care and services (total and mental and behavioral disorders) per 1,000 enrollee months among health home enrollees.", - ], - questionListItems: [], - measureName, - inputFieldNames, - ndrFormulas, - categories, - qualifiers, +export const data: MeasureTemplateData = { + type: "CMS", + coreset: "health", + performanceMeasure: { + customPrompt: + "Enter the appropriate data below. Completion of at least one set of Numerator/Denominator/Rate (numeric entry, other than zero) is required.", + questionText: [ + "Rate of acute inpatient care and services (total and mental and behavioral disorders) per 1,000 enrollee months among health home enrollees.", + ], + questionListItems: [], + categories, + qualifiers, + measureName: "IUHH", + inputFieldNames, + ndrFormulas, + }, + custom: { + calcTotal: true, + customMask: xNumbersYDecimals(12, 1), + allowNumeratorGreaterThanDenominator: true, + RateComponent: ComplexRate, + }, + opm: { + componentFlag: "IU", + }, }; diff --git a/services/ui-src/src/measures/2025/IUHH/index.test.tsx b/services/ui-src/src/measures/2025/IUHH/index.test.tsx deleted file mode 100644 index e67f5d445..000000000 --- a/services/ui-src/src/measures/2025/IUHH/index.test.tsx +++ /dev/null @@ -1,781 +0,0 @@ -import { screen, waitFor, act } from "@testing-library/react"; -import { createElement } from "react"; -import { RouterWrappedComp } from "utils/testing"; -import { MeasureWrapper } from "components/MeasureWrapper"; -import { useApiMock } from "utils/testUtils/useApiMock"; -import { useUser } from "hooks/authHooks"; -import Measures from "measures"; -import { Suspense } from "react"; -import { MeasuresLoading } from "views"; -import { measureDescriptions } from "measures/measureDescriptions"; -import { renderWithHookForm } from "utils/testUtils/reactHookFormRenderer"; -import { validationFunctions } from "./validation"; -import { - mockValidateAndSetErrors, - clearMocks, - validationsMockObj as V, -} from "shared/util/validationsMock"; -import { axe, toHaveNoViolations } from "jest-axe"; -expect.extend(toHaveNoViolations); - -// Test Setup -const measureAbbr = "IU-HH"; -const coreSet = "HHCS"; -const state = "DC"; -const year = 2025; -const description = measureDescriptions[`${year}`][measureAbbr]; -const apiData: any = {}; - -jest.mock("hooks/authHooks"); -const mockUseUser = useUser as jest.Mock; - -describe(`Test FFY ${year} ${measureAbbr}`, () => { - let component: JSX.Element; - beforeEach(() => { - clearMocks(); - apiData.useGetMeasureValues = { - data: { - Item: { - compoundKey: `${state}${year}${coreSet}${measureAbbr}`, - coreSet, - createdAt: 1642517935305, - description, - lastAltered: 1642517935305, - lastAlteredBy: "undefined", - measure: measureAbbr, - state, - status: "incomplete", - year, - data: {}, - }, - }, - isLoading: false, - refetch: jest.fn(), - isError: false, - error: undefined, - }; - - mockUseUser.mockImplementation(() => { - return { isStateUser: false }; - }); - - const measure = createElement(Measures[year][measureAbbr]); - component = ( - - - - - - ); - }); - - it("should pass a11y tests", async () => { - useApiMock(apiData); - await act(async () => { - const { container } = renderWithHookForm(component); - expect(await axe(container)).toHaveNoViolations(); - }); - }); - - it("measure should render", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("measure-wrapper-form")).toBeInTheDocument(); - await waitFor(() => { - expect(screen.getByText(measureAbbr + " - " + description)); - }); - }); - - /** - * Render the measure and confirm that all expected components exist. - * */ - it("Always shows Are you reporting question", async () => { - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("reporting")); - }); - - it("shows corresponding questions if yes to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).toBeInTheDocument(); - }); - - it("does not show corresponding questions if no to reporting then ", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("status-of-data")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("measurement-specification") - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("data-source")).not.toBeInTheDocument(); - expect(screen.queryByTestId("date-range")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("definition-of-population") - ).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is selected", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("performance-measure")).toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).toBeInTheDocument(); - expect(screen.queryByTestId("OPM")).not.toBeInTheDocument(); - }); - - it("shows corresponding components and hides others when primary measure is NOT selected", async () => { - apiData.useGetMeasureValues.data.Item.data = OPMData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OPM")); - expect(screen.queryByTestId("performance-measure")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("deviation-from-measure-specification") - ).not.toBeInTheDocument(); - }); - - it("shows OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = completedMeasureData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")); - }); - it("does not show OMS when performance measure data has been entered", async () => { - apiData.useGetMeasureValues.data.Item.data = notReportingData; - useApiMock(apiData); - renderWithHookForm(component); - expect(screen.queryByTestId("OMS")).not.toBeInTheDocument(); - }); - - /** Validations Test - * - * Confirm that correct functions are called. Comprehensive testing of the validations is done in specific test files - * for each validation function. See globalValidations directory. - */ - it("(Not Reporting) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, notReportingData); // trigger validations - expect(V.validateReasonForNotReporting).toHaveBeenCalled(); - expect(V.validateAtLeastOneRateComplete).not.toHaveBeenCalled(); - expect(V.ComplexValidateDualPopInformation).not.toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).not.toHaveBeenCalled(); - expect(V.validateRateZeroPM).not.toHaveBeenCalled(); - expect( - V.validateRequiredRadioButtonForCombinedRates - ).not.toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).not.toHaveBeenCalled(); - expect(V.validateDeviationTextFieldFilled).not.toHaveBeenCalled(); - expect(V.validateNumeratorLessThanDenominatorOMS).not.toHaveBeenCalled(); - expect(V.validateRateZeroOMS).not.toHaveBeenCalled(); - expect(V.validateRateNotZeroOMS).not.toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).not.toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).not.toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).not.toHaveBeenCalled(); - }); - - it("(Completed) validationFunctions should call all expected validation functions", async () => { - mockValidateAndSetErrors(validationFunctions, completedMeasureData); // trigger validations - expect(V.validateReasonForNotReporting).not.toHaveBeenCalled(); - expect(V.ComplexAtLeastOneRateComplete).toHaveBeenCalled(); - expect(V.ComplexNoNonZeroNumOrDenom).toHaveBeenCalled(); - expect(V.validateRequiredRadioButtonForCombinedRates).toHaveBeenCalled(); - expect(V.validateBothDatesCompleted).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSource).toHaveBeenCalled(); - expect(V.validateAtLeastOneDataSourceType).toHaveBeenCalled(); - expect(V.ComplexValidateNDRTotals).toHaveBeenCalled(); - expect(V.validateAtLeastOneDeliverySystem).toHaveBeenCalled(); - expect(V.validateFfsRadioButtonCompletion).toHaveBeenCalled(); - expect(V.validateAtLeastOneDefinitionOfPopulation).toHaveBeenCalled(); - }); -}); - -const notReportingData = { - DidReport: "no", -}; - -const OPMData = { MeasurementSpecification: "Other", DidReport: "yes" }; - -const completedMeasureData = { - PerformanceMeasure: { - rates: { - Inpatient: [ - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: "1", - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: "1", - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - value: "1", - label: "Number of Enrollee Months", - }, - { - value: 1, - label: "Discharges", - }, - { - value: "1000.0", - label: "Discharges per 1,000 Enrollee Months", - }, - { - value: 1, - label: "Days", - }, - { - value: "1000.0", - label: "Days per 1,000 Enrollee Months", - }, - { - value: "1.0", - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Maternity: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Medicine: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - MentalandBehavioralDisorders: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - Surgery: [ - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 0 to 17", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages 18 to 64", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Age 65 and older", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - label: "Ages unknown", - }, - { - fields: [ - { - label: "Number of Enrollee Months", - }, - { - label: "Discharges", - }, - { - label: "Discharges per 1,000 Enrollee Months", - }, - { - label: "Days", - }, - { - label: "Days per 1,000 Enrollee Months", - }, - { - label: "Average Length of Stay", - }, - ], - isTotal: true, - label: "Total", - }, - ], - }, - }, - MeasurementSpecification: "NCQA/HEDIS", - DidReport: "yes", -}; diff --git a/services/ui-src/src/measures/2025/IUHH/index.tsx b/services/ui-src/src/measures/2025/IUHH/index.tsx deleted file mode 100644 index c440b2f00..000000000 --- a/services/ui-src/src/measures/2025/IUHH/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import * as CMQ from "shared/commonQuestions"; -import * as PMD from "./data"; -import * as QMR from "components"; -import { getPerfMeasureRateArray } from "shared/globalValidations"; -import { useEffect } from "react"; -import { useFormContext } from "react-hook-form"; -import { validationFunctions } from "./validation"; -import { xNumbersYDecimals } from "utils"; -//form type -import { DefaultFormData as FormData } from "shared/types/FormData"; - -export const IUHH = ({ - name, - year, - measureId, - setValidationFunctions, - isNotReportingData, - isPrimaryMeasureSpecSelected, - showOptionalMeasureStrat, - isOtherMeasureSpecSelected, -}: QMR.MeasureWrapperProps) => { - const { watch } = useFormContext(); - const data = watch(); - - useEffect(() => { - if (setValidationFunctions) { - setValidationFunctions(validationFunctions); - } - }, [setValidationFunctions]); - - const performanceMeasureArray = getPerfMeasureRateArray(data, PMD.data); - - return ( - <> - - - {!isNotReportingData && ( - <> - - - - - - {isPrimaryMeasureSpecSelected && ( - <> - - - - )} - {isOtherMeasureSpecSelected && ( - - )} - - {showOptionalMeasureStrat && ( - - )} - - )} - - - ); -}; diff --git a/services/ui-src/src/measures/2025/IUHH/validation.ts b/services/ui-src/src/measures/2025/IUHH/validation.ts index 4a07f71d8..44457b788 100644 --- a/services/ui-src/src/measures/2025/IUHH/validation.ts +++ b/services/ui-src/src/measures/2025/IUHH/validation.ts @@ -35,7 +35,10 @@ const IUHHValidation = (data: FormData) => { const definitionOfDenominator = data[DC.DEFINITION_OF_DENOMINATOR]; const didCalculationsDeviate = data[DC.DID_CALCS_DEVIATE] === DC.YES; const deviationReason = data[DC.DEVIATION_REASON]; - const performanceMeasureArray = GV.getPerfMeasureRateArray(data, PMD.data); + const performanceMeasureArray = GV.getPerfMeasureRateArray( + data, + PMD.data.performanceMeasure + ); OPM = data[DC.OPM_RATES]; const whyNotReporting = data[DC.WHY_ARE_YOU_NOT_REPORTING]; diff --git a/services/ui-src/src/measures/2025/index.tsx b/services/ui-src/src/measures/2025/index.tsx index 87606ab34..30e994a1b 100644 --- a/services/ui-src/src/measures/2025/index.tsx +++ b/services/ui-src/src/measures/2025/index.tsx @@ -3,9 +3,6 @@ import { measureTemplate } from "./measureTemplate"; import { Qualifier } from "shared/Qualifiers"; import { Data } from "labels/2025/qualifierFormsData"; -const AIFHH = lazy(() => - import("./AIFHH").then((module) => ({ default: module.AIFHH })) -); const AMRAD = lazy(() => import("./AMRAD").then((module) => ({ default: module.AMRAD })) ); @@ -18,9 +15,6 @@ const CPCCH = lazy(() => const CPUAD = lazy(() => import("./CPUAD").then((module) => ({ default: module.CPUAD })) ); -const IUHH = lazy(() => - import("./IUHH").then((module) => ({ default: module.IUHH })) -); const LBWCH = lazy(() => import("./LBWCH").then((module) => ({ default: module.LBWCH })) ); @@ -49,7 +43,7 @@ const twentyTwentyFiveMeasures = { "AAB-AD": measureTemplate, "AAB-CH": measureTemplate, "ADD-CH": measureTemplate, - "AIF-HH": AIFHH, + "AIF-HH": measureTemplate, // "AIS-AD": measureTemplate, //TO DO: replace with real measure "AMM-AD": measureTemplate, "AMR-AD": AMRAD, @@ -93,7 +87,7 @@ const twentyTwentyFiveMeasures = { "IET-AD": measureTemplate, "IET-HH": measureTemplate, "IMA-CH": measureTemplate, - "IU-HH": IUHH, + "IU-HH": measureTemplate, "LBW-CH": LBWCH, "LRCD-AD": LRCDAD, "LRCD-CH": LRCDCH, diff --git a/services/ui-src/src/measures/2025/measureTemplate.tsx b/services/ui-src/src/measures/2025/measureTemplate.tsx index 85d63c33f..28cbe9fe6 100644 --- a/services/ui-src/src/measures/2025/measureTemplate.tsx +++ b/services/ui-src/src/measures/2025/measureTemplate.tsx @@ -113,9 +113,13 @@ export const measureTemplate = ({ allowNumeratorGreaterThanDenominator={ custom?.allowNumeratorGreaterThanDenominator } + componentFlag={opm?.componentFlag} excludeOptions={opm?.excludeOptions} customPrompt={custom?.customPrompt} rateCalc={custom?.rateCalc} + inputFieldNames={performanceMeasure?.inputFieldNames} + ndrFormulas={performanceMeasure?.ndrFormulas} + measureName={performanceMeasure?.measureName} /> ))} diff --git a/services/ui-src/src/measures/2025/measureTemplateData.tsx b/services/ui-src/src/measures/2025/measureTemplateData.tsx index c1f90f647..3dc3cca7f 100644 --- a/services/ui-src/src/measures/2025/measureTemplateData.tsx +++ b/services/ui-src/src/measures/2025/measureTemplateData.tsx @@ -7,6 +7,9 @@ import { validationFunctions as AABCH_Validations } from "./AABCH/validation"; import { data as ADDCH_Data } from "./ADDCH/data"; import { validationFunctions as ADDCH_Validations } from "./ADDCH/validation"; +import { data as AIFHH_Data } from "./AIFHH/data"; +import { validationFunctions as AIFHH_Validations } from "./AIFHH/validation"; + import { data as AMMAD_Data } from "./AMMAD/data"; import { validationFunctions as AMMAD_Validations } from "./AMMAD/validation"; @@ -121,6 +124,9 @@ import { validationFunctions as IETHH_Validations } from "./IETHH/validation"; import { data as IMACH_Data } from "./IMACH/data"; import { validationFunctions as IMACH_Validations } from "./IMACH/validation"; +import { data as IUHH_Data } from "./IUHH/data"; +import { validationFunctions as IUHH_Validations } from "./IUHH/validation"; + import { data as LSCCH_Data } from "./LSCCH/data"; import { validationFunctions as LSCCH_Validations } from "./LSCCH/validation"; @@ -185,6 +191,7 @@ export const measureTemplateData: { [measure: string]: any } = { "AAB-AD": { data: AABAD_Data, validationFunctions: AABAD_Validations }, "AAB-CH": { data: AABCH_Data, validationFunctions: AABCH_Validations }, "ADD-CH": { data: ADDCH_Data, validationFunctions: ADDCH_Validations }, + "AIF-HH": { data: AIFHH_Data, validationFunctions: AIFHH_Validations }, "AMM-AD": { data: AMMAD_Data, validationFunctions: AMMAD_Validations }, "AMR-CH": { data: AMRCH_Data, validationFunctions: AMRCH_Validations }, "APM-CH": { data: APMCH_Data, validationFunctions: APMCH_Validations }, @@ -223,6 +230,7 @@ export const measureTemplateData: { [measure: string]: any } = { "IET-AD": { data: IETAD_Data, validationFunctions: IETAD_Validations }, "IET-HH": { data: IETHH_Data, validationFunctions: IETHH_Validations }, "IMA-CH": { data: IMACH_Data, validationFunctions: IMACH_Validations }, + "IU-HH": { data: IUHH_Data, validationFunctions: IUHH_Validations }, "LSC-CH": { data: LSCCH_Data, validationFunctions: LSCCH_Validations }, "OEV-CH": { data: OEVCH_Data, validationFunctions: OEVCH_Validations }, "OEVP-AD": { data: OEVPAD_Data, validationFunctions: OEVPAD_Validations }, diff --git a/services/ui-src/src/shared/commonQuestions/OptionalMeasureStrat/index.tsx b/services/ui-src/src/shared/commonQuestions/OptionalMeasureStrat/index.tsx index 85f4eb5df..c01127a18 100644 --- a/services/ui-src/src/shared/commonQuestions/OptionalMeasureStrat/index.tsx +++ b/services/ui-src/src/shared/commonQuestions/OptionalMeasureStrat/index.tsx @@ -123,8 +123,6 @@ const arrayIsReadOnly = (dataSource: string[]) => { */ export const OptionalMeasureStrat = ({ performanceMeasureArray, - IUHHPerformanceMeasureArray, - AIFHHPerformanceMeasureArray, qualifiers = [], categories = [], measureName, @@ -150,6 +148,14 @@ export const OptionalMeasureStrat = ({ const labels: any = useContext(SharedContext); const year = labels.year; + const IUHHPerformanceMeasureArray = + measureName === "IUHH" ? performanceMeasureArray : undefined; + const AIFHHPerformanceMeasureArray = + measureName === "AIFHH" ? performanceMeasureArray : undefined; + + if (IUHHPerformanceMeasureArray || AIFHHPerformanceMeasureArray) + performanceMeasureArray = undefined; + const omsData = data ?? OMSData(year, coreset === "adult"); const { control, watch, getValues, setValue, unregister } = useFormContext(); diff --git a/services/ui-src/src/shared/types/MeasureTemplate.tsx b/services/ui-src/src/shared/types/MeasureTemplate.tsx index 935bf894c..9bfd5e142 100644 --- a/services/ui-src/src/shared/types/MeasureTemplate.tsx +++ b/services/ui-src/src/shared/types/MeasureTemplate.tsx @@ -29,5 +29,6 @@ export interface MeasureTemplateData { custom?: customData; opm?: { excludeOptions?: string[]; + componentFlag?: string; }; }