Skip to content

Commit

Permalink
Merge pull request #37 from gabriel090/complication_search_v2
Browse files Browse the repository at this point in the history
Complications should be searchable and allow multi select
  • Loading branch information
PatrickWaweru authored Apr 17, 2024
2 parents 9766552 + f896404 commit a2230a1
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 74 deletions.
7 changes: 7 additions & 0 deletions src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,10 @@ export interface ConfigObject {
procedureParticipantsGroupingConceptUuid: string;
procedureParticipantsConceptUuid: string;
}

export const StringPath =
"M24 9.4L22.6 8 16 14.6 9.4 8 8 9.4 14.6 16 8 22.6 9.4 24 16 17.4 22.6 24 24 22.6 17.4 16 24 9.4z";

export const encounterRole = "a0b03050-c99b-11e0-9572-0800200c9a66";

export const encounterType = "d1059fb9-a079-4feb-a749-eedd709ae542";
172 changes: 98 additions & 74 deletions src/form/post-procedures/post-procedure-form.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import {
Stack,
ComboBox,
TextArea,
MultiSelect,
Layer,
FormLabel,
ButtonSet,
Button,
Search,
InlineLoading,
Tile,
Tag,
} from "@carbon/react";
import { useTranslation } from "react-i18next";
import styles from "./post-procedure-form.scss";
Expand All @@ -34,7 +34,12 @@ import { CodedProvider, CodedCondition, ProcedurePayload } from "../../types";
import { Result } from "../../work-list/work-list.resource";
import dayjs from "dayjs";
import { closeOverlay } from "../../components/overlay/hook";
import { type ConfigObject } from "../../config-schema";
import {
type ConfigObject,
StringPath,
encounterRole,
encounterType,
} from "../../config-schema";

