From 8b54ef922e124eebeadfc881d7eeb5492b48eb7c Mon Sep 17 00:00:00 2001 From: Bob Zhao Date: Tue, 15 Oct 2024 11:49:02 -0400 Subject: [PATCH] add loading state to results view --- containers/tefca-viewer/next-env.d.ts | 2 +- containers/tefca-viewer/src/app/constants.ts | 19 ++++ .../app/query/components/CustomizeQuery.tsx | 11 ++- .../src/app/query/components/ResultsView.tsx | 4 +- .../src/app/query/components/SelectQuery.tsx | 95 +++++++++++-------- .../selectQuery/SelectSavedQuery.tsx | 6 +- .../components/selectQuery/queryHooks.ts | 45 +++++---- .../tefca-viewer/src/app/query/page.tsx | 5 +- 8 files changed, 115 insertions(+), 72 deletions(-) diff --git a/containers/tefca-viewer/next-env.d.ts b/containers/tefca-viewer/next-env.d.ts index 4f11a03dc..40c3d6809 100644 --- a/containers/tefca-viewer/next-env.d.ts +++ b/containers/tefca-viewer/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/containers/tefca-viewer/src/app/constants.ts b/containers/tefca-viewer/src/app/constants.ts index a9a1a1395..81eaedfcd 100644 --- a/containers/tefca-viewer/src/app/constants.ts +++ b/containers/tefca-viewer/src/app/constants.ts @@ -37,11 +37,30 @@ export const demoQueryOptions = [ { value: "syphilis", label: "Syphilis case investigation" }, ]; +type DemoQueryOptionValue = (typeof demoQueryLabels)[number]; +export const demoQueryValToLabelMap = demoQueryOptions.reduce( + (acc, curVal) => { + acc[curVal.value as DemoQueryOptionValue] = curVal.label; + return acc; + }, + {} as Record, +); /* * Map between the queryType property used to define a demo use case's options, * and the name of that query for purposes of searching the DB. */ const demoQueryLabels = demoQueryOptions.map((dqo) => dqo.label); +export const QueryValueToQueryName: { + [key in DemoQueryOptionValue]: string; +} = { + "Gather social determinants of health": "Social Determinants of Health", + "Newborn screening follow-up": "Newborn Screening", + "Syphilis case investigation": "Congenital syphilis (disorder)", + "Gonorrhea case investigation": "Gonorrhea (disorder)", + "Chlamydia case investigation": "Chlamydia trachomatis infection (disorder)", + "Cancer case investigation": "Cancer (Leukemia)", +}; + export const QueryTypeToQueryName: { [key in (typeof demoQueryLabels)[number]]: string; } = { diff --git a/containers/tefca-viewer/src/app/query/components/CustomizeQuery.tsx b/containers/tefca-viewer/src/app/query/components/CustomizeQuery.tsx index 4302fe766..a8a6f4770 100644 --- a/containers/tefca-viewer/src/app/query/components/CustomizeQuery.tsx +++ b/containers/tefca-viewer/src/app/query/components/CustomizeQuery.tsx @@ -2,7 +2,12 @@ import React, { useState, useEffect } from "react"; import { Button } from "@trussworks/react-uswds"; -import { ValueSetType, ValueSetItem } from "../../constants"; +import { + ValueSetType, + ValueSetItem, + USE_CASES, + demoQueryValToLabelMap, +} from "../../constants"; import { UseCaseQueryResponse } from "@/app/query-service"; import LoadingView from "./LoadingView"; import { showRedirectConfirmation } from "../designSystem/redirectToast/RedirectToast"; @@ -16,7 +21,7 @@ import Backlink from "./backLink/Backlink"; interface CustomizeQueryProps { useCaseQueryResponse: UseCaseQueryResponse; - queryType: string; + queryType: USE_CASES; queryValuesets: ValueSetItem[]; setQueryValuesets: (queryVS: ValueSetItem[]) => void; goBack: () => void; @@ -161,7 +166,7 @@ const CustomizeQuery: React.FC = ({ Customize query
- Query: {queryType} + Query: {demoQueryValToLabelMap[queryType]}
{countLabs} labs found, {countMedications} medications found,{" "} diff --git a/containers/tefca-viewer/src/app/query/components/ResultsView.tsx b/containers/tefca-viewer/src/app/query/components/ResultsView.tsx index e06aacb05..ac1debfc6 100644 --- a/containers/tefca-viewer/src/app/query/components/ResultsView.tsx +++ b/containers/tefca-viewer/src/app/query/components/ResultsView.tsx @@ -12,7 +12,7 @@ import EncounterTable from "./resultsView/tableComponents/EncounterTable"; import MedicationRequestTable from "./resultsView/tableComponents/MedicationRequestTable"; import ObservationTable from "./resultsView/tableComponents/ObservationTable"; import Backlink from "./backLink/Backlink"; -import { USE_CASES } from "@/app/constants"; +import { USE_CASES, UseCaseToQueryName } from "@/app/constants"; type ResultsViewProps = { useCaseQueryResponse: UseCaseQueryResponse; @@ -80,7 +80,7 @@ const ResultsView: React.FC = ({

Query:{" "} - {selectedQuery} + {UseCaseToQueryName[selectedQuery]}

diff --git a/containers/tefca-viewer/src/app/query/components/SelectQuery.tsx b/containers/tefca-viewer/src/app/query/components/SelectQuery.tsx index 90e27a896..71e932a30 100644 --- a/containers/tefca-viewer/src/app/query/components/SelectQuery.tsx +++ b/containers/tefca-viewer/src/app/query/components/SelectQuery.tsx @@ -10,9 +10,10 @@ import { fetchQueryResponse, fetchUseCaseValueSets, } from "./selectQuery/queryHooks"; +import LoadingView from "./LoadingView"; interface SelectQueryProps { - onSubmit: () => void; // Callback when the user submits the query + goForward: () => void; goBack: () => void; selectedQuery: USE_CASES; setSelectedQuery: React.Dispatch>; @@ -21,6 +22,7 @@ interface SelectQueryProps { setResultsQueryResponse: React.Dispatch>; fhirServer: FHIR_SERVERS; setFhirServer: React.Dispatch>; + setLoading: (isLoading: boolean) => void; } /** @@ -38,71 +40,80 @@ interface SelectQueryProps { * @returns - The selectQuery component. */ const SelectQuery: React.FC = ({ - onSubmit, - goBack, selectedQuery, - setSelectedQuery, patientForQuery, resultsQueryResponse, - setResultsQueryResponse, fhirServer, + goForward, + goBack, + setSelectedQuery, + setResultsQueryResponse, setFhirServer, }) => { const [showCustomizeQuery, setShowCustomizedQuery] = useState(false); const [queryValueSets, setQueryValueSets] = useState( [] as ValueSetItem[], ); - useEffect(() => { - // Gate whether we actually update state after fetching so we - // avoid name-change race conditions - let isSubscribed = true; + const [loadingQueryValueSets, setLoadingQueryValueSets] = + useState(false); - fetchUseCaseValueSets(selectedQuery, setQueryValueSets, isSubscribed).catch( - console.error, - ); - - // Destructor hook to prevent future state updates - return () => { - isSubscribed = false; - }; - }, [selectedQuery, setQueryValueSets]); + const [loadingResultResponse, setLoadingResultResponse] = + useState(false); useEffect(() => { + // Gate whether we actually update state after fetching so we + // avoid name-change race conditions let isSubscribed = true; - fetchQueryResponse( - patientForQuery, + fetchUseCaseValueSets( selectedQuery, + setQueryValueSets, isSubscribed, - queryValueSets, - setResultsQueryResponse, - fhirServer, + setLoadingQueryValueSets, ).catch(console.error); // Destructor hook to prevent future state updates return () => { isSubscribed = false; }; - }, [patientForQuery, selectedQuery, queryValueSets, setResultsQueryResponse]); + }, [selectedQuery, setQueryValueSets]); + + async function onSubmit() { + await fetchQueryResponse({ + patientForQuery: patientForQuery, + selectedQuery: selectedQuery, + queryValueSets: queryValueSets, + fhirServer: fhirServer, + queryResponseStateCallback: setResultsQueryResponse, + setIsLoading: setLoadingResultResponse, + }).catch(console.error); + // goForward(); + } - return showCustomizeQuery ? ( - setShowCustomizedQuery(false)} - > - ) : ( - + return ( + <> + {showCustomizeQuery ? ( + setShowCustomizedQuery(false)} + > + ) : ( + + )} + {loadingResultResponse && } + ); }; diff --git a/containers/tefca-viewer/src/app/query/components/selectQuery/SelectSavedQuery.tsx b/containers/tefca-viewer/src/app/query/components/selectQuery/SelectSavedQuery.tsx index 24fa48506..7b20ee14d 100644 --- a/containers/tefca-viewer/src/app/query/components/selectQuery/SelectSavedQuery.tsx +++ b/containers/tefca-viewer/src/app/query/components/selectQuery/SelectSavedQuery.tsx @@ -18,6 +18,7 @@ type SelectSavedQueryProps = { handleSubmit: () => void; fhirServer: FHIR_SERVERS; setFhirServer: React.Dispatch>; + loadingQueryValueSets: boolean; }; /** @@ -35,12 +36,13 @@ type SelectSavedQueryProps = { * @returns SelectedSavedQuery component */ const SelectSavedQuery: React.FC = ({ - goBack, selectedQuery, + fhirServer, + loadingQueryValueSets, + goBack, setSelectedQuery, setShowCustomizedQuery, handleSubmit, - fhirServer, setFhirServer, }) => { const [showAdvanced, setShowAdvanced] = useState(false); diff --git a/containers/tefca-viewer/src/app/query/components/selectQuery/queryHooks.ts b/containers/tefca-viewer/src/app/query/components/selectQuery/queryHooks.ts index 29a1a4f3d..760ab6224 100644 --- a/containers/tefca-viewer/src/app/query/components/selectQuery/queryHooks.ts +++ b/containers/tefca-viewer/src/app/query/components/selectQuery/queryHooks.ts @@ -23,9 +23,12 @@ export async function fetchUseCaseValueSets( selectedQuery: USE_CASES, valueSetStateCallback: SetStateCallback, isSubscribed: boolean, + setLoadingQuery: (isLoading: boolean) => void, ) { if (selectedQuery) { const queryName = UseCaseToQueryName[selectedQuery as USE_CASES]; + + setLoadingQuery(true); const queryResults = await getSavedQueryByName(queryName); const vsItems = await mapQueryRowsToValueSetItems(queryResults); @@ -33,6 +36,7 @@ export async function fetchUseCaseValueSets( if (isSubscribed) { valueSetStateCallback(vsItems); } + setLoadingQuery(false); } } @@ -40,49 +44,50 @@ export async function fetchUseCaseValueSets( * Query to apply for future view * @param patientForQuery - patient to do query against * @param selectedQuery - query use case - * @param isSubscribed - state destructor hook to prevent race conditions * @param queryValueSets - valuesets to filter query from default usecase * @param queryResponseStateCallback - callback function to update state of the * query response * @param fhirServer - fhir server to do the querying against */ -export async function fetchQueryResponse( - patientForQuery: Patient | undefined, - selectedQuery: USE_CASES, - isSubscribed: boolean, - queryValueSets: ValueSetItem[], - queryResponseStateCallback: SetStateCallback, - fhirServer: FHIR_SERVERS, -) { - if (patientForQuery && selectedQuery && isSubscribed) { +export async function fetchQueryResponse(p: { + patientForQuery: Patient | undefined; + selectedQuery: USE_CASES; + queryValueSets: ValueSetItem[]; + fhirServer: FHIR_SERVERS; + queryResponseStateCallback: SetStateCallback; + setIsLoading: (isLoading: boolean) => void; +}) { + if (p.patientForQuery && p.selectedQuery) { const patientFirstName = - getNthElementIfDefined(patientForQuery.name, -1)?.given?.join(" ") ?? + getNthElementIfDefined(p.patientForQuery.name, -1)?.given?.join(" ") ?? "Hyper"; const patientLastName = - getNthElementIfDefined(patientForQuery.name, -1)?.family ?? "Unlucky"; + getNthElementIfDefined(p.patientForQuery.name, -1)?.family ?? "Unlucky"; const patientMRN = - getNthElementIfDefined(patientForQuery.identifier)?.value ?? + getNthElementIfDefined(p.patientForQuery.identifier)?.value ?? HYPER_UNLUCKY_MRN; const newRequest = { first_name: patientFirstName as string, last_name: patientLastName as string, - dob: patientForQuery.birthDate as string, + dob: p.patientForQuery.birthDate as string, mrn: patientMRN, - fhir_server: fhirServer, - use_case: selectedQuery, + fhir_server: p.fhirServer, + use_case: p.selectedQuery, }; + p.setIsLoading(true); const queryResponse = await UseCaseQuery( newRequest, - queryValueSets.filter((item) => item.include), + p.queryValueSets.filter((item) => item.include), { - Patient: [patientForQuery], + Patient: [p.patientForQuery], }, ); - - queryResponseStateCallback(queryResponse); + console.log(queryResponse); + p.queryResponseStateCallback(queryResponse); + p.setIsLoading(false); } } diff --git a/containers/tefca-viewer/src/app/query/page.tsx b/containers/tefca-viewer/src/app/query/page.tsx index 5844109e2..148870da3 100644 --- a/containers/tefca-viewer/src/app/query/page.tsx +++ b/containers/tefca-viewer/src/app/query/page.tsx @@ -62,7 +62,7 @@ const Query: React.FC = () => { {mode === "select-query" && ( setMode("patient-results")} - onSubmit={() => setMode("results")} + goForward={() => setMode("results")} selectedQuery={useCase} setSelectedQuery={setUseCase} patientForQuery={patientForQuery} @@ -70,6 +70,7 @@ const Query: React.FC = () => { setResultsQueryResponse={setResultsQueryResponse} fhirServer={fhirServer} setFhirServer={setFhirServer} + setLoading={setLoading} /> )} @@ -89,7 +90,7 @@ const Query: React.FC = () => { )} )} - + {loading && }