From 2e4a9c063fd7db028d452d0e747d7e896f8d978b Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Thu, 8 Jun 2023 22:53:18 +0530 Subject: [PATCH 1/8] CareUI: Adds `UserAutocompleteFormField` and used it in Assigned To field of Shifting Filter --- src/Common/hooks/useAsyncOptions.ts | 6 ++- .../Common/UserAutocompleteFormField.tsx | 46 +++++++++++++++++++ src/Components/Shifting/ListFilter.tsx | 28 ++++------- src/Components/Users/models.tsx | 4 +- 4 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 src/Components/Common/UserAutocompleteFormField.tsx diff --git a/src/Common/hooks/useAsyncOptions.ts b/src/Common/hooks/useAsyncOptions.ts index 7ed5121e2a..f0a1c89543 100644 --- a/src/Common/hooks/useAsyncOptions.ts +++ b/src/Common/hooks/useAsyncOptions.ts @@ -4,6 +4,7 @@ import { useDispatch } from "react-redux"; interface IUseAsyncOptionsArgs { debounceInterval?: number; + queryResponseExtractor?: (data: any) => any; } /** @@ -40,7 +41,10 @@ export function useAsyncOptions>( debounce(async (action: any) => { setIsLoading(true); const res = await dispatch(action); - if (res?.data) setQueryOptions(res.data as T[]); + if (res?.data) + setQueryOptions( + args?.queryResponseExtractor?.(res.data) ?? (res.data as T[]) + ); setIsLoading(false); }, args?.debounceInterval ?? 300), [dispatch, args?.debounceInterval] diff --git a/src/Components/Common/UserAutocompleteFormField.tsx b/src/Components/Common/UserAutocompleteFormField.tsx new file mode 100644 index 0000000000..ba2e2cd19e --- /dev/null +++ b/src/Components/Common/UserAutocompleteFormField.tsx @@ -0,0 +1,46 @@ +import { useAsyncOptions } from "../../Common/hooks/useAsyncOptions"; +import { getUserList } from "../../Redux/actions"; +import { Autocomplete } from "../Form/FormFields/Autocomplete"; +import FormField from "../Form/FormFields/FormField"; +import { + FormFieldBaseProps, + useFormFieldPropsResolver, +} from "../Form/FormFields/Utils"; +import { UserModel } from "../Users/models"; + +type Props = FormFieldBaseProps & { + placeholder?: string; +}; + +export default function UserAutocompleteFormField(props: Props) { + const field = useFormFieldPropsResolver(props as any); + const { fetchOptions, isLoading, options } = useAsyncOptions( + "id", + { queryResponseExtractor: (data) => data.results } + ); + + return ( + + `${option.user_type}`} + optionValue={(option) => option} + onQuery={(query) => + fetchOptions(getUserList({ limit: 5, offset: 0, search_text: query })) + } + isLoading={isLoading} + /> + + ); +} + +const getUserFullName = (user: UserModel) => { + const personName = user.first_name + " " + user.last_name; + return personName.trim().length > 0 ? personName : user.username || ""; +}; diff --git a/src/Components/Shifting/ListFilter.tsx b/src/Components/Shifting/ListFilter.tsx index 099926f78e..cef9f31b93 100644 --- a/src/Components/Shifting/ListFilter.tsx +++ b/src/Components/Shifting/ListFilter.tsx @@ -18,7 +18,6 @@ import { FieldLabel } from "../Form/FormFields/FormField"; import FiltersSlideover from "../../CAREUI/interactive/FiltersSlideover"; import { LegacySelectField } from "../Common/HelperInputFields"; import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; -import { UserSelect } from "../Common/UserSelect2"; import moment from "moment"; import { navigate } from "raviger"; import parsePhoneNumberFromString from "libphonenumber-js"; @@ -26,6 +25,7 @@ import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import useMergeState from "../../Common/hooks/useMergeState"; import { useTranslation } from "react-i18next"; +import UserAutocompleteFormField from "../Common/UserAutocompleteFormField"; const clearFilterState = { orgin_facility: "", @@ -57,7 +57,6 @@ export default function ListFilter(props: any) { const [isOriginLoading, setOriginLoading] = useState(false); const [isShiftingLoading, setShiftingLoading] = useState(false); const [isAssignedLoading, setAssignedLoading] = useState(false); - const [isAssignedUserLoading, setAssignedUserLoading] = useState(false); const { t } = useTranslation(); const shiftStatusOptions = ( @@ -143,16 +142,13 @@ export default function ListFilter(props: any) { useEffect(() => { async function fetchData() { if (filter.assigned_to) { - setAssignedUserLoading(true); const res = await dispatch(getUserList({ id: filter.assigned_to })); - if (res && res.data && res.data.count) { setFilterState({ ...filterState, assigned_user_ref: res.data.results[0], }); } - setAssignedUserLoading(false); } } fetchData(); @@ -345,21 +341,13 @@ export default function ListFilter(props: any) { -
- {t("assigned_to")} - {isAssignedUserLoading ? ( - - ) : ( - setAssignedUser(obj)} - className="shifting-page-filter-dropdown" - errors={""} - /> - )} -
+ setAssignedUser(value)} + errorClassName="hidden" + />
{t("ordering")} diff --git a/src/Components/Users/models.tsx b/src/Components/Users/models.tsx index fd5f24c273..6f26ec8cc9 100644 --- a/src/Components/Users/models.tsx +++ b/src/Components/Users/models.tsx @@ -2,7 +2,7 @@ interface HomeFacilityObjectModel { id?: string; name?: string; } -export interface UserModel { +export type UserModel = { id?: number; username?: string; first_name?: string; @@ -23,7 +23,7 @@ export interface UserModel { doctor_qualification?: string; doctor_experience_commenced_on?: string; doctor_medical_council_registration?: string; -} +}; export interface SkillObjectModel { id: string; From 142f5ca24d58436c759ad4195f6df8d8a311a860 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Thu, 8 Jun 2023 22:59:55 +0530 Subject: [PATCH 2/8] delete unused `UserSelect2` --- src/Components/Common/UserSelect2.tsx | 109 -------------------------- 1 file changed, 109 deletions(-) delete mode 100644 src/Components/Common/UserSelect2.tsx diff --git a/src/Components/Common/UserSelect2.tsx b/src/Components/Common/UserSelect2.tsx deleted file mode 100644 index 612c02871c..0000000000 --- a/src/Components/Common/UserSelect2.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React, { useCallback, useState } from "react"; -import { useDispatch } from "react-redux"; -import { getUserList } from "../../Redux/actions"; -import { LegacyAutoCompleteAsyncField } from "../Common/HelperInputFields"; -import { UserModel } from "../Users/models"; -import { debounce } from "lodash"; -interface UserSelectProps { - name?: string | ""; - margin?: string; - errors: string; - className?: string; - multiple?: boolean; - selected: UserModel | UserModel[] | null; - setSelected: (selected: UserModel | UserModel[] | null) => void; -} - -export const UserSelect = (props: UserSelectProps) => { - const { - name, - multiple, - selected, - setSelected, - margin, - errors, - className = "", - } = props; - const dispatchAction: any = useDispatch(); - const [userLoading, isUserLoading] = useState(false); - const [hasSearchText, setHasSearchText] = useState(false); - const [UserList, setUserList] = useState>([]); - - const getPersonName = (user: any) => { - const personName = user.first_name + " " + user.last_name; - - return personName.trim().length > 0 ? personName : user.username; - }; - - const handleValueChange = (current: UserModel | UserModel[] | null) => { - if (!current) { - setUserList([]); - isUserLoading(false); - setHasSearchText(false); - } - setSelected(current); - }; - - const handelSearch = (e: any) => { - isUserLoading(true); - setHasSearchText(!!e.target.value); - onUserSearch(e.target.value); - }; - - const onUserSearch = useCallback( - debounce(async (text: string) => { - if (text) { - const params = { - limit: 50, - offset: 0, - search_text: text, - }; - - const res = await dispatchAction(getUserList(params)); - - if (res && res.data) { - setUserList(res.data.results); - } - isUserLoading(false); - } else { - setUserList([]); - isUserLoading(false); - } - }, 300), - [] - ); - - return ( - handleValueChange(selected)} - loading={userLoading} - placeholder="Search by name or username" - noOptionsText={ - hasSearchText - ? "No user found, please try again" - : "Start typing to begin search" - } - renderOption={(option: any) => ( -
- - {getPersonName(option)} - ({option.user_type}) - -
- )} - getOptionSelected={(option: any, value: any) => option.id === value.id} - getOptionLabel={(option: any) => - `${getPersonName(option)} - (${option.user_type})` - } - filterOptions={(options: UserModel[]) => options} - errors={errors} - className={className} - /> - ); -}; From 686c71ccc4371c4239a86c6efc693dbbaa823038 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 13 Jun 2023 10:07:35 +0530 Subject: [PATCH 3/8] fix cypress --- cypress/e2e/shifting_spec/filter.cy.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/shifting_spec/filter.cy.ts b/cypress/e2e/shifting_spec/filter.cy.ts index 2429648946..f90a731fbc 100644 --- a/cypress/e2e/shifting_spec/filter.cy.ts +++ b/cypress/e2e/shifting_spec/filter.cy.ts @@ -32,8 +32,11 @@ describe("Shifting section filter", () => { it("filter by assigned to user", () => { cy.intercept(/\/api\/v1\/users/).as("users_filter"); - cy.get("[name='assigned_to']").type("cypress").wait("@users_filter"); - cy.get("[name='assigned_to']").type("{downarrow}{enter}"); + cy.get("[id='assigned-to']") + .wait(100) + .type("cypress") + .wait("@users_filter"); + cy.get("[id='assigned-to']").wait(100).type("{downarrow}{enter}"); cy.contains("Apply").click(); }); From 22a76f5c36b4d939e777a3198ebe76399d3edbbe Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 13 Jun 2023 12:23:53 +0530 Subject: [PATCH 4/8] fix cypress --- cypress/e2e/shifting_spec/filter.cy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/shifting_spec/filter.cy.ts b/cypress/e2e/shifting_spec/filter.cy.ts index f90a731fbc..8bb4148b52 100644 --- a/cypress/e2e/shifting_spec/filter.cy.ts +++ b/cypress/e2e/shifting_spec/filter.cy.ts @@ -32,11 +32,11 @@ describe("Shifting section filter", () => { it("filter by assigned to user", () => { cy.intercept(/\/api\/v1\/users/).as("users_filter"); - cy.get("[id='assigned-to']") + cy.get("[name='assigned_to']") .wait(100) .type("cypress") .wait("@users_filter"); - cy.get("[id='assigned-to']").wait(100).type("{downarrow}{enter}"); + cy.get("[name='assigned_to']").wait(100).type("{downarrow}{enter}"); cy.contains("Apply").click(); }); From c0d70272b02410e2a378acb0b51485b4d9c651c6 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 13 Jun 2023 12:33:06 +0530 Subject: [PATCH 5/8] fix cypress --- cypress/e2e/shifting_spec/filter.cy.ts | 2 +- src/Components/Shifting/ListFilter.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/shifting_spec/filter.cy.ts b/cypress/e2e/shifting_spec/filter.cy.ts index 8bb4148b52..bcfa12100b 100644 --- a/cypress/e2e/shifting_spec/filter.cy.ts +++ b/cypress/e2e/shifting_spec/filter.cy.ts @@ -36,7 +36,7 @@ describe("Shifting section filter", () => { .wait(100) .type("cypress") .wait("@users_filter"); - cy.get("[name='assigned_to']").wait(100).type("{downarrow}{enter}"); + cy.get("[id='assigned_to']").wait(100).type("{downarrow}{enter}"); cy.contains("Apply").click(); }); diff --git a/src/Components/Shifting/ListFilter.tsx b/src/Components/Shifting/ListFilter.tsx index cef9f31b93..b225d1316e 100644 --- a/src/Components/Shifting/ListFilter.tsx +++ b/src/Components/Shifting/ListFilter.tsx @@ -344,6 +344,7 @@ export default function ListFilter(props: any) { setAssignedUser(value)} errorClassName="hidden" From 2b96390095bc2f1d4a75cad4c24e427c6abce65b Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 13 Jun 2023 12:34:32 +0530 Subject: [PATCH 6/8] fix cypress --- cypress/e2e/shifting_spec/filter.cy.ts | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/cypress/e2e/shifting_spec/filter.cy.ts b/cypress/e2e/shifting_spec/filter.cy.ts index bcfa12100b..18b35e322e 100644 --- a/cypress/e2e/shifting_spec/filter.cy.ts +++ b/cypress/e2e/shifting_spec/filter.cy.ts @@ -12,27 +12,27 @@ describe("Shifting section filter", () => { cy.get("button").should("contain", "Filters").contains("Filters").click(); }); - it("filter by origin facility", () => { - cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); - cy.get("[name='orgin_facility']") - .type("Dummy Facility 1") - .wait("@facilities_filter"); - cy.get("[role='option']").first().click(); - cy.contains("Apply").click(); - }); + // it("filter by origin facility", () => { + // cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); + // cy.get("[name='orgin_facility']") + // .type("Dummy Facility 1") + // .wait("@facilities_filter"); + // cy.get("[role='option']").first().click(); + // cy.contains("Apply").click(); + // }); - it("filter by assigned facility", () => { - cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); - cy.get("[name='assigned_facility']") - .type("Dummy Shifting Center") - .wait("@facilities_filter"); - cy.get("[role='option']").first().click(); - cy.contains("Apply").click(); - }); + // it("filter by assigned facility", () => { + // cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); + // cy.get("[name='assigned_facility']") + // .type("Dummy Shifting Center") + // .wait("@facilities_filter"); + // cy.get("[role='option']").first().click(); + // cy.contains("Apply").click(); + // }); it("filter by assigned to user", () => { cy.intercept(/\/api\/v1\/users/).as("users_filter"); - cy.get("[name='assigned_to']") + cy.get("[id='assigned_to']") .wait(100) .type("cypress") .wait("@users_filter"); From 9e77b8b796c5f31e9f5373a80f7e0d408fb97745 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 13 Jun 2023 12:36:30 +0530 Subject: [PATCH 7/8] oops uncomment it --- cypress/e2e/shifting_spec/filter.cy.ts | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/cypress/e2e/shifting_spec/filter.cy.ts b/cypress/e2e/shifting_spec/filter.cy.ts index 18b35e322e..3e755db5c6 100644 --- a/cypress/e2e/shifting_spec/filter.cy.ts +++ b/cypress/e2e/shifting_spec/filter.cy.ts @@ -12,23 +12,23 @@ describe("Shifting section filter", () => { cy.get("button").should("contain", "Filters").contains("Filters").click(); }); - // it("filter by origin facility", () => { - // cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); - // cy.get("[name='orgin_facility']") - // .type("Dummy Facility 1") - // .wait("@facilities_filter"); - // cy.get("[role='option']").first().click(); - // cy.contains("Apply").click(); - // }); + it("filter by origin facility", () => { + cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); + cy.get("[name='orgin_facility']") + .type("Dummy Facility 1") + .wait("@facilities_filter"); + cy.get("[role='option']").first().click(); + cy.contains("Apply").click(); + }); - // it("filter by assigned facility", () => { - // cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); - // cy.get("[name='assigned_facility']") - // .type("Dummy Shifting Center") - // .wait("@facilities_filter"); - // cy.get("[role='option']").first().click(); - // cy.contains("Apply").click(); - // }); + it("filter by assigned facility", () => { + cy.intercept(/\/api\/v1\/getallfacilities/).as("facilities_filter"); + cy.get("[name='assigned_facility']") + .type("Dummy Shifting Center") + .wait("@facilities_filter"); + cy.get("[role='option']").first().click(); + cy.contains("Apply").click(); + }); it("filter by assigned to user", () => { cy.intercept(/\/api\/v1\/users/).as("users_filter"); From f9b03870fe407bcc9324f43d145414cc0ebe079a Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 13 Jun 2023 15:13:53 +0530 Subject: [PATCH 8/8] Update src/Components/Shifting/ListFilter.tsx --- src/Components/Shifting/ListFilter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Shifting/ListFilter.tsx b/src/Components/Shifting/ListFilter.tsx index b225d1316e..ed6baa7d32 100644 --- a/src/Components/Shifting/ListFilter.tsx +++ b/src/Components/Shifting/ListFilter.tsx @@ -350,7 +350,7 @@ export default function ListFilter(props: any) { errorClassName="hidden" /> -
+
{t("ordering")}