Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAAAR analysis methods statusing: more custom logic! #12018

Merged
merged 9 commits into from
Jan 31, 2025
73 changes: 70 additions & 3 deletions services/ui-src/src/components/fields/DynamicField.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import userEvent from "@testing-library/user-event";
import { FormProvider, useForm } from "react-hook-form";
// components
import { DynamicField, ReportContext } from "components";
// constants
import { DEFAULT_ANALYSIS_METHODS } from "../../constants";
// types
import { ReportStatus } from "types";
// utils
Expand All @@ -17,6 +19,9 @@ import {
mockQualityMeasuresEntity,
mockAdminUserStore,
mockMcparReportStore,
mockNaaarReportWithAnalysisMethodsContext,
mockNaaarAnalysisMethodsReportStore,
mockAnalysisMethodEntityStore,
} from "utils/testing/setupJest";
import { testA11y } from "utils/testing/commonTests";

Expand Down Expand Up @@ -63,7 +68,7 @@ const MockForm = (props: any) => {
shouldFocusError: false,
});
return (
<ReportContext.Provider value={mockedReportContext}>
<ReportContext.Provider value={props?.customContext ?? mockedReportContext}>
<FormProvider {...form}>
<form id="uniqueId" onSubmit={form.handleSubmit(jest.fn())}>
<DynamicField
Expand All @@ -77,8 +82,8 @@ const MockForm = (props: any) => {
);
};

const dynamicFieldComponent = (hydrationValue?: any) => (
<MockForm hydrationValue={hydrationValue} />
const dynamicFieldComponent = (hydrationValue?: any, customContext?: any) => (
<MockForm hydrationValue={hydrationValue} customContext={customContext} />
);

const MockIlosForm = (props: any) => {
Expand Down Expand Up @@ -327,6 +332,68 @@ describe("<DynamicField />", () => {
);
});

test("Deletes plan and associated analysis methods plan in NAAAR if state user", async () => {
mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockNaaarAnalysisMethodsReportStore,
...mockAnalysisMethodEntityStore,
});

const mockedReportContext = {
...mockNaaarReportWithAnalysisMethodsContext,
updateReport: mockUpdateReport,
report: mockNaaarReportWithAnalysisMethodsContext.report,
};

await act(async () => {
await render(
dynamicFieldComponent(mockHydrationPlans, mockedReportContext)
);
});
// delete mock-plan-1
const removeButton = screen.queryAllByTestId("removeButton")[0];
await userEvent.click(removeButton);
const deleteButton = screen.getByText("Yes, delete plan");
await userEvent.click(deleteButton);

expect(mockUpdateReport).toHaveBeenCalledWith(
{
...mockReportKeys,
reportType: "NAAAR",
state: mockStateUserStore.user?.state,
},
{
metadata: {
status: ReportStatus.IN_PROGRESS,
lastAlteredBy: mockStateUserStore.user?.full_name,
},
fieldData: {
plans: [
{
id: "mock-plan-id-2",
name: "mock-plan-2",
},
],
analysisMethods: [
{
...DEFAULT_ANALYSIS_METHODS[0],
analysis_method_applicable_plans: [
{
key: "mock-plan-id-2",
name: "mock-plan-2",
},
],
},
{
id: "custom_entity",
name: "custom entity",
},
],
},
}
);
});

