Skip to content

Commit

Permalink
part two with actual features
Browse files Browse the repository at this point in the history
  • Loading branch information
fzhao99 committed Nov 6, 2024
1 parent 32f5a4e commit 31c32dd
Show file tree
Hide file tree
Showing 6 changed files with 387 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import {
CategoryNameToConditionDetailsMap,
filterSearchByCategoryAndCondition,
} from "../utils";
import styles from "./buildfromTemplate.module.scss";
import ConditionOption from "./ConditionOption";
import classNames from "classnames";

type ConditionColumnDisplayProps = {
fetchedConditions: CategoryNameToConditionDetailsMap;
searchFilter: string | undefined;
setFetchedConditions: Dispatch<
SetStateAction<CategoryNameToConditionDetailsMap | undefined>
>;
};
/**
* Column display component for the query building page
* @param root0 - params
* @param root0.fetchedConditions - conditions queried from backend to display
* @param root0.searchFilter - filter grabbed from search field to filter fetched
* components against
* @param root0.setFetchedConditions
* @returns Conditions split out into two columns that will filter themselves
* at both the category and condition levels if a valid search filter is applied.
*/
export const ConditionColumnDisplay: React.FC<ConditionColumnDisplayProps> = ({
fetchedConditions,
searchFilter,
setFetchedConditions,
}) => {
const [conditionsToDisplay, setConditionsToDisplay] =
useState(fetchedConditions);

useEffect(() => {
if (searchFilter === "") {
setConditionsToDisplay(fetchedConditions);
}
if (searchFilter) {
const filteredDisplay = filterSearchByCategoryAndCondition(
searchFilter,
fetchedConditions,
);
setConditionsToDisplay(filteredDisplay);
}
}, [searchFilter]);

function toggleFetchedConditionSelection(
category: string,
conditionId: string,
) {
const prevFetch = structuredClone(fetchedConditions);
const prevValues = prevFetch[category][conditionId];
prevFetch[category][conditionId] = {
name: prevValues.name,
include: !prevValues.include,
};
setFetchedConditions(prevFetch);
}

const columnOneEntries = Object.entries(conditionsToDisplay).filter(
(_, i) => i % 2 === 0,
);
const columnTwoEntries = Object.entries(conditionsToDisplay).filter(
(_, i) => i % 2 === 1,
);

const colsToDisplay = [
columnOneEntries,
columnTwoEntries,
// alphabetize by category
].map((arr) => arr.sort((a, b) => (a[0] > b[0] ? 1 : -1)));

return (
<div className="grid-container ">
<div className="grid-row grid-gap">
{colsToDisplay.map((colsToDisplay, i) => {
return (
<div
className={classNames(styles.displayCol, "grid-col")}
key={`col-${i}`}
>
{colsToDisplay.map(([category, arr]) => {
const handleConditionSelection = (conditionId: string) => {
toggleFetchedConditionSelection(category, conditionId);
};
return (
<div key={category}>
<h3 className={styles.categoryHeading}>{category}</h3>
{Object.entries(arr).map(
([conditionId, conditionNameAndInclude]) => {
return (
<ConditionOption
key={conditionId}
conditionId={conditionId}
conditionNameAndInclude={conditionNameAndInclude}
handleConditionSelection={handleConditionSelection}
/>
);
},
)}
</div>
);
})}
</div>
);
})}
</div>
</div>
);
};

export default ConditionColumnDisplay;
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Checkbox from "../../query/designSystem/checkbox/Checkbox";
import { ConditionDetails, formatDiseaseDisplay } from "../utils";

type ConditionOptionProps = {
conditionId: string;
conditionNameAndInclude: ConditionDetails;
handleConditionSelection: (conditionId: string) => void;
};

/**
* Display component for a condition on the query building page
* @param root0 - params
* @param root0.conditionIdToTemplateMap - the ID: Condition name map that needs to
* be displayed
* @param root0.conditionId
* @param root0.conditionNameAndInclude
* @param root0.handleConditionSelection
* @returns A component for display to redner on the query building page
*/
const ConditionOption: React.FC<ConditionOptionProps> = ({
conditionId,
conditionNameAndInclude,
handleConditionSelection,
}) => {
return (
<div className="margin-y-2">
<Checkbox
onClick={() => {
handleConditionSelection(conditionId);
}}
id={conditionId}
label={formatDiseaseDisplay(conditionNameAndInclude.name)}
/>
</div>
);
};

export default ConditionOption;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@use "../../../styles/variables" as *;

