diff --git a/src/Components/Common/ConfirmDialog.tsx b/src/Components/Common/ConfirmDialog.tsx index 915bafc7973..a6bc14e8d4f 100644 --- a/src/Components/Common/ConfirmDialog.tsx +++ b/src/Components/Common/ConfirmDialog.tsx @@ -27,7 +27,7 @@ const ConfirmDialog = ({ return ( {children} -
+
{action} diff --git a/src/Components/Common/Dialog.tsx b/src/Components/Common/Dialog.tsx index bfd4c87a3ea..ad60edd5a74 100644 --- a/src/Components/Common/Dialog.tsx +++ b/src/Components/Common/Dialog.tsx @@ -53,20 +53,16 @@ const DialogModal = (props: DialogProps) => { -
-

{title}

-

- {description} -

-
+

{title}

+

{description}

{props.titleAction}
{children} diff --git a/src/Components/Common/OnlineUsersSelect.tsx b/src/Components/Common/OnlineUsersSelect.tsx deleted file mode 100644 index bb5e55ef65a..00000000000 --- a/src/Components/Common/OnlineUsersSelect.tsx +++ /dev/null @@ -1,264 +0,0 @@ -import CircularProgress from "../Common/components/CircularProgress"; -import React, { useCallback, useState, useEffect } from "react"; -import { useDispatch } from "react-redux"; -import { statusType, useAbortableEffect } from "../../Common/utils"; -import moment from "moment"; -import { getUserList } from "../../Redux/actions"; -import { UserModel } from "../Users/models"; -import { classNames } from "../../Utils/utils"; -import CareIcon from "../../CAREUI/icons/CareIcon"; -import ButtonV2 from "./components/ButtonV2"; -import { FieldLabel } from "../Form/FormFields/FormField"; - -type UserFetchState = { - loading: boolean; - users: Array; - searchTerm: string; - searchFieldRef: React.RefObject; -}; - -type Props = { - selectedUser: UserModel | null; - userId: string; - onSelect: (user: UserModel | null) => void; - user_type: string; - outline?: boolean; -}; - -const initialState: UserFetchState = { - loading: false, - users: new Array(), - searchTerm: "", - searchFieldRef: React.createRef(), -}; - -/** - * This component consists temperory design hacks made to look identical to a - * form field during the consultation form redesign. - * - * However to make the design and functionallity consistent, this component is - * to be converted to use `AutocompleteFormField` along with `useAsyncOptions` - * hook and `prefixIcon` for the online state of the users. - */ -export const OnlineUsersSelect = (props: Props) => { - const dispatchAction: any = useDispatch(); - const { selectedUser, userId, onSelect, user_type, outline } = props; - const [state, setState] = useState(initialState); - const { loading, users, searchTerm, searchFieldRef } = state; - const [isDropdownExpanded, setDropdownExpand] = useState(false); - - const fetchUsers = useCallback( - async (status: statusType) => { - setState({ ...state, loading: true }); - const params = { - user_type: user_type, - ordering: "-last-login", - search_text: searchTerm, - }; - const res = await dispatchAction(getUserList(params)); - if (!status.aborted) { - if (res && res.data) { - setState({ ...state, loading: false, users: res.data.results }); - } - } - }, - [dispatchAction, searchTerm] - ); - - useAbortableEffect( - (status: statusType) => { - const debounce_timer = setTimeout(() => { - fetchUsers(status); - }, 1000); - return () => clearTimeout(debounce_timer); - }, - [searchTerm] - ); - - useEffect(() => { - if (isDropdownExpanded && searchFieldRef.current) { - searchFieldRef.current.focus(); - } - }, [isDropdownExpanded]); - - return ( -
-
- Assigned to -
-
- - - - {isDropdownExpanded && ( -
- {!loading ? ( - users.map((user: UserModel) => { - return ( - - ); - }) - ) : ( -
- -
- )} -
- )} -
- { - onSelect(null); - setDropdownExpand(false); - }} - > - - -
-
-
- ); -}; diff --git a/src/Components/Common/UserAutocompleteFormField.tsx b/src/Components/Common/UserAutocompleteFormField.tsx index ceb7d6a3045..51b2ec8622c 100644 --- a/src/Components/Common/UserAutocompleteFormField.tsx +++ b/src/Components/Common/UserAutocompleteFormField.tsx @@ -1,3 +1,4 @@ +import moment from "moment"; import { useAsyncOptions } from "../../Common/hooks/useAsyncOptions"; import { getFacilityUsers, getUserList } from "../../Redux/actions"; import { Autocomplete } from "../Form/FormFields/Autocomplete"; @@ -11,6 +12,8 @@ import { UserModel } from "../Users/models"; type Props = FormFieldBaseProps & { placeholder?: string; facilityId?: string; + userType?: string; + showActiveStatus?: boolean; }; export default function UserAutocompleteFormField(props: Props) { @@ -20,27 +23,64 @@ export default function UserAutocompleteFormField(props: Props) { { queryResponseExtractor: (data) => data.results } ); + let search_filter: { + limit: number; + offset: number; + user_type?: string; + search_text?: string; + } = { limit: 5, offset: 0 }; + + if (props.showActiveStatus && props.userType) { + search_filter = { ...search_filter, user_type: props.userType }; + } + + const getStatusIcon = (option: UserModel) => { + if (!props.showActiveStatus) return null; + + const isOnline = moment() + .subtract(5, "minutes") + .isBefore(option.last_login); + + return ( +
+ + + +
+ ); + }; + return ( - `${option.user_type}`} - optionValue={(option) => option} - onQuery={(query) => - fetchOptions( - props.facilityId - ? getFacilityUsers(props.facilityId) - : getUserList({ limit: 5, offset: 0, search_text: query }) - ) - } - isLoading={isLoading} - /> +
+ `${option.user_type}`} + optionValue={(option) => option} + onQuery={(query) => + fetchOptions( + props.facilityId + ? getFacilityUsers(props.facilityId) + : getUserList({ + ...search_filter, + search_text: query, + }) + ) + } + isLoading={isLoading} + /> +
); } diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index cf187561df1..c2eb2294354 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -21,7 +21,6 @@ import { import * as Notification from "../../Utils/Notifications.js"; import { FacilitySelect } from "../Common/FacilitySelect"; import { BedModel, FacilityModel, ICD11DiagnosisModel } from "./models"; -import { OnlineUsersSelect } from "../Common/OnlineUsersSelect"; import { UserModel } from "../Users/models"; import { BedSelect } from "../Common/BedSelect"; import Beds from "./Consultations/Beds"; @@ -48,6 +47,8 @@ import CareIcon from "../../CAREUI/icons/CareIcon"; import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField"; import { DraftSection, useAutoSaveReducer } from "../../Utils/AutoSave"; import { FormAction } from "../Form/Utils"; +import UserAutocompleteFormField from "../Common/UserAutocompleteFormField"; + const Loading = loadable(() => import("../Common/Loading")); const PageTitle = loadable(() => import("../Common/PageTitle")); @@ -1238,12 +1239,16 @@ export const ConsultationForm = (props: any) => { className="flex-[2] col-span-6" ref={fieldRef["assigned_to"]} > - + handleDoctorSelect(option.value) + } + userType={"Doctor"} + name={"assigned_to"} />
)} diff --git a/src/Components/Form/FormFields/Autocomplete.tsx b/src/Components/Form/FormFields/Autocomplete.tsx index 7622f59da42..303f13298d7 100644 --- a/src/Components/Form/FormFields/Autocomplete.tsx +++ b/src/Components/Form/FormFields/Autocomplete.tsx @@ -91,18 +91,17 @@ type AutocompleteProps = { export const Autocomplete = (props: AutocompleteProps) => { const [query, setQuery] = useState(""); // Ensure lower case useEffect(() => { - props.onQuery && props.onQuery(query); + props.onQuery?.(query); }, [query]); const mappedOptions = props.options.map((option) => { const label = props.optionLabel(option); - const description = - props.optionDescription && props.optionDescription(option); + const description = props.optionDescription?.(option); return { label, description, search: label.toLowerCase(), - icon: props.optionIcon && props.optionIcon(option), + icon: props.optionIcon?.(option), value: props.optionValue ? props.optionValue(option) : option, }; }); @@ -139,27 +138,27 @@ export const Autocomplete = (props: AutocompleteProps) => {
props.onChange(selection.value)} >
value?.label} + className="cui-input-base truncate pr-16" + placeholder={props.placeholder ?? "Select"} + displayValue={(value: any) => value?.label || ""} onChange={(event) => setQuery(event.target.value.toLowerCase())} autoComplete="off" /> -
+
{value?.icon} {props.isLoading ? ( @@ -167,11 +166,24 @@ export const Autocomplete = (props: AutocompleteProps) => { )}
+ {value && ( +
{ + e.preventDefault(); + if (!props.required) props.onChange(undefined); + }} + > + {!props.isLoading && ( + + )} +
+ )}
- + {filteredOptions.length === 0 && (
No options found diff --git a/src/Components/Patient/PatientHome.tsx b/src/Components/Patient/PatientHome.tsx index c0f12d7419e..2db425836e7 100644 --- a/src/Components/Patient/PatientHome.tsx +++ b/src/Components/Patient/PatientHome.tsx @@ -5,7 +5,6 @@ import { useDispatch, useSelector } from "react-redux"; import { GENDER_TYPES, SAMPLE_TEST_STATUS } from "../../Common/constants"; import loadable from "@loadable/component"; import { statusType, useAbortableEffect } from "../../Common/utils"; -import { OnlineUsersSelect } from "../Common/OnlineUsersSelect"; import { getConsultationList, listShiftRequests, @@ -31,7 +30,7 @@ import { useTranslation } from "react-i18next"; import CircularProgress from "../Common/components/CircularProgress"; import Page from "../Common/components/Page"; import ConfirmDialog from "../Common/ConfirmDialog"; -import { FieldErrorText } from "../Form/FormFields/FormField"; +import UserAutocompleteFormField from "../Common/UserAutocompleteFormField"; const Loading = loadable(() => import("../Common/Loading")); @@ -144,7 +143,7 @@ export const PatientHome = (props: any) => { }; const handleVolunteerSelect = (volunteer: any) => { - setAssignedVolunteerObject(volunteer); + setAssignedVolunteerObject(volunteer.value); }; const limit = 5; @@ -1423,19 +1422,20 @@ export const PatientHome = (props: any) => {
setOpenAssignVolunteerDialog(false)} description={ -
- + -
} action="Assign"