const validationSchema = z.object({
startDatetime: z.date({ required_error: "Start datetime is required" }),
Expand Down Expand Up @@ -85,8 +90,24 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
useConditionsSearch(debouncedSearchTerm);
const [selectedCondition, setSelectedCondition] =
useState<CodedCondition>(null);
const handleSearchTermChange = (event: React.ChangeEvent<HTMLInputElement>) =>
setSearchTerm(event.target.value);

const handleSearchInputChange = (event) => {
const value = event.target.value;
setSearchTerm(value);
if (!value) {
setSelectedCondition(null);
setShowItems(false);
} else {
setShowItems(true);
}
};

const [showItems, setShowItems] = useState(false);
const [selectedItems, setSelectedItems] = useState([]);

const handleSelect = useCallback((item: CodedCondition) => {
setSelectedCondition(item);
}, []);

const {
procedureComplicationGroupingConceptUuid,
Expand All @@ -111,19 +132,12 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
[]
);

const handleConditionChange = useCallback(
(selectedCondition: CodedCondition) => {
setSelectedCondition(selectedCondition);
},
[]
);

const onSubmit = async (data: PostProcedureFormSchema) => {
const participants = [];
if (selectedProvider) {
const provider = {
provider: selectedProvider.concept.uuid,
encounterRole: "a0b03050-c99b-11e0-9572-0800200c9a66",
encounterRole: encounterRole,
};
participants.push(provider);
}
Expand Down Expand Up @@ -156,7 +170,7 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
{
encounterDatetime: new Date(),
patient: patientUuid,
encounterType: "d1059fb9-a079-4feb-a749-eedd709ae542",
encounterType: encounterType,
encounterProviders: participants,
obs: complications,
},
Expand Down Expand Up @@ -366,71 +380,78 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
{t("complications", "Complications")}
</FormLabel>
<div>
<Controller
name="complications"
control={control}
render={({ field: { onChange, value } }) => (
<Search
autoFocus
size="md"
id="conditionsSearch"
labelText={t("enterCondition", "Enter condition")}
placeholder={t("searchConditions", "Search conditions")}
onChange={(e) => {
onChange(e);
handleSearchTermChange(e);
}}
onClear={() => {
setSearchTerm("");
setSelectedCondition(null);
}}
value={(() => {
if (selectedCondition) {
return selectedCondition.display;
}
if (debouncedSearchTerm) {
return value;
}
})()}
/>
)}
/>
{(() => {
if (!debouncedSearchTerm || selectedCondition) return null;
if (isSearching)
return (
<InlineLoading
className={styles.loader}
description={t("searching", "Searching") + "..."}
/>
);
if (searchResults && searchResults.length) {
return (
<ul className={styles.conditionsList}>
{searchResults?.map((searchResult) => (
<li
role="menuitem"
className={styles.condition}
key={searchResult?.concept?.uuid}
onClick={() => handleConditionChange(searchResult)}
{selectedItems?.map(
(item) =>
(
<>
<Tag
style={{ display: "inline-flex", alignItems: "center" }}
>
<span style={{ marginRight: "8px" }}>{item.display}</span>
<svg
focusable="false"
fill="currentColor"
width="16"
height="16"
viewBox="0 0 32 32"
aria-hidden="true"
onClick={() =>
setSelectedItems((prevItems) =>
prevItems.filter((i) => i !== item)
)
}
>
{searchResult.display}
</li>
))}
</ul>
);
}
return (
<Layer>
<Tile className={styles.emptyResults}>
<span>
{t("noResultsFor", "No results for")}{" "}
<strong>"{debouncedSearchTerm}"</strong>
<path d={StringPath}></path>
</svg>
</Tag>
</>
) ?? "-"
)}
</div>
<div>
<Search
autoFocus
size="md"
id="conditionsSearch"
placeholder={t("complications", "complications")}
labelText={t("enterCondition", "Enter condition")}
onChange={handleSearchInputChange}
onClear={() => setSearchTerm("")}
/>
{searchResults?.length === 0 ? (
<div className={styles.filterEmptyState}>
<Layer level={0}>
<Tile className={styles.filterEmptyStateTile}>
<span className={styles.filterEmptyStateContent}>
<strong>{debouncedSearchTerm}</strong>
</span>
</Tile>
</Layer>
);
})()}
</div>
) : (
showItems && (
<ul className={styles.complicationsList}>
{searchResults.map((item) => (
<li
key={item?.concept?.uuid}
role="menuitem"
tabIndex={0}
className={styles.complicationService}
onClick={() => {
handleSelect(item);
setSelectedItems((prevItems) => [...prevItems, item]);
setShowItems(false);
}}
>
{item.display}
</li>
))}
</ul>
)
)}
{isSearching && (
<InlineLoading description="Loading complications..." />
)}
</div>
</Layer>
</Stack>
Expand All @@ -447,3 +468,6 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
};

export default PostProcedureForm;
function setValue(arg0: string, arg1: CodedCondition[]) {

Check warning on line 471 in src/form/post-procedures/post-procedure-form.component.tsx

View workflow job for this annotation

GitHub Actions / build

'setValue' is defined but never used

Check warning on line 471 in src/form/post-procedures/post-procedure-form.component.tsx

View workflow job for this annotation

GitHub Actions / build

'arg0' is defined but never used

Check warning on line 471 in src/form/post-procedures/post-procedure-form.component.tsx

View workflow job for this annotation

GitHub Actions / build

'arg1' is defined but never used
throw new Error("Function not implemented.");
}
17 changes: 17 additions & 0 deletions src/form/post-procedures/post-procedure-form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,21 @@
.required {
color: colors.$red-60;
margin-left: 0.125rem;
}


.complicationService {
padding: 1rem 0.75rem;
}


.complicationsList {
background-color: $ui-02;
max-height: 14rem;
overflow-y: auto;
border: 1px solid $ui-03;

li:hover {
background-color: $ui-03;
}
}

0 comments on commit a2230a1

Please sign in to comment.