test("If there's no ILOS entities left, associated plan responses are cleared from field data", async () => {
const mcparReportWithoutIlos = {
...mockMcparReport,
Expand Down
14 changes: 14 additions & 0 deletions services/ui-src/src/components/fields/DynamicField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,19 @@ export const DynamicField = ({ name, label, ...props }: Props) => {
}
);

// filter analysis methods to remove deleted plans
const filteredAnalysisMethods = report?.fieldData?.analysisMethods?.map(
(method: EntityShape) => {
if (method?.analysis_method_applicable_plans?.length) {
method.analysis_method_applicable_plans =
method.analysis_method_applicable_plans.filter(
(plan: AnyObject) => plan.key !== selectedRecord.id
);
}
return method;
}
);

// delete ILOS data from corresponding plans
const filteredPlans =
name === "plans"
Expand Down Expand Up @@ -189,6 +202,7 @@ export const DynamicField = ({ name, label, ...props }: Props) => {
sanctions: filteredSanctions,
qualityMeasures: filteredQualityMeasures,
plans: filteredPlans,
analysisMethods: filteredAnalysisMethods,
},
};

Expand Down
132 changes: 33 additions & 99 deletions services/ui-src/src/components/reports/DrawerReportPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import userEvent from "@testing-library/user-event";
// components
import { ReportContext, DrawerReportPage } from "components";
// constants
import { DEFAULT_ANALYSIS_METHODS, saveAndCloseText } from "../../constants";
// types
import { McrEntityState } from "types";
import { saveAndCloseText } from "../../constants";
// utils
import { useStore } from "utils";
import {
Expand All @@ -19,9 +17,10 @@ import {
mockEntityStore,
mockVerbiageIntro,
mockDrawerForm,
mockNaaarReportStore,
mockNaaarReportContext,
mockNaaarAnalysisMethodsPageJson,
mockAnalysisMethodEntityStore,
mockNaaarReportWithAnalysisMethodsContext,
mockNaaarAnalysisMethodsReportStore,
} from "utils/testing/setupJest";
import { testA11y } from "utils/testing/commonTests";

Expand Down Expand Up @@ -68,6 +67,14 @@ const drawerReportPageWithCompletedEntity = (
</RouterWrappedComponent>
);

const drawerReportPageWithCustomEntities = (
<RouterWrappedComponent>
<ReportContext.Provider value={mockNaaarReportWithAnalysisMethodsContext}>
<DrawerReportPage route={mockNaaarAnalysisMethodsPageJson} />
</ReportContext.Provider>
</RouterWrappedComponent>
);

describe("<DrawerReportPage />", () => {
afterEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -312,44 +319,10 @@ describe("<DrawerReportPage />", () => {
});

describe("Test DrawerReportPage with custom entities", () => {
const mockAnalysisMethodEntityStore: McrEntityState = {
entities: [],
entityType: "analysisMethods",
selectedEntity: {
id: "k9t7YoOeTOAXX3s7qF6XfN33",
name: "Geomapping",
isRequired: true,
},
// ACTIONS
setSelectedEntity: () => {},
setEntityType: () => {},
setEntities: () => {},
};

const mockNaaarReportContextWithAnalysisMethods: any =
mockNaaarReportContext;
mockNaaarReportContextWithAnalysisMethods.report.fieldData[
"analysisMethods"
] = [DEFAULT_ANALYSIS_METHODS[0]];

const mockCustomNaaarReportStore = {
...mockNaaarReportStore,
report: mockNaaarReportContextWithAnalysisMethods.report,
reportsByState: [mockNaaarReportContextWithAnalysisMethods.report],
};
const drawerReportPageWithCustomEntities = (
<RouterWrappedComponent>
<ReportContext.Provider
value={mockNaaarReportContextWithAnalysisMethods}
>
<DrawerReportPage route={mockNaaarAnalysisMethodsPageJson} />
</ReportContext.Provider>
</RouterWrappedComponent>
);
test("Can enter default analysis method drawer", async () => {
mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockCustomNaaarReportStore,
...mockNaaarAnalysisMethodsReportStore,
...mockAnalysisMethodEntityStore,
});

Expand All @@ -367,7 +340,7 @@ describe("<DrawerReportPage />", () => {
mockAnalysisMethodNoSelectedEntityStore.selectedEntity = undefined;
mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockCustomNaaarReportStore,
...mockNaaarAnalysisMethodsReportStore,
...mockAnalysisMethodNoSelectedEntityStore,
});

Expand All @@ -384,67 +357,28 @@ describe("<DrawerReportPage />", () => {
expect(enterDefaultMethod).toBeVisible();
});

describe("test analysis methods custom logic", () => {
beforeEach(() => {
const mockNaaarReportContextWithCustomAnalysisMethods: any =
mockNaaarReportContext;

const { report } = mockNaaarReportContextWithCustomAnalysisMethods;

// add custom entity to render special row type
report.fieldData["analysisMethods"] = [
DEFAULT_ANALYSIS_METHODS[0],
{
id: "custom_entity",
name: "custom entity",
},
];

const mockCustomNaaarReportStore = {
...mockNaaarReportStore,
report,
reportsByState: [report],
};

mockedUseStore.mockReturnValue({
...mockStateUserStore,
...mockCustomNaaarReportStore,
...mockAnalysisMethodEntityStore,
});

const drawerReportPageWithCustomEntities = (
<RouterWrappedComponent>
<ReportContext.Provider
value={mockNaaarReportContextWithCustomAnalysisMethods}
>
<DrawerReportPage route={mockNaaarAnalysisMethodsPageJson} />
</ReportContext.Provider>
</RouterWrappedComponent>
);

render(drawerReportPageWithCustomEntities);
});

test("Can shows statusing for custom analysis methods", async () => {
const iconAltText = screen.getAllByAltText("Entity is incomplete");
expect(iconAltText.length).toBeGreaterThan(0);
});
test("Can shows statusing for custom analysis methods", async () => {
render(drawerReportPageWithCustomEntities);
const iconAltText = screen.getAllByAltText("Entity is incomplete");
expect(iconAltText.length).toBeGreaterThan(0);
});

test("DrawerReportPage opens the delete modal on remove click", async () => {
const addCustomMethod = screen.getByText("Add other analysis method");
const removeButton = screen.getByTestId("delete-entity");
await userEvent.click(removeButton);
// click delete in modal
const deleteButton = screen.getByText("Yes, delete method");
await userEvent.click(deleteButton);

// verify that the field is removed
const inputBoxLabelAfterRemove = screen.queryAllByTestId("test-label");
expect(inputBoxLabelAfterRemove).toHaveLength(0);
expect(addCustomMethod).toBeVisible();
});
test("DrawerReportPage opens the delete modal on remove click", async () => {
render(drawerReportPageWithCustomEntities);
const addCustomMethod = screen.getByText("Add other analysis method");
const removeButton = screen.getByTestId("delete-entity");
await userEvent.click(removeButton);
// click delete in modal
const deleteButton = screen.getByText("Yes, delete method");
await userEvent.click(deleteButton);

// verify that the field is removed
const inputBoxLabelAfterRemove = screen.queryAllByTestId("test-label");
expect(inputBoxLabelAfterRemove).toHaveLength(0);
expect(addCustomMethod).toBeVisible();
});
});

testA11y(drawerReportPageWithEntities, () => {
mockedUseStore.mockReturnValue({
...mockStateUserStore,
Expand Down
16 changes: 14 additions & 2 deletions services/ui-src/src/components/reports/DrawerReportPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,18 @@ export const DrawerReportPage = ({ route, validateOnRender }: Props) => {
const isCustomEntity =
canAddEntities && !getDefaultAnalysisMethodIds().includes(entity.id);
const calculateEntityCompletion = () => {
// logic to ensure analysis methods always have a plan selected
bangbay-bluetiger marked this conversation as resolved.
Show resolved Hide resolved
if (
isAnalysisMethodsPage &&
!entity?.analysis_method_applicable_plans?.length
) {
if (isCustomEntity) {
return false;
gmrabian marked this conversation as resolved.
Show resolved Hide resolved
} else if (entity?.analysis_applicable?.[0]?.value === "Yes") {
return false;
}
}

let formFields = form.fields;
if (isCustomEntity) {
formFields = addEntityForm.fields;
Expand Down Expand Up @@ -305,7 +317,7 @@ export const DrawerReportPage = ({ route, validateOnRender }: Props) => {
<Text>{entity.custom_analysis_method_description}</Text>
)}
{entity.analysis_method_frequency &&
entity.analysis_method_applicable_plans && (
entity.analysis_method_applicable_plans?.length > 0 && (
<Text>
{entity.analysis_method_frequency[0].value}:&nbsp;
{entity.analysis_method_applicable_plans
Expand All @@ -321,7 +333,7 @@ export const DrawerReportPage = ({ route, validateOnRender }: Props) => {
)}
<Box sx={buttonBoxStyling(canAddEntities)}>
{enterButton(entity, isEntityCompleted)}
{canAddEntities && !entity.isRequired && (
{hasPlans && canAddEntities && !entity.isRequired && (
<Button
sx={sx.deleteButton}
data-testid="delete-entity"
Expand Down
Loading
Loading