Skip to content

Commit

Permalink
Merge pull request #36 from PatrickWaweru/KHP3-5428-ProcedureParticip…
Browse files Browse the repository at this point in the history
…antsShouldBeSearchable

Khp3 5428 procedure participants should be searchable
  • Loading branch information
PatrickWaweru authored Apr 17, 2024
2 parents 5e7a101 + 960c538 commit 9766552
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 27 deletions.
14 changes: 14 additions & 0 deletions src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ export const configSchema = {
_description: "The concept UUID for capturing procedure complications",
_default: "120198AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
},
procedureParticipantsGroupingConceptUuid: {
_type: Type.ConceptUuid,
_description: "The concept UUID for grouping procedure participants obs",
_default: "120202AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
},
procedureParticipantsConceptUuid: {
_type: Type.ConceptUuid,
_description: "The concept UUID for capturing procedure participants",
_default: "120198AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
},
};

export interface OrderReason {
Expand All @@ -58,4 +68,8 @@ export interface ConfigObject {
labOrderableConcepts: Array<string>;
};
conditionConceptClassUuid: string;
procedureComplicationGroupingConceptUuid: string;
procedureComplicationConceptUuid: string;
procedureParticipantsGroupingConceptUuid: string;
procedureParticipantsConceptUuid: string;
}
120 changes: 94 additions & 26 deletions src/form/post-procedures/post-procedure-form.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ import { zodResolver } from "@hookform/resolvers/zod";
import {
savePostProcedure,
useConditionsSearch,
useProviders,
useProvidersSearch,
} from "./post-procedure.resource";
import { CodedCondition, ProcedurePayload } from "../../types";
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";

const validationSchema = z.object({
startDatetime: z.date({ required_error: "Start datetime is required" }),
Expand Down Expand Up @@ -67,21 +68,32 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
}) => {
const { sessionLocation } = useSession();
const { t } = useTranslation();
const { providers } = useProviders();

const [providerSearchTerm, setProviderSearchTerm] = useState("");
const debouncedProviderSearchTerm = useDebounce(providerSearchTerm);
const { providerSearchResults, isProviderSearching } = useProvidersSearch(
debouncedProviderSearchTerm
);
const [selectedProvider, setSelectedProvider] = useState<CodedProvider>(null);
const handleProviderSearchTermChange = (
event: React.ChangeEvent<HTMLInputElement>
) => setProviderSearchTerm(event.target.value);

const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm);
const { searchResults, isSearching } =
useConditionsSearch(debouncedSearchTerm);
const [selectedCondition, setSelectedCondition] =
useState<CodedCondition>(null);

const handleSearchTermChange = (event: React.ChangeEvent<HTMLInputElement>) =>
setSearchTerm(event.target.value);

const {
procedureComplicationGroupingConceptUuid,
procedureComplicationConceptUuid,
} = useConfig();
procedureParticipantsGroupingConceptUuid,

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

View workflow job for this annotation

GitHub Actions / build

'procedureParticipantsGroupingConceptUuid' is assigned a value but never used
procedureParticipantsConceptUuid,

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

View workflow job for this annotation

GitHub Actions / build

'procedureParticipantsConceptUuid' is assigned a value but never used
} = useConfig<ConfigObject>();

const {
control,
Expand All @@ -92,6 +104,13 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
resolver: zodResolver(validationSchema),
});

const handleProviderChange = useCallback(
(selectedProvider: CodedProvider) => {
setSelectedProvider(selectedProvider);
},
[]
);

