From 8b99a2743cfec24643acdde6cd361a5c8e0c5135 Mon Sep 17 00:00:00 2001 From: fzhao99 Date: Thu, 7 Sep 2023 10:52:16 -0400 Subject: [PATCH] replace manage facility admin screen dropdowns with combos (#6439) * refactor using truss * add tests * temporarily wrap things in act * fix accessibility violations and refactor tests * scope down unnecessary changes * use recommended userEvent setup pattern * fix mocks * move gql alias to before each hook * switch selector * rework e2e to work with combo box * add org util query to simplify selectors * add extracted combo box component * add forwardRef hook * relax label selectors --- cypress/e2e/11-support-manage-facility.cy.js | 38 ++++-- cypress/utils/testing-data-utils.js | 63 +++++---- .../src/app/commonComponents/ComboBox.tsx | 35 +++++ .../FacilitySelectFilter.test.tsx | 67 +++++++--- .../ManageFacility/FacilitySelectFilter.tsx | 76 ++++++----- .../ManageFacility/ManageFacility.test.tsx | 126 ++++++++++-------- .../ManageFacility/ManageFacility.tsx | 95 ++++++++----- 7 files changed, 319 insertions(+), 181 deletions(-) create mode 100644 frontend/src/app/commonComponents/ComboBox.tsx diff --git a/cypress/e2e/11-support-manage-facility.cy.js b/cypress/e2e/11-support-manage-facility.cy.js index a7d4a6efeb..3deb1d5b4c 100644 --- a/cypress/e2e/11-support-manage-facility.cy.js +++ b/cypress/e2e/11-support-manage-facility.cy.js @@ -1,29 +1,37 @@ -import {loginHooks, testNumber} from "../support/e2e"; -import {addMockFacility, whoAmI} from "../utils/testing-data-utils"; -import {graphqlURL} from "../utils/request-utils"; -import {aliasGraphqlOperations} from "../utils/graphql-test-utils"; +import { loginHooks, testNumber } from "../support/e2e"; +import { addMockFacility, whoAmI, getOrganizationById } from "../utils/testing-data-utils"; +import { graphqlURL } from "../utils/request-utils"; +import { aliasGraphqlOperations } from "../utils/graphql-test-utils"; loginHooks(); describe("Support admin: manage facility", () => { - let organizationId=""; + let organizationId = ""; + let organizationName = ""; let facilityId = ""; let facilityCreated = { - id:"", - name:`RainbowCenter-${testNumber()}`, - } + id: "", + name: `RainbowCenter-${testNumber()}` + }; before(() => { - addMockFacility(facilityCreated.name).then(response=>{ + addMockFacility(facilityCreated.name).then(response => { facilityCreated.id = response.body.data.addFacility.id; }); whoAmI().then((res) => { organizationId = res.body.data.whoami.organization.id; facilityId = res.body.data.whoami.organization.facilities[0].id; + + getOrganizationById(organizationId).then((res) => { + organizationName = res.body.data.organization.name; + }); }); + }); + + beforeEach(() => { cy.intercept("POST", graphqlURL, (req) => { - aliasGraphqlOperations(req) + aliasGraphqlOperations(req); }); }); @@ -38,11 +46,13 @@ describe("Support admin: manage facility", () => { // selects organization cy.wait("@GetAllOrganizations"); - cy.get("div.bg-base-lightest select").first().select(organizationId); - // selects facility + // selects org combo box + cy.get("input[role=\"combobox\"]").first().type(`${organizationName}{enter}`); + + // selects facility combo box cy.wait("@GetFacilitiesByOrgId"); - cy.get("div.bg-base-lightest select").eq(1).select(facilityCreated.id); + cy.get("input[role=\"combobox\"]").last().type(`${facilityCreated.name}{enter}`); // clicks search button cy.get("button").contains("Search").click(); @@ -62,7 +72,7 @@ describe("Support admin: manage facility", () => { cy.contains(`Delete ${facilityCreated.name}`).should("not.exist"); }); - it("Deletes a facility",()=>{ + it("Deletes a facility", () => { cy.get("button").contains("Delete facility").click(); cy.get("button").contains("Yes, delete facility").click(); cy.get(".Toastify").contains(`Facility ${facilityCreated.name} successfully deleted`); diff --git a/cypress/utils/testing-data-utils.js b/cypress/utils/testing-data-utils.js index 544b4e1e0d..3fc937efd6 100644 --- a/cypress/utils/testing-data-utils.js +++ b/cypress/utils/testing-data-utils.js @@ -1,32 +1,47 @@ -export const whoAmI=()=>{ +export const whoAmI = () => { return cy.makePOSTRequest({ operationName: "WhoAmI", variables: {}, query: - "query WhoAmI {\n whoami {\n organization {\n id\n facilities {\n id\n }\n }\n} \n}", + "query WhoAmI {\n whoami {\n organization {\n id\n facilities {\n id\n }\n }\n} \n}" }); -} +}; + +export const getOrganizationById = (organizationId) => { + return cy.makePOSTRequest({ + operationName: "Organization", + variables: { id: organizationId }, + query: + `query Organization($id: ID!) { + organization(id: $id){ + id + name + } + }` + }); +}; -export const addMockFacility=(facilityName)=>{ -return cy.makePOSTRequest({ - operationName: "AddFacility", - variables: { - "testingFacilityName":facilityName, - "street":"123 maint street", - "state":"NJ","zipCode":"07601", - "orderingProviderFirstName":"Jane", - "orderingProviderLastName":"Austen", - "orderingProviderNPI":"1234567890", - "orderingProviderStreet":"", - "orderingProviderStreetTwo":"", - "orderingProviderCity":"", - "orderingProviderState":"", - "orderingProviderZipCode":"", - "orderingProviderPhone":"7328392412", - "devices":[]}, - query: - `mutation AddFacility( +export const addMockFacility = (facilityName) => { + return cy.makePOSTRequest({ + operationName: "AddFacility", + variables: { + "testingFacilityName": facilityName, + "street": "123 maint street", + "state": "NJ", "zipCode": "07601", + "orderingProviderFirstName": "Jane", + "orderingProviderLastName": "Austen", + "orderingProviderNPI": "1234567890", + "orderingProviderStreet": "", + "orderingProviderStreetTwo": "", + "orderingProviderCity": "", + "orderingProviderState": "", + "orderingProviderZipCode": "", + "orderingProviderPhone": "7328392412", + "devices": [] + }, + query: + `mutation AddFacility( $testingFacilityName: String! $street: String! $state: String! @@ -70,6 +85,6 @@ return cy.makePOSTRequest({ ) { id } -}`, -}); +}` + }); }; \ No newline at end of file diff --git a/frontend/src/app/commonComponents/ComboBox.tsx b/frontend/src/app/commonComponents/ComboBox.tsx new file mode 100644 index 0000000000..7319eec174 --- /dev/null +++ b/frontend/src/app/commonComponents/ComboBox.tsx @@ -0,0 +1,35 @@ +import { ComboBox as TrussComboBox, Label } from "@trussworks/react-uswds"; +import React, { ComponentPropsWithRef, forwardRef } from "react"; + +import Required from "./Required"; + +type TrussComponentProps = ComponentPropsWithRef; +export type ComboBoxProps = TrussComponentProps & { + required?: boolean; +}; + +// props here are only the required ones from Truss and can be extended +// as needed with additional values. +const ComboBox: React.FC = forwardRef(function ( + { id, name, required, options, onChange, disabled }: ComboBoxProps, + ref +) { + return ( + <> + + + + ); +}); + +export default ComboBox; diff --git a/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.test.tsx b/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.test.tsx index 1fb1529eb9..45b8550b87 100644 --- a/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.test.tsx +++ b/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.test.tsx @@ -1,11 +1,33 @@ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { act, render, screen, waitFor, within } from "@testing-library/react"; import { MemoryRouter } from "react-router-dom"; +import React from "react"; +import { ComboBoxRef } from "@trussworks/react-uswds"; +import userEvent from "@testing-library/user-event"; import { Option } from "../../commonComponents/Dropdown"; import FacilitySelectFilter from "./FacilitySelectFilter"; import { initialState, ManageFacilityState } from "./ManageFacility"; +export const getOrgComboBoxElements = () => { + const orgSelectionDiv = screen.getByTestId("org-selection-container"); + const orgComboBoxInput = screen.getByLabelText(/organization/i); + const orgComboBoxList = within(orgSelectionDiv).getByTestId( + "combo-box-option-list" + ); + return [orgComboBoxInput, orgComboBoxList] as const; +}; + +export const getFacilityComboBoxElements = () => { + const facilitySelectionDiv = screen.getByTestId( + "facility-selection-container" + ); + const facilityComboBoxInput = screen.getByLabelText(/testing facility/i); + const facilityComboBoxList = within(facilitySelectionDiv).getByTestId( + "combo-box-option-list" + ); + return [facilityComboBoxInput, facilityComboBoxList] as const; +}; describe("FacilitySelectFilter", () => { const handleClearFilter = jest.fn(); const handleSelectOrg = jest.fn(); @@ -22,7 +44,9 @@ describe("FacilitySelectFilter", () => { orgOptions: Option[], facilityOptions: Option[], manageFacilityState: ManageFacilityState - ) => + ) => { + const orgRef = React.createRef(); + const facilityRef = React.createRef(); render( { onSearch={handleSearch} manageFacilityState={manageFacilityState} loading={true} + orgRef={orgRef} + facilityRef={facilityRef} /> ); + }; + const user = userEvent.setup(); it("disables controls when loading data", () => { renderWithMocks([], [], initialState); - expect( - screen.getByRole("combobox", { name: /organization/i }) - ).toBeDisabled(); - expect(screen.getByRole("combobox", { name: /facility/i })).toBeDisabled(); + const [orgDropdown] = getOrgComboBoxElements(); + const [facilityDropdown] = getFacilityComboBoxElements(); + + expect(facilityDropdown).toBeDisabled(); + expect(orgDropdown).toBeDisabled(); }); it("calls handleClearFilter upon clicking clear filters button", async () => { renderWithMocks(mockOrganizationOptions, mockFacilityOptions, { orgId: "123", - facilityId: "", + facilityId: undefined, facility: undefined, }); const clearFiltersBtn = screen.getByRole("button", { name: /clear facility selection filters/i, }); expect(clearFiltersBtn).toBeEnabled(); - fireEvent.click(clearFiltersBtn); + await act(() => user.click(clearFiltersBtn)); await waitFor(() => expect(handleClearFilter).toHaveBeenCalled()); }); it("calls event handlers when organization is selected", async () => { renderWithMocks(mockOrganizationOptions, mockFacilityOptions, initialState); - const orgDropdown = screen.getByRole("combobox", { name: /organization/i }); - fireEvent.change(orgDropdown, { target: { value: "123" } }); + + const [, orgDropdown] = getOrgComboBoxElements(); + + await act(() => user.selectOptions(orgDropdown, ["organization-123"])); await waitFor(() => expect(handleSelectOrg).toHaveBeenCalled()); }); it("calls event handlers when facility is selected", async () => { renderWithMocks(mockOrganizationOptions, mockFacilityOptions, { orgId: "123", - facilityId: "", + facilityId: undefined, facility: undefined, }); - const facilityDropdown = screen.getByRole("combobox", { - name: /facility/i, - }); - fireEvent.change(facilityDropdown, { target: { value: "123" } }); + + const [, facilityDropdown] = getFacilityComboBoxElements(); + await act(() => user.selectOptions(facilityDropdown, ["facility-123"])); await waitFor(() => expect(handleSelectFacility).toHaveBeenCalled()); }); @@ -87,15 +117,12 @@ describe("FacilitySelectFilter", () => { facilityId: "123", facility: undefined, }); - const facilityDropdown = screen.getByRole("combobox", { - name: /facility/i, - }); - fireEvent.change(facilityDropdown, { target: { value: "123" } }); const searchBtn = screen.getByRole("button", { name: /search/i, }); - fireEvent.click(searchBtn); + expect(searchBtn).toBeEnabled(); + await act(() => user.click(searchBtn)); await waitFor(() => expect(handleSearch).toHaveBeenCalled()); }); diff --git a/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.tsx b/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.tsx index 33fcc9c6d3..9b00101214 100644 --- a/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.tsx +++ b/frontend/src/app/supportAdmin/ManageFacility/FacilitySelectFilter.tsx @@ -1,21 +1,25 @@ import { faSlidersH } from "@fortawesome/free-solid-svg-icons"; -import React from "react"; +import React, { Ref } from "react"; +import { ComboBoxRef } from "@trussworks/react-uswds"; -import Dropdown, { Option } from "../../commonComponents/Dropdown"; +import ComboBox from "../../commonComponents/ComboBox"; import Button from "../../commonComponents/Button/Button"; import SupportHomeLink from "../SupportHomeLink"; +import { Option } from "../../commonComponents/Dropdown"; import { ManageFacilityState } from "./ManageFacility"; export interface FacilitySelectFilterProps { organizationOptions: Option[]; facilityOptions: Option[]; + manageFacilityState: ManageFacilityState; onClearFilter: () => void; - onSelectOrg: (e: any) => void; - onSelectFacility: (e: any) => void; + onSelectOrg: (selectedOrg: string | undefined) => void; + onSelectFacility: (selectedFacility: string | undefined) => void; onSearch: (e: any) => void; - manageFacilityState: ManageFacilityState; loading: boolean; + facilityRef: Ref | undefined; + orgRef: Ref | undefined; } const FacilitySelectFilter: React.FC = ({ @@ -27,6 +31,8 @@ const FacilitySelectFilter: React.FC = ({ onSelectFacility, onSearch, loading, + facilityRef, + orgRef, }) => { /** * HTML @@ -43,7 +49,7 @@ const FacilitySelectFilter: React.FC = ({
diff --git a/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.test.tsx b/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.test.tsx index 702bd2a94e..65cd92baeb 100644 --- a/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.test.tsx +++ b/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.test.tsx @@ -1,6 +1,7 @@ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { act, render, screen, waitFor, within } from "@testing-library/react"; import { MemoryRouter } from "react-router-dom"; import { MockedProvider, MockedResponse } from "@apollo/client/testing"; +import userEvent from "@testing-library/user-event"; import { DeleteFacilityDocument, @@ -10,6 +11,10 @@ import { } from "../../../generated/graphql"; import ManageFacility from "./ManageFacility"; +import { + getFacilityComboBoxElements, + getOrgComboBoxElements, +} from "./FacilitySelectFilter.test"; describe("ManageFacility", () => { const renderWithMocks = () => @@ -26,6 +31,8 @@ describe("ManageFacility", () => { name: /clear facility selection filters/i, }); + const user = userEvent.setup(); + beforeEach(() => { renderWithMocks(); }); @@ -34,9 +41,8 @@ describe("ManageFacility", () => { const clearFiltersBtn = getClearFilterBtn(); expect(clearFiltersBtn).toBeDisabled(); - const orgDropdown = screen.getByRole("combobox", { name: /organization/i }); - await waitFor(() => expect(orgDropdown).toBeEnabled()); - fireEvent.change(orgDropdown, { target: { value: "" } }); // picks -Select- option + const [orgComboBoxInput] = getOrgComboBoxElements(); + await waitFor(() => expect(orgComboBoxInput).toBeEnabled()); expect(clearFiltersBtn).toBeDisabled(); expect(screen.getByText(/No facility selected/)).toBeInTheDocument(); @@ -46,38 +52,38 @@ describe("ManageFacility", () => { const clearFiltersBtn = getClearFilterBtn(); expect(clearFiltersBtn).toBeDisabled(); - const orgDropdown = screen.getByRole("combobox", { name: /organization/i }); - await waitFor(() => expect(orgDropdown).toBeEnabled()); - fireEvent.change(orgDropdown, { - target: { value: "604f2e80-b4b7-4fff-806a-2a77973aa08f" }, - }); // picks Dis Organization + const [orgComboBoxInput, orgComboBoxList] = getOrgComboBoxElements(); - const facilityDropdown = screen.getByRole("combobox", { - name: /facility/i, - }); - await waitFor(() => expect(facilityDropdown).toBeEnabled()); + await waitFor(() => expect(orgComboBoxInput).toBeEnabled()); + await act(async () => await user.type(orgComboBoxInput, "dis")); + await act( + async () => + await user.click(within(orgComboBoxList).getByText("Dis Organization")) + ); + expect(orgComboBoxInput).toHaveValue("Dis Organization"); expect(clearFiltersBtn).toBeEnabled(); - fireEvent.change(facilityDropdown, { target: { value: "" } }); // picks -Select- - await waitFor(() => expect(clearFiltersBtn).toBeEnabled()); - expect(screen.getByText(/No facility selected/)).toBeInTheDocument(); + await screen.findByText(/No facility selected/); }); it("resets the controls after clicking clear filters", async () => { const clearFiltersBtn = getClearFilterBtn(); expect(clearFiltersBtn).toBeDisabled(); - const orgDropdown = screen.getByRole("combobox", { name: /organization/i }); - await waitFor(() => expect(orgDropdown).toBeEnabled()); - fireEvent.change(orgDropdown, { - target: { value: "604f2e80-b4b7-4fff-806a-2a77973aa08f" }, - }); // picks Dis Organization + const [orgComboBoxInput, orgComboBoxList] = getOrgComboBoxElements(); + await waitFor(() => expect(orgComboBoxInput).toBeEnabled()); + + await act(async () => await user.type(orgComboBoxInput, "dis")); + await act( + async () => + await user.click(within(orgComboBoxList).getByText("Dis Organization")) + ); await waitFor(() => expect(clearFiltersBtn).toBeEnabled()); - fireEvent.click(clearFiltersBtn); + await act(async () => await user.click(clearFiltersBtn)); await waitFor(() => expect(clearFiltersBtn).toBeDisabled()); - expect(orgDropdown).toHaveValue(""); + expect(orgComboBoxInput).toHaveValue(""); expect(screen.getByText(/No facility selected/)).toBeInTheDocument(); }); @@ -85,38 +91,44 @@ describe("ManageFacility", () => { const clearFiltersBtn = getClearFilterBtn(); expect(clearFiltersBtn).toBeDisabled(); - const orgDropdown = screen.getByRole("combobox", { name: /organization/i }); - await waitFor(() => expect(orgDropdown).toBeEnabled()); - fireEvent.change(orgDropdown, { - target: { value: "604f2e80-b4b7-4fff-806a-2a77973aa08f" }, - }); // picks Dis Organization + const [orgComboBoxInput, orgComboBoxList] = getOrgComboBoxElements(); + const [facilityComboBoxInput, facilityComboBoxList] = + getFacilityComboBoxElements(); - const facilityDropdown = screen.getByRole("combobox", { - name: /facility/i, - }); - await waitFor(() => expect(facilityDropdown).toBeEnabled()); - expect(clearFiltersBtn).toBeEnabled(); - fireEvent.change(facilityDropdown, { - target: { value: "1919865a-92eb-4c46-b73b-471b02b131b7" }, - }); // picks testing site + await waitFor(() => expect(orgComboBoxInput).toBeEnabled()); + await act(async () => await user.type(orgComboBoxInput, "dis")); + await act( + async () => + await user.click(within(orgComboBoxList).getByText("Dis Organization")) + ); + + await waitFor(() => expect(facilityComboBoxInput).toBeEnabled()); + await waitFor(() => expect(clearFiltersBtn).toBeEnabled()); + await act( + async () => await user.type(facilityComboBoxInput, "testing site") + ); + await act( + async () => + await user.click(within(facilityComboBoxList).getByText("Testing Site")) + ); const searchBtn = screen.getByRole("button", { name: /search/i, }); - fireEvent.click(searchBtn); + await act(async () => await user.click(searchBtn)); await screen.findByRole("heading", { name: /Testing Site/i }); const deleteFacilityBtn = screen.getByRole("button", { name: /delete facility testing site/i, }); - fireEvent.click(deleteFacilityBtn); + await act(async () => await user.click(deleteFacilityBtn)); await screen.findByRole("heading", { name: /delete testing site/i }); const yesDeleteBtn = screen.getByRole("button", { name: /yes, delete facility/i, }); - fireEvent.click(yesDeleteBtn); + await act(async () => await user.click(yesDeleteBtn)); await waitFor(() => expect( @@ -126,8 +138,8 @@ describe("ManageFacility", () => { // Facility testing site successfully deleted // page resets - await waitFor(() => expect(orgDropdown).toHaveValue("")); - expect(facilityDropdown).toHaveValue(""); + await waitFor(() => expect(orgComboBoxInput).toHaveValue("")); + expect(facilityComboBoxInput).toHaveValue(""); expect(clearFiltersBtn).toBeDisabled(); }); @@ -135,25 +147,31 @@ describe("ManageFacility", () => { const clearFiltersBtn = getClearFilterBtn(); expect(clearFiltersBtn).toBeDisabled(); - const orgDropdown = screen.getByRole("combobox", { name: /organization/i }); - await waitFor(() => expect(orgDropdown).toBeEnabled()); - fireEvent.change(orgDropdown, { - target: { value: "09cdf298-39b3-41b0-92f7-092c2bfe065e" }, - }); // picks Dis Organization + const [orgComboBoxInput, orgComboBoxList] = getOrgComboBoxElements(); + const [facilityComboBoxInput, facilityComboBoxList] = + getFacilityComboBoxElements(); - const facilityDropdown = screen.getByRole("combobox", { - name: /facility/i, - }); - await waitFor(() => expect(facilityDropdown).toBeEnabled()); + await waitFor(() => expect(orgComboBoxInput).toBeEnabled()); + await act(async () => await user.type(orgComboBoxInput, "dat")); + await act( + async () => + await user.click(within(orgComboBoxList).getByText("Dat Organization")) + ); + + await waitFor(() => expect(facilityComboBoxInput).toBeEnabled()); expect(clearFiltersBtn).toBeEnabled(); - fireEvent.change(facilityDropdown, { - target: { value: "1919865a-92eb-4c46-b73b-471b02b131b8" }, - }); // picks testing site + await act(async () => await user.type(facilityComboBoxInput, "incom")); + await act( + async () => + await user.click( + within(facilityComboBoxList).getByText("Incomplete Site") + ) + ); const searchBtn = screen.getByRole("button", { name: /search/i, }); - fireEvent.click(searchBtn); + await act(async () => await user.click(searchBtn)); await screen.findByRole("heading", { name: /Incomplete Site/i }); }); diff --git a/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.tsx b/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.tsx index 873a851e6a..104b5901ac 100644 --- a/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.tsx +++ b/frontend/src/app/supportAdmin/ManageFacility/ManageFacility.tsx @@ -1,4 +1,5 @@ -import React, { useState } from "react"; +import { useRef, useState } from "react"; +import { ComboBoxRef } from "@trussworks/react-uswds"; import { Option } from "../../commonComponents/Dropdown"; import { @@ -27,14 +28,14 @@ type Facility = { }; export interface ManageFacilityState { - orgId: string; - facilityId: string; + orgId: string | undefined; + facilityId: string | undefined; facility: Facility | undefined; } export const initialState: ManageFacilityState = { - orgId: "", - facilityId: "", + facilityId: undefined, + orgId: undefined, facility: undefined, }; @@ -42,12 +43,22 @@ const ManageFacility = () => { useDocumentTitle(manageFacility); const [localState, updateLocalState] = useState(initialState); + const orgSelectionRef = useRef(null); + const facilitySelectionRef = useRef(null); /** * Fetch organizations (on initial load) */ const { data: orgResponse, loading: loadingOrgs } = - useGetAllOrganizationsQuery(); + useGetAllOrganizationsQuery({ + onCompleted: () => { + // for some reason, our combination of Truss + Apollo requires us clear + // a non-existent ref so that the options to the org combobox loads + // on first try. If we exclude this line, the fetched data doesn't load + // on initial render. ¯\_(ツ)_/¯ + orgSelectionRef.current?.clearSelection(); + }, + }); const orgOptions: Option[] = orgResponse?.organizations?.map((org) => ({ @@ -64,7 +75,8 @@ const ManageFacility = () => { ] = useGetFacilitiesByOrgIdLazyQuery(); const facilitiesOptions: Option[] = - localState.orgId === "" || !facilitiesResponse?.organization?.facilities + localState.orgId === undefined || + !facilitiesResponse?.organization?.facilities ? [] : facilitiesResponse?.organization?.facilities.map((facility) => ({ value: facility.id, @@ -79,52 +91,60 @@ const ManageFacility = () => { /** * Facility select filter handlers */ - function handleSelectOrganization(e: React.ChangeEvent) { - const selectedOrg = e.target.value; - if (selectedOrg !== "") { + function handleSelectOrganization(selectedOrg: string | undefined) { + if (selectedOrg) { queryGetFacilitiesByOrgId({ variables: { orgId: selectedOrg }, fetchPolicy: "no-cache", - }).then(); - } + }).then(() => facilitySelectionRef.current?.clearSelection()); - updateLocalState((prevState) => ({ - ...prevState, - orgId: selectedOrg, - facilityId: "", - })); + updateLocalState({ + facility: undefined, + facilityId: undefined, + orgId: selectedOrg, + }); + } else { + orgSelectionRef.current?.clearSelection(); + facilitySelectionRef.current?.clearSelection(); + + updateLocalState({ + facility: undefined, + facilityId: undefined, + orgId: undefined, + }); + } } - async function handleSelectFacility(e: React.ChangeEvent) { - const facilityId = e.target.value; + async function handleSelectFacility(selectedFacility: string | undefined) { updateLocalState((prevState) => ({ ...prevState, - facilityId: facilityId, + facilityId: selectedFacility, })); } async function handleSearch() { const facilityId = localState.facilityId; - if (facilityId === "") { + if (facilityId === undefined) { updateLocalState((prevState) => ({ ...prevState, facility: undefined, })); } else { + const localSelectedFacilityId = localState.facilityId as string; const selectedFacility = facilitiesResponse?.organization?.facilities?.filter( - (f) => f.id === facilityId + (f) => f.id === localSelectedFacilityId )?.[0]; const facilityStats = await queryGetFacilityStats({ fetchPolicy: "no-cache", - variables: { facilityId }, + variables: { facilityId: localSelectedFacilityId }, }).then((response) => response.data?.facilityStats); updateLocalState((prevState) => ({ - orgId: prevState.orgId, - facilityId: facilityId, + ...prevState, + selectedFacilityId: localSelectedFacilityId, facility: { city: selectedFacility?.city || "", state: selectedFacility?.state || "", @@ -141,7 +161,8 @@ const ManageFacility = () => { } function handleClearFilter() { - updateLocalState(initialState); + orgSelectionRef.current?.clearSelection(); + facilitySelectionRef.current?.clearSelection(); } /** @@ -149,15 +170,17 @@ const ManageFacility = () => { */ const [deleteFacilityMutation] = useDeleteFacilityMutation(); function handleDeleteFacility() { - deleteFacilityMutation({ - variables: { facilityId: localState.facilityId }, - }).then(() => { - showSuccess( - "", - `Facility ${localState.facility?.name} successfully deleted` - ); - handleClearFilter(); - }); + if (localState.facilityId) { + deleteFacilityMutation({ + variables: { facilityId: localState.facilityId }, + }).then(() => { + showSuccess( + "", + `Facility ${localState.facility?.name} successfully deleted` + ); + handleClearFilter(); + }); + } } /** @@ -171,6 +194,8 @@ const ManageFacility = () => { onClearFilter={handleClearFilter} onSelectOrg={handleSelectOrganization} onSearch={handleSearch} + facilityRef={facilitySelectionRef} + orgRef={orgSelectionRef} facilityOptions={facilitiesOptions} organizationOptions={orgOptions} manageFacilityState={localState}