Skip to content

Commit

Permalink
add loading state to results view
Browse files Browse the repository at this point in the history
  • Loading branch information
fzhao99 committed Oct 15, 2024
1 parent ef8a654 commit 8b54ef9
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 72 deletions.
2 changes: 1 addition & 1 deletion containers/tefca-viewer/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// 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.
19 changes: 19 additions & 0 deletions containers/tefca-viewer/src/app/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<DemoQueryOptionValue, string>,
);
/*
* 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;
} = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;
Expand Down Expand Up @@ -161,7 +166,7 @@ const CustomizeQuery: React.FC<CustomizeQueryProps> = ({
Customize query
</h1>
<div className="font-sans-lg text-light padding-bottom-0 padding-top-05">
Query: {queryType}
Query: {demoQueryValToLabelMap[queryType]}
</div>
<div className="font-sans-sm text-light padding-bottom-0 padding-top-05">
{countLabs} labs found, {countMedications} medications found,{" "}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -80,7 +80,7 @@ const ResultsView: React.FC<ResultsViewProps> = ({
<h3>
Query:{" "}
<span className="text-normal display-inline-block">
{selectedQuery}
{UseCaseToQueryName[selectedQuery]}
</span>
</h3>
</div>
Expand Down
95 changes: 53 additions & 42 deletions containers/tefca-viewer/src/app/query/components/SelectQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<React.SetStateAction<USE_CASES>>;
Expand All @@ -21,6 +22,7 @@ interface SelectQueryProps {
setResultsQueryResponse: React.Dispatch<React.SetStateAction<QueryResponse>>;
fhirServer: FHIR_SERVERS;
setFhirServer: React.Dispatch<React.SetStateAction<FHIR_SERVERS>>;
setLoading: (isLoading: boolean) => void;
}

/**
Expand All @@ -38,71 +40,80 @@ interface SelectQueryProps {
* @returns - The selectQuery component.
*/
const SelectQuery: React.FC<SelectQueryProps> = ({
onSubmit,
goBack,
selectedQuery,
setSelectedQuery,
patientForQuery,
resultsQueryResponse,
setResultsQueryResponse,
fhirServer,
goForward,
goBack,
setSelectedQuery,
setResultsQueryResponse,
setFhirServer,
}) => {
const [showCustomizeQuery, setShowCustomizedQuery] = useState(false);
const [queryValueSets, setQueryValueSets] = useState<ValueSetItem[]>(
[] 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<boolean>(false);

fetchUseCaseValueSets(selectedQuery, setQueryValueSets, isSubscribed).catch(
console.error,
);

// Destructor hook to prevent future state updates
return () => {
isSubscribed = false;
};
}, [selectedQuery, setQueryValueSets]);
const [loadingResultResponse, setLoadingResultResponse] =
useState<boolean>(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 ? (
<CustomizeQuery
useCaseQueryResponse={resultsQueryResponse}
queryType={selectedQuery}
queryValuesets={queryValueSets}
setQueryValuesets={setQueryValueSets}
goBack={() => setShowCustomizedQuery(false)}
></CustomizeQuery>
) : (
<SelectSavedQuery
goBack={goBack}
selectedQuery={selectedQuery}
setSelectedQuery={setSelectedQuery}
setShowCustomizedQuery={setShowCustomizedQuery}
handleSubmit={onSubmit}
fhirServer={fhirServer}
setFhirServer={setFhirServer}
></SelectSavedQuery>
return (
<>
{showCustomizeQuery ? (
<CustomizeQuery
useCaseQueryResponse={resultsQueryResponse}
queryType={selectedQuery}
queryValuesets={queryValueSets}
setQueryValuesets={setQueryValueSets}
goBack={() => setShowCustomizedQuery(false)}
></CustomizeQuery>
) : (
<SelectSavedQuery
loadingQueryValueSets={loadingQueryValueSets}
goBack={goBack}
selectedQuery={selectedQuery}
setSelectedQuery={setSelectedQuery}
setShowCustomizedQuery={setShowCustomizedQuery}
handleSubmit={onSubmit}
fhirServer={fhirServer}
setFhirServer={setFhirServer}
></SelectSavedQuery>
)}
{loadingResultResponse && <LoadingView loading={loadingResultResponse} />}
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type SelectSavedQueryProps = {
handleSubmit: () => void;
fhirServer: FHIR_SERVERS;
setFhirServer: React.Dispatch<React.SetStateAction<FHIR_SERVERS>>;
loadingQueryValueSets: boolean;
};

/**
Expand All @@ -35,12 +36,13 @@ type SelectSavedQueryProps = {
* @returns SelectedSavedQuery component
*/
const SelectSavedQuery: React.FC<SelectSavedQueryProps> = ({
goBack,
selectedQuery,
fhirServer,
loadingQueryValueSets,
goBack,
setSelectedQuery,
setShowCustomizedQuery,
handleSubmit,
fhirServer,
setFhirServer,
}) => {
const [showAdvanced, setShowAdvanced] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,66 +23,71 @@ export async function fetchUseCaseValueSets(
selectedQuery: USE_CASES,
valueSetStateCallback: SetStateCallback<ValueSetItem[]>,
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);

// Only update if the fetch hasn't altered state yet
if (isSubscribed) {
valueSetStateCallback(vsItems);
}
setLoadingQuery(false);
}
}

/**
* 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<UseCaseQueryResponse>,
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<UseCaseQueryResponse>;
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);
}
}

Expand Down
5 changes: 3 additions & 2 deletions containers/tefca-viewer/src/app/query/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,15 @@ const Query: React.FC = () => {
{mode === "select-query" && (
<SelectQuery
goBack={() => setMode("patient-results")}
onSubmit={() => setMode("results")}
goForward={() => setMode("results")}
selectedQuery={useCase}
setSelectedQuery={setUseCase}
patientForQuery={patientForQuery}
resultsQueryResponse={resultsQueryResponse}
setResultsQueryResponse={setResultsQueryResponse}
fhirServer={fhirServer}
setFhirServer={setFhirServer}
setLoading={setLoading}
/>
)}

Expand All @@ -89,7 +90,7 @@ const Query: React.FC = () => {
)}
</>
)}
<LoadingView loading={loading} />
{loading && <LoadingView loading={loading} />}

<ToastContainer icon={false} />
</div>
Expand Down

0 comments on commit 8b54ef9

Please sign in to comment.