const handleConditionChange = useCallback(
(selectedCondition: CodedCondition) => {
setSelectedCondition(selectedCondition);
Expand All @@ -101,13 +120,13 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({

const onSubmit = async (data: PostProcedureFormSchema) => {
const participants = [];
data.participants.forEach((p) => {
if (selectedProvider) {
const provider = {
provider: p.uuid,
provider: selectedProvider.concept.uuid,
encounterRole: "a0b03050-c99b-11e0-9572-0800200c9a66",
};
participants.push(provider);
});
}
const complications = [];
if (selectedCondition) {
complications.push({
Expand Down Expand Up @@ -274,24 +293,73 @@ const PostProcedureForm: React.FC<PostProcedureFormProps> = ({
<FormLabel className={styles.formLabel}>
{t("participants", "Participants")}
</FormLabel>
<Controller
control={control}
name="participants"
render={({ field: { onChange } }) => (
<MultiSelect
id="participants"
titleText={t("participants", "Participants")}
label={t("selectParticipants", "Select participants")}
items={providers}
onChange={({ selectedItems }) => onChange(selectedItems)}
itemToString={(item) => (item ? item.display : "")}
selectionFeedback="top-after-reopen"
placeholder={t("selectParticipants", "Select participants")}
invalid={!!errors.participants}
invalidText={errors.participants?.message}
/>
)}
/>
<div>
<Controller
name="participants"
control={control}
render={({ field: { onChange, value } }) => (
<Search
autoFocus
size="md"
id="conditionsSearch"
labelText={t("enterParticipants", "Enter participants")}
placeholder={t("searchParticipants", "Search participants")}
onChange={(e) => {
onChange(e);
handleProviderSearchTermChange(e);
}}
onClear={() => {
setProviderSearchTerm("");
setSelectedProvider(null);
}}
value={(() => {
if (selectedProvider) {
return selectedProvider.display;
}
if (debouncedProviderSearchTerm) {
return value;
}
})()}
/>
)}
/>
{(() => {
if (!debouncedProviderSearchTerm || selectedProvider) return null;
if (isProviderSearching)
return (
<InlineLoading
className={styles.loader}
description={t("searching", "Searching") + "..."}
/>
);
if (providerSearchResults && providerSearchResults.length) {
return (
<ul className={styles.conditionsList}>
{providerSearchResults?.map((searchResult) => (
<li
role="menuitem"
className={styles.condition}
key={searchResult?.concept?.uuid}
onClick={() => handleProviderChange(searchResult)}
>
{searchResult.display}
</li>
))}
</ul>
);
}
return (
<Layer>
<Tile className={styles.emptyResults}>
<span>
{t("noResultsFor", "No results for")}{" "}
<strong>"{debouncedProviderSearchTerm}"</strong>
</span>
</Tile>
</Layer>
);
})()}
</div>
</Layer>
<Layer>
<FormLabel className={styles.formLabel}>
Expand Down
16 changes: 15 additions & 1 deletion src/form/post-procedures/post-procedure.resource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
restBaseUrl,
useConfig,
} from "@openmrs/esm-framework";
import { CodedCondition, ProcedurePayload } from "../../types";
import { CodedProvider, CodedCondition, ProcedurePayload } from "../../types";

type Provider = {
uuid: string;
Expand Down Expand Up @@ -52,3 +52,17 @@ export function useConditionsSearch(conditionToLookup: string) {
isSearching: isLoading,
};
}

export function useProvidersSearch(providerToLookup: string) {
const providerSearchUrl = `${restBaseUrl}/provider?v=custom:(uuid,display,person:(uuid,display))&q=${providerToLookup}`;
const { data, error, isLoading } = useSWR<
{ data: { results: Array<CodedProvider> } },
Error
>(providerToLookup ? providerSearchUrl : null, openmrsFetch);

return {
providerSearchResults: data?.data?.results ?? [],
error: error,
isProviderSearching: isLoading,
};
}
12 changes: 12 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,18 @@ export type CodedCondition = {
display: string;
};

export type CodedProvider = {
concept: {
uuid: string;
display: string;
};
conceptName: {
uuid: string;
display: string;
};
display: string;
};

export type ProcedurePayload = {
patient: string;
procedureOrder: string;
Expand Down

0 comments on commit 9766552

Please sign in to comment.