.queryTemplateContainer {
padding: 3.5rem 5rem;
border-radius: 4px;
}

.querySelectionForm {
background-color: #fff;
padding: 2rem;
}

.querySelectionFormSearch {
border: 1px solid #919191;
border-radius: 4px;
height: 1.5rem;
padding: 0.75rem;
}

.querySelectionFormHeader {
width: 50rem;
}

#conditionTemplateSearch:first-child {
flex: 1;
}

.categoryHeading {
text-transform: uppercase;
color: $gray-500;
font-weight: 700;
font-size: 1rem;
margin-bottom: 1rem;
}

.categoryHeading:not(first-of-type) {
margin-top: 2rem;
}

.displayCol:first-of-type {
border-right: 1px solid $base-lighter;
}

.displayCol:nth-of-type(2) {
padding-left: 2rem;
}
122 changes: 122 additions & 0 deletions query-connector/src/app/queryBuilding/buildFromTemplates/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"use client";

import Backlink from "@/app/query/components/backLink/Backlink";
import styles from "./buildfromTemplate.module.scss";
import { useRouter } from "next/navigation";
import { Button, Label, TextInput } from "@trussworks/react-uswds";
import { useEffect, useState } from "react";
import classNames from "classnames";
import { getConditionsData } from "@/app/database-service";
import {
CategoryNameToConditionDetailsMap,
mapFetchedDataToFrontendStructure,
} from "../utils";
import ConditionColumnDisplay from "./ConditionColumnDisplay";
import SearchField from "@/app/query/designSystem/searchField/SearchField";

/**
* The query building page
* @returns the component for the query building page
*/
export default function QueryTemplateSelection() {
const router = useRouter();
const [queryName, setQueryName] = useState<string>();
const [searchFilter, setSearchFilter] = useState<string>();
const [fetchedConditions, setFetchedConditions] =
useState<CategoryNameToConditionDetailsMap>();

useEffect(() => {
let isSubscribed = true;

async function fetchConditionsAndUpdateState() {
const { conditionCategoryToIdNameArrayMap } = await getConditionsData();

if (isSubscribed) {
setFetchedConditions(
mapFetchedDataToFrontendStructure(conditionCategoryToIdNameArrayMap),
);
}
}

fetchConditionsAndUpdateState().catch(console.error);

return () => {
isSubscribed = false;
};
}, []);

const noTemplateSelected =
fetchedConditions &&
Object.values(Object.values(fetchedConditions))
.map((arr) => Object.values(arr).flatMap((e) => e.include))
.flatMap((e) => e.some(Boolean))
.some(Boolean);

return (
<div className="main-container__wide">
<Backlink
onClick={() => {
router.push("/queryBuilding");
}}
label={"Back to My Queries"}
/>
<h1 className={styles.queryTitle}>Custom query</h1>
<Label htmlFor="queryNameInput" className="margin-top-0-important">
Query Name
</Label>
<TextInput
id="queryNameInput"
name="queryNameInput"
type="text"
className="maxw-mobile"
onChange={(event) => {
setQueryName(event.target.value);
}}
/>

<div
className={classNames(
"bg-gray-5 margin-top-4 ",
styles.queryTemplateContainer,
)}
>
<div
className={classNames(
styles.querySelectionFormHeader,
"display-flex flex-justify flex-align-center margin-bottom-3 ",
)}
>
<h2 className="">Select condition(s)</h2>
<Button
className="margin-0"
type={"button"}
disabled={!noTemplateSelected}
>
Create query
</Button>
</div>
<div className={classNames(styles.querySelectionForm, "radius-lg")}>
<SearchField
id="conditionTemplateSearch"
placeholder="Search conditions"
className={classNames(
"float-none maxw-mobile margin-x-auto margin-top-0 margin-bottom-2",
)}
onChange={(e) => {
e.preventDefault();
setSearchFilter(e.target.value);
}}
/>

{fetchedConditions && (
<ConditionColumnDisplay
fetchedConditions={fetchedConditions}
searchFilter={searchFilter}
setFetchedConditions={setFetchedConditions}
/>
)}
</div>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion query-connector/src/app/queryBuilding/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import styles from "./query.module.scss";
import styles from "./queryBuilding.module.scss";
import EmptyQueriesDisplay from "./emptyState/EmptyQueriesDisplay";
/**
* Component for Query Building Flow
Expand Down
Loading

0 comments on commit 31c32dd

Please sign in to comment.