Skip to content

Commit

Permalink
use DibbsValueSet instead of VsGrouping
Browse files Browse the repository at this point in the history
  • Loading branch information
katyasoup committed Jan 8, 2025
1 parent 5aa8526 commit 9ea0441
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 118 deletions.
109 changes: 50 additions & 59 deletions query-connector/src/app/query/components/CustomizeQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ import Accordion from "../designSystem/Accordion";
import CustomizeQueryNav from "./customizeQuery/CustomizeQueryNav";
import Backlink from "./backLink/Backlink";
import { RETURN_LABEL } from "./stepIndicator/StepIndicator";
import {
VsGrouping,
generateValueSetGroupingsByDibbsConceptType,
} from "@/app/utils/valueSetTranslation";
import { generateValueSetGroupingsByDibbsConceptType } from "@/app/utils/valueSetTranslation";

interface CustomizeQueryProps {
useCaseQueryResponse: UseCaseQueryResponse;
Expand Down Expand Up @@ -52,7 +49,7 @@ const CustomizeQuery: React.FC<CustomizeQueryProps> = ({

const [valueSetOptions, setValueSetOptions] = useState<{
[dibbsConceptType in DibbsConceptType]: {
[vsNameAuthorSystem: string]: VsGrouping;
[vsNameAuthorSystem: string]: DibbsValueSet;
};
}>({
labs: {},
Expand Down Expand Up @@ -89,84 +86,80 @@ const CustomizeQuery: React.FC<CustomizeQueryProps> = ({

// Handles the toggle of the 'include' state for individual concepts in
// the accordion
const toggleInclude = (
groupIndex: string,
valueSetIndex: number,
conceptIndex: number,
) => {
const updatedGroups = valueSetOptions[activeTab];
const updatedValueSets = [...updatedGroups[groupIndex].items]; // Clone the current group items
const updatedConceptsInIndexedValueSet = [
...updatedValueSets[valueSetIndex].concepts,
];
updatedConceptsInIndexedValueSet[conceptIndex] = {
...updatedConceptsInIndexedValueSet[conceptIndex],
include: !updatedConceptsInIndexedValueSet[conceptIndex].include, // Toggle the include for the clicked concept
const toggleInclude = (vsNameAuthorSystem: string, conceptIndex: number) => {
const updatedNameToVsMap = valueSetOptions[activeTab];
let updatedValueSet = updatedNameToVsMap[vsNameAuthorSystem];
const updatedConcepts = updatedValueSet.concepts;
updatedConcepts[conceptIndex] = {
...updatedConcepts[conceptIndex],
include: !updatedConcepts[conceptIndex].include, // Toggle the include for the clicked concept
};

updatedValueSets[valueSetIndex] = {
...updatedValueSets[valueSetIndex],
concepts: updatedConceptsInIndexedValueSet, // Update the concepts in the accessed value set
updatedValueSet = {
...updatedValueSet,
concepts: updatedConcepts, // Update the concepts in the accessed value set
};

updatedGroups[groupIndex] = {
...updatedGroups[groupIndex],
items: updatedValueSets, // Update the whole group's items
updatedNameToVsMap[vsNameAuthorSystem] = {
...updatedNameToVsMap[vsNameAuthorSystem],
...updatedValueSet, // Update the entire VS
};

setValueSetOptions((prevState) => ({
...prevState,
[activeTab]: updatedGroups, // Update the state with the new group
[activeTab]: updatedNameToVsMap, // Update the state with the modified VS
}));
};

// Allows all items to be selected within all accordion sections of the active tab
const handleSelectAllChange = (groupIndex: string, checked: boolean) => {
const updatedGroups = valueSetOptions[activeTab];

const handleSelectAllChange = (
vsNameAuthorSystem: string,
checked: boolean,
) => {
const updatedNameToVsMap = valueSetOptions[activeTab]; // a single group of lab/med/etc.
// Update only the group at the specified index
updatedGroups[groupIndex].items = updatedGroups[groupIndex].items.map(
(item) => ({
...item,
includeValueSet: checked, // Set all items in this group to checked or unchecked
concepts: item.concepts.map((ic) => {
return { ...ic, include: checked };
}),
}),
updatedNameToVsMap[vsNameAuthorSystem].includeValueSet = checked;
const updatedConcepts = updatedNameToVsMap[vsNameAuthorSystem].concepts.map(
(concept) => {
return { ...concept, include: checked };
},
);
updatedNameToVsMap[vsNameAuthorSystem].concepts = updatedConcepts;

setValueSetOptions((prevState) => ({
...prevState,
[activeTab]: updatedGroups, // Update the state for the current tab
[activeTab]: updatedNameToVsMap, // Update the state for the current tab
}));
};

// Allows all items to be selected within the entire active tab
const handleSelectAllForTab = (checked: boolean) => {
const activeItems = valueSetOptions[activeTab] ?? {};
const updatedGroups = Object.values(activeItems).map((group) => ({
...group,
items: group.items.map((item) => ({
...item,
const updatedValueSets = Object.values(activeItems).map((vs) => {
const updatedValueSetData = {
includeValueSet: checked, // Set all items in this group to checked or unchecked
concepts: item.concepts.map((ic) => {
return { ...ic, include: checked };
concepts: vs.concepts.map((concept) => {
return { ...concept, include: checked };
}),
})),
}));
};
return {
...vs,
...updatedValueSetData,
};
});

setValueSetOptions((prevState) => ({
...prevState,
[activeTab]: updatedGroups, // Update the state for the current tab
[activeTab]: updatedValueSets, // Update the state for the current tab
}));
};

// Persist the changes made on this page to the valueset state maintained
// by the entire query branch of the app
const handleApplyChanges = () => {
const selectedItems = Object.keys(valueSetOptions).reduce((acc, key) => {
const items = valueSetOptions[key as DibbsConceptType] ?? {};
acc = acc.concat(Object.values(items).flatMap((dict) => dict.items));
const nameToVs = valueSetOptions[key as DibbsConceptType] ?? {};
acc = acc.concat(Object.values(nameToVs));
return acc;
}, [] as DibbsValueSet[]);
setQueryValuesets(selectedItems);
Expand Down Expand Up @@ -202,24 +195,24 @@ const CustomizeQuery: React.FC<CustomizeQueryProps> = ({
handleSelectAllForTab={handleSelectAllForTab}
valueSetOptions={valueSetOptions}
/>
{valueSetOptionsToDisplay.map(([groupIndex, group]) => {
const id = group.author + ":" + group.system + ":" + group.valueSetName;
{valueSetOptionsToDisplay.map(([vsNameAuthorSystem, vs]) => {
const id = vs.author + ":" + vs.system + ":" + vs.valueSetName;
return (
<Accordion
key={id}
id={id}
title={
<CustomizeQueryAccordionHeader
handleSelectAllChange={handleSelectAllChange}
groupIndex={groupIndex}
group={group}
vsIndex={vsNameAuthorSystem}
valueSet={vs}
/>
}
content={
<CustomizeQueryAccordionBody
group={group}
valueSet={vs}
toggleInclude={toggleInclude}
groupIndex={groupIndex}
vsName={vsNameAuthorSystem}
/>
}
headingLevel="h3"
Expand Down Expand Up @@ -251,12 +244,10 @@ export const QUERY_CUSTOMIZATION_CONFIRMATION_BODY =
* @returns A count of the number of items in each of the DibbsConceptTypes
*/
const countDibbsConceptTypeToVsMapItems = (obj: {
[vsNameAuthorSystem: string]: VsGrouping;
[vsNameAuthorSystem: string]: DibbsValueSet;
}) => {
return Object.values(obj).reduce((runningSum, gvs) => {
gvs.items.forEach((vs) => {
runningSum += vs.concepts.length;
});
return Object.values(obj).reduce((runningSum, vs) => {
runningSum += vs.concepts.length;
return runningSum;
}, 0);
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import styles from "./customizeQuery.module.scss";
import Table from "../../designSystem/table/Table";
import { VsGrouping } from "@/app/utils/valueSetTranslation";
import { DibbsValueSet } from "@/app/constants";
import classNames from "classnames";
import Checkbox from "../../designSystem/checkbox/Checkbox";

type CustomizeQueryAccordionBodyProps = {
group: VsGrouping;
valueSet: DibbsValueSet;
toggleInclude: (
groupIndex: string,
valueSetIndex: number,
conceptIndex: number,
) => void;
groupIndex: string;
vsName: string;
};

type ValueSetIndexedConcept = {
Expand All @@ -24,16 +24,16 @@ type ValueSetIndexedConcept = {
/**
* Styling component to render the body table for the customize query components
* @param param0 - props for rendering
* @param param0.group - Matched concept associated with the query that
* @param param0.valueSet - Matched concept associated with the query that
* contains valuesets to filter query on
* @param param0.toggleInclude - Listener event to handle a concept inclusion/
* exclusion check
* @param param0.groupIndex - Index corresponding to group
* @param param0.vsName - Identifier for the value set
* @returns JSX Fragment for the accordion body
*/
const CustomizeQueryAccordionBody: React.FC<
CustomizeQueryAccordionBodyProps
> = ({ group, toggleInclude, groupIndex }) => {
> = ({ valueSet, toggleInclude, vsName }) => {
return (
<Table className={classNames(styles.customizeQueryGridContainer)}>
<thead>
Expand All @@ -44,17 +44,15 @@ const CustomizeQueryAccordionBody: React.FC<
</tr>
</thead>
<tbody className="display-flex flex-column">
{group.items
{valueSet.concepts
.reduce((acc, vs, vsIndex) => {
vs.concepts.forEach((c) => {
acc.push({ ...c, vsIndex: vsIndex });
});
acc.push({ ...vs, vsIndex: vsIndex });
return acc;
}, [] as ValueSetIndexedConcept[])
.map((item, conceptIndex) => (
<tr
onClick={() => {
toggleInclude(groupIndex, item.vsIndex, conceptIndex);
toggleInclude(vsName, item.vsIndex, conceptIndex);
}}
className={classNames(
"tableRowWithHover_clickable",
Expand All @@ -68,7 +66,7 @@ const CustomizeQueryAccordionBody: React.FC<
id={item.code}
checked={item.include}
onChange={() => {
toggleInclude(groupIndex, item.vsIndex, conceptIndex);
toggleInclude(vsName, item.vsIndex, conceptIndex);
}}
/>
</td>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,56 @@
import { VsGrouping } from "@/app/utils/valueSetTranslation";
import { DibbsValueSet } from "@/app/constants";
import styles from "./customizeQuery.module.scss";
import Checkbox from "../../designSystem/checkbox/Checkbox";

type CustomizeQueryAccordionProps = {
handleSelectAllChange: (groupIndex: string, checked: boolean) => void;
groupIndex: string;
group: VsGrouping;
vsIndex: string;
valueSet: DibbsValueSet;
};

/**
* Rendering component for customize query header
* @param param0 - props for rendering
* @param param0.handleSelectAllChange
* Listner function to include all valuesets when checkbox is selected
* @param param0.groupIndex - index corresponding to group
* @param param0.group - matched concept containing all rendered valuesets
* @param param0.vsIndex - index corresponding to group
* @param param0.valueSet - matched concept containing all rendered valuesets
* @returns A component that renders the customization query body
*/
const CustomizeQueryAccordionHeader: React.FC<CustomizeQueryAccordionProps> = ({
handleSelectAllChange,
groupIndex,
group,
vsIndex,
valueSet,
}) => {
const selectedTotal = group.items.reduce((sum, vs) => {
sum += vs.concepts.length;
return sum;
}, 0);
const selectedCount = group.items.reduce((sum, vs) => {
const includedConcepts = vs.concepts.filter((c) => c.include);
sum += includedConcepts.length;
return sum;
}, 0);
const selectedTotal = valueSet.concepts.length;
const selectedCount = valueSet.concepts.filter(
(concept) => concept.include,
).length;
const isMinusState = selectedCount !== selectedTotal && selectedCount !== 0;

return (
<div
className={`${styles.accordionHeader} display-flex flex-no-wrap flex-align-start customize-query-header`}
>
<Checkbox
id={group.valueSetName}
id={valueSet.valueSetName}
checked={selectedCount === selectedTotal}
isMinusState={isMinusState}
onChange={() => {
handleSelectAllChange(
groupIndex,
vsIndex,
isMinusState ? false : selectedCount !== selectedTotal,
);
}}
className={styles.checkboxCell}
/>
<div className={`${styles.accordionButtonTitle}`}>
{`${group.valueSetName}`}
{`${valueSet.valueSetName}`}

<span className={`${styles.accordionSubtitle} margin-top-2`}>
<strong>Author:</strong> {group.author}{" "}
<strong style={{ marginLeft: "20px" }}>System:</strong> {group.system}
<strong>Author:</strong> {valueSet.author}{" "}
<strong style={{ marginLeft: "20px" }}>System:</strong>{" "}
{valueSet.system}
</span>
</div>
<span className="margin-left-auto">{`${selectedCount} of ${selectedTotal} selected`}</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { DibbsConceptType } from "@/app/constants";
import styles from "./customizeQuery.module.scss";
import CustomizeQueryBulkSelect from "./CustomizeQueryBulkSelect";
import { ConceptTypeToVsNameToVsGroupingMap } from "@/app/utils/valueSetTranslation";
import { temp__ConceptTypeToVsNameToVsGroupingMap } from "@/app/utils/valueSetTranslation";
import { Button } from "@trussworks/react-uswds";

type CustomizeQueryNavProps = {
activeTab: DibbsConceptType;
handleTabChange: (tabName: DibbsConceptType) => void;
handleSelectAllForTab: (checked: boolean) => void;
valueSetOptions: ConceptTypeToVsNameToVsGroupingMap;
valueSetOptions: temp__ConceptTypeToVsNameToVsGroupingMap;
};

/**
Expand All @@ -29,19 +29,13 @@ const CustomizeQueryNav: React.FC<CustomizeQueryNavProps> = ({
}) => {
const activeItems = valueSetOptions[activeTab] ?? {};

const hasSelectableItems = Object.values(activeItems).some(
(group) => group.items.length > 0,
);
const hasSelectableItems = Object.values(activeItems).some((vs) => !!vs);
const allItemsDeselected = Object.values(activeItems)
.flatMap((groupedValSets) =>
groupedValSets.items.flatMap((i) => i.includeValueSet),
)
.flatMap((vs) => vs.includeValueSet)
.every((p) => !p);

const allItemsSelected = Object.values(activeItems)
.flatMap((groupedValSets) =>
groupedValSets.items.flatMap((i) => i.includeValueSet),
)
.flatMap((vs) => vs.includeValueSet)
.every((p) => p);

return (
Expand Down
Loading

0 comments on commit 9ea0441

Please sign in to comment.