From ae8ac6fba08ee4ea0914fe528beef0a5f4c62c08 Mon Sep 17 00:00:00 2001 From: Noufal Rahim <120470585+noufalrahim@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:10:42 +0530 Subject: [PATCH 01/31] fix: fixed enter key issue (#9396) --- src/components/Form/Form.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/Form/Form.tsx b/src/components/Form/Form.tsx index 5a3bf552b26..18f190ccc3c 100644 --- a/src/components/Form/Form.tsx +++ b/src/components/Form/Form.tsx @@ -98,6 +98,11 @@ const Form = ({ return (
{ + if (e.key === "Enter") { + handleSubmit(e); + } + }} className={classNames( "mx-auto w-full", !props.noPadding && "px-8 py-5 md:px-16 md:py-11", From ed48ece8e1c243138e3d73056094e0905f861580 Mon Sep 17 00:00:00 2001 From: Aditya Jindal Date: Thu, 12 Dec 2024 21:50:05 +0530 Subject: [PATCH 02/31] Fix: Added location for linked facility (#9383) --- src/components/Users/LinkedFacilities.tsx | 61 +++++++++++++++-------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/src/components/Users/LinkedFacilities.tsx b/src/components/Users/LinkedFacilities.tsx index e582b81dec0..4c75c885ca2 100644 --- a/src/components/Users/LinkedFacilities.tsx +++ b/src/components/Users/LinkedFacilities.tsx @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, @@ -24,8 +25,6 @@ import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import ButtonV2 from "../Common/ButtonV2"; - const initModalProps: { selectedFacility?: FacilityModel; type: string; @@ -201,11 +200,22 @@ export default function LinkedFacilities({ return (
-
-
{facility.name}
+
+
+ {facility.name} + {facility.district_object?.name && ( +
+ {facility.district_object?.name} + {facility.district_object?.name && + facility.state_object?.name && + ", "} + {facility.state_object?.name} +
+ )} +
-
- +
+
@@ -244,12 +254,21 @@ export default function LinkedFacilities({ id={`facility_${homeFacility.id}`} key={`facility_${homeFacility.id}`} > -
-
+
+
{homeFacility.name} + {homeFacility.district_object?.name && ( +
+ {homeFacility.district_object?.name} + {homeFacility.district_object?.name && + homeFacility.state_object?.name && + ", "} + {homeFacility.state_object?.name} +
+ )}
{(authorizeForHomeFacility || isCurrentUser) && ( -
+
)} @@ -280,7 +299,7 @@ export default function LinkedFacilities({ /> )}
-
+
- linkFacility(userData.username, facility)} disabled={!authorizeForHomeFacility} - tooltip={ - !authorizeForHomeFacility - ? t("contact_your_admin_to_add_facilities") - : undefined - } > {t("add_facility")} - +
{homeFacility && (

{t("home_facility")}

-
+
{renderHomeFacilityButton(homeFacility)}
)} + {userFacilities && userFacilities.length > 0 && (

{t("linked_facilities")}

{userFacilities.map((facility: FacilityModel) => { if (homeFacility?.id === facility.id) { From ead041beb1f4cd2e5f7f51d4ee53d05a250b4ce5 Mon Sep 17 00:00:00 2001 From: Aditya Jindal Date: Thu, 12 Dec 2024 22:56:50 +0530 Subject: [PATCH 03/31] Fix: Allergy count to Updated to has allergies text (#9399) --- public/locale/en.json | 1 + src/components/Patient/PatientHome.tsx | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 4fb925ac941..4b262e61d10 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -794,6 +794,7 @@ "get_tests": "Get Tests", "goal": "Our goal is to continuously improve the quality and accessibility of public healthcare services using digital tools.", "granted_on": "Granted On", + "has_allergies": "Has Allergies", "has_domestic_healthcare_support": "Has domestic healthcare support?", "has_sari": "Has SARI (Severe Acute Respiratory illness)?", "health-profile": "Health Profile", diff --git a/src/components/Patient/PatientHome.tsx b/src/components/Patient/PatientHome.tsx index 48d754d6d26..7ae439fa80b 100644 --- a/src/components/Patient/PatientHome.tsx +++ b/src/components/Patient/PatientHome.tsx @@ -362,13 +362,14 @@ export const PatientHome = (props: { text={t("TELEMEDICINE")} /> )} - {patientData.allergies && ( - - )} + {patientData.allergies && + patientData.allergies.trim().length > 0 && ( + + )}
From 2611a322d9633631e2213d04274aa71ccb5c8965 Mon Sep 17 00:00:00 2001 From: Jacob John Jeevan <40040905+Jacobjeevan@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:11:57 +0530 Subject: [PATCH 04/31] User Creation Form Bug Fix (#9404) --- src/components/Users/UserAddEditForm.tsx | 2 +- src/components/Users/UserFormValidations.tsx | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Users/UserAddEditForm.tsx b/src/components/Users/UserAddEditForm.tsx index c0f75dbe850..00793ce8fff 100644 --- a/src/components/Users/UserAddEditForm.tsx +++ b/src/components/Users/UserAddEditForm.tsx @@ -1179,7 +1179,7 @@ const UserAddEditForm = (props: UserProps) => { )} )} - {includedFields?.includes("local_body") && ( + {showLocalbody && includedFields?.includes("local_body") && ( <> {isLocalbodyLoading ? ( diff --git a/src/components/Users/UserFormValidations.tsx b/src/components/Users/UserFormValidations.tsx index a5af4549803..c59d4a4bd5c 100644 --- a/src/components/Users/UserFormValidations.tsx +++ b/src/components/Users/UserFormValidations.tsx @@ -50,8 +50,6 @@ export const newUserFields: Array = [ "qualification", "doctor_experience_commenced_on", "doctor_medical_council_registration", - "weekly_working_hours", - "video_connect_link", ]; export const editUserFields: Array = [ From 05e8f4ca9d4ad8eb31167751ff1f411fabe43098 Mon Sep 17 00:00:00 2001 From: Amjith Titus Date: Fri, 13 Dec 2024 18:10:56 +0530 Subject: [PATCH 05/31] Util function for cleaner usage of TanStack useQuery (#9395) ---- Co-authored-by: rithviknishad --- src/App.tsx | 12 ++- src/Utils/request/README.md | 137 +++++++++++++++++++++--------- src/Utils/request/errorHandler.ts | 54 ++++++++++++ src/Utils/request/query.ts | 56 ++++++++++++ src/Utils/request/queryError.ts | 24 ++++++ src/Utils/request/request.ts | 2 +- src/Utils/request/types.ts | 8 ++ 7 files changed, 251 insertions(+), 42 deletions(-) create mode 100644 src/Utils/request/errorHandler.ts create mode 100644 src/Utils/request/query.ts create mode 100644 src/Utils/request/queryError.ts diff --git a/src/App.tsx b/src/App.tsx index c91849de559..b4d1a1570a9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,8 @@ -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { + QueryCache, + QueryClient, + QueryClientProvider, +} from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { Suspense } from "react"; @@ -12,17 +16,21 @@ import AuthUserProvider from "@/Providers/AuthUserProvider"; import HistoryAPIProvider from "@/Providers/HistoryAPIProvider"; import Routers from "@/Routers"; import { FeatureFlagsProvider } from "@/Utils/featureFlags"; +import { handleQueryError } from "@/Utils/request/errorHandler"; import { PubSubProvider } from "./Utils/pubsubContext"; const queryClient = new QueryClient({ defaultOptions: { queries: { - retry: 3, + retry: 2, refetchOnWindowFocus: false, staleTime: 5 * 60 * 1000, // 5 minutes }, }, + queryCache: new QueryCache({ + onError: handleQueryError, + }), }); const App = () => { diff --git a/src/Utils/request/README.md b/src/Utils/request/README.md index 0780d3149f6..3c1279e1554 100644 --- a/src/Utils/request/README.md +++ b/src/Utils/request/README.md @@ -4,41 +4,108 @@ CARE now uses TanStack Query (formerly React Query) as its data fetching solutio ## Using TanStack Query (Recommended for new code) -For new API integrations, we recommend using TanStack Query directly: +For new API integrations, we recommend using TanStack Query with `query` utility function. This is a wrapper around `fetch` that works seamlessly with TanStack Query. It handles response parsing, error handling, setting headers, and more. ```tsx import { useQuery } from "@tanstack/react-query"; -import request from "@/Utils/request/request"; -import FooRoutes from "@foo/routes"; +import query from "@/Utils/request/query"; -export default function FooDetails({ id }) { - const { data, isLoading, error } = useQuery({ - queryKey: [FooRoutes.getFoo.path, id], - queryFn: async () => { - const response = await request(FooRoutes.getFoo, { - pathParams: { id } - }); - return response.data; - } +export default function UserProfile() { + const { data, isLoading } = useQuery({ + queryKey: [routes.users.current.path], + queryFn: query(routes.users.current) }); if (isLoading) return ; - if (error) return ; + return
{data?.name}
; +} - return ( -
- {data.id} - {data.name} -
- ); +// With path parameters +function PatientDetails({ id }: { id: string }) { + const { data } = useQuery({ + queryKey: ['patient', id], + queryFn: query(routes.patient.get, { + pathParams: { id } + }) + }); + + return
{data?.name}
; +} + +// With query parameters +function SearchMedicines() { + const { data } = useQuery({ + queryKey: ['medicines', 'paracetamol'], + queryFn: query(routes.medicine.search, { + queryParams: { search: 'paracetamol' } + }) + }); + + return ; +} + +// When you need response status/error handling +function FacilityDetails({ id }: { id: string }) { + const { data, isLoading } = useQuery({ + queryKey: ["facility", id], + queryFn: query(routes.getFacility, { + pathParams: { id }, + silent: true + }) + }); + + if (isLoading) return ; + return
{data?.name}
; +} + +### query + +`query` is our wrapper around fetch that works seamlessly with TanStack Query. It: +- Handles response parsing (JSON, text, blobs). +- Constructs proper error objects. +- Sets the headers appropriately. +- Integrates with our global error handling. + +```typescript +interface QueryOptions { + pathParams?: Record; // URL parameters + queryParams?: Record; // Query string parameters + silent?: boolean; // Suppress error notifications } + +// Basic usage +useQuery({ + queryKey: ["users"], + queryFn: query(routes.users.list) +}); + +// With parameters +useQuery({ + queryKey: ["user", id], + queryFn: query(routes.users.get, { + pathParams: { id }, + queryParams: { include: "details" }, + silent: true // Optional: suppress error notifications + }) +}); ``` +### Error Handling + +All API errors are now handled globally. Common scenarios like: + +- Session expiry -> Redirects to /session-expired +- Bad requests (400/406) -> Shows error notification +are automatically handled. + +Use the `silent: true` option to suppress error notifications for specific queries. + ## Migration Guide & Reference ### Understanding the Transition Our codebase contains two patterns for data fetching: + 1. Legacy pattern using `useTanStackQueryInstead` (wrapper around TanStack Query) 2. Modern pattern using TanStack Query directly @@ -60,12 +127,9 @@ function LegacyComponent({ id }) { function ModernComponent({ id }) { const { data, isLoading, error, refetch } = useQuery({ queryKey: [UserRoutes.getUser.path, id], - queryFn: async () => { - const response = await request(UserRoutes.getUser, { - pathParams: { id } - }); - return response.data; - }, + queryFn: query(UserRoutes.getUser, { + pathParams: { id } + }), enabled: true, refetchOnWindowFocus: false }); @@ -100,7 +164,7 @@ useTanStackQueryInstead(route, { prefetch: shouldFetch }) // Modern useQuery({ queryKey: [route.path], - queryFn: async () => (await request(route)).data, + queryFn: query(route), enabled: shouldFetch }) ``` @@ -116,13 +180,10 @@ useTanStackQueryInstead(route, { // Modern useQuery({ queryKey: [route.path, id, filter], - queryFn: async () => { - const response = await request(route, { - pathParams: { id }, - query: { filter } - }); - return response.data; - } + queryFn: query(route, { + pathParams: { id }, + queryParams: { filter } + }) }) ``` @@ -135,12 +196,10 @@ if (res?.status === 403) handleForbidden(); // Modern useQuery({ queryKey: [route.path], - queryFn: async () => { - const response = await request(route); - if (response.res.status === 403) handleForbidden(); - return response.data; - }, - onError: (error) => handleError(error) + queryFn: query(route, { + silent: true // Optional: suppress error notifications + }) + // Error handling is now done globally }) ``` diff --git a/src/Utils/request/errorHandler.ts b/src/Utils/request/errorHandler.ts new file mode 100644 index 00000000000..68d7e4600bb --- /dev/null +++ b/src/Utils/request/errorHandler.ts @@ -0,0 +1,54 @@ +import { navigate } from "raviger"; + +import * as Notifications from "@/Utils/Notifications"; +import { QueryError } from "@/Utils/request/queryError"; + +export function handleQueryError(error: Error) { + if (error.name === "AbortError") { + return; + } + + if (!(error instanceof QueryError)) { + Notifications.Error({ msg: error.message || "Something went wrong!" }); + return; + } + + if (error.silent) { + return; + } + + const cause = error.cause; + + if (isSessionExpired(cause)) { + handleSessionExpired(); + return; + } + + if (isBadRequest(error)) { + Notifications.BadRequest({ errs: cause }); + return; + } + + Notifications.Error({ + msg: cause?.detail || "Something went wrong...!", + }); +} + +function isSessionExpired(error: QueryError["cause"]) { + return ( + // If Authorization header is not valid + error?.code === "token_not_valid" || + // If Authorization header is not provided + error?.detail === "Authentication credentials were not provided." + ); +} + +function handleSessionExpired() { + if (!location.pathname.startsWith("/session-expired")) { + navigate(`/session-expired?redirect=${window.location.href}`); + } +} + +function isBadRequest(error: QueryError) { + return error.status === 400 || error.status === 406; +} diff --git a/src/Utils/request/query.ts b/src/Utils/request/query.ts new file mode 100644 index 00000000000..3431f625728 --- /dev/null +++ b/src/Utils/request/query.ts @@ -0,0 +1,56 @@ +import careConfig from "@careConfig"; + +import { QueryError } from "@/Utils/request/queryError"; +import { getResponseBody } from "@/Utils/request/request"; +import { QueryOptions, Route } from "@/Utils/request/types"; +import { makeHeaders, makeUrl } from "@/Utils/request/utils"; + +async function queryRequest( + { path, method, noAuth }: Route, + options?: QueryOptions, +): Promise { + const url = `${careConfig.apiUrl}${makeUrl(path, options?.queryParams, options?.pathParams)}`; + + const fetchOptions: RequestInit = { + method, + headers: makeHeaders(noAuth ?? false), + signal: options?.signal, + }; + + if (options?.body) { + fetchOptions.body = JSON.stringify(options.body); + } + + let res: Response; + + try { + res = await fetch(url, fetchOptions); + } catch { + throw new Error("Network Error"); + } + + const data = await getResponseBody(res); + + if (!res.ok) { + throw new QueryError({ + message: "Request Failed", + status: res.status, + silent: options?.silent ?? false, + cause: data as unknown as Record, + }); + } + + return data; +} + +/** + * Creates a TanStack Query compatible request function + */ +export default function query( + route: Route, + options?: QueryOptions, +) { + return ({ signal }: { signal: AbortSignal }) => { + return queryRequest(route, { ...options, signal }); + }; +} diff --git a/src/Utils/request/queryError.ts b/src/Utils/request/queryError.ts new file mode 100644 index 00000000000..cdfad312ef4 --- /dev/null +++ b/src/Utils/request/queryError.ts @@ -0,0 +1,24 @@ +type QueryErrorCause = Record | undefined; + +export class QueryError extends Error { + status: number; + silent: boolean; + cause?: QueryErrorCause; + + constructor({ + message, + status, + silent, + cause, + }: { + message: string; + status: number; + silent: boolean; + cause?: Record; + }) { + super(message, { cause }); + this.status = status; + this.silent = silent; + this.cause = cause; + } +} diff --git a/src/Utils/request/request.ts b/src/Utils/request/request.ts index 73bc9763f50..bd1cabc523c 100644 --- a/src/Utils/request/request.ts +++ b/src/Utils/request/request.ts @@ -61,7 +61,7 @@ export default async function request( return result; } -async function getResponseBody(res: Response): Promise { +export async function getResponseBody(res: Response): Promise { if (!(res.headers.get("content-length") !== "0")) { return null as TData; } diff --git a/src/Utils/request/types.ts b/src/Utils/request/types.ts index 668f937dbf0..20f095ae6fd 100644 --- a/src/Utils/request/types.ts +++ b/src/Utils/request/types.ts @@ -35,6 +35,14 @@ export interface RequestOptions { silent?: boolean; } +export interface QueryOptions { + pathParams?: Record; + queryParams?: Record; + body?: TBody; + silent?: boolean; + signal?: AbortSignal; +} + export interface PaginatedResponse { count: number; next: string | null; From c8963adf533f4e11b5a864934ae7e99fdd7a1eeb Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Sat, 14 Dec 2024 06:16:49 +0530 Subject: [PATCH 06/31] Fixed the date format in the user details page (#9409) --- cypress/e2e/users_spec/UsersManage.cy.ts | 2 +- package-lock.json | 9 ++++----- package.json | 2 +- src/components/Users/UserViewDetails.tsx | 8 +++----- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/cypress/e2e/users_spec/UsersManage.cy.ts b/cypress/e2e/users_spec/UsersManage.cy.ts index c7d237efb43..8d7ac8695c6 100644 --- a/cypress/e2e/users_spec/UsersManage.cy.ts +++ b/cypress/e2e/users_spec/UsersManage.cy.ts @@ -66,7 +66,7 @@ describe("Manage User", () => { manageUserPage.verifyEditUserDetails( "Devo", "Districto", - "8/11/1999", + "11/08/1999", "Female", ); }); diff --git a/package-lock.json b/package-lock.json index 106518926f4..41d7fcfff8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "clsx": "^2.1.1", "cmdk": "^1.0.4", "cross-env": "^7.0.3", - "cypress": "^13.16.1", + "cypress": "^13.16.0", "dayjs": "^1.11.13", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", @@ -7807,11 +7807,10 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "13.16.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.1.tgz", - "integrity": "sha512-17FtCaz0cx7ssWYKXzGB0Vub8xHwpVPr+iPt2fHhLMDhVAPVrplD+rTQsZUsfb19LVBn5iwkEUFjQ1yVVJXsLA==", + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.0.tgz", + "integrity": "sha512-g6XcwqnvzXrqiBQR/5gN+QsyRmKRhls1y5E42fyOvsmU7JuY+wM6uHJWj4ZPttjabzbnRvxcik2WemR8+xT6FA==", "hasInstallScript": true, - "license": "MIT", "dependencies": { "@cypress/request": "^3.0.6", "@cypress/xvfb": "^1.2.4", diff --git a/package.json b/package.json index 7bc7e5c117b..15392d09410 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "clsx": "^2.1.1", "cmdk": "^1.0.4", "cross-env": "^7.0.3", - "cypress": "^13.16.1", + "cypress": "^13.16.0", "dayjs": "^1.11.13", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", diff --git a/src/components/Users/UserViewDetails.tsx b/src/components/Users/UserViewDetails.tsx index 8b6fb40a1d3..9f4c78fbacf 100644 --- a/src/components/Users/UserViewDetails.tsx +++ b/src/components/Users/UserViewDetails.tsx @@ -1,5 +1,7 @@ import { useTranslation } from "react-i18next"; +import { formatDate } from "@/Utils/utils"; + import { UserModel } from "./models"; interface UserViewDetailsProps { @@ -77,11 +79,7 @@ export const BasicInfoDetails = ({ user }: UserViewDetailsProps) => {
From f82dfa8c55dfba7d9471c84592073b19f7d87eb8 Mon Sep 17 00:00:00 2001 From: Bodhish Thomas Date: Sat, 14 Dec 2024 23:42:52 +0530 Subject: [PATCH 07/31] Remove Sample management system (#9425) Co-authored-by: Aakash Singh --- .../SampleTestAdvanceFilters.cy.ts | 38 -- .../sample_test_spec/SampleTestHomepage.cy.ts | 54 -- .../sample_test_spec/SampleTestRequest.cy.ts | 88 --- cypress/fixtures/external-result-sample.csv | 2 - cypress/pageobject/Sample/SampleTestCreate.ts | 116 ---- public/External-Results-Template.csv | 3 - public/locale/en.json | 12 +- public/locale/hi.json | 1 - src/Routers/AppRouter.tsx | 2 - src/Routers/routes/SampleRoutes.tsx | 24 - src/Utils/request/api.tsx | 41 +- src/common/constants.tsx | 49 -- src/components/Common/Breadcrumbs.tsx | 1 - src/components/Common/Sidebar/Sidebar.tsx | 1 - .../PatientDetailsTab/SampleTestHistory.tsx | 107 ---- .../Patient/PatientDetailsTab/index.tsx | 5 - src/components/Patient/PatientHome.tsx | 42 +- src/components/Patient/SampleDetails.tsx | 558 ------------------ src/components/Patient/SampleFilters.tsx | 131 ---- src/components/Patient/SamplePreview.tsx | 459 -------------- src/components/Patient/SampleTest.tsx | 350 ----------- src/components/Patient/SampleTestCard.tsx | 227 ------- src/components/Patient/SampleViewAdmin.tsx | 423 ------------- src/components/Patient/UpdateStatusDialog.tsx | 230 -------- src/components/Patient/models.tsx | 131 ---- src/hooks/useActiveLink.ts | 1 - 26 files changed, 4 insertions(+), 3092 deletions(-) delete mode 100644 cypress/e2e/sample_test_spec/SampleTestAdvanceFilters.cy.ts delete mode 100644 cypress/e2e/sample_test_spec/SampleTestHomepage.cy.ts delete mode 100644 cypress/e2e/sample_test_spec/SampleTestRequest.cy.ts delete mode 100644 cypress/fixtures/external-result-sample.csv delete mode 100644 cypress/pageobject/Sample/SampleTestCreate.ts delete mode 100644 public/External-Results-Template.csv delete mode 100644 src/Routers/routes/SampleRoutes.tsx delete mode 100644 src/components/Patient/PatientDetailsTab/SampleTestHistory.tsx delete mode 100644 src/components/Patient/SampleDetails.tsx delete mode 100644 src/components/Patient/SampleFilters.tsx delete mode 100644 src/components/Patient/SamplePreview.tsx delete mode 100644 src/components/Patient/SampleTest.tsx delete mode 100644 src/components/Patient/SampleTestCard.tsx delete mode 100644 src/components/Patient/SampleViewAdmin.tsx delete mode 100644 src/components/Patient/UpdateStatusDialog.tsx diff --git a/cypress/e2e/sample_test_spec/SampleTestAdvanceFilters.cy.ts b/cypress/e2e/sample_test_spec/SampleTestAdvanceFilters.cy.ts deleted file mode 100644 index 562eb22a75e..00000000000 --- a/cypress/e2e/sample_test_spec/SampleTestAdvanceFilters.cy.ts +++ /dev/null @@ -1,38 +0,0 @@ -import LoginPage from "pageobject/Login/LoginPage"; - -const loginPage = new LoginPage(); - -describe("Sample Filter", () => { - before(() => { - loginPage.loginByRole("districtAdmin"); - cy.saveLocalStorage(); - }); - - beforeEach(() => { - cy.restoreLocalStorage(); - cy.clearLocalStorage(/filters--.+/); - cy.awaitUrl("/sample"); - cy.contains("Advanced Filters").click(); - }); - - it("Filter by Status", () => { - cy.get("#status").click(); - cy.get("li[role='option']") - .contains(/^APPROVED$/) - .click(); - }); - - it("Filter by sample type", () => { - cy.get("#sample_type").click(); - cy.get("li[role='option']") - .contains(/^Biopsy$/) - .click(); - }); - - afterEach(() => { - cy.intercept(/\/api\/v1\/test_sample/).as("sample_filter"); - cy.contains("Apply").click(); - cy.wait("@sample_filter"); - cy.saveLocalStorage(); - }); -}); diff --git a/cypress/e2e/sample_test_spec/SampleTestHomepage.cy.ts b/cypress/e2e/sample_test_spec/SampleTestHomepage.cy.ts deleted file mode 100644 index 491da5ee7ad..00000000000 --- a/cypress/e2e/sample_test_spec/SampleTestHomepage.cy.ts +++ /dev/null @@ -1,54 +0,0 @@ -import LoginPage from "pageobject/Login/LoginPage"; - -const loginPage = new LoginPage(); - -describe("Sample List", () => { - before(() => { - loginPage.loginByRole("districtAdmin"); - cy.saveLocalStorage(); - }); - - beforeEach(() => { - cy.restoreLocalStorage(); - cy.clearLocalStorage(/filters--.+/); - cy.awaitUrl("/sample"); - }); - - it("Search by District name", () => { - cy.intercept(/\/api\/v1\/test_sample/).as("test_sample"); - cy.get("[name='district_name']").type("Test"); - cy.wait("@test_sample").its("response.statusCode").should("eq", 200); - cy.url().should("include", "Test"); - }); - - it("Search by Patient Name", () => { - cy.intercept(/\/api\/v1\/test_sample/).as("test_sample"); - cy.get("[name='patient_name']").type("Test"); - cy.wait("@test_sample").its("response.statusCode").should("eq", 200); - cy.url().should("include", "Test"); - }); - - it("Update Sample Status", () => { - cy.contains("UPDATE SAMPLE TEST STATUS").click(); - }); - - it("View Sample Details", () => { - cy.contains("Sample Details").click(); - }); - - it("Next/Previous Page", () => { - // only works for desktop mode - cy.get("button") - .should("contain", "Next") - .contains("Next") - .click({ force: true }); - cy.get("button") - .should("contain", "Previous") - .contains("Previous") - .click({ force: true }); - }); - - afterEach(() => { - cy.saveLocalStorage(); - }); -}); diff --git a/cypress/e2e/sample_test_spec/SampleTestRequest.cy.ts b/cypress/e2e/sample_test_spec/SampleTestRequest.cy.ts deleted file mode 100644 index a4b26d328e5..00000000000 --- a/cypress/e2e/sample_test_spec/SampleTestRequest.cy.ts +++ /dev/null @@ -1,88 +0,0 @@ -import LoginPage from "pageobject/Login/LoginPage"; -import { PatientConsultationPage } from "pageobject/Patient/PatientConsultation"; -import { PatientPage } from "pageobject/Patient/PatientCreation"; -import { SampleTestPage } from "pageobject/Sample/SampleTestCreate"; - -describe("Sample Test", () => { - const sampleTestPage = new SampleTestPage(); - const patientPage = new PatientPage(); - const loginPage = new LoginPage(); - const patientConsultationPage = new PatientConsultationPage(); - const patientName = "Dummy Patient Eleven"; - const sampleTestType = "BA/ETA"; - const icmrCategory = "Cat 0"; - const icmrLabel = "Test Icmr Label"; - const doctorName = "Dr John Doe"; - const atypicalDetails = "Patient showing unusual symptoms"; - const diagnosis = "Suspected respiratory infection"; - const etiologyIdentified = "Bacterial infection suspected"; - const differentialDiagnosis = "Possibly a viral infection"; - const fastTrackReason = - "The patient has a high risk of complications and requires immediate testing."; - const sampleTestStatus = "Request Submitted"; - const expectedSampleTestType = "ba/eta"; - const sampleTestResult = "Awaiting"; - - before(() => { - loginPage.loginByRole("districtAdmin"); - cy.saveLocalStorage(); - }); - - beforeEach(() => { - cy.restoreLocalStorage(); - cy.clearLocalStorage(/filters--.+/); - }); - - it("should request a new sample test", () => { - // Ensure patient list API is loaded before proceeding - cy.awaitUrl("/patients"); - patientPage.visitPatient(patientName); - patientConsultationPage.interceptPatientDetailsAPI(); - patientConsultationPage.clickPatientDetails(); - patientConsultationPage.verifyPatientDetailsResponse(); - // Visit SampleRequest Page - sampleTestPage.visitSampleRequestPage(); - // Fill Sample Test Request Form - sampleTestPage.selectSampleType(sampleTestType); - sampleTestPage.selectIcmrCategory(icmrCategory); - sampleTestPage.fillIcmrLabel(icmrLabel); - sampleTestPage.fillFastTrackReason(fastTrackReason); - sampleTestPage.fillDoctorName(doctorName); - sampleTestPage.fillAtypicalPresentation(atypicalDetails); - sampleTestPage.fillDiagnosis(diagnosis); - sampleTestPage.fillEtiology(etiologyIdentified); - sampleTestPage.fillDiffDiagnosis(differentialDiagnosis); - sampleTestPage.checkHasSari(); - sampleTestPage.checkHasAri(); - sampleTestPage.checkIsUnusualCourse(); - sampleTestPage.interceptSampleTestReq(); - // Submit the form and verify notification - cy.clickSubmitButton("Confirm your request to send sample for testing"); - sampleTestPage.verifySampleTestReq(); - cy.verifyNotification("Sample test created successfully"); - // Check the updated request history - sampleTestPage.checkRequestHistory( - sampleTestStatus, - expectedSampleTestType, - fastTrackReason, - sampleTestResult, - ); - // Checking Reflection on Sample Page - cy.awaitUrl("/sample"); - sampleTestPage.interceptGetSampleTestReq(); - sampleTestPage.searchPatientSample(patientName); - sampleTestPage.verifyGetSampleTestReq(); - sampleTestPage.verifyPatientName(patientName); - sampleTestPage.interceptGetSampleTestReq(); - sampleTestPage.clickOnSampleDetailsBtn(); - sampleTestPage.verifyGetSampleTestReq(); - sampleTestPage.verifyPatientTestDetails( - patientName, - fastTrackReason, - doctorName, - diagnosis, - differentialDiagnosis, - etiologyIdentified, - ); - }); -}); diff --git a/cypress/fixtures/external-result-sample.csv b/cypress/fixtures/external-result-sample.csv deleted file mode 100644 index 2905cdc1af3..00000000000 --- a/cypress/fixtures/external-result-sample.csv +++ /dev/null @@ -1,2 +0,0 @@ -District,SRF ID,Name,Age,Age in,Gender,Mobile Number,Address,Ward,Local Body,Local Body Type,Source,Sample Collection Date,Result Date,Test Type,Lab Name,Sample Type,Patient Status,Is Repeat,Patient Category,Result -Ernakulam,00/EKM/0000,Test Upload,24,years,m,8888888888,Upload test address,7,Poothrikka,grama panchayath,Secondary contact aparna,2020-10-14,2020-10-14,Antigen,Karothukuzhi Laboratory,Ag-SD_Biosensor_Standard_Q_COVID-19_Ag_detection_kit,Asymptomatic,NO,Cat 17: All individuals who wish to get themselves tested,Negative diff --git a/cypress/pageobject/Sample/SampleTestCreate.ts b/cypress/pageobject/Sample/SampleTestCreate.ts deleted file mode 100644 index 445d08732c3..00000000000 --- a/cypress/pageobject/Sample/SampleTestCreate.ts +++ /dev/null @@ -1,116 +0,0 @@ -export class SampleTestPage { - visitSampleRequestPage(): void { - cy.get("a").contains("Service Request").click(); - cy.verifyAndClickElement("#sample-request-btn", "Request Sample Test"); - cy.url().should("include", "/sample-test"); - } - - selectSampleType(option: string): void { - cy.clickAndSelectOption("#sample-type", option); - } - - selectIcmrCategory(option: string): void { - cy.clickAndSelectOption("#icmr-category", option); - } - - fillIcmrLabel(label: string): void { - cy.get("#icmr-label").should("be.visible").type(label); - } - - fillFastTrackReason(value: string): void { - cy.get("#is_fast_track").should("be.visible").check(); - cy.get("#fast_track").should("be.visible").type(value); - } - - fillDoctorName(value: string): void { - cy.get("#doctor_name").should("be.visible").type(value); - } - - fillAtypicalPresentation(value: string): void { - cy.get("#is_atypical_presentation").should("be.visible").check(); - cy.get("#atypical_presentation").should("be.visible").type(value); - } - - fillDiagnosis(value: string): void { - cy.get("#diagnosis").should("be.visible").type(value); - } - - fillEtiology(value: string): void { - cy.get("#etiology_identified").should("be.visible").type(value); - } - - fillDiffDiagnosis(value: string): void { - cy.get("#diff_diagnosis").should("be.visible").type(value); - } - - checkHasSari(): void { - cy.get("#has_sari").should("be.visible").check(); - } - - checkHasAri(): void { - cy.get("#has_ari").should("be.visible").check(); - } - - checkIsUnusualCourse(): void { - cy.get("#is_unusual_course").should("be.visible").check(); - } - - checkRequestHistory( - sampleTestStatus: string, - sampleTestType: string, - fastTrack: string, - sampleTestResult: string, - ): void { - cy.get("a").contains("Service Request").click(); - cy.verifyContentPresence("#sample-test-status", [sampleTestStatus]); - cy.verifyContentPresence("#sample-test-type", [sampleTestType]); - cy.verifyContentPresence("#sample-test-fast-track", [fastTrack]); - cy.verifyContentPresence("#sample-test-result", [sampleTestResult]); - } - - searchPatientSample(patientName: string): void { - cy.get("#search_patient_name").should("be.visible").type(patientName); - } - - verifyPatientName(patientName: string): void { - cy.verifyContentPresence("#sample-test-patient-name", [patientName]); - } - - clickOnSampleDetailsBtn(): void { - cy.get("#sample-details-btn").should("be.visible").first().click(); - } - - verifyPatientTestDetails( - patientName: string, - fastTrackReason: string, - doctorName: string, - diagnosis: string, - differentialDiagnosis: string, - etiologyIdentified: string, - ): void { - cy.verifyContentPresence("#patient_name", [patientName]); - cy.verifyContentPresence("#fast_track_reason", [fastTrackReason]); - cy.verifyContentPresence("#doctor_name", [doctorName]); - cy.verifyContentPresence("#diagnosis", [diagnosis]); - cy.verifyContentPresence("#diff_diagnosis", [differentialDiagnosis]); - cy.verifyContentPresence("#etiology_identified", [etiologyIdentified]); - } - - interceptSampleTestReq(): void { - cy.intercept("POST", "**/api/v1/patient/*/test_sample/").as( - "sampleDetails", - ); - } - - verifySampleTestReq(): void { - cy.wait("@sampleDetails").its("response.statusCode").should("eq", 201); - } - - interceptGetSampleTestReq(): void { - cy.intercept("GET", "**/api/v1/test_sample/**").as("getSampleTestReq"); - } - - verifyGetSampleTestReq(): void { - cy.wait("@getSampleTestReq").its("response.statusCode").should("eq", 200); - } -} diff --git a/public/External-Results-Template.csv b/public/External-Results-Template.csv deleted file mode 100644 index c2601f2d64f..00000000000 --- a/public/External-Results-Template.csv +++ /dev/null @@ -1,3 +0,0 @@ -District,SRF ID,Name,Age,Age in,Gender,Mobile Number,Address,Ward,Local Body,Local Body Type,Source,Sample Collection Date,Result Date,Test Type,Lab Name,Sample Type,Patient Status,Is Repeat,Patient Category,Result -Ernakulam,00/EKM/0000,Bodhi CSN,24,years,m,8888888888,"CSN HQ -Kochi, Kerala ",7,Poothrikka,grama panchayath,Secondary contact aparna,2020-10-14,2020-10-14,Antigen,Karothukuzhi Laboratory,Ag-SD_Biosensor_Standard_Q_COVID-19_Ag_detection_kit,Asymptomatic,NO,Cat 17: All individuals who wish to get themselves tested,Negative \ No newline at end of file diff --git a/public/locale/en.json b/public/locale/en.json index 4b262e61d10..b9418edd719 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -181,14 +181,6 @@ "ROUNDS_TYPE__NORMAL": "Brief Update", "ROUNDS_TYPE__TELEMEDICINE": "Tele-medicine Log", "ROUNDS_TYPE__VENTILATOR": "Detailed Update", - "SAMPLE_TEST_HISTORY__APPROVED": "Approved", - "SAMPLE_TEST_HISTORY__COMPLETED": "Completed", - "SAMPLE_TEST_HISTORY__RECEIVED_AT_LAB": "Received At Lab", - "SAMPLE_TEST_HISTORY__REQUEST_SUBMITTED": "Request Submitted", - "SAMPLE_TEST_RESULT__AWAITING": "Awaiting", - "SAMPLE_TEST_RESULT__INVALID": "Invalid", - "SAMPLE_TEST_RESULT__NEGATIVE": "Negative", - "SAMPLE_TEST_RESULT__POSITIVE": "Positive", "SLEEP__EXCESSIVE": "Excessive", "SLEEP__NO_SLEEP": "No sleep", "SLEEP__SATISFACTORY": "Satisfactory", @@ -354,7 +346,6 @@ "asset_type": "Asset Type", "assets": "Assets", "assign": "Assign", - "unassign":"Unassign", "assign_a_volunteer_to": "Assign a volunteer to {{name}}", "assign_bed": "Assign Bed", "assign_to_volunteer": "Assign to a Volunteer", @@ -1444,6 +1435,7 @@ "type_your_comment": "Type your comment", "type_your_reason_here": "Type your reason here", "unable_to_get_current_position": "Unable to get current position.", + "unassign": "Unassign", "unconfirmed": "Unconfirmed", "unique_id": "Unique Id", "unknown": "Unknown", @@ -1558,8 +1550,8 @@ "voice_autofill": "Voice Autofill", "volunteer_assigned": "Volunteer assigned successfully", "volunteer_contact": "Volunteer Contact", - "volunteer_update" : "Volunteer updated successfully", "volunteer_unassigned": "Volunteer unassigned successfully", + "volunteer_update": "Volunteer updated successfully", "ward": "Ward", "warranty_amc_expiry": "Warranty / AMC Expiry", "weekly_working_hours_error": "Average weekly working hours must be a number between 0 and 168", diff --git a/public/locale/hi.json b/public/locale/hi.json index b3c172021dd..9e6a667ba23 100644 --- a/public/locale/hi.json +++ b/public/locale/hi.json @@ -106,7 +106,6 @@ "SORT_OPTIONS__name": "मरीज़ का नाम AZ", "SORT_OPTIONS__review_time": "सबसे पुरानी समीक्षा तिथि पहले", "SORT_OPTIONS__taken_at": "सबसे पुरानी ली गई तारीख पहले", - "Sample Test": "नमूना परीक्षण", "Shifting": "स्थानांतरण", "Submit": "जमा करना", "TELEMEDICINE": "सुदूर", diff --git a/src/Routers/AppRouter.tsx b/src/Routers/AppRouter.tsx index 8ba9460e34b..e5b3d5b3eb1 100644 --- a/src/Routers/AppRouter.tsx +++ b/src/Routers/AppRouter.tsx @@ -24,7 +24,6 @@ import ConsultationRoutes from "@/Routers/routes/ConsultationRoutes"; import FacilityRoutes from "@/Routers/routes/FacilityRoutes"; import PatientRoutes from "@/Routers/routes/PatientRoutes"; import ResourceRoutes from "@/Routers/routes/ResourceRoutes"; -import SampleRoutes from "@/Routers/routes/SampleRoutes"; import ShiftingRoutes from "@/Routers/routes/ShiftingRoutes"; import UserRoutes from "@/Routers/routes/UserRoutes"; @@ -51,7 +50,6 @@ const Routes: AppRoutes = { ...FacilityRoutes, ...PatientRoutes, ...ResourceRoutes, - ...SampleRoutes, ...ShiftingRoutes, ...UserRoutes, diff --git a/src/Routers/routes/SampleRoutes.tsx b/src/Routers/routes/SampleRoutes.tsx deleted file mode 100644 index d9d3162cdd9..00000000000 --- a/src/Routers/routes/SampleRoutes.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SampleDetails } from "@/components/Patient/SampleDetails"; -import SampleReport from "@/components/Patient/SamplePreview"; -import { SampleTest } from "@/components/Patient/SampleTest"; -import SampleViewAdmin from "@/components/Patient/SampleViewAdmin"; - -import { AppRoutes } from "@/Routers/AppRouter"; - -const SampleRoutes: AppRoutes = { - "/sample": () => , - "/sample/:id": ({ id }) => , - "/patient/:patientId/test_sample/:sampleId/icmr_sample": ({ - patientId, - sampleId, - }) => , - "/facility/:facilityId/patient/:patientId/sample-test": ({ - facilityId, - patientId, - }) => , - "/facility/:facilityId/patient/:patientId/sample/:id": ({ id }) => ( - - ), -}; - -export default SampleRoutes; diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index 40021007773..e7df6312c84 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -70,12 +70,7 @@ import { NotificationData, PNconfigData, } from "@/components/Notifications/models"; -import { - DailyRoundsModel, - PatientModel, - SampleReportModel, - SampleTestModel, -} from "@/components/Patient/models"; +import { DailyRoundsModel, PatientModel } from "@/components/Patient/models"; import { CreateFileRequest, CreateFileResponse, @@ -785,22 +780,6 @@ const routes = { method: "GET", TRes: Type>(), }, - sampleTestList: { - path: "/api/v1/patient/{patientId}/test_sample/", - method: "GET", - TRes: Type>(), - }, - createSampleTest: { - path: "/api/v1/patient/{patientId}/test_sample/", - method: "POST", - TRes: Type(), - TBody: Type(), - }, - sampleReport: { - path: "/api/v1/patient/{id}/test_sample/{sampleId}/icmr_sample/", - method: "GET", - TRes: Type(), - }, // States statesList: { @@ -869,24 +848,6 @@ const routes = { TRes: Type>(), }, - // Sample Test - getTestSampleList: { - path: "/api/v1/test_sample/", - method: "GET", - TRes: Type>(), - }, - getTestSample: { - path: "/api/v1/test_sample/{id}/", - method: "GET", - TRes: Type(), - }, - patchSample: { - path: "/api/v1/test_sample/{id}/", - method: "PATCH", - TBody: Type(), - TRes: Type(), - }, - //inventory getItems: { path: "/api/v1/items/", diff --git a/src/common/constants.tsx b/src/common/constants.tsx index 9d0be731565..ff215a0635a 100644 --- a/src/common/constants.tsx +++ b/src/common/constants.tsx @@ -363,13 +363,6 @@ export const GENDER_TYPES = [ { id: 3, text: "Transgender", icon: "TRANS" }, ] as const; -export const SAMPLE_TEST_RESULT = [ - { id: 1, text: "POSITIVE" }, - { id: 2, text: "NEGATIVE" }, - { id: 3, text: "AWAITING" }, - { id: 4, text: "INVALID" }, -]; - export const CONSULTATION_SUGGESTION = [ { id: "HI", text: "Home Isolation", deprecated: true }, // # Deprecated. Preserving option for backward compatibility (use only for readonly operations) { id: "A", text: "Admission" }, @@ -463,48 +456,6 @@ export const PATIENT_CATEGORIES: { export const PATIENT_FILTER_CATEGORIES = PATIENT_CATEGORIES; -export const SAMPLE_TEST_STATUS = [ - { id: 1, text: "REQUEST_SUBMITTED", desc: "Request Submitted" }, - { id: 2, text: "APPROVED", desc: "Approved for Sample Collection" }, - { id: 3, text: "DENIED", desc: "Request Denied" }, - { - id: 4, - text: "SENT_TO_COLLECTON_CENTRE", - desc: "Sample taken and sent to collection centre", - }, - { id: 5, text: "RECEIVED_AND_FORWARED", desc: "Received And Forwarded" }, - { id: 6, text: "RECEIVED_AT_LAB", desc: "Received At Lab" }, - { id: 7, text: "COMPLETED", desc: "Test Completed" }, -]; - -export const SAMPLE_FLOW_RULES = { - REQUEST_SUBMITTED: ["APPROVED", "DENIED"], - APPROVED: [ - "SENT_TO_COLLECTON_CENTRE", - "RECEIVED_AND_FORWARED", - "RECEIVED_AT_LAB", - "COMPLETED", - ], - DENIED: ["REQUEST_SUBMITTED"], - SENT_TO_COLLECTON_CENTRE: [ - "RECEIVED_AND_FORWARED", - "RECEIVED_AT_LAB", - "COMPLETED", - ], - RECEIVED_AND_FORWARED: ["RECEIVED_AT_LAB", "COMPLETED"], - RECEIVED_AT_LAB: ["COMPLETED"], -}; - -export const TEST_TYPE = [ - "UNK", - "ANTIGEN", - "RTPCR", - "CBNAAT", - "TRUENAT", - "RTLAMP", - "POCPCR", -]; - export const VACCINES = [ "CoviShield", "Covaxin", diff --git a/src/components/Common/Breadcrumbs.tsx b/src/components/Common/Breadcrumbs.tsx index 0435d7675d9..c2c4aa57446 100644 --- a/src/components/Common/Breadcrumbs.tsx +++ b/src/components/Common/Breadcrumbs.tsx @@ -13,7 +13,6 @@ const MENU_TAGS: { [key: string]: string } = { facility: "Facilities", patients: "Patients", assets: "Assets", - sample: "Sample Tests", shifting: "Shiftings", resource: "Resources", users: "Users", diff --git a/src/components/Common/Sidebar/Sidebar.tsx b/src/components/Common/Sidebar/Sidebar.tsx index ed0a1a4eee5..423d0d6f18b 100644 --- a/src/components/Common/Sidebar/Sidebar.tsx +++ b/src/components/Common/Sidebar/Sidebar.tsx @@ -59,7 +59,6 @@ const StatelessSidebar = ({ { text: t("facilities"), to: "/facility", icon: "d-hospital" }, { text: t("patients"), to: "/patients", icon: "d-patient" }, { text: t("assets"), to: "/assets", icon: "d-folder" }, - { text: t("sample_test"), to: "/sample", icon: "d-microscope" }, { text: t("shifting"), to: "/shifting", icon: "d-ambulance" }, { text: t("resource"), to: "/resource", icon: "d-book-open" }, { text: t("users"), to: "/users", icon: "d-people" }, diff --git a/src/components/Patient/PatientDetailsTab/SampleTestHistory.tsx b/src/components/Patient/PatientDetailsTab/SampleTestHistory.tsx deleted file mode 100644 index b7a907fe662..00000000000 --- a/src/components/Patient/PatientDetailsTab/SampleTestHistory.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { navigate } from "raviger"; -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; -import PaginatedList from "@/CAREUI/misc/PaginatedList"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import CircularProgress from "@/components/Common/CircularProgress"; - -import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; -import routes from "@/Utils/request/api"; - -import { PatientProps } from "."; -import { SampleTestCard } from "../SampleTestCard"; -import { PatientModel, SampleTestModel } from "../models"; - -export const SampleTestHistory = (props: PatientProps) => { - const { patientData, facilityId, id } = props; - const [_selectedStatus, setSelectedStatus] = useState<{ - status: number; - sample: SampleTestModel | null; - }>({ status: 0, sample: null }); - const [_showAlertMessage, setShowAlertMessage] = useState(false); - - const isPatientInactive = (patientData: PatientModel, facilityId: string) => { - if (!patientData) return true; - return ( - !patientData.is_active || - !( - patientData?.last_consultation && - patientData.last_consultation.facility === facilityId - ) - ); - }; - - const confirmApproval = (status: number, sample: SampleTestModel) => { - setSelectedStatus({ status, sample }); - setShowAlertMessage(true); - }; - - const { t } = useTranslation(); - - return ( -
-
-
-

- {t("sample_test_history")} -

- - navigate( - `/facility/${patientData?.facility}/patient/${id}/sample-test`, - ) - } - authorizeFor={NonReadOnlyUsers} - id="sample-request-btn" - > - - - {t("request_sample_test")} - - -
-
- - - {(_, query) => ( -
- - - - -
-
- {t("no_records_found")} -
-
-
- > - {(item) => ( - - )} - -
- -
-
- )} -
-
- ); -}; diff --git a/src/components/Patient/PatientDetailsTab/index.tsx b/src/components/Patient/PatientDetailsTab/index.tsx index effc9b667f8..6f4b7ecc982 100644 --- a/src/components/Patient/PatientDetailsTab/index.tsx +++ b/src/components/Patient/PatientDetailsTab/index.tsx @@ -4,7 +4,6 @@ import EncounterHistory from "./EncounterHistory"; import { HealthProfileSummary } from "./HealthProfileSummary"; import { ImmunisationRecords } from "./ImmunisationRecords"; import PatientNotes from "./Notes"; -import { SampleTestHistory } from "./SampleTestHistory"; import ShiftingHistory from "./ShiftingHistory"; export interface PatientProps { @@ -34,10 +33,6 @@ export const patientTabs = [ route: "shift", component: ShiftingHistory, }, - { - route: "request-sample-test", - component: SampleTestHistory, - }, { route: "patient-notes", component: PatientNotes, diff --git a/src/components/Patient/PatientHome.tsx b/src/components/Patient/PatientHome.tsx index 7ae439fa80b..253bd823ac0 100644 --- a/src/components/Patient/PatientHome.tsx +++ b/src/components/Patient/PatientHome.tsx @@ -11,7 +11,6 @@ import { DISCHARGE_REASONS, GENDER_TYPES, OCCUPATION_TYPES, - SAMPLE_TEST_STATUS, } from "@/common/constants"; import dayjs from "@/Utils/dayjs"; @@ -40,7 +39,7 @@ import Page from "../Common/Page"; import { SkillModel, UserBareMinimum } from "../Users/models"; import { patientTabs } from "./PatientDetailsTab"; import { isPatientMandatoryDataFilled } from "./Utils"; -import { AssignedToObjectModel, PatientModel, SampleTestModel } from "./models"; +import { AssignedToObjectModel, PatientModel } from "./models"; export const parseOccupation = (occupation: string | undefined) => { return OCCUPATION_TYPES.find((i) => i.value === occupation)?.text; @@ -56,10 +55,6 @@ export const PatientHome = (props: { const authUser = useAuthUser(); const { t } = useTranslation(); - const [selectedStatus, _setSelectedStatus] = useState<{ - status: number; - sample: SampleTestModel | null; - }>({ status: 0, sample: null }); const [assignedVolunteer, setAssignedVolunteer] = useState< AssignedToObjectModel | undefined @@ -69,7 +64,6 @@ export const PatientHome = (props: { setAssignedVolunteer(patientData.assigned_to_object); }, [patientData.assigned_to_object]); - const [showAlertMessage, setShowAlertMessage] = useState(false); const [openAssignVolunteerDialog, setOpenAssignVolunteerDialog] = useState(false); @@ -152,31 +146,6 @@ export const PatientHome = (props: { return `${first}, ${second} and ${rest.length} other skills...`; }; - const handleApproval = async () => { - const { status, sample } = selectedStatus; - const sampleData = { - id: sample?.id, - status: status.toString(), - consultation: sample?.consultation, - }; - const statusName = SAMPLE_TEST_STATUS.find((i) => i.id === status)?.desc; - - await request(routes.patchSample, { - body: sampleData, - pathParams: { - id: sample?.id || "", - }, - onResponse: ({ res }) => { - if (res?.ok) { - Notification.Success({ - msg: `Request ${statusName}`, - }); - } - setShowAlertMessage(false); - }, - }); - }; - if (isLoading) { return ; } @@ -216,15 +185,6 @@ export const PatientHome = (props: { }} backUrl={facilityId ? `/facility/${facilityId}/patients` : "/patients"} > - handleApproval()} - onClose={() => setShowAlertMessage(false)} - /> -
diff --git a/src/components/Patient/SampleDetails.tsx b/src/components/Patient/SampleDetails.tsx deleted file mode 100644 index f0e5f0039e5..00000000000 --- a/src/components/Patient/SampleDetails.tsx +++ /dev/null @@ -1,558 +0,0 @@ -import { Link, navigate } from "raviger"; -import { useTranslation } from "react-i18next"; - -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; - -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; -import { FileUpload } from "@/components/Files/FileUpload"; -import { FlowModel } from "@/components/Patient/models"; - -import { GENDER_TYPES, TEST_TYPE_CHOICES } from "@/common/constants"; - -import { DetailRoute } from "@/Routers/types"; -import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import { formatDateTime, formatPatientAge } from "@/Utils/utils"; - -export const SampleDetails = ({ id }: DetailRoute) => { - const { t } = useTranslation(); - const { loading: isLoading, data: sampleDetails } = useTanStackQueryInstead( - routes.getTestSample, - { - pathParams: { - id, - }, - onResponse: ({ res, data }) => { - if (!(res?.ok && data)) { - navigate("/not-found"); - } - }, - }, - ); - - const yesOrNoBadge = (param: any) => - param ? ( - {t("yes")} - ) : ( - {t("no")} - ); - - const showPatientCard = (patientData: any) => { - const patientGender = GENDER_TYPES.find( - (i) => i.id === patientData?.gender, - )?.text; - const testType = TEST_TYPE_CHOICES.find( - (i) => i.id === patientData?.test_type, - )?.text; - - return ( -
-
-
-
- - {t("name")}:{" "} - - {patientData?.name} -
- {patientData?.is_medical_worker && ( -
- - {t("medical_worker")}:{" "} - - - {t("yes")} - -
- )} -
- - {t("disease_status")}:{" "} - - - {patientData?.disease_status} - -
- -
- - {t("srf_id")}:{" "} - - {(patientData?.srf_id && patientData?.srf_id) || "-"} -
-
- - {t("test_type")}:{" "} - - {(patientData?.test_type && testType) || "-"} -
-
- - {t("date_of_test")}:{" "} - - {(patientData?.date_of_test && - formatDateTime(patientData?.date_of_test)) || - "-"} -
- -
- - {t("facility")}:{" "} - - {patientData?.facility_object?.name || "-"} -
- {patientData?.date_of_birth ? ( -
- - {t("date_of_birth")}:{" "} - - {patientData?.date_of_birth} -
- ) : ( -
- - {t("age")}:{" "} - - {formatPatientAge(patientData)} -
- )} -
- - {t("gender")}:{" "} - - {patientGender} -
-
- - {t("phone")}:{" "} - - - {patientData?.phone_number || "-"} - -
-
- - {t("nationality")}:{" "} - - {patientData?.nationality || "-"} -
-
-
-
- - {t("blood_group")}:{" "} - - {patientData?.blood_group || "-"} -
- {patientData?.nationality !== "India" && ( -
- - {t("passport_number")}:{" "} - - {patientData?.passport_no || "-"} -
- )} - {patientData?.nationality === "India" && ( - <> -
- - {t("state")}:{" "} - - {patientData?.state_object?.name} -
-
- - {t("district")}:{" "} - - {patientData?.district_object?.name || "-"} -
-
- - {t("local_body")}:{" "} - - {patientData?.local_body_object?.name || "-"} -
- - )} -
- - {t("address")}:{" "} - - {patientData?.address || "-"} -
-
- - {t("contact_with_confirmed_carrier")}:{" "} - - {yesOrNoBadge(patientData?.contact_with_confirmed_carrier)} -
-
- - {t("contact_with_suspected_carrier")}:{" "} - - {yesOrNoBadge(patientData?.contact_with_suspected_carrier)} -
- {patientData?.estimated_contact_date && ( -
- - {t("estimated_contact_date")}:{" "} - - {formatDateTime(patientData?.estimated_contact_date)} -
- )} -
- - {t("has_sari")}:{" "} - - {yesOrNoBadge(patientData?.has_SARI)} -
-
- - {t("domestic_international_travel")}:{" "} - - {yesOrNoBadge(patientData?.past_travel)} -
- {patientData?.countries_travelled && - !!patientData?.countries_travelled.length && ( -
- - {t("countries_travelled")}:{" "} - - {patientData?.countries_travelled.join(", ")} -
- )} - {patientData?.ongoing_medication && ( -
- - {t("ongoing_medications")}{" "} - - {patientData?.ongoing_medication} -
- )} - {patientData?.allergies && ( -
- - {t("allergies")}:{" "} - - {patientData?.allergies} -
- )} - {!!patientData?.number_of_aged_dependents && ( -
- - {t("number_of_aged_dependents")}:{" "} - - {patientData?.number_of_aged_dependents} -
- )} - {!!patientData?.number_of_chronic_diseased_dependents && ( -
- - {t("number_of_chronic_diseased_dependents")}:{" "} - - {patientData?.number_of_chronic_diseased_dependents} -
- )} -
-
-
- ); - }; - - const renderFlow = (flow: FlowModel) => { - return ( - -
-
- - {t("status")}:{" "} - {" "} - {t(`SAMPLE_TEST_HISTORY__${flow.status}`) || "Unknown"} -
-
- {t("label")}:{" "} - {flow.notes} -
-
- - {t("created_on")}: - {" "} - {flow.created_date ? formatDateTime(flow.created_date) : "-"} -
-
- - {t("modified_on")}: - {" "} - {flow.modified_date ? formatDateTime(flow.modified_date) : "-"} -
-
-
- ); - }; - - if (isLoading || !sampleDetails) { - return ; - } - - return ( - - -
- ) - } - > - - -
-
-
- {t("status")}:{" "} -
- - {t(`SAMPLE_TEST_HISTORY__${sampleDetails?.status}`)} - -
-
-
- {t("result")}:{" "} -
- - {t(`SAMPLE_TEST_RESULT__${sampleDetails?.result}`)} - -
-
-
- -
-
-
- {t("patient")}: -
-
- {sampleDetails?.patient_name || "-"} -
-
- {sampleDetails?.facility_object && ( -
-
- {t("facility")}:{" "} -
-
- {sampleDetails?.facility_object.name} -
-
- )} -
-
- {t("tested_on")}:{" "} -
-
- {sampleDetails?.date_of_result - ? formatDateTime(sampleDetails.date_of_result) - : "-"} -
-
-
-
- {t("result_on")}:{" "} -
-
- {sampleDetails?.date_of_result - ? formatDateTime(sampleDetails.date_of_result) - : "-"} -
-
-
- - {sampleDetails?.doctor_name && ( -
-
- {t("doctors_name")}: -
-
- {sampleDetails.doctor_name} -
-
- )} -
-
- {sampleDetails?.fast_track && ( -
-
- {t("fast_track_testing_reason")}:{" "} -
- {sampleDetails.fast_track} -
- )} - {sampleDetails?.diagnosis && ( -
-
{t("diagnosis")}:
- - {" "} - {sampleDetails.diagnosis} - -
- )} - {sampleDetails?.diff_diagnosis && ( -
-
- {t("differential_diagnosis")}:{" "} -
- - {" "} - {sampleDetails?.diff_diagnosis} - -
- )} - {sampleDetails?.etiology_identified && ( -
-
- {t("etiology_identified")}:{" "} -
- - {" "} - {sampleDetails.etiology_identified} - -
- )} -
-
- {t("is_atypical_presentation")} -
- - {" "} - {yesOrNoBadge(sampleDetails?.is_atypical_presentation)} - -
-
-
- {t("is_unusual_course")} -
- - {" "} - {yesOrNoBadge(sampleDetails?.is_unusual_course)} - -
- {sampleDetails?.atypical_presentation && ( -
-
- {t("atypical_presentation_details")}:{" "} -
- - {" "} - {sampleDetails.atypical_presentation} - -
- )} -
-
{t("sari")}
- - {" "} - {yesOrNoBadge(sampleDetails?.has_sari)} - -
-
-
{t("ari")}
- - {" "} - {yesOrNoBadge(sampleDetails?.has_ari)} - -
-
-
- {t("contact_with_confirmed_carrier")}{" "} -
- - {" "} - {yesOrNoBadge(sampleDetails?.patient_has_confirmed_contact)} - -
-
-
- {t("contact_with_suspected_carrier")}{" "} -
- - {" "} - {yesOrNoBadge(sampleDetails?.patient_has_suspected_contact)} - -
- {sampleDetails?.patient_travel_history && - sampleDetails.patient_travel_history.length !== 0 && ( -
-
- {t("countries_travelled")}:{" "} -
- - {" "} - {sampleDetails.patient_travel_history} - -
- )} -
-
- {sampleDetails?.sample_type && ( -
-
- {t("sample_type")}:{" "} -
- - {sampleDetails.sample_type} - -
- )} - {sampleDetails?.sample_type === "OTHER TYPE" && ( -
-
- {t("sample_type_description")}:{" "} -
-
- {sampleDetails?.sample_type_other} -
-
- )} -
-
- -
-

{t("details_of_patient")}

- {showPatientCard(sampleDetails?.patient_object)} -
- -
-

{t("sample_test_history")}

- {sampleDetails?.flow && - sampleDetails.flow.map((flow: FlowModel) => ( -
- {renderFlow(flow)} -
- ))} -
- - - - ); -}; diff --git a/src/components/Patient/SampleFilters.tsx b/src/components/Patient/SampleFilters.tsx deleted file mode 100644 index 6ac3a4532b7..00000000000 --- a/src/components/Patient/SampleFilters.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import FiltersSlideover from "@/CAREUI/interactive/FiltersSlideover"; - -import CircularProgress from "@/components/Common/CircularProgress"; -import { FacilitySelect } from "@/components/Common/FacilitySelect"; -import { FacilityModel } from "@/components/Facility/models"; -import { FieldLabel } from "@/components/Form/FormFields/FormField"; -import { SelectFormField } from "@/components/Form/FormFields/SelectFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; - -import useMergeState from "@/hooks/useMergeState"; - -import { - SAMPLE_TEST_RESULT, - SAMPLE_TEST_STATUS, - SAMPLE_TYPE_CHOICES, -} from "@/common/constants"; - -import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -export default function UserFilter(props: any) { - const { filter, onChange, closeFilter, removeFilters } = props; - - const [filterState, setFilterState] = useMergeState({ - status: filter.status || "", - result: filter.result || "", - facility: filter.facility || "", - facility_ref: filter.facility_ref || null, - sample_type: filter.sample_type || "", - }); - - const handleChange = ({ name, value }: FieldChangeEvent) => { - setFilterState({ ...filterState, [name]: value }); - }; - - const applyFilter = () => { - const { status, result, facility, sample_type } = filterState; - const data = { - status: status || "", - result: result || "", - facility: facility || "", - sample_type: sample_type || "", - }; - onChange(data); - }; - - const { loading: isFacilityLoading } = useTanStackQueryInstead( - routes.getAnyFacility, - { - pathParams: { - id: filter.facility, - }, - prefetch: !!filter.facility, - onResponse: ({ data }) => { - setFilterState({ ...filterState, facility_ref: data }); - }, - }, - ); - - return ( - { - removeFilters(); - closeFilter(); - }} - > - { - return { id, text: text.replaceAll("_", " ") }; - })} - optionValue={(option) => option.id} - optionLabel={(option) => option.text} - labelClassName="text-sm" - errorClassName="hidden" - /> - - option.id} - optionLabel={(option) => option.text} - labelClassName="text-sm" - errorClassName="hidden" - /> - - option.id} - optionLabel={(option) => option.text} - labelClassName="text-sm" - errorClassName="hidden" - /> - -
- Facility -
- {isFacilityLoading ? ( - - ) : ( - - setFilterState({ - facility: (obj as FacilityModel)?.id, - facility_ref: obj, - }) - } - errors={""} - /> - )} -
-
-
- ); -} diff --git a/src/components/Patient/SamplePreview.tsx b/src/components/Patient/SamplePreview.tsx deleted file mode 100644 index 18862712533..00000000000 --- a/src/components/Patient/SamplePreview.tsx +++ /dev/null @@ -1,459 +0,0 @@ -import ButtonV2 from "@/components/Common/ButtonV2"; -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; - -import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import { classNames, formatDateTime, humanizeStrings } from "@/Utils/utils"; - -interface ISamplePreviewProps { - id: string; - sampleId: string; -} - -interface ISampleReportSectionProps { - title: string; - fields: { - title: string; - value: string | undefined | null; - }[]; -} - -function SampleReportSection({ title, fields }: ISampleReportSectionProps) { - return ( - <> -
-
{title}
-
-
- {fields.map((field, i) => ( -
-
-

- {field.title} -

-
-
-

- {field.value} -

-
-
- ))} -
- - ); -} - -export default function SampleReport(props: ISamplePreviewProps) { - const { id, sampleId } = props; - - let report: JSX.Element = <>; - let reportData: JSX.Element = <>; - - const { loading: isLoading, data: sampleData } = useTanStackQueryInstead( - routes.sampleReport, - { - pathParams: { - id, - sampleId, - }, - }, - ); - - if (sampleData) { - reportData = ( - <> -
- - Print Report - -
-
-
-
-
-
-
- Open HealthCare Network -
-
-
-
-
-

- ICMR Specimen Referral Data for COVID-19 (SARS-CoV2) -

-
-
-
-
- FOR INTERNAL USE ONLY -
-
-
-
-
Sample Id : {sampleId}
-
-
-
Patient Id : {id}
-
-
-
-
SECTION A - MANDATORY FIELDS
-
- - - - - { - switch (sampleData?.specimen_details?.icmr_category) { - case "Cat 0": - return "Repeat Sample of Positive Case / Follow Up case"; - case "Cat 1": - return "Symptomatic International Traveller in last 14 days"; - case "Cat 2": - return "Symptomatic contact of lab confirmed Case"; - case "Cat 3": - return "Symptomatic Healthcare Worker"; - case "Cat 4": - return "Hospitalized SARI (Severe Acute Respiratory illness Patient)"; - case "Cat 5a": - return "Asymptomatic Direct and High Risk contact of confirmed case - family Member"; - case "Cat 5b": - return "Asymptomatic Healthcare worker in contact with confimred case without adequete protection"; - } - })(), - }, - ]} - /> - -
-
- SECTION B - OTHER FIELDS TO BE UPDATED -
-
- - - - - - - - - - -
-
-
-
- - ); - } - if (isLoading) { - report = ( -
- -
- ); - } else if (sampleData && reportData) { - report = reportData; - } else if (!sampleData) { - report = ( -
-
No Data Found
-
- ); - } - return ( -
- - {report} - -
- ); -} diff --git a/src/components/Patient/SampleTest.tsx b/src/components/Patient/SampleTest.tsx deleted file mode 100644 index 7025faf407e..00000000000 --- a/src/components/Patient/SampleTest.tsx +++ /dev/null @@ -1,350 +0,0 @@ -import { navigate } from "raviger"; -import { useReducer, useState } from "react"; - -import { Cancel, Submit } from "@/components/Common/ButtonV2"; -import { FacilitySelect } from "@/components/Common/FacilitySelect"; -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; -import CheckBoxFormField from "@/components/Form/FormFields/CheckBoxFormField"; -import { FieldLabel } from "@/components/Form/FormFields/FormField"; -import { SelectFormField } from "@/components/Form/FormFields/SelectFormField"; -import TextAreaFormField from "@/components/Form/FormFields/TextAreaFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; -import { SampleTestModel } from "@/components/Patient/models"; - -import useAppHistory from "@/hooks/useAppHistory"; - -import { ICMR_CATEGORY, SAMPLE_TYPE_CHOICES } from "@/common/constants"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -const initForm: SampleTestModel = { - isFastTrack: false, - fast_track: "", - icmr_label: "", - atypical_presentation: "", - diagnosis: "", - diff_diagnosis: "", - doctor_name: "", - testing_facility: "", - etiology_identified: "", - has_ari: false, - has_sari: false, - is_atypical_presentation: false, - is_unusual_course: false, - sample_type: "0", - icmr_category: "Cat 0", - sample_type_other: "", -}; - -const initError = Object.assign( - {}, - ...Object.keys(initForm).map((k) => ({ [k]: "" })), -); - -const initialState = { - form: { ...initForm }, - errors: { ...initError }, -}; - -const sampleTestFormReducer = (state = initialState, action: any) => { - switch (action.type) { - case "set_form": { - return { - ...state, - form: action.form, - }; - } - case "set_error": { - return { - ...state, - errors: action.errors, - }; - } - default: - return state; - } -}; - -export const SampleTest = ({ facilityId, patientId }: any) => { - const { goBack } = useAppHistory(); - const [state, dispatch] = useReducer(sampleTestFormReducer, initialState); - const [isLoading, setIsLoading] = useState(false); - - const headerText = "Request Sample"; - const buttonText = "Confirm your request to send sample for testing"; - - const { data } = useTanStackQueryInstead(routes.getPatient, { - pathParams: { - id: patientId, - }, - prefetch: !!patientId, - }); - - const validateForm = () => { - const errors = { ...initError }; - let invalidForm = false; - Object.keys(state.form).forEach((field) => { - switch (field) { - case "fast_track": - if (state.form.isFastTrack && !state.form[field]) { - errors[field] = "Please provide reasons for fast-track testing"; - invalidForm = true; - } - break; - case "icmr_label": - if (!state.form[field]) { - errors[field] = "Please specify the label"; - invalidForm = true; - } - break; - case "sample_type_other": - if (state.form.sample_type === "9" && !state.form[field]) { - errors[field] = "Please provide details of the sample type"; - invalidForm = true; - } - break; - case "atypical_presentation": - if (state.form.is_atypical_presentation && !state.form[field]) { - errors[field] = "Please provide details of atypical presentation"; - invalidForm = true; - } - break; - default: - return; - } - }); - if (invalidForm) { - dispatch({ type: "set_error", errors }); - return false; - } - dispatch({ type: "set_error", errors }); - return true; - }; - - const handleSubmit = async (e: any) => { - e.preventDefault(); - const validForm = validateForm(); - if (validForm) { - setIsLoading(true); - const data: SampleTestModel = { - date_of_sample: new Date().toISOString(), - fast_track: state.form.isFastTrack ? state.form.fast_track : undefined, - icmr_label: state.form.icmr_label ? state.form.icmr_label : undefined, - facility: facilityId, - patient: patientId, - has_ari: state.form.has_ari, - has_sari: state.form.has_sari, - is_unusual_course: state.form.is_unusual_course, - is_atypical_presentation: state.form.is_atypical_presentation, - atypical_presentation: state.form.is_atypical_presentation - ? state.form.atypical_presentation - : undefined, - diagnosis: state.form.diagnosis ? state.form.diagnosis : undefined, - diff_diagnosis: state.form.diff_diagnosis - ? state.form.diff_diagnosis - : undefined, - testing_facility: state.form.testing_facility?.id, - doctor_name: state.form.doctor_name - ? state.form.doctor_name - : undefined, - etiology_identified: state.form.etiology_identified - ? state.form.etiology_identified - : undefined, - sample_type: state.form.sample_type, - icmr_category: state.form.icmr_category, - sample_type_other: - state.form.sample_type === "9" - ? state.form.sample_type_other - : undefined, - }; - - await request(routes.createSampleTest, { - pathParams: { - patientId, - }, - body: data, - onResponse: ({ res, data }) => { - setIsLoading(false); - if (res?.ok && data) { - dispatch({ type: "set_form", form: initForm }); - Notification.Success({ - msg: "Sample test created successfully", - }); - navigate(`/facility/${facilityId}/patient/${patientId}`); - } - }, - }); - } - }; - - const handleFormFieldChange = (e: FieldChangeEvent) => { - dispatch({ type: "set_form", form: { ...state.form, [e.name]: e.value } }); - }; - - const field = (name: string, label: string) => ({ - name, - label, - value: state.form[name], - onChange: handleFormFieldChange, - error: state.errors[name], - }); - - if (isLoading) { - return ; - } - return ( - - - option.text} - optionValue={(option) => option.id} - id="sample-type" - /> - - {state.form.sample_type === "9" && ( - - )} - - option} - optionValue={(option) => option} - id="icmr-category" - /> -
-

- Refer below to know more about ICMR Categories -

- -
  • Cat 0 - Repeat Sample of Positive Case / Follow Up case
  • -
  • Cat 1 - Symptomatic International Traveller in last 14 days
  • -
  • Cat 2 - Symptomatic contact of lab confirmed Case
  • -
  • Cat 3 - Symptomatic Healthcare Worker
  • -
  • - Cat 4 - Hospitalized SARI (Severe Acute Respiratory illness - Patient) -
  • -
  • - Cat 5a - Asymptomatic Direct and High Risk contact of confirmed - case - family Member -
  • -
  • - Cat 5b - Asymptomatic Healthcare worker in contact with confirmed - case without adequate protection -
  • -
    -
    - - -
    - Testing Facility - - dispatch({ - type: "set_form", - form: { ...state.form, testing_facility: selected }, - }) - } - facilityType={950} - selected={state.form.testing_facility} - errors={state.errors.testing_facility} - showAll - multiple={false} - /> -
    - - {state.form.isFastTrack && ( - - )} - - - - {state.form.is_atypical_presentation && ( -
    - -
    - )} - - - - - - - -
    - goBack()} /> - -
    - -
    - ); -}; diff --git a/src/components/Patient/SampleTestCard.tsx b/src/components/Patient/SampleTestCard.tsx deleted file mode 100644 index f1d59980c23..00000000000 --- a/src/components/Patient/SampleTestCard.tsx +++ /dev/null @@ -1,227 +0,0 @@ -import { navigate } from "raviger"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import RelativeDateUserMention from "@/components/Common/RelativeDateUserMention"; -import UpdateStatusDialog from "@/components/Patient/UpdateStatusDialog"; -import { SampleTestModel } from "@/components/Patient/models"; - -import { SAMPLE_TEST_STATUS } from "@/common/constants"; - -import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import { formatDateTime } from "@/Utils/utils"; - -interface SampleDetailsProps { - facilityId: string; - patientId: string; - itemData: SampleTestModel; - refetch: () => void; - handleApproval: (status: number, sample: SampleTestModel) => void; -} - -export const SampleTestCard = (props: SampleDetailsProps) => { - const { t } = useTranslation(); - const { itemData, handleApproval, facilityId, patientId, refetch } = props; - - const [statusDialog, setStatusDialog] = useState<{ - show: boolean; - sample: SampleTestModel; - }>({ show: false, sample: {} }); - - const handleApproval1 = async ( - sample: SampleTestModel, - status: number, - result: number, - ) => { - const sampleData: any = { - id: sample.id, - status, - consultation: sample.consultation, - }; - if (status === 7) { - sampleData.result = result; - sampleData.date_of_result = new Date().toISOString(); - } - const statusName = SAMPLE_TEST_STATUS.find((i) => i.id === status)?.desc; - await request(routes.patchSample, { - pathParams: { - id: sample.id!, - }, - body: sampleData, - onResponse: ({ res }) => { - if (res?.ok) { - refetch(); - Notification.Success({ - msg: `Success - ${statusName}`, - }); - } - dismissUpdateStatus(); - }, - }); - }; - - const showUpdateStatus = (sample: SampleTestModel) => { - setStatusDialog({ - show: true, - sample, - }); - }; - - const dismissUpdateStatus = () => { - setStatusDialog({ - show: false, - sample: {}, - }); - }; - - return ( -
    -
    - navigate( - `/facility/${facilityId}/patient/${patientId}/sample/${itemData.id}`, - ) - } - className="ml-2 mt-2 grid grid-cols-1 gap-4 md:grid-cols-4" - > -
    -
    -
    - Status{" "} -
    -
    - {t(`SAMPLE_TEST_HISTORY__${itemData.status}`) || "Unknown"} -
    -
    -
    -
    -
    -
    - Sample Type{" "} -
    -
    - {itemData.sample_type?.toLowerCase()} -
    -
    -
    - {itemData.fast_track && ( -
    -
    -
    - Fast-Track{" "} -
    -
    - {itemData.fast_track} -
    -
    -
    - )} -
    -
    -
    - Result{" "} -
    -
    - {t(`SAMPLE_TEST_RESULT__${itemData.result}`) || "Unknown"} -
    -
    -
    -
    -
    -
    -
    -
    - Date of Sample:{" "} - {itemData.date_of_sample - ? formatDateTime(itemData.date_of_sample) - : "Not Available"} -
    -
    - Date of Result:{" "} - {itemData.date_of_result - ? formatDateTime(itemData.date_of_result) - : "Not Available"} -
    -
    -
    -
    -
    -
    Created:
    - - -
    -
    -
    Last Modified:
    - -
    -
    -
    -
    - {itemData.status === "APPROVED" && ( - { - e.stopPropagation(); - handleApproval(4, itemData); - }} - className="border border-secondary-500 bg-white text-black hover:bg-secondary-300" - > - Send to Collection Centre - - )} - showUpdateStatus(itemData)} - className="border border-secondary-500 bg-white text-black hover:bg-secondary-300" - authorizeFor={NonReadOnlyUsers} - > - Update Sample Test Status - - navigate(`/sample/${itemData.id}`)} - className="border border-secondary-500 bg-white text-black hover:bg-secondary-300" - > - Sample Report - -
    - {statusDialog.show && ( - - )} -
    - ); -}; diff --git a/src/components/Patient/SampleViewAdmin.tsx b/src/components/Patient/SampleViewAdmin.tsx deleted file mode 100644 index cf86b582dd8..00000000000 --- a/src/components/Patient/SampleViewAdmin.tsx +++ /dev/null @@ -1,423 +0,0 @@ -import { navigate } from "raviger"; -import { useState } from "react"; - -import CountBlock from "@/CAREUI/display/Count"; -import CareIcon from "@/CAREUI/icons/CareIcon"; -import { AdvancedFilterButton } from "@/CAREUI/interactive/FiltersSlideover"; - -import { ExportButton } from "@/components/Common/Export"; -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; -import SearchInput from "@/components/Form/SearchInput"; -import SampleFilter from "@/components/Patient/SampleFilters"; -import UpdateStatusDialog from "@/components/Patient/UpdateStatusDialog"; -import { SampleTestModel } from "@/components/Patient/models"; - -import useFilters from "@/hooks/useFilters"; - -import { - SAMPLE_FLOW_RULES, - SAMPLE_TEST_RESULT, - SAMPLE_TEST_STATUS, - SAMPLE_TYPE_CHOICES, -} from "@/common/constants"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import { formatDateTime } from "@/Utils/utils"; - -export default function SampleViewAdmin() { - const { - qParams, - updateQuery, - Pagination, - FilterBadges, - advancedFilter, - resultsPerPage, - } = useFilters({ - limit: 10, - cacheBlacklist: ["patient_name", "district_name"], - }); - let manageSamples: any = null; - const [statusDialog, setStatusDialog] = useState<{ - show: boolean; - sample: SampleTestModel; - }>({ show: false, sample: {} }); - - const { data: facilityData } = useTanStackQueryInstead( - routes.getAnyFacility, - { - pathParams: { - id: qParams.facility, - }, - prefetch: !!qParams.facility, - }, - ); - - const { - loading: isLoading, - data: sampeleData, - refetch, - } = useTanStackQueryInstead(routes.getTestSampleList, { - query: { - limit: resultsPerPage, - offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage, - patient_name: qParams.patient_name || undefined, - district_name: qParams.district_name || undefined, - status: qParams.status || undefined, - result: qParams.result || undefined, - facility: qParams.facility || undefined, - sample_type: qParams.sample_type || undefined, - }, - }); - - const handleApproval = async ( - sample: SampleTestModel, - status: number, - result: number, - ) => { - const sampleData: any = { - id: sample.id, - status, - consultation: sample.consultation, - }; - if (status === 7) { - sampleData.result = result; - sampleData.date_of_result = new Date().toISOString(); - } - const statusName = SAMPLE_TEST_STATUS.find((i) => i.id === status)?.desc; - - await request(routes.patchSample, { - pathParams: { - id: sample.id || 0, - }, - body: sampleData, - onResponse: ({ res }) => { - if (res?.ok) { - Notification.Success({ - msg: `Success - ${statusName}`, - }); - refetch(); - } - dismissUpdateStatus(); - }, - }); - }; - - const showUpdateStatus = (sample: SampleTestModel) => { - setStatusDialog({ - show: true, - sample, - }); - }; - - const dismissUpdateStatus = () => { - setStatusDialog({ - show: false, - sample: {}, - }); - }; - - const parseExportData = (data: string) => { - const [header, ...rows] = data.trim().split("\n"); - const headerColumns = header.split(",").map((col) => col.trim()); - - return [ - header, - ...rows.map((row) => { - const columns = row.split(",").map((field, index) => { - const header = headerColumns[index]; - - if (header === "Patient Age") { - return field.trim(); - } - - if (["Date of Sample", "Date of Result"].includes(header)) { - const formattedDate = formatDateTime(field.trim()); - return formattedDate === "Invalid Date" ? "" : formattedDate; - } - return field.includes(",") ? `"${field.trim()}"` : field.trim(); - }); - - return columns.join(","); - }), - ].join("\n"); - }; - - let sampleList: any[] = []; - if (sampeleData?.count) { - sampleList = sampeleData.results.map((item) => { - const status = String(item.status) as keyof typeof SAMPLE_FLOW_RULES; - const statusText = SAMPLE_TEST_STATUS.find( - (i) => i.text === status, - )?.desc; - return ( -
    -
    -
    -
    -
    -
    - {item.patient_name} -
    -
    - {item.sample_type && ( - - Type: {item.sample_type} - - )} -
    -
    - {item.result !== "AWAITING" && ( -
    - - Result:{" "} - - {item.result ? item.result.toLocaleLowerCase() : "-"} -
    - )} -
    - - Status:{" "} - - {statusText} -
    - {item.facility_object && ( -
    - - Facility:{" "} - - {item.facility_object.name} -
    - )} - {item.fast_track && ( -
    - - Fast track:{" "} - - {item.fast_track} -
    - )} - {item.patient_has_confirmed_contact && ( -
    - - Contact:{" "} - - Confirmed carrier - -
    - )} - {item.patient_has_suspected_contact && - !item.patient_has_confirmed_contact && ( -
    - - Contact:{" "} - - Suspected carrier - -
    - )} - {item.has_sari && ( -
    - - SARI:{" "} - - Severe Acute Respiratory illness - -
    - )} - {item.has_ari && !item.has_sari && ( -
    - ARI: - Acute Respiratory illness - -
    - )} -
    - -
    -
    - Date of Sample:{" "} - {item.date_of_sample - ? formatDateTime(item.date_of_sample) - : "Not Available"} -
    - -
    - Date of Result:{" "} - {item.date_of_result - ? formatDateTime(item.date_of_result) - : "Not Available"} -
    -
    - -
    - {item.result === "AWAITING" && ( -
    - -
    - )} - - -
    -
    -
    -
    - ); - }); - } - - if (isLoading || !sampeleData) { - manageSamples = ( -
    - -
    - ); - } else if (sampeleData?.count) { - manageSamples = ( - <> - {sampleList} - - - ); - } else if (sampeleData?.count === 0) { - manageSamples = ( -
    -
    - No Sample Tests Found -
    -
    - ); - } - - return ( - { - const { data } = await request(routes.getTestSampleList, { - query: { ...qParams, csv: true }, - }); - return data ?? null; - }} - parse={parseExportData} - filenamePrefix="samples" - /> - } - > - {statusDialog.show && ( - - )} -
    -
    -
    - -
    - -
    - updateQuery({ [e.name]: e.value })} - placeholder="Search patient" - /> - updateQuery({ [e.name]: e.value })} - placeholder="Search by district" - secondary - /> -
    - - advancedFilter.setShow(true)} /> - -
    - [ - badge("Patient Name", "patient_name"), - badge("District Name", "district_name"), - value( - "Status", - "status", - SAMPLE_TEST_STATUS.find( - (status) => status.id == qParams.status, - )?.text.replaceAll("_", " ") || "", - ), - value( - "Result", - "result", - SAMPLE_TEST_RESULT.find((result) => result.id == qParams.result) - ?.text || "", - ), - value( - "Sample Test Type", - "sample_type", - SAMPLE_TYPE_CHOICES.find( - (type) => type.id === qParams.sample_type, - )?.text || "", - ), - value( - "Facility", - "facility", - qParams.facility ? facilityData?.name || "" : "", - ), - ]} - /> -
    -
    -
    {manageSamples}
    -
    -
    - ); -} diff --git a/src/components/Patient/UpdateStatusDialog.tsx b/src/components/Patient/UpdateStatusDialog.tsx deleted file mode 100644 index e9a767847aa..00000000000 --- a/src/components/Patient/UpdateStatusDialog.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { useEffect, useReducer } from "react"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Button } from "@/components/ui/button"; - -import ConfirmDialog from "@/components/Common/ConfirmDialog"; -import { LinearProgressWithLabel } from "@/components/Files/FileUpload"; -import CheckBoxFormField from "@/components/Form/FormFields/CheckBoxFormField"; -import { SelectFormField } from "@/components/Form/FormFields/SelectFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; - -import useFileUpload from "@/hooks/useFileUpload"; - -import { - SAMPLE_FLOW_RULES, - SAMPLE_TEST_RESULT, - SAMPLE_TEST_STATUS, -} from "@/common/constants"; - -import * as Notification from "@/Utils/Notifications"; - -import { SampleTestModel } from "./models"; - -interface Props { - sample: SampleTestModel; - handleOk: (sample: SampleTestModel, status: number, result: number) => void; - handleCancel: () => void; -} - -const statusChoices = [...SAMPLE_TEST_STATUS]; -const statusFlow = { ...SAMPLE_FLOW_RULES }; - -const initForm: any = { - confirm: false, - status: 0, - result: 0, - disabled: true, -}; - -const initialState = { - form: { ...initForm }, -}; - -const updateStatusReducer = (state = initialState, action: any) => { - switch (action.type) { - case "set_form": { - return { - ...state, - form: action.form, - }; - } - default: - return state; - } -}; -const UpdateStatusDialog = (props: Props) => { - const { t } = useTranslation(); - const { sample, handleOk, handleCancel } = props; - const [state, dispatch] = useReducer(updateStatusReducer, initialState); - - const fileUpload = useFileUpload({ - type: "SAMPLE_MANAGEMENT", - allowedExtensions: ["pdf", "jpg", "jpeg", "png"], - allowNameFallback: true, - }); - const currentStatus = SAMPLE_TEST_STATUS.find( - (i) => i.text === sample.status, - ); - - const status = String(sample.status) as keyof typeof SAMPLE_FLOW_RULES; - const validStatusChoices = statusChoices.filter( - (i) => status && statusFlow[status] && statusFlow[status].includes(i.text), - ); - - useEffect(() => { - const form = { ...state.form }; - form.status = 0; - dispatch({ type: "set_form", form }); - }, []); - - const okClicked = () => { - handleOk(sample, state.form.status, state.form.result); - dispatch({ type: "set_form", form: initForm }); - }; - - const cancelClicked = () => { - handleCancel(); - dispatch({ type: "set_form", form: initForm }); - }; - - const handleChange = ({ name, value }: FieldChangeEvent) => { - const form = { ...state.form }; - form[name] = name === "status" || name === "result" ? Number(value) : value; - form.disabled = - !form.status || !form.confirm || (form.status === 7 && !form.result); - dispatch({ type: "set_form", form }); - }; - - const handleUpload = async () => { - if (fileUpload.files.length > 0) { - if (!fileUpload.fileNames[0]) { - Notification.Error({ - msg: "Please enter a file name before uploading", - }); - return; - } - if (sample.id) { - await fileUpload.handleFileUpload(sample.id); - if (!fileUpload.error) { - return; - } else { - Notification.Error({ msg: `Upload failed: ${fileUpload.error}` }); - } - } else { - Notification.Error({ msg: "Sample ID is missing" }); - } - } else { - Notification.Error({ msg: "No file selected for upload" }); - } - }; - - return ( - -
    - - i.desc} - optionValue={(i) => i.id} - onChange={handleChange} - /> - {Number(state.form.status) === 7 && ( - <> - i.text} - optionValue={(i) => i.id} - onChange={handleChange} - /> - - {t("upload_report")}: - - {fileUpload.files[0] ? ( -
    -
    - - - {fileUpload.files[0].name} - -
    - fileUpload.setFileName(e.value)} - error={fileUpload.error || undefined} - required - /> -
    - - -
    - {!!fileUpload.progress && ( - - )} -
    - ) : ( -
    - -
    - )} - - )} - -
    -
    - ); -}; - -export default UpdateStatusDialog; diff --git a/src/components/Patient/models.tsx b/src/components/Patient/models.tsx index 2b1c3c84d0c..dc3a0f5f681 100644 --- a/src/components/Patient/models.tsx +++ b/src/components/Patient/models.tsx @@ -143,137 +143,6 @@ export interface PatientModel { age?: string; } -export interface SampleTestModel { - patient_object?: PatientModel; - atypical_presentation?: string; - diagnosis?: string; - diff_diagnosis?: string; - testing_facility?: string; - doctor_name?: string; - etiology_identified?: string; - has_ari?: boolean; - has_sari?: boolean; - is_atypical_presentation?: boolean; - is_unusual_course?: boolean; - sample_type?: string; - sample_type_other?: string; - id?: string; - status?: string; - result?: string; - icmr_category?: string; - icmr_label?: string; - date_of_sample?: string; - date_of_result?: string; - consultation?: number; - patient_name?: string; - patient_has_sari?: boolean; - patient_has_confirmed_contact?: boolean; - patient_has_suspected_contact?: boolean; - patient_travel_history?: string[]; - facility?: number; - facility_object?: { - id: number; - name: string; - facility_type?: { id: number; name: string }; - }; - patient?: number; - fast_track?: string; - isFastTrack?: boolean; - flow?: Array; - created_by?: any; - last_edited_by?: any; - created_date?: string; - modified_date?: string; -} - -export interface SampleReportModel { - id?: number; - personal_details?: { - name?: string; - gender?: string; - age_years?: number; - age_months?: number; - date_of_birth?: string; - phone_number?: string; - email?: string; - address?: string; - pincode?: string; - passport_no?: string; - aadhaar_no?: string; - local_body_name?: string; - district_name?: string; - state_name?: string; - }; - specimen_details?: { - created_date?: string; - sample_type?: string; - collection_type?: string; - icmr_category?: string; - icmr_label?: string; - is_repeated_sample?: boolean; - lab_name?: string; - lab_pincode?: string; - }; - patient_category?: { - symptomatic_international_traveller?: boolean; - symptomatic_contact_of_confirmed_case?: boolean; - symptomatic_healthcare_worker?: boolean; - hospitalized_sari_patient?: boolean; - asymptomatic_family_member_of_confirmed_case?: boolean; - asymptomatic_healthcare_worker_without_protection?: boolean; - }; - exposure_history?: { - has_travel_to_foreign_last_14_days?: boolean; - places_of_travel?: Array; - travel_start_date?: string; - travel_end_date?: string; - contact_with_confirmed_case?: boolean; - contact_case_name?: string; - was_quarantined?: boolean; - quarantined_type?: string; - healthcare_worker?: boolean; - }; - medical_conditions?: { - date_of_onset_of_symptoms?: string; - symptoms?: Array; - has_sari?: boolean; - has_ari?: boolean; - medical_conditions_list?: Array; - hospitalization_date?: string; - diagnosis?: string; - diff_diagnosis?: string; - etiology_identified?: string; - is_atypical_presentation?: boolean; - is_unusual_course?: boolean; - hospital_phone_number?: string; - hospital_name?: string; - doctor_name?: string; - hospital_pincode?: string; - }; -} - -export interface SampleListModel { - id?: number; - patient_name?: string; - patient_has_sari?: boolean; - patient_has_confirmed_contact?: boolean; - patient_has_suspected_contact?: boolean; - patient_travel_history?: string; - facility?: number; - facility_object?: { - id: number; - name: string; - facility_type?: { id: number; name: string }; - }; - status?: string; - result?: string; - patient?: number; - consultation?: number; - date_of_sample?: string; - date_of_result?: string; - fast_track?: string; -} - export const DailyRoundTypes = [ "NORMAL", "COMMUNITY_NURSES_LOG", diff --git a/src/hooks/useActiveLink.ts b/src/hooks/useActiveLink.ts index b52b15600dd..609a518bc6d 100644 --- a/src/hooks/useActiveLink.ts +++ b/src/hooks/useActiveLink.ts @@ -12,7 +12,6 @@ const activeLinkPriority = { "/patient/": "/patients", "/death_report": "/patients", "/assets": "/assets", - "/sample": "/sample", "/shifting": "/shifting", "/resource": "/resource", "/users": "/users", From b1470271e66b0af5e7fc6e1ac991b021cb51cec7 Mon Sep 17 00:00:00 2001 From: Bodhish Thomas Date: Sun, 15 Dec 2024 22:33:18 +0530 Subject: [PATCH 08/31] Cleanup capacity related fields from facility (#9436) Co-authored-by: rithviknishad Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- .../e2e/facility_spec/FacilityCreation.cy.ts | 374 ++------- .../e2e/facility_spec/FacilityHomepage.cy.ts | 18 - .../e2e/facility_spec/FacilityManage.cy.ts | 64 -- .../e2e/patient_spec/PatientHomepage.cy.ts | 4 - .../e2e/resource_spec/ResourcesHomepage.cy.ts | 8 +- .../pageobject/Facility/FacilityCreation.ts | 269 +----- cypress/pageobject/Facility/FacilityHome.ts | 7 +- cypress/pageobject/Facility/FacilityManage.ts | 34 - cypress/pageobject/Resource/ResourcePage.ts | 4 + cypress/pageobject/utils/constants.ts | 116 ++- cypress/support/commands.ts | 18 + cypress/support/index.ts | 5 + package-lock.json | 8 +- package.json | 2 +- src/Routers/routes/FacilityRoutes.tsx | 7 - src/Utils/request/api.tsx | 109 +-- src/components/ExternalResult/models.ts | 18 - src/components/Facility/BedCapacity.tsx | 301 ------- src/components/Facility/BedTypeCard.tsx | 181 ---- .../Facility/FacilityBedCapacity.tsx | 126 --- src/components/Facility/FacilityCreate.tsx | 776 +++++------------- src/components/Facility/FacilityHome.tsx | 47 +- .../Facility/FacilityHomeTriage.tsx | 89 -- src/components/Facility/FacilityList.tsx | 35 +- src/components/Facility/FacilityStaffList.tsx | 138 ---- src/components/Facility/StaffCapacity.tsx | 241 ------ src/components/Facility/StaffCountCard.tsx | 118 --- src/components/Facility/TriageForm.tsx | 321 -------- src/components/Facility/models.tsx | 33 - src/components/Patient/PatientRegister.tsx | 4 +- 30 files changed, 459 insertions(+), 3016 deletions(-) delete mode 100644 src/components/ExternalResult/models.ts delete mode 100644 src/components/Facility/BedCapacity.tsx delete mode 100644 src/components/Facility/BedTypeCard.tsx delete mode 100644 src/components/Facility/FacilityBedCapacity.tsx delete mode 100644 src/components/Facility/FacilityHomeTriage.tsx delete mode 100644 src/components/Facility/FacilityStaffList.tsx delete mode 100644 src/components/Facility/StaffCapacity.tsx delete mode 100644 src/components/Facility/StaffCountCard.tsx delete mode 100644 src/components/Facility/TriageForm.tsx diff --git a/cypress/e2e/facility_spec/FacilityCreation.cy.ts b/cypress/e2e/facility_spec/FacilityCreation.cy.ts index f644c9829d3..d2893166745 100644 --- a/cypress/e2e/facility_spec/FacilityCreation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityCreation.cy.ts @@ -1,20 +1,25 @@ -import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; +import { + generateFacilityName, + generatePhoneNumber, + generateRandomAddress, +} from "pageobject/utils/constants"; import FacilityPage, { FacilityData, } from "../../pageobject/Facility/FacilityCreation"; -import FacilityHome from "../../pageobject/Facility/FacilityHome"; import LoginPage from "../../pageobject/Login/LoginPage"; -import ManageUserPage from "../../pageobject/Users/ManageUserPage"; import { nonAdminRoles } from "../../pageobject/utils/userConfig"; -describe("Facility Creation", () => { - let facilityUrl1: string; +describe("Facility Creation with multiple user roles", () => { const facilityPage = new FacilityPage(); const loginPage = new LoginPage(); - const facilityHome = new FacilityHome(); - const manageUserPage = new ManageUserPage(); - const facilityFeature = [ + const facilityName = generateFacilityName(); + const facilityNumber = generatePhoneNumber(); + const facilityAddress = generateRandomAddress(false); + const facilityUpdatedNumber = generatePhoneNumber(); + const facilityUpdatedName = generateFacilityName(); + const facilityUpdatedAddress = generateRandomAddress(true); + const facilityFeatures = [ "CT Scan", "X-Ray", "Maternity Care", @@ -22,22 +27,6 @@ describe("Facility Creation", () => { "Operation Theater", "Blood Bank", ]; - const bedCapacity = "10"; - const bedOccupancy = "5"; - const oxygenCapacity = "100"; - const oxygenExpected = "80"; - const totalCapacity = "20"; - const totalOccupancy = "10"; - const doctorCapacity = "5"; - const totalDoctor = "10"; - const facilityName = "Cypress Facility"; - const facilityName2 = "Dummy Facility 40"; - const facilityAddress = "cypress address"; - const facilityUpdateAddress = "cypress updated address"; - const facilityNumber = "9898469865"; - const triageDate = "02122023"; - const initialTriageValue = "60"; - const modifiedTriageValue = "50"; const facilityErrorMessage = [ "Required", "Required", @@ -50,22 +39,11 @@ describe("Facility Creation", () => { "Required", "Invalid Phone Number", ]; - const bedErrorMessage = [ - "This field is required", - "Total capacity cannot be 0", - "This field is required", - ]; - const doctorErrorMessage = [ - "This field is required", - "This field is required", - ]; - const triageErrorMessage = ["This field is required"]; const facilityType = "Primary Health Centres"; const testFacilityData: FacilityData = { basic: { name: facilityName, type: facilityType, - features: facilityFeature, address: facilityAddress, phoneNumber: facilityNumber, location: "Kochi, Kerala", @@ -77,44 +55,6 @@ describe("Facility Creation", () => { localBody: "Aluva", ward: "4", }, - oxygen: { - capacity: oxygenCapacity, - expected: oxygenExpected, - bType: { - capacity: oxygenCapacity, - expected: oxygenExpected, - }, - cType: { - capacity: oxygenCapacity, - expected: oxygenExpected, - }, - dType: { - capacity: oxygenCapacity, - expected: oxygenExpected, - }, - }, - beds: [ - { - type: "Oxygen Supported Bed", - totalCapacity: bedCapacity, - occupied: bedOccupancy, - }, - { - type: "Ordinary Bed", - totalCapacity: bedCapacity, - occupied: bedOccupancy, - }, - ], - doctors: [ - { - specialization: "General Medicine", - count: doctorCapacity, - }, - { - specialization: "Pulmonology", - count: doctorCapacity, - }, - ], }; before(() => { @@ -128,262 +68,72 @@ describe("Facility Creation", () => { cy.awaitUrl("/facility"); }); - it("Verify Facility Triage Function", () => { - // mandatory field error throw - facilityHome.typeFacilitySearch(facilityName2); - advanceFilters.verifyFilterBadgePresence( - "Facility/District Name", - facilityName2, - true, - ); - facilityHome.assertFacilityInCard(facilityName2); - facilityHome.verifyURLContains(facilityName2); - facilityPage.visitAlreadyCreatedFacility(); - facilityPage.scrollToFacilityTriage(); - facilityPage.clickAddFacilityTriage(); - manageUserPage.clickSubmit(); - cy.verifyErrorMessages(triageErrorMessage); - // create a entry and verify reflection - facilityPage.fillEntryDate(triageDate); - facilityPage.fillTriageEntryFields( - initialTriageValue, - initialTriageValue, - initialTriageValue, - initialTriageValue, - initialTriageValue, - ); - manageUserPage.clickSubmit(); - // edit the entry and verify reflection - facilityPage.scrollToFacilityTriage(); - facilityPage.verifyTriageTableContains(initialTriageValue); - facilityPage.clickEditButton(); - facilityPage.fillTriageEntryFields( - modifiedTriageValue, - modifiedTriageValue, - modifiedTriageValue, - modifiedTriageValue, - modifiedTriageValue, - ); - manageUserPage.clickSubmit(); - facilityPage.scrollToFacilityTriage(); - facilityPage.verifyTriageTableContains(modifiedTriageValue); - // validate error of filling data on same date already data exist and verify reflection - facilityPage.scrollToFacilityTriage(); - facilityPage.clickAddFacilityTriage(); - facilityPage.fillEntryDate(triageDate); - facilityPage.clickButtonsMultipleTimes("button#submit"); - }); - - it("Create a new facility with multiple bed and doctor capacity", () => { - // create facility with multiple capacity and verify form error message for facility form + it("Create a new facility with all fields | Edit Existing Data | Verify its reflection", () => { + // Create a new facility facilityPage.visitCreateFacilityPage(); - facilityPage.submitForm(); - cy.verifyErrorMessages(facilityErrorMessage); - facilityPage.fillBasicDetails(testFacilityData.basic); + facilityPage.fillBasicDetails({ + ...testFacilityData.basic, + features: facilityFeatures, + }); facilityPage.fillLocationDetails(testFacilityData.location); - facilityPage.fillOxygenDetails(testFacilityData.oxygen); - facilityPage.submitForm(); - cy.closeNotification(); - // add the bed capacity - facilityPage.selectBedType("Oxygen Supported Bed"); - facilityPage.fillTotalCapacity(bedCapacity); - facilityPage.fillCurrentlyOccupied(bedOccupancy); - facilityPage.clickbedcapcityaddmore(); - cy.closeNotification(); - facilityPage.selectBedType("Ordinary Bed"); - facilityPage.fillTotalCapacity(bedCapacity); - facilityPage.fillCurrentlyOccupied(bedOccupancy); - facilityPage.clickbedcapcityaddmore(); - cy.closeNotification(); - facilityPage.getTotalBedCapacity().contains(totalCapacity); - facilityPage.getTotalBedCapacity().contains(totalOccupancy); - facilityPage.clickcancelbutton(); - // create multiple bed capacity and verify card reflection - facilityPage.selectAreaOfSpecialization("General Medicine"); - facilityPage.fillDoctorCount(doctorCapacity); - facilityPage.clickdoctorcapacityaddmore(); - cy.closeNotification(); - facilityPage.selectAreaOfSpecialization("Pulmonology"); - facilityPage.fillDoctorCount(doctorCapacity); - facilityPage.clickdoctorcapacityaddmore(); - cy.closeNotification(); - facilityPage.getTotalDoctorCapacity().contains(doctorCapacity); - facilityPage.clickcancelbutton(); - facilityPage.verifyfacilitynewurl(); - // verify the facility card - facilityPage.getFacilityName().contains(facilityName).should("be.visible"); - facilityPage - .getAddressDetailsView() - .contains(facilityAddress) - .should("be.visible"); - facilityPage - .getPhoneNumberView() - .contains(facilityNumber) - .should("be.visible"); - facilityPage - .getFacilityAvailableFeatures() - .invoke("text") - .then((text) => { - facilityFeature.forEach((feature) => { - expect(text).to.contain(feature); - }); - }); - facilityPage.getFacilityOxygenInfo().scrollIntoView(); - facilityPage - .getFacilityOxygenInfo() - .contains(oxygenCapacity) - .should("be.visible"); - facilityPage.getFacilityTotalBedCapacity().scrollIntoView(); - facilityPage.getFacilityTotalBedCapacity().contains(totalCapacity); - facilityPage.getFacilityTotalBedCapacity().contains(totalOccupancy); - facilityPage.getFacilityTotalDoctorCapacity().scrollIntoView(); - facilityPage.getFacilityTotalDoctorCapacity().contains(totalDoctor); - // verify the delete functionality - cy.get("#manage-facility-dropdown button").scrollIntoView(); - facilityPage.clickManageFacilityDropdown(); - facilityPage.clickDeleteFacilityOption(); - facilityPage.confirmDeleteFacility(); - cy.verifyNotification("Facility deleted successfully"); - }); - - it("Create a new facility with single bed and doctor capacity", () => { - const singleCapacityData = { - ...testFacilityData, - // Remove features, location, and oxygen that aren't used in this test - basic: { - ...testFacilityData.basic, - features: undefined, - location: undefined, - }, - oxygen: undefined, - // Override with single bed capacity - beds: [ - { - type: "Oxygen Supported Bed", - totalCapacity: oxygenCapacity, - occupied: oxygenExpected, - }, - ], - // Override with single doctor capacity - doctors: [ - { - specialization: "General Medicine", - count: doctorCapacity, - }, - ], - }; - facilityPage.createNewFacility(singleCapacityData); - // verify the created facility details - facilityPage.getFacilityName().contains(facilityName).should("be.visible"); - facilityPage - .getAddressDetailsView() - .contains(facilityAddress) - .should("be.visible"); - facilityPage - .getPhoneNumberView() - .contains(facilityNumber) - .should("be.visible"); - // verify the facility homepage - facilityHome.navigateToFacilityHomepage(); - facilityHome.typeFacilitySearch(facilityName); - advanceFilters.verifyFilterBadgePresence( - "Facility/District Name", + facilityPage.selectLocation("Kochi, Kerala"); + facilityPage.clickSaveFacilityButton(); + facilityPage.verifyFacilityCreatedNotification(); + // verify the facility card info + cy.verifyContentPresence("#facility-details-card", [ facilityName, - true, - ); - facilityHome.assertFacilityInCard(facilityName); - facilityHome.verifyURLContains(facilityName); - }); - - it("Create a new facility with no bed and doctor capacity", () => { - const noCapacityData = { - ...testFacilityData, - basic: { - ...testFacilityData.basic, - features: undefined, - location: undefined, - }, - oxygen: undefined, - beds: [], - doctors: [], - }; - facilityPage.visitCreateFacilityPage(); - facilityPage.fillBasicDetails(noCapacityData.basic); - facilityPage.fillLocationDetails(noCapacityData.location); - facilityPage.submitForm(); - // add no bed capacity and verify form error message - facilityPage.isVisibleselectBedType(); - facilityPage.saveAndExitBedCapacityForm(); - cy.verifyErrorMessages(bedErrorMessage); - facilityPage.clickcancelbutton(); - // add no doctor capacity and verify form error message - facilityPage.isVisibleAreaOfSpecialization(); - facilityPage.clickdoctorcapacityaddmore(); - cy.verifyErrorMessages(doctorErrorMessage); - facilityPage.clickcancelbutton(); - cy.url().then((newUrl) => { - facilityUrl1 = newUrl; - }); - // verify the created facility details - facilityPage.getFacilityName().contains(facilityName).should("be.visible"); - facilityPage - .getAddressDetailsView() - .contains(facilityAddress) - .should("be.visible"); - facilityPage - .getPhoneNumberView() - .contains(facilityNumber) - .should("be.visible"); - }); - - it("Update the existing facility", () => { - // update a existing dummy data facility - facilityPage.visitUpdateFacilityPage(facilityUrl1); + facilityAddress, + facilityNumber, + ]); + // Edit the facility data facilityPage.clickManageFacilityDropdown(); facilityPage.clickUpdateFacilityOption(); - facilityPage.selectFacilityType(facilityType); - facilityPage.fillAddress(facilityUpdateAddress); - facilityPage.fillOxygenCapacity(oxygenCapacity); - facilityPage.fillExpectedOxygenRequirement(oxygenExpected); - facilityPage.selectLocation("Kochi, Kerala"); - facilityPage.submitForm(); - cy.url().should("not.include", "/update"); - // verify the updated data - facilityPage.getFacilityOxygenInfo().scrollIntoView(); - facilityPage - .getFacilityOxygenInfo() - .contains(oxygenCapacity) - .should("be.visible"); - facilityPage.getAddressDetailsView().scrollIntoView(); - facilityPage - .getAddressDetailsView() - .contains(facilityUpdateAddress) - .should("be.visible"); + facilityPage.typeFacilityName(facilityUpdatedName, true); + facilityPage.typeFacilityPhoneNumber(facilityUpdatedNumber, true); + facilityPage.typeFacilityAddress(facilityUpdatedAddress, true); + facilityPage.clickUpdateFacilityButton(); + facilityPage.verifyFacilityUpdatedNotification(); + // verify the facility card updated info + cy.verifyContentPresence("#facility-details-card", [ + facilityUpdatedName, + facilityUpdatedAddress, + facilityUpdatedNumber, + ]); }); - it("Configure the existing facility", () => { - facilityPage.visitUpdateFacilityPage(facilityUrl1); + it("Create a new facility with only mandatory fields | Delete the facility", () => { + // Create a new facility + facilityPage.visitCreateFacilityPage(); + facilityPage.fillBasicDetails(testFacilityData.basic); + facilityPage.fillLocationDetails(testFacilityData.location); + facilityPage.clickSaveFacilityButton(); + facilityPage.verifyFacilityCreatedNotification(); + // verify the facility card info + cy.verifyContentPresence("#facility-details-card", [ + facilityName, + facilityAddress, + facilityNumber, + ]); + // verify the delete facility functionality facilityPage.clickManageFacilityDropdown(); - facilityPage.clickConfigureFacilityOption(); - facilityPage.fillMiddleWareAddress("dev_middleware.coronasafe.live"); - facilityPage.clickupdateMiddleWare(); - facilityPage.verifySuccessNotification( - "Facility middleware updated successfully", - ); + facilityPage.clickDeleteFacilityOption(); + facilityPage.confirmDeleteFacility(); + cy.verifyNotification(`${facilityName} deleted successfully`); }); it("Should display error when district admin tries to create facility in a different district", () => { + // Verify the entire form error message facilityPage.visitCreateFacilityPage(); - facilityPage.fillFacilityName(facilityName); - facilityPage.selectFacilityType(facilityType); + facilityPage.clickSaveFacilityButton(); + cy.verifyErrorMessages(facilityErrorMessage); + // Verify the user access based error message + facilityPage.fillBasicDetails(testFacilityData.basic); facilityPage.fillPincode("682001"); facilityPage.selectStateOnPincode("Kerala"); facilityPage.selectDistrictOnPincode("Kottayam"); facilityPage.selectLocalBody("Arpookara"); facilityPage.selectWard("5"); - facilityPage.fillAddress(facilityAddress); - facilityPage.fillPhoneNumber(facilityNumber); - facilityPage.submitForm(); + facilityPage.clickSaveFacilityButton(); facilityPage.verifyErrorNotification( "You do not have permission to perform this action.", ); diff --git a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts index 680ce6fa2ce..0aa8518a6d1 100644 --- a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts @@ -21,8 +21,6 @@ describe("Facility Homepage Function", () => { const patientPage = new PatientPage(); const facilityLocation = new FacilityLocation(); const facilitiesAlias = "downloadFacilitiesCSV"; - const doctorsAlias = "downloadDoctorsCSV"; - const triagesAlias = "downloadTriagesCSV"; const facilityName = "Dummy Facility 40"; const facilityLocaion = "Dummy Location"; const stateName = "Kerala"; @@ -118,23 +116,7 @@ describe("Facility Homepage Function", () => { // Verify Facility Export facilityHome.csvDownloadIntercept(facilitiesAlias, ""); facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Facilities"); facilityHome.verifyDownload(facilitiesAlias); - // Verify Doctor Export - facilityHome.csvDownloadIntercept(doctorsAlias, "&doctors"); - facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Doctors"); - facilityHome.verifyDownload(doctorsAlias); - // Verify Triage Export - facilityHome.csvDownloadIntercept(triagesAlias, "&triage"); - facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Triages"); - facilityHome.verifyDownload(triagesAlias); - }); - - it("Verify Capacity Export Functionality", () => { - facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Capacities"); }); it("Verify Facility Detail page redirection to CNS and Live Minitoring ", () => { diff --git a/cypress/e2e/facility_spec/FacilityManage.cy.ts b/cypress/e2e/facility_spec/FacilityManage.cy.ts index 9f1523768c1..3930f470160 100644 --- a/cypress/e2e/facility_spec/FacilityManage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityManage.cy.ts @@ -21,12 +21,6 @@ describe("Facility Manage Functions", () => { /Health Facility config updated successfully|Health ID registration failed/; const facilityHfrId = "IN180000018"; const facilityUpdatedHfrId = "IN180000020"; - const doctorCapacity = "5"; - const doctorModifiedCapacity = "7"; - const totalCapacity = "100"; - const currentOccupied = "80"; - const totalUpdatedCapacity = "120"; - const currentUpdatedOccupied = "100"; before(() => { loginPage.loginByRole("districtAdmin"); @@ -116,64 +110,6 @@ describe("Facility Manage Functions", () => { facilityManage.verifyHfrIdValue(facilityUpdatedHfrId); }); - it("Modify doctor capacity in Facility detail page", () => { - // Add a doctor capacity - facilityManage.clickFacilityAddDoctorTypeButton(); - facilityPage.selectAreaOfSpecialization("Pulmonology"); - facilityPage.fillDoctorCount(doctorCapacity); - facilityPage.saveAndExitDoctorForm(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Staff count added successfully", - ); - facilityManage.verifyTotalDoctorCapacity(doctorCapacity); - // edit a existing doctor - facilityManage.clickEditFacilityDoctorCapacity(); - facilityPage.fillDoctorCount(doctorModifiedCapacity); - facilityPage.clickdoctorcapacityaddmore(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Staff count updated successfully", - ); - facilityManage.verifyTotalDoctorCapacity(doctorModifiedCapacity); - // delete a bed - facilityManage.clickDeleteFacilityDoctorCapacity(); - facilityManage.clickButtonWithText("Delete"); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Staff specialization type deleted successfully", - ); - }); - - it("Modify bed capacity in Facility detail page", () => { - // add multiple new bed capacity - facilityManage.clickFacilityAddBedTypeButton(); - facilityPage.selectBedType("Isolation Bed"); - facilityPage.fillTotalCapacity(totalCapacity); - facilityPage.fillCurrentlyOccupied(currentOccupied); - facilityPage.saveAndExitBedCapacityForm(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Bed capacity added successfully", - ); - cy.closeNotification(); - facilityManage.verifyFacilityBedCapacity(totalCapacity); - facilityManage.verifyFacilityBedCapacity(currentOccupied); - // edit a existing bed - facilityManage.clickEditFacilityBedCapacity(); - facilityPage.fillTotalCapacity(totalUpdatedCapacity); - facilityPage.fillCurrentlyOccupied(currentUpdatedOccupied); - facilityPage.clickbedcapcityaddmore(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Bed capacity updated successfully", - ); - cy.closeNotification(); - facilityManage.verifyFacilityBedCapacity(totalUpdatedCapacity); - facilityManage.verifyFacilityBedCapacity(currentUpdatedOccupied); - // delete a bed - facilityManage.clickDeleteFacilityBedCapacity(); - facilityManage.clickButtonWithText("Delete"); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Bed type deleted successfully", - ); - }); - afterEach(() => { cy.saveLocalStorage(); }); diff --git a/cypress/e2e/patient_spec/PatientHomepage.cy.ts b/cypress/e2e/patient_spec/PatientHomepage.cy.ts index a120e282a2d..8949fc3e324 100644 --- a/cypress/e2e/patient_spec/PatientHomepage.cy.ts +++ b/cypress/e2e/patient_spec/PatientHomepage.cy.ts @@ -54,7 +54,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyPatientAdmittedBeforeDate(patientToDateBadge); patientHome.verifyPatientAdmittedAfterDate(patientFromDateBadge); cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); }); it("Facility Geography based advance filters applied in the patient tab", () => { @@ -71,7 +70,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyFacilityLsgBadgeContent(facilityLsgBody); patientHome.verifyFacilityDistrictContent(facilityDistrict); cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); }); it("Patient diagnosis based advance filters applied in the patient tab", () => { @@ -104,7 +102,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyDifferentialDiagnosisBadgeContent(patientIcdDiagnosis); // Clear the badges and verify the patient count along with badges cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); // Apply Any and confirmed diagonsis to verify patient count 17 advanceFilters.clickAdvancedFiltersButton(); patientHome.selectAnyIcdDiagnosis(patientIcdDiagnosis, patientIcdDiagnosis); @@ -142,7 +139,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyMedicoBadgeContent("false"); // Clear the badges and verify the patient count along with badges cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); }); it("Export the live patient list based on a date range", () => { diff --git a/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts b/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts index 23077a71ed8..160884978fd 100644 --- a/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts +++ b/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts @@ -20,14 +20,15 @@ describe("Resource Page", () => { beforeEach(() => { cy.restoreLocalStorage(); cy.clearLocalStorage(/filters--.+/); - cy.awaitUrl("/resource"); }); it("Checks if all download button works", () => { + resourcePage.navigationToResourcePage(); resourcePage.verifyDownloadButtonWorks(); }); it("Switch between active/completed", () => { + resourcePage.navigationToResourcePage(); resourcePage.spyResourceApi(); resourcePage.clickCompletedResources(); resourcePage.verifyCompletedResources(); @@ -37,6 +38,7 @@ describe("Resource Page", () => { }); it("Switch between list view and board view", () => { + resourcePage.navigationToResourcePage(); resourcePage.clickListViewButton(); resourcePage.clickBoardViewButton(); }); @@ -68,7 +70,7 @@ describe("Resource Page", () => { }); it("Update the status of resource", () => { - cy.visit(createdResource); + cy.awaitUrl(createdResource); resourcePage.clickUpdateStatus(); resourcePage.updateStatus("APPROVED"); resourcePage.clickSubmitButton(); @@ -78,7 +80,7 @@ describe("Resource Page", () => { }); it("Post comment for a resource", () => { - cy.visit(createdResource); + cy.awaitUrl(createdResource); resourcePage.addCommentForResource("Test comment"); resourcePage.clickPostCommentButton(); resourcePage.verifySuccessNotification("Comment added successfully"); diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index e59dfef09f3..9776433e523 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -16,31 +16,6 @@ export interface FacilityData { localBody: string; ward: string; }; - oxygen?: { - capacity: string; - expected: string; - bType?: { - capacity: string; - expected: string; - }; - cType?: { - capacity: string; - expected: string; - }; - dType?: { - capacity: string; - expected: string; - }; - }; - beds?: Array<{ - type: string; - totalCapacity: string; - occupied: string; - }>; - doctors?: Array<{ - specialization: string; - count: string; - }>; } class FacilityPage { @@ -60,15 +35,8 @@ class FacilityPage { advanceFilters.selectLocalBody(localBody); } - visitUpdateFacilityPage(url: string) { - cy.intercept("GET", "**/api/v1/facility/**").as("getFacilities"); - cy.visit(url); - cy.wait("@getFacilities").its("response.statusCode").should("eq", 200); - cy.get("#manage-facility-dropdown button").should("be.visible"); - } - - fillFacilityName(name: string) { - cy.get("#name").click().clear().click().type(name); + typeFacilityName(name: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#name", name, { clearBeforeTyping }); } fillPincode(pincode: string) { @@ -80,90 +48,29 @@ class FacilityPage { cy.get("[role='option']").contains(ward).click(); } - fillAddress(address: string) { - cy.get("#address").click().type(address); - } - - fillPhoneNumber(phoneNumber: string) { - cy.get("#phone_number").type(phoneNumber); - } - - submitForm() { - cy.get("button#submit").click(); - } - - selectBedType(bedType: string) { - cy.clickAndSelectOption("div#bed-type button", bedType); - } - - isVisibleselectBedType() { - cy.get("div#bed-type button").should("be.visible"); - } - - fillTotalCapacity(capacity: string) { - cy.get("input#total-capacity").click().clear().click().type(capacity); - } - - fillCurrentlyOccupied(occupied: string) { - cy.get("input#currently-occupied").click().clear().click().type(occupied); - } - - saveAndExitBedCapacityForm() { - cy.get("button#bed-capacity-save-and-exit").click(); - } - - selectAreaOfSpecialization(area: string) { - cy.get("div#area-of-specialization button").click(); - cy.get("[role='option']").contains(area).click(); + typeFacilityAddress(address: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#address", address, { clearBeforeTyping }); } - isVisibleAreaOfSpecialization() { - cy.get("div#area-of-specialization button").should("be.visible"); - } - - fillDoctorCount(count: string) { - cy.get("input#count").click().clear().click().type(count); - } - - fillOxygenCapacity(capacity: string) { - cy.get("#oxygen_capacity").click().clear().type(capacity); - } - - fillExpectedOxygenRequirement(requirement: string) { - cy.get("#expected_oxygen_requirement").click().clear().type(requirement); - } - - fillBTypeCylinderCapacity(capacity: string) { - cy.get("#type_b_cylinders").click().clear().type(capacity); - } - - fillExpectedBTypeCylinderRequirement(requirement: string) { - cy.get("#expected_type_b_cylinders").focus().clear(); - cy.get("#expected_type_b_cylinders").focus().type(requirement); - } - - fillCTypeCylinderCapacity(capacity: string) { - cy.get("#type_c_cylinders").click().clear().type(capacity); - } - - fillExpectedCTypeCylinderRequirement(requirement: string) { - cy.get("#expected_type_c_cylinders").focus().clear(); - cy.get("#expected_type_c_cylinders").focus().type(requirement); + typeFacilityPhoneNumber( + phoneNumber: string, + clearBeforeTyping: boolean = false, + ) { + cy.typeIntoField("#phone_number", phoneNumber, { clearBeforeTyping }); } - fillDTypeCylinderCapacity(capacity: string) { - cy.get("#type_d_cylinders").click().clear().type(capacity); + clickSaveFacilityButton() { + cy.verifyAndClickElement("#submit", "Save Facility"); } - fillExpectedDTypeCylinderRequirement(requirement: string) { - cy.get("#expected_type_d_cylinders").focus().clear(); - cy.get("#expected_type_d_cylinders").focus().type(requirement); + verifyFacilityCreatedNotification() { + cy.verifyNotification("Facility added successfully"); + cy.closeNotification(); } - saveAndExitDoctorForm() { - cy.intercept("GET", "**/api/v1/facility/**").as("createFacilities"); - cy.get("button#save-and-exit").click(); - cy.wait("@createFacilities").its("response.statusCode").should("eq", 200); + verifyFacilityUpdatedNotification() { + cy.verifyNotification("Facility updated successfully"); + cy.closeNotification(); } clickManageFacilityDropdown() { @@ -178,6 +85,10 @@ class FacilityPage { cy.get("#update-facility").contains("Update Facility").click(); } + clickUpdateFacilityButton() { + cy.verifyAndClickElement("#submit", "Update Facility"); + } + clickConfigureFacilityOption() { cy.get("#configure-facility").contains("Configure Facility").click(); } @@ -199,22 +110,6 @@ class FacilityPage { cy.get("#inventory-management").click(); } - getTotalBedCapacity() { - return cy.get("#total-bed-capacity"); - } - - getFacilityTotalBedCapacity() { - return cy.get("#facility-bed-capacity-details"); - } - - getFacilityTotalDoctorCapacity() { - return cy.get("#facility-doctor-capacity-details"); - } - - getTotalDoctorCapacity() { - return cy.get("#total-doctor-capacity"); - } - getFacilityName() { return cy.get("#facility-name"); } @@ -231,10 +126,6 @@ class FacilityPage { return cy.get("#facility-available-features"); } - getFacilityOxygenInfo() { - return cy.get("#facility-oxygen-info"); - } - clickResourceRequestOption() { cy.get("#resource-request").contains("Resource Request").click(); } @@ -243,64 +134,10 @@ class FacilityPage { cy.get("#delete-facility").contains("Delete Facility").click(); } - scrollToFacilityTriage() { - cy.get("#add-facility-triage").scrollIntoView(); - } - - fillTriageEntryFields( - visited: string, - homeQuarantine: string, - isolation: string, - referred: string, - confirmedPositive: string, - ) { - cy.get("#num_patients_visited").clear().click().type(visited); - cy.get("#num_patients_home_quarantine") - .clear() - .click() - .type(homeQuarantine); - cy.get("#num_patients_isolation").clear().click().type(isolation); - cy.get("#num_patient_referred").clear().click().type(referred); - cy.get("#num_patient_confirmed_positive") - .clear() - .click() - .type(confirmedPositive); - } - - fillEntryDate(date: string) { - cy.clickAndTypeDate("#entry_date", date); - } - - clickEditButton() { - cy.get("#edit-button").click(); - } - - clickButtonsMultipleTimes(selector: string) { - cy.get(selector).each(($button) => { - cy.wrap($button).click(); - }); - } - - verifyTriageTableContains(value: string) { - cy.get("#triage-table").contains(value); - } - - clickAddFacilityTriage() { - cy.get("#add-facility-triage").click(); - } - clickfacilityfeatureoption() { cy.get("#features").click(); } - clickbedcapcityaddmore() { - cy.get("#bed-capacity-save").click(); - } - - clickdoctorcapacityaddmore() { - cy.get("#doctor-save").click(); - } - clickcancelbutton() { cy.get("#cancel").click(); } @@ -509,30 +346,15 @@ class FacilityPage { // Fill location details this.fillLocationDetails(data.location); - // Fill oxygen details if provided - if (data.oxygen) { - this.fillOxygenDetails(data.oxygen); - } - - this.submitForm(); + this.clickSaveFacilityButton(); cy.closeNotification(); - // Add bed capacity if provided - if (data.beds) { - this.addBedCapacities(data.beds); - } - - // Add doctor capacity if provided - if (data.doctors) { - this.addDoctorCapacities(data.doctors); - } - this.verifyfacilitynewurl(); return this; } fillBasicDetails(basic: FacilityData["basic"]) { - this.fillFacilityName(basic.name); + this.typeFacilityName(basic.name); this.selectFacilityType(basic.type); if (basic.features?.length) { @@ -543,8 +365,8 @@ class FacilityPage { this.clickfacilityfeatureoption(); } - this.fillAddress(basic.address); - this.fillPhoneNumber(basic.phoneNumber); + this.typeFacilityAddress(basic.address); + this.typeFacilityPhoneNumber(basic.phoneNumber); if (basic.location) { this.selectLocation(basic.location); @@ -558,47 +380,6 @@ class FacilityPage { this.selectLocalBody(location.localBody); this.selectWard(location.ward); } - - fillOxygenDetails(oxygen: NonNullable) { - this.fillOxygenCapacity(oxygen.capacity); - this.fillExpectedOxygenRequirement(oxygen.expected); - - if (oxygen.bType) { - this.fillBTypeCylinderCapacity(oxygen.bType.capacity); - this.fillExpectedBTypeCylinderRequirement(oxygen.bType.expected); - } - - if (oxygen.cType) { - this.fillCTypeCylinderCapacity(oxygen.cType.capacity); - this.fillExpectedCTypeCylinderRequirement(oxygen.cType.expected); - } - - if (oxygen.dType) { - this.fillDTypeCylinderCapacity(oxygen.dType.capacity); - this.fillExpectedDTypeCylinderRequirement(oxygen.dType.expected); - } - } - - addBedCapacities(beds: NonNullable) { - beds.forEach((bed) => { - this.selectBedType(bed.type); - this.fillTotalCapacity(bed.totalCapacity); - this.fillCurrentlyOccupied(bed.occupied); - this.clickbedcapcityaddmore(); - cy.closeNotification(); - }); - this.clickcancelbutton(); - } - - addDoctorCapacities(doctors: NonNullable) { - doctors.forEach((doctor) => { - this.selectAreaOfSpecialization(doctor.specialization); - this.fillDoctorCount(doctor.count); - this.clickdoctorcapacityaddmore(); - cy.closeNotification(); - }); - this.clickcancelbutton(); - } } export default FacilityPage; diff --git a/cypress/pageobject/Facility/FacilityHome.ts b/cypress/pageobject/Facility/FacilityHome.ts index bbf5945453e..24f7d321628 100644 --- a/cypress/pageobject/Facility/FacilityHome.ts +++ b/cypress/pageobject/Facility/FacilityHome.ts @@ -1,7 +1,6 @@ class FacilityHome { // Selectors exportButton = "#export-button"; - menuItem = "[role='menuitem']"; // Operations clickExportButton() { @@ -10,7 +9,7 @@ class FacilityHome { } navigateToFacilityHomepage() { - cy.visit("/facility"); + cy.awaitUrl("/facility"); } assertFacilityInCard(facilityName: string) { @@ -29,10 +28,6 @@ class FacilityHome { cy.get("#facility-search").click().clear().type(facilityName); } - clickMenuItem(itemName: string) { - cy.get(this.menuItem).contains(itemName).click(); - } - csvDownloadIntercept(alias: string, queryParam: string) { cy.intercept("GET", `**/api/v1/facility/?csv${queryParam}`).as(alias); } diff --git a/cypress/pageobject/Facility/FacilityManage.ts b/cypress/pageobject/Facility/FacilityManage.ts index e7eecddab3c..00d9f642bbc 100644 --- a/cypress/pageobject/Facility/FacilityManage.ts +++ b/cypress/pageobject/Facility/FacilityManage.ts @@ -18,30 +18,6 @@ class FacilityManage { cy.get("#save-cover-image").click(); } - verifyTotalDoctorCapacity(expectedCapacity: string) { - cy.get("#facility-doctor-totalcapacity").contains(expectedCapacity); - } - - verifyFacilityBedCapacity(expectedCapacity: string) { - cy.get("#facility-bed-capacity-details").contains(expectedCapacity); - } - - clickEditFacilityDoctorCapacity() { - cy.get("#edit-facility-doctorcapacity").click(); - } - - clickEditFacilityBedCapacity() { - cy.get("#edit-facility-bedcapacity").click(); - } - - clickDeleteFacilityDoctorCapacity() { - cy.get("#delete-facility-doctorcapacity").click(); - } - - clickDeleteFacilityBedCapacity() { - cy.get("#delete-facility-bedcapacity").click(); - } - clickFacilityConfigureButton() { cy.get("#configure-facility").should("be.visible"); cy.get("#configure-facility").click(); @@ -90,16 +66,6 @@ class FacilityManage { cy.get("#hf_id").should("have.value", expectedValue); } - clickFacilityAddDoctorTypeButton() { - cy.get("#facility-add-doctortype").scrollIntoView(); - cy.get("#facility-add-doctortype").click(); - } - - clickFacilityAddBedTypeButton() { - cy.get("#facility-add-bedtype").scrollIntoView(); - cy.get("#facility-add-bedtype").click(); - } - visitViewPatients() { cy.intercept("GET", "**/api/v1/facility/**").as("getFacilityPatients"); cy.get("#view-patient-facility-list").scrollIntoView().click(); diff --git a/cypress/pageobject/Resource/ResourcePage.ts b/cypress/pageobject/Resource/ResourcePage.ts index 730d3dd9148..c01c60baec5 100644 --- a/cypress/pageobject/Resource/ResourcePage.ts +++ b/cypress/pageobject/Resource/ResourcePage.ts @@ -28,6 +28,10 @@ class ResourcePage { cy.contains("button", "Active").click(); } + navigationToResourcePage() { + cy.awaitUrl("/resource"); + } + verifyActiveResources() { cy.wait("@resource").its("response.statusCode").should("eq", 200); cy.contains("button", "Active").should("have.class", "text-white"); diff --git a/cypress/pageobject/utils/constants.ts b/cypress/pageobject/utils/constants.ts index 053d0561ce8..90baf3b6d4b 100644 --- a/cypress/pageobject/utils/constants.ts +++ b/cypress/pageobject/utils/constants.ts @@ -1,10 +1,122 @@ -export function generatePhoneNumber(): string { +function generatePhoneNumber(): string { const array = new Uint32Array(1); window.crypto.getRandomValues(array); const randomNum = (array[0] % 900000000) + 100000000; return "9" + randomNum.toString(); } -export function generateEmergencyPhoneNumber(): string { +function generateEmergencyPhoneNumber(): string { return generatePhoneNumber(); } + +function generateFacilityName(): string { + const prefixes = [ + "GHC", + "NHC", + "SHC", + "Apollo", + "General", + "St. Mary's", + "Central", + "Kochi", + ]; + const locations = [ + "North", + "South", + "East", + "West", + "Downtown", + "Metro", + "Springfield", + "Ernakulam", + ]; + const identifiers = [ + () => Math.floor(Math.random() * 100), // Numeric IDs + () => `Zone-${Math.floor(Math.random() * 10)}`, // Zone IDs + () => `Block-${String.fromCharCode(65 + Math.floor(Math.random() * 26))}`, // Alphabetic Blocks + ]; + const suffixes = [ + "Meta", + "Prime", + "Care", + "Wellness", + "Clinic", + "Center", + "Specialists", + "Hospital", + ]; + + const randomPrefix = prefixes[Math.floor(Math.random() * prefixes.length)]; + const randomLocation = + locations[Math.floor(Math.random() * locations.length)]; + const randomIdentifier = + identifiers[Math.floor(Math.random() * identifiers.length)](); + const randomSuffix = suffixes[Math.floor(Math.random() * suffixes.length)]; + + // Randomize the format of the name + const formats = [ + `${randomPrefix} ${randomLocation}-${randomIdentifier} ${randomSuffix}`, + `${randomLocation} ${randomPrefix} ${randomSuffix}`, + `${randomPrefix} ${randomLocation} ${randomSuffix}`, + ]; + + return formats[Math.floor(Math.random() * formats.length)]; +} + +function generateRandomAddress(multiline: boolean = false): string { + const localities = [ + "Marine Drive", + "Fort Kochi", + "Thevara", + "Vyttila", + "Edappally", + "Palarivattom", + "Kakkanad", + "Mattancherry", + "Kaloor", + "Tripunithura", + ]; + const neighborhoods = [ + "Lane 1", + "Lane 2", + "North Block", + "East End", + "West Side", + "Central Area", + "Market Road", + "Garden Street", + "Highland Avenue", + ]; + const districts = ["Kochi", "Ernakulam"]; + const states = ["Kerala"]; + const pincode = Math.floor(682000 + Math.random() * 1000).toString(); // Generate random pincodes in the 682XXX range. + + const randomLocality = + localities[Math.floor(Math.random() * localities.length)]; + const randomNeighborhood = + neighborhoods[Math.floor(Math.random() * neighborhoods.length)]; + const randomDistrict = + districts[Math.floor(Math.random() * districts.length)]; + const randomState = states[Math.floor(Math.random() * states.length)]; + + // Create address components + const addressParts = [ + randomNeighborhood, + randomLocality, + randomDistrict, + randomState, + `Pincode: ${pincode}`, + ]; + + // Return address as single line or multiline + // If 'multiline' is false, return address as a single line + // If 'multiline' is true, return address with each component on a new line + return multiline ? addressParts.join("\n") : addressParts.join(", "); +} + +export { + generatePhoneNumber, + generateEmergencyPhoneNumber, + generateFacilityName, + generateRandomAddress, +}; diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 0268beebc42..f5bbcf42290 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -241,3 +241,21 @@ Cypress.Commands.add("verifyErrorMessages", (errorMessages: string[]) => { }); }); }); + +Cypress.Commands.add( + "typeIntoField", + ( + selector: string, + value: string, + options: { clearBeforeTyping?: boolean } = {}, + ) => { + const { clearBeforeTyping = false } = options; + const inputField = cy.get(selector); + + if (clearBeforeTyping) { + inputField.clear(); // Clear the input field + } + + inputField.click().type(value); // Click and type the new value + }, +); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index 831ee71a5bc..fa01326698c 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -46,6 +46,11 @@ declare global { texts: string[], ): Chainable; verifyErrorMessages(errorMessages: string[]): Chainable; + typeIntoField( + selector: string, + value: string, + options?: { clearBeforeTyping?: boolean }, + ): Chainable; } } } diff --git a/package-lock.json b/package-lock.json index 41d7fcfff8c..6e57456063b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "clsx": "^2.1.1", "cmdk": "^1.0.4", "cross-env": "^7.0.3", - "cypress": "^13.16.0", + "cypress": "^13.15.2", "dayjs": "^1.11.13", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", @@ -7807,9 +7807,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.0.tgz", - "integrity": "sha512-g6XcwqnvzXrqiBQR/5gN+QsyRmKRhls1y5E42fyOvsmU7JuY+wM6uHJWj4ZPttjabzbnRvxcik2WemR8+xT6FA==", + "version": "13.15.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.2.tgz", + "integrity": "sha512-ARbnUorjcCM3XiPwgHKuqsyr5W9Qn+pIIBPaoilnoBkLdSC2oLQjV1BUpnmc7KR+b7Avah3Ly2RMFnfxr96E/A==", "hasInstallScript": true, "dependencies": { "@cypress/request": "^3.0.6", diff --git a/package.json b/package.json index 15392d09410..3db351e974b 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "clsx": "^2.1.1", "cmdk": "^1.0.4", "cross-env": "^7.0.3", - "cypress": "^13.16.0", + "cypress": "^13.15.2", "dayjs": "^1.11.13", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", diff --git a/src/Routers/routes/FacilityRoutes.tsx b/src/Routers/routes/FacilityRoutes.tsx index 8c942518996..bf5d67ca67c 100644 --- a/src/Routers/routes/FacilityRoutes.tsx +++ b/src/Routers/routes/FacilityRoutes.tsx @@ -5,7 +5,6 @@ import { FacilityCreate } from "@/components/Facility/FacilityCreate"; import { FacilityHome } from "@/components/Facility/FacilityHome"; import { FacilityList } from "@/components/Facility/FacilityList"; import FacilityUsers from "@/components/Facility/FacilityUsers"; -import { TriageForm } from "@/components/Facility/TriageForm"; import ResourceCreate from "@/components/Resource/ResourceCreate"; import { AppRoutes } from "@/Routers/AppRouter"; @@ -36,12 +35,6 @@ const FacilityRoutes: AppRoutes = { "/facility/:facilityId/resource/new": ({ facilityId }) => ( ), - "/facility/:facilityId/triage": ({ facilityId }) => ( - - ), - "/facility/:facilityId/triage/:id": ({ facilityId, id }) => ( - - ), ...FacilityLocationRoutes, ...FacilityInventoryRoutes, }; diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index e7df6312c84..86886291f11 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -10,11 +10,6 @@ import { PatientAssetBed, } from "@/components/Assets/AssetTypes"; import { ICD11DiagnosisModel } from "@/components/Diagnosis/types"; -import { - IDeleteBedCapacity, - ILocalBodies, - ILocalBodyByDistrict, -} from "@/components/ExternalResult/models"; import { EventGeneric, type Type, @@ -27,7 +22,6 @@ import { Investigation } from "@/components/Facility/Investigations/Reports/type import { InvestigationSessionType } from "@/components/Facility/Investigations/investigationsTab"; import { BedModel, - CapacityModal, CommentModel, ConsultationModel, CreateBedBody, @@ -35,7 +29,6 @@ import { DailyRoundsBody, DailyRoundsRes, DistrictModel, - DoctorModal, FacilityModel, FacilityRequest, FacilitySpokeModel, @@ -51,7 +44,6 @@ import { MinimumQuantityItemResponse, PatientNotesEditModel, PatientNotesModel, - PatientStatsModel, PatientTransferResponse, ResourceModel, ShiftingModel, @@ -530,23 +522,6 @@ const routes = { method: "GET", TRes: Type(), }, - downloadFacilityCapacity: { - path: "/api/v1/facility/?csv&capacity", - method: "GET", - TRes: Type(), - }, - downloadFacilityDoctors: { - path: "/api/v1/facility/?csv&doctors", - method: "GET", - TRes: Type(), - }, - - downloadFacilityTriage: { - path: "/api/v1/facility/?csv&triage", - method: "GET", - TRes: Type(), - }, - downloadPatients: { path: "/api/v1/patient/?csv", method: "GET", @@ -634,86 +609,6 @@ const routes = { TRes: Type>(), }, - // Hospital Beds - createCapacity: { - path: "/api/v1/facility/{facilityId}/capacity/", - method: "POST", - TRes: Type(), - }, - - createDoctor: { - path: "/api/v1/facility/{facilityId}/hospital_doctor/", - method: "POST", - TRes: Type(), - TBody: Type(), - }, - - getCapacity: { - path: "/api/v1/facility/{facilityId}/capacity/", - TRes: Type>(), - }, - - getCapacityBed: { - path: "/api/v1/facility/{facilityId}/capacity/{bed_id}/", - TRes: Type(), - }, - - deleteCapacityBed: { - path: "/api/v1/facility/{facilityId}/capacity/{bed_id}/", - method: "DELETE", - TRes: Type(), - }, - - listDoctor: { - path: "/api/v1/facility/{facilityId}/hospital_doctor/", - TRes: Type>(), - }, - getDoctor: { - path: "/api/v1/facility/{facilityId}/hospital_doctor/{id}/", - TRes: Type(), - }, - - updateCapacity: { - path: "/api/v1/facility/{facilityId}/capacity/{bed_id}/", - method: "PUT", - TRes: Type(), - }, - - updateDoctor: { - path: "/api/v1/facility/{facilityId}/hospital_doctor/{id}/", - method: "PUT", - TRes: Type(), - }, - - deleteDoctor: { - path: "/api/v1/facility/{facilityId}/hospital_doctor/{area}/", - method: "DELETE", - TRes: Type>(), - }, - - //Triage - createTriage: { - path: "/api/v1/facility/{facilityId}/patient_stats/", - method: "POST", - TBody: Type(), - TRes: Type(), - }, - getTriage: { - path: "/api/v1/facility/{facilityId}/patient_stats/", - TRes: Type>(), - }, - - getTriageDetails: { - path: "/api/v1/facility/{facilityId}/patient_stats/{id}/", - TRes: Type(), - }, - - // //Care Center - // createCenter: { - // path: "/api/v1/carecenter/", - // method: 'POST' - // } - // Patient searchPatient: { @@ -813,12 +708,12 @@ const routes = { getAllLocalBodyByDistrict: { path: "/api/v1/district/{id}/get_all_local_body/", method: "GET", - TRes: Type(), + TRes: Type(), }, getLocalbodyByDistrict: { path: "/api/v1/district/{id}/local_bodies/", method: "GET", - TRes: Type(), + TRes: Type(), }, // Local Body diff --git a/src/components/ExternalResult/models.ts b/src/components/ExternalResult/models.ts deleted file mode 100644 index bc5f8d29e03..00000000000 --- a/src/components/ExternalResult/models.ts +++ /dev/null @@ -1,18 +0,0 @@ -export interface ILocalBodies { - id: number; - name: string; - state: number; - number: number; - body_type: number; - localbody_code: string; - district: number; -} -export interface IDeleteBedCapacity { - detail: string; -} - -export interface ILocalBodyByDistrict { - id: number; - name: string; - state: number; -} diff --git a/src/components/Facility/BedCapacity.tsx b/src/components/Facility/BedCapacity.tsx deleted file mode 100644 index 156dc6adce6..00000000000 --- a/src/components/Facility/BedCapacity.tsx +++ /dev/null @@ -1,301 +0,0 @@ -import { useEffect, useReducer, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import { Cancel, Submit } from "@/components/Common/ButtonV2"; -import { CapacityModal, OptionsType } from "@/components/Facility/models"; -import { SelectFormField } from "@/components/Form/FormFields/SelectFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; - -import { BED_TYPES } from "@/common/constants"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; - -interface BedCapacityProps extends CapacityModal { - facilityId: string; - handleClose: () => void; - handleUpdate: () => void; - className?: string; - id?: number; -} - -const initForm: any = { - bedType: "", - totalCapacity: "", - currentOccupancy: "", -}; - -const initialState = { - form: { ...initForm }, - errors: { ...initForm }, -}; - -const bedCountReducer = (state = initialState, action: any) => { - switch (action.type) { - case "set_form": { - return { - ...state, - form: action.form, - }; - } - case "set_error": { - return { - ...state, - errors: action.errors, - }; - } - default: - return state; - } -}; - -export const BedCapacity = (props: BedCapacityProps) => { - const { t } = useTranslation(); - const { facilityId, handleClose, handleUpdate, className, id } = props; - const [state, dispatch] = useReducer(bedCountReducer, initialState); - const [isLastOptionType, setIsLastOptionType] = useState(false); - const [bedTypes, setBedTypes] = useState( - BED_TYPES.map((o) => ({ id: o, text: t(`bed_type__${o}`) })), - ); - const [isLoading, setIsLoading] = useState(false); - - const headerText = !id ? "Add Bed Capacity" : "Edit Bed Capacity"; - const buttonText = !id - ? `Save ${!isLastOptionType ? "& Add More" : "Bed Capacity"}` - : "Update Bed Capacity"; - - async function fetchCapacityBed() { - setIsLoading(true); - if (!id) { - // Add Form functionality - const capacityQuery = await request(routes.getCapacity, { - pathParams: { facilityId: props.facilityId }, - }); - if (capacityQuery?.data) { - const existingData = capacityQuery.data?.results; - // if all options are diabled - if (existingData.length === BED_TYPES.length) { - setBedTypes([]); - setIsLoading(false); - return; - } - // disable existing bed types - const updatedBedTypes = BED_TYPES.map((type) => { - const isExisting = existingData.find( - (i: CapacityModal) => i.room_type === type, - ); - return { - id: type, - text: t(`bed_type__${type}`), - disabled: !!isExisting, - }; - }); - setBedTypes(updatedBedTypes); - } - } else { - // Edit Form functionality - const capacityQuery = await request(routes.getCapacityBed, { - pathParams: { facilityId: props.facilityId, bed_id: id.toString() }, - }); - if (capacityQuery.data) { - dispatch({ - type: "set_form", - form: { - bedType: capacityQuery.data.room_type, - totalCapacity: capacityQuery.data.total_capacity, - currentOccupancy: capacityQuery.data.current_capacity, - }, - }); - } - } - setIsLoading(false); - } - - useEffect(() => { - fetchCapacityBed(); - }, []); - - useEffect(() => { - const lastBedType = - bedTypes.filter((i: OptionsType) => i.disabled).length === - BED_TYPES.length - 1; - setIsLastOptionType(lastBedType); - }, [bedTypes]); - - const handleChange = (e: FieldChangeEvent) => { - const form = { ...state.form }; - form[e.name] = e.value; - dispatch({ type: "set_form", form }); - }; - - const validateData = () => { - const errors = { ...initForm }; - let invalidForm = false; - Object.keys(state.form).forEach((field) => { - if (!state.form[field]) { - errors[field] = t("field_required"); - invalidForm = true; - } else if ( - field === "currentOccupancy" && - Number(state.form[field] < 0) - ) { - errors[field] = "Occupied cannot be negative"; - invalidForm = true; - } else if ( - field === "currentOccupancy" && - Number(state.form[field]) > Number(state.form.totalCapacity) - ) { - errors[field] = "Occupied must be less than or equal to total capacity"; - invalidForm = true; - } - if (field === "totalCapacity" && Number(state.form[field]) === 0) { - errors[field] = "Total capacity cannot be 0"; - invalidForm = true; - } else if (field === "totalCapacity" && Number(state.form[field]) < 0) { - errors[field] = "Total capacity cannot be negative"; - invalidForm = true; - } - }); - if (invalidForm) { - dispatch({ type: "set_error", errors }); - return false; - } - dispatch({ type: "set_error", errors }); - return true; - }; - - const handleSubmit = async (e: any, btnType = "Save") => { - e.preventDefault(); - const valid = validateData(); - if (valid) { - setIsLoading(true); - const bodyData = { - room_type: Number(state.form.bedType), - total_capacity: Number(state.form.totalCapacity), - current_capacity: Number(state.form.currentOccupancy), - }; - const { data } = await request( - id ? routes.updateCapacity : routes.createCapacity, - { - pathParams: { facilityId, ...(id ? { bed_id: id.toString() } : {}) }, - body: bodyData, - }, - ); - setIsLoading(false); - if (data) { - const updatedBedTypes = bedTypes.map((type) => { - return { - ...type, - disabled: data.room_type !== type.id ? type.disabled : true, - }; - }); - setBedTypes(updatedBedTypes); - // reset form - dispatch({ type: "set_form", form: initForm }); - // show success message - if (!id) { - Notification.Success({ - msg: "Bed capacity added successfully", - }); - } else { - Notification.Success({ - msg: "Bed capacity updated successfully", - }); - } - handleUpdate(); - } - if (btnType == "Save and Exit") handleClose(); - } - }; - - return ( -
    - {isLoading ? ( -
    -
    - - Loading... -
    -
    - ) : ( -
    - !type.disabled)} - optionLabel={(option) => option.text} - optionValue={(option) => option.id} - onChange={handleChange} - disabled={!!id} - error={state.errors.bedType} - /> -
    - - -
    - -
    - - {headerText === "Add Bed Capacity" && ( - handleSubmit(e, "Save and Exit")} - label="Save Bed Capacity" - /> - )} - {!isLastOptionType && ( - handleSubmit(e)} - label={buttonText} - /> - )} -
    -
    - )} -
    - ); -}; diff --git a/src/components/Facility/BedTypeCard.tsx b/src/components/Facility/BedTypeCard.tsx deleted file mode 100644 index 99244bd7eb1..00000000000 --- a/src/components/Facility/BedTypeCard.tsx +++ /dev/null @@ -1,181 +0,0 @@ -import { useEffect, useState } from "react"; - -import RecordMeta from "@/CAREUI/display/RecordMeta"; -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import ConfirmDialog from "@/components/Common/ConfirmDialog"; -import DialogModal from "@/components/Common/Dialog"; -import { BedCapacity } from "@/components/Facility/BedCapacity"; - -import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; - -interface BedTypeCardProps { - facilityId?: string; - bedCapacityId?: number; - room_type?: number; - label: string; - used: number; - total: number; - lastUpdated?: string; - removeBedType?: (bedTypeId: number | undefined) => void; - handleUpdate: () => void; -} - -export const BedTypeCard: React.FC = ({ - facilityId, - bedCapacityId, - room_type, - label, - used, - total, - lastUpdated, - removeBedType, - handleUpdate, -}) => { - const [isRefreshing, setIsRefreshing] = useState(false); - const [openDeleteDialog, setOpenDeleteDialog] = useState(false); - const [open, setOpen] = useState(false); - const [selectedId, setSelectedId] = useState(-1); - const handleDeleteSubmit = async () => { - if (room_type) { - const { res } = await request(routes.deleteCapacityBed, { - pathParams: { - facilityId: facilityId ?? "", - bed_id: room_type.toString(), - }, - }); - if (res?.status == 204) { - Notification.Success({ - msg: "Bed type deleted successfully", - }); - setOpenDeleteDialog(false); - if (removeBedType) { - removeBedType(bedCapacityId); - } - } - } - }; - - useEffect(() => { - if (isRefreshing) { - setTimeout(() => { - setIsRefreshing(false); - }, 500); - } - }, [isRefreshing]); - - const usedPercent = total ? Math.round((used / total) * 100) : 0; - - return ( -
    -
    -
    - {label} -
    - - {usedPercent}% - -
    -
    - {used} / {total} -
    -
    -
    -
    -
    - -
    - {" "} - Currently Occupied / Total Capacity{" "} -
    - {facilityId ? ( -
    -
    - {lastUpdated && ( - - )} -
    -
    - { - setSelectedId(room_type || 0); - setOpen(true); - }} - authorizeFor={NonReadOnlyUsers} - className="tooltip bg-opacity/20 flex aspect-square h-7 w-7 flex-col items-center justify-center rounded bg-secondary-300 px-4 py-0" - variant="secondary" - ghost - > - - Edit - - - setOpenDeleteDialog(true)} - authorizeFor={NonReadOnlyUsers} - className="tooltip bg-opacity/10 flex aspect-square h-7 w-7 flex-col items-center justify-center rounded bg-red-100 px-4 py-0 hover:bg-red-200" - variant="secondary" - ghost - > - - Delete - -
    -
    - ) : ( -
    - )} -
    - setOpenDeleteDialog(false)} - title={`Delete ${label}?`} - description="You will not be able to access this bed type later." - action="Delete" - variant="danger" - onConfirm={handleDeleteSubmit} - /> - {open && ( - setOpen(false)} - title="Update Bed Capacity" - className="max-w-lg md:min-w-[650px]" - > - { - setOpen(false); - }} - handleUpdate={() => { - handleUpdate(); - setOpen(false); - }} - id={selectedId} - /> - - )} -
    - ); -}; - -export default BedTypeCard; diff --git a/src/components/Facility/FacilityBedCapacity.tsx b/src/components/Facility/FacilityBedCapacity.tsx deleted file mode 100644 index cf0ac28a24a..00000000000 --- a/src/components/Facility/FacilityBedCapacity.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import DialogModal from "@/components/Common/Dialog"; -import { BedCapacity } from "@/components/Facility/BedCapacity"; -import BedTypeCard from "@/components/Facility/BedTypeCard"; - -import { BED_TYPES } from "@/common/constants"; - -import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; -import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -export const FacilityBedCapacity = (props: any) => { - const { t } = useTranslation(); - - const [bedCapacityModalOpen, setBedCapacityModalOpen] = useState(false); - - const capacityQuery = useTanStackQueryInstead(routes.getCapacity, { - pathParams: { facilityId: props.facilityId }, - }); - - let capacityList: any = null; - if (!capacityQuery.data || !capacityQuery.data.results.length) { - capacityList = ( -
    - No Bed Types Found -
    - ); - } else { - const totalBedCount = capacityQuery.data.results.reduce( - (acc, x) => acc + (x.total_capacity ? x.total_capacity : 0), - 0, - ); - const totalOccupiedBedCount = capacityQuery.data.results.reduce( - (acc, x) => acc + (x.current_capacity ? x.current_capacity : 0), - 0, - ); - - capacityList = ( -
    - { - return; - }} - /> - {BED_TYPES.map((x) => { - const res = capacityQuery.data?.results.find((data) => { - return data.room_type === x; - }); - if ( - res && - res.current_capacity !== undefined && - res.total_capacity !== undefined - ) { - const removeCurrentBedType = (bedTypeId: number | undefined) => { - if (capacityQuery.data !== undefined) { - capacityQuery.data.results.filter((i) => i.id !== bedTypeId); - capacityQuery.refetch(); - } - }; - return ( - { - capacityQuery.refetch(); - }} - /> - ); - } - })} -
    - ); - } - - return ( -
    -
    -
    -
    Bed Capacity
    - setBedCapacityModalOpen(true)} - authorizeFor={NonReadOnlyUsers} - > - - Add More Bed Types - -
    -
    {capacityList}
    -
    - - {bedCapacityModalOpen && ( - setBedCapacityModalOpen(false)} - title="Add Bed Capacity" - className="max-w-md md:min-w-[600px]" - > - setBedCapacityModalOpen(false)} - handleUpdate={async () => { - capacityQuery.refetch(); - }} - /> - - )} -
    - ); -}; diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index 37b98492c6f..84af22aabee 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -16,18 +16,8 @@ import ButtonV2, { Cancel, Submit } from "@/components/Common/ButtonV2"; import GLocationPicker from "@/components/Common/GLocationPicker"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; -import Steps, { Step } from "@/components/Common/Steps"; -import { BedCapacity } from "@/components/Facility/BedCapacity"; -import BedTypeCard from "@/components/Facility/BedTypeCard"; import SpokeFacilityEditor from "@/components/Facility/SpokeFacilityEditor"; -import { StaffCapacity } from "@/components/Facility/StaffCapacity"; -import StaffCountCard from "@/components/Facility/StaffCountCard"; -import { - CapacityModal, - DistrictModel, - DoctorModal, - FacilityRequest, -} from "@/components/Facility/models"; +import { DistrictModel, FacilityRequest } from "@/components/Facility/models"; import { PhoneNumberValidator } from "@/components/Form/FieldValidators"; import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormField"; import RadioFormField from "@/components/Form/FormFields/RadioFormField"; @@ -43,11 +33,7 @@ import { FormAction } from "@/components/Form/Utils"; import useAppHistory from "@/hooks/useAppHistory"; import useAuthUser from "@/hooks/useAuthUser"; -import { - BED_TYPES, - FACILITY_FEATURE_TYPES, - FACILITY_TYPES, -} from "@/common/constants"; +import { FACILITY_FEATURE_TYPES, FACILITY_TYPES } from "@/common/constants"; import { phonePreg, validateLatitude, @@ -86,14 +72,6 @@ type FacilityForm = { latitude: string; longitude: string; pincode: string; - oxygen_capacity?: number; - type_b_cylinders?: number; - type_c_cylinders?: number; - type_d_cylinders?: number; - expected_oxygen_requirement?: number; - expected_type_b_cylinders?: number; - expected_type_c_cylinders?: number; - expected_type_d_cylinders?: number; }; const initForm: FacilityForm = { @@ -110,14 +88,6 @@ const initForm: FacilityForm = { latitude: "", longitude: "", pincode: "", - oxygen_capacity: undefined, - type_b_cylinders: undefined, - type_c_cylinders: undefined, - type_d_cylinders: undefined, - expected_oxygen_requirement: undefined, - expected_type_b_cylinders: undefined, - expected_type_c_cylinders: undefined, - expected_type_d_cylinders: undefined, }; const initError: Record = Object.assign( @@ -152,13 +122,8 @@ export const FacilityCreate = (props: FacilityProps) => { initialState, ); const [isLoading, setIsLoading] = useState(false); - const [currentStep, setCurrentStep] = useState(1); - const [createdFacilityId, setCreatedFacilityId] = useState(""); + const [showAutoFilledPincode, setShowAutoFilledPincode] = useState(false); - const [capacityData, setCapacityData] = useState>([]); - const [doctorData, setDoctorData] = useState>([]); - const [bedCapacityKey, setBedCapacityKey] = useState(0); - const [docCapacityKey, setDocCapacityKey] = useState(0); const [stateId, setStateId] = useState(); const [districtId, setDistrictId] = useState(); const [localBodyId, setLocalBodyId] = useState(); @@ -200,43 +165,6 @@ export const FacilityCreate = (props: FacilityProps) => { prefetch: !!districtId, }); - const getSteps = (): Step[] => { - return [ - { - id: 1, - name: "Facility details", - onClick: () => { - setCurrentStep(1); - }, - status: currentStep === 1 ? "current" : "complete", - disabled: currentStep > 1, - }, - { - id: 2, - name: "Bed Capacity", - onClick: () => { - setCurrentStep(2); - }, - status: - currentStep === 2 - ? "current" - : currentStep > 2 - ? "complete" - : "upcoming", - disabled: createdFacilityId == "", - }, - { - id: 3, - name: "Staff Capacity", - onClick: () => { - setCurrentStep(3); - }, - disabled: createdFacilityId == "", - status: currentStep === 3 ? "current" : "upcoming", - }, - ]; - }; - const { data: wardData, loading: isWardLoading } = useTanStackQueryInstead( routes.getWardByLocalBody, { @@ -276,14 +204,6 @@ export const FacilityCreate = (props: FacilityProps) => { longitude: data.longitude ? parseFloat(data.longitude).toFixed(7) : "", - type_b_cylinders: data.type_b_cylinders, - type_c_cylinders: data.type_c_cylinders, - type_d_cylinders: data.type_d_cylinders, - expected_type_b_cylinders: data.expected_type_b_cylinders, - expected_type_c_cylinders: data.expected_type_c_cylinders, - expected_type_d_cylinders: data.expected_type_d_cylinders, - expected_oxygen_requirement: data.expected_oxygen_requirement, - oxygen_capacity: data.oxygen_capacity, }; dispatch({ type: "set_form", form: formData }); setStateId(data.state); @@ -469,32 +389,6 @@ export const FacilityCreate = (props: FacilityProps) => { latitude: state.form.latitude, longitude: state.form.longitude, phone_number: parsePhoneNumber(state.form.phone_number), - oxygen_capacity: state.form.oxygen_capacity - ? state.form.oxygen_capacity - : 0, - type_b_cylinders: state.form.type_b_cylinders - ? state.form.type_b_cylinders - : 0, - type_c_cylinders: state.form.type_c_cylinders - ? state.form.type_c_cylinders - : 0, - type_d_cylinders: state.form.type_d_cylinders - ? state.form.type_d_cylinders - : 0, - expected_oxygen_requirement: state.form.expected_oxygen_requirement - ? state.form.expected_oxygen_requirement - : 0, - expected_type_b_cylinders: state.form.expected_type_b_cylinders - ? state.form.expected_type_b_cylinders - : 0, - - expected_type_c_cylinders: state.form.expected_type_c_cylinders - ? state.form.expected_type_c_cylinders - : 0, - - expected_type_d_cylinders: state.form.expected_type_d_cylinders - ? state.form.expected_type_d_cylinders - : 0, }; const { res, data: requestData } = facilityId @@ -515,14 +409,12 @@ export const FacilityCreate = (props: FacilityProps) => { Notification.Success({ msg: "Facility added successfully", }); - setCreatedFacilityId(String(id)); - setCurrentStep(2); } else { Notification.Success({ msg: "Facility updated successfully", }); - navigate(`/facility/${facilityId}`); } + navigate(`/facility/${id}`); } setIsLoading(false); } @@ -532,112 +424,6 @@ export const FacilityCreate = (props: FacilityProps) => { return ; } - let capacityList: any = null; - let totalBedCount = 0; - let totalOccupiedBedCount = 0; - - if (!capacityData || !capacityData.length) { - capacityList = ( -
    - {t("no_bed_types_found")} -
    - ); - } else { - capacityData.forEach((x) => { - totalBedCount += x.total_capacity ? x.total_capacity : 0; - totalOccupiedBedCount += x.current_capacity ? x.current_capacity : 0; - }); - - capacityList = ( -
    - { - return; - }} - /> - {BED_TYPES.map((x) => { - const res = capacityData.find((data) => { - return data.room_type === x; - }); - if (res) { - const removeCurrentBedType = (bedTypeId: number | undefined) => { - setCapacityData((state) => - state.filter((i) => i.id !== bedTypeId), - ); - setBedCapacityKey((bedCapacityKey) => bedCapacityKey + 1); - }; - return ( - { - const { res, data } = await request(routes.getCapacity, { - pathParams: { facilityId: createdFacilityId }, - }); - if (res?.ok && data) { - setCapacityData(data.results); - } - }} - /> - ); - } - })} -
    - ); - } - let doctorList: any = null; - if (!doctorData || !doctorData.length) { - doctorList = ( -
    - {t("no_staff")} -
    - ); - } else { - doctorList = ( -
    - {doctorData.map((data: DoctorModal) => { - const removeCurrentDoctorData = (doctorId: number | undefined) => { - setDoctorData((state) => - state.filter((i: DoctorModal) => i.id !== doctorId), - ); - setDocCapacityKey((docCapacityKey) => docCapacityKey + 1); - }; - - return ( - { - const { res, data } = await request(routes.listDoctor, { - pathParams: { facilityId: createdFacilityId }, - }); - if (res?.ok && data) { - setDoctorData(data.results); - } - }} - {...data} - removeDoctor={removeCurrentDoctorData} - /> - ); - })} -
    - ); - } - const field = (name: string) => { return { name, @@ -649,370 +435,210 @@ export const FacilityCreate = (props: FacilityProps) => { }; }; - switch (currentStep) { - case 3: - return ( - - -
    - { - navigate(`/facility/${createdFacilityId}`); - }} - handleUpdate={async () => { - const { res, data } = await request(routes.listDoctor, { - pathParams: { facilityId: createdFacilityId }, - }); - if (res?.ok && data) { - setDoctorData(data.results); - } + return ( + + +
    +
    handleSubmit(e)}> + { + dispatch({ type: "set_state", state: newState }); + setStateId(newState.form.state); + setDistrictId(newState.form.district); + setLocalBodyId(newState.form.local_body); }} + formData={state.form} /> -
    -
    -
    -
    {t("staff_list")}
    -
    -
    - {doctorList} -
    -
    -
    - ); - case 2: - return ( - - -
    - { - setCurrentStep(3); - }} - handleUpdate={async () => { - const { res, data } = await request(routes.getCapacity, { - pathParams: { facilityId: createdFacilityId }, - }); - if (res?.ok && data) { - setCapacityData(data.results); - } - }} - /> -
    -
    -
    -
    - {t("bed_capacity")} -
    -
    -
    {capacityList}
    -
    -
    - ); - case 1: - default: - return ( - - {!facilityId && } - -
    - handleSubmit(e)}> - { - dispatch({ type: "set_state", state: newState }); - setStateId(newState.form.state); - setDistrictId(newState.form.district); - setLocalBodyId(newState.form.local_body); - }} - formData={state.form} +
    + o.text} + optionValue={(o) => o.text} + /> + + o.name} + optionValue={(o) => o.id} + /> +
    + -
    - o.text} - optionValue={(o) => o.text} - /> - - o.name} - optionValue={(o) => o.id} - /> -
    - - {showAutoFilledPincode && ( -
    - - - State and district auto-filled from pincode - -
    - )} + {showAutoFilledPincode && ( +
    + + + State and district auto-filled from pincode +
    - o.name} - optionValue={(o) => o.id} - onChange={(event) => { - handleChange(event); - if (!event) return; - setStateId(event.value); - }} - /> - o.name} - optionValue={(o) => o.id} - onChange={(event) => { - handleChange(event); - if (!event) return; - setDistrictId(event.value); - }} - /> - o.name} - optionValue={(o) => o.id} - onChange={(event) => { - handleChange(event); - if (!event) return; - setLocalBodyId(event.value); - }} - /> - { - return { - id: e.id, - name: e.number + ": " + e.name, - }; - })} - optionLabel={(o) => o.name} - optionValue={(o) => o.id} - /> - - + o.name} + optionValue={(o) => o.id} + onChange={(event) => { + handleChange(event); + if (!event) return; + setStateId(event.value); + }} + /> + o.name} + optionValue={(o) => o.id} + onChange={(event) => { + handleChange(event); + if (!event) return; + setDistrictId(event.value); + }} + /> + o.name} + optionValue={(o) => o.id} + onChange={(event) => { + handleChange(event); + if (!event) return; + setLocalBodyId(event.value); + }} + /> + { + return { + id: e.id, + name: e.number + ": " + e.name, + }; + })} + optionLabel={(o) => o.name} + optionValue={(o) => o.id} + /> + + + {facilityId && ( +
    +

    {t("spokes")}

    + - {facilityId && ( -
    -

    {t("spokes")}

    - -
    - )} -
    - } - min={0} - /> - } - label={t("expected_burn_rate")} - min={0} - /> - - } - min={0} - /> - } - min={0} - /> - } - min={0} - /> - } - label={t("expected_burn_rate")} - min={0} - /> - } - min={0} - /> - } - min={0} - /> -
    - - {careConfig.kasp.enabled && ( - (o ? "Yes" : "No")} - optionValue={(o) => String(o)} - /> - )}
    + )} + {careConfig.kasp.enabled && ( + (o ? "Yes" : "No")} + optionValue={(o) => String(o)} + /> + )} +
    -
    - +
    + -
    - - <> - - - - - Select location from map - - - - - - - null} - handleOnSelectCurrentLocation={ - handleSelectCurrentLocation - } - /> - - - - -
    - } - placeholder="Longitude" - /> -
    -
    - goBack()} /> - -
    - +
    + + <> + + + + + Select location from map + + + + + + + null} + handleOnSelectCurrentLocation={ + handleSelectCurrentLocation + } + /> + + + + +
    + } + placeholder="Longitude" + />
    - - - ); - } -}; - -const FieldUnit = ({ unit }: { unit: string }) => { - return

    {unit}

    ; +
    + goBack()} /> + +
    + +
    + + + ); }; diff --git a/src/components/Facility/FacilityHome.tsx b/src/components/Facility/FacilityHome.tsx index cf671a51530..1808a1087ee 100644 --- a/src/components/Facility/FacilityHome.tsx +++ b/src/components/Facility/FacilityHome.tsx @@ -22,11 +22,7 @@ import Loading from "@/components/Common/Loading"; import { LocationSelect } from "@/components/Common/LocationSelect"; import DropdownMenu, { DropdownItem } from "@/components/Common/Menu"; import Page from "@/components/Common/Page"; -import Table from "@/components/Common/Table"; -import { FacilityBedCapacity } from "@/components/Facility/FacilityBedCapacity"; import FacilityBlock from "@/components/Facility/FacilityBlock"; -import { FacilityHomeTriage } from "@/components/Facility/FacilityHomeTriage"; -import { FacilityStaffList } from "@/components/Facility/FacilityStaffList"; import { FieldLabel } from "@/components/Form/FormFields/FormField"; import useAuthUser from "@/hooks/useAuthUser"; @@ -215,7 +211,10 @@ export const FacilityHome = ({ facilityId }: Props) => { onClick={() => setEditCoverImage(true)} className="md:mr-2 lg:mr-6 lg:h-80 lg:w-80" /> -
    +

    @@ -488,44 +487,6 @@ export const FacilityHome = ({ facilityId }: Props) => {

    - - - -
    -

    {t("oxygen_information")}

    -
    - - - - - ); }; diff --git a/src/components/Facility/FacilityHomeTriage.tsx b/src/components/Facility/FacilityHomeTriage.tsx deleted file mode 100644 index 25d2e0a7334..00000000000 --- a/src/components/Facility/FacilityHomeTriage.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { navigate } from "raviger"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import Table from "@/components/Common/Table"; - -import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; -import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -interface FacilityHomeTriageProps { - facilityId: string; -} - -export function FacilityHomeTriage({ facilityId }: FacilityHomeTriageProps) { - const { data } = useTanStackQueryInstead(routes.getTriage, { - pathParams: { facilityId }, - }); - - const tableRows = - data?.results?.map((result) => [ - String(result.entry_date), - String(result.num_patients_visited), - String(result.num_patients_home_quarantine), - String(result.num_patients_isolation), - String(result.num_patient_referred), - String(result.num_patient_confirmed_positive), - navigate(`/facility/${facilityId}/triage/${result.id}`)} - authorizeFor={NonReadOnlyUsers} - > - Edit - , - ]) ?? []; - - const tableHeadings = [ - "Date", - "Total Triaged", - "Advised Home Quarantine", - "Suspects Isolated", - "Referred", - "Confirmed positives", - "Actions", - ]; - - return ( -
    -
    -
    -
    Corona Triage
    - navigate(`/facility/${facilityId}/triage`)} - authorizeFor={NonReadOnlyUsers} - > - - Add Triage - -
    - -
    -
    - - {tableRows.length === 0 && ( - <> -
    -
    - No Data Found -
    - - )} - - - - ); -} diff --git a/src/components/Facility/FacilityList.tsx b/src/components/Facility/FacilityList.tsx index 0c1164649ca..f62f630dcaa 100644 --- a/src/components/Facility/FacilityList.tsx +++ b/src/components/Facility/FacilityList.tsx @@ -157,30 +157,17 @@ export const FacilityList = () => { options={
    advancedFilter.setShow(true)} /> - +
    + +
    } > diff --git a/src/components/Facility/FacilityStaffList.tsx b/src/components/Facility/FacilityStaffList.tsx deleted file mode 100644 index 5a3cd512ba9..00000000000 --- a/src/components/Facility/FacilityStaffList.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import DialogModal from "@/components/Common/Dialog"; -import Pagination from "@/components/Common/Pagination"; -import { StaffCapacity } from "@/components/Facility/StaffCapacity"; -import DoctorsCountCard from "@/components/Facility/StaffCountCard"; -import { DoctorModal } from "@/components/Facility/models"; -import { DoctorIcon } from "@/components/TeleIcu/Icons/DoctorIcon"; - -import useFilters from "@/hooks/useFilters"; - -import { DOCTOR_SPECIALIZATION } from "@/common/constants"; - -import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; -import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -export const FacilityStaffList = (props: any) => { - const { t } = useTranslation(); - const [doctorCapacityModalOpen, setDoctorCapacityModalOpen] = useState(false); - const { qParams, resultsPerPage, updatePage } = useFilters({ limit: 15 }); - const [totalDoctors, setTotalDoctors] = useState(0); - - const { data: doctorsList, refetch } = useTanStackQueryInstead( - routes.listDoctor, - { - pathParams: { facilityId: props.facilityId }, - query: { - limit: resultsPerPage, - offset: (qParams.page - 1) * resultsPerPage, - }, - onResponse: ({ res, data }) => { - if (res?.ok && data) { - let totalCount = 0; - data.results.map((doctor: DoctorModal) => { - if (doctor.count) { - totalCount += doctor.count; - } - }); - setTotalDoctors(totalCount); - } - }, - }, - ); - - let doctorList: any = null; - if (!doctorsList || !doctorsList.results.length) { - doctorList = ( -
    - {t("no_staff")} -
    - ); - } else { - doctorList = ( -
    -
    -
    -
    -
    - -
    -
    -
    - {t("total_staff")} -
    -

    {totalDoctors}

    -
    -
    -
    -
    - - {doctorsList.results.map((data: DoctorModal) => { - return ( - { - refetch(); - }} - {...data} - removeDoctor={() => refetch()} - /> - ); - })} -
    - ); - } - - return ( -
    -
    -
    -
    Staff Capacity
    - setDoctorCapacityModalOpen(true)} - disabled={doctorList.length === DOCTOR_SPECIALIZATION.length} - authorizeFor={NonReadOnlyUsers} - > - - Add Staff Types - -
    -
    - {doctorList} -
    -
    - - {doctorCapacityModalOpen && ( - setDoctorCapacityModalOpen(false)} - title="Add Staff Capacity" - className="max-w-md md:min-w-[600px]" - > - setDoctorCapacityModalOpen(false)} - handleUpdate={async () => { - refetch(); - }} - /> - - )} - updatePage(page)} - /> -
    - ); -}; diff --git a/src/components/Facility/StaffCapacity.tsx b/src/components/Facility/StaffCapacity.tsx deleted file mode 100644 index 53235dd68d0..00000000000 --- a/src/components/Facility/StaffCapacity.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import { useReducer, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import ButtonV2, { Cancel } from "@/components/Common/ButtonV2"; -import { DoctorModal } from "@/components/Facility/models"; -import { - FieldErrorText, - FieldLabel, -} from "@/components/Form/FormFields/FormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { FieldChangeEventHandler } from "@/components/Form/FormFields/Utils"; -import SelectMenuV2 from "@/components/Form/SelectMenuV2"; - -import { DOCTOR_SPECIALIZATION } from "@/common/constants"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -interface DoctorCapacityProps extends DoctorModal { - facilityId: string; - handleClose: () => void; - handleUpdate: () => void; - className?: string; - id?: number; -} - -const initForm: any = { - area: "", - count: "", -}; - -const initialState = { - form: { ...initForm }, - errors: { ...initForm }, -}; - -const doctorCapacityReducer = (state = initialState, action: any) => { - switch (action.type) { - case "set_form": { - return { - ...state, - form: action.form, - }; - } - case "set_error": { - return { - ...state, - errors: action.errors, - }; - } - default: - return state; - } -}; - -const getAllowedDoctorTypes = (existing?: DoctorModal[]) => { - if (!existing) return [...DOCTOR_SPECIALIZATION]; - - return DOCTOR_SPECIALIZATION.map((specialization) => { - const disabled = existing.some((i) => i.area === specialization.id); - return { ...specialization, disabled }; - }); -}; - -export const StaffCapacity = (props: DoctorCapacityProps) => { - const { t } = useTranslation(); - const { facilityId, handleClose, handleUpdate, className, id } = props; - const [state, dispatch] = useReducer(doctorCapacityReducer, initialState); - const [isLoading, setIsLoading] = useState(false); - - const specializationsQuery = useTanStackQueryInstead(routes.listDoctor, { - pathParams: { facilityId }, - query: { - limit: DOCTOR_SPECIALIZATION.length - 1, - }, - }); - - const { loading } = useTanStackQueryInstead(routes.getDoctor, { - pathParams: { facilityId, id: `${id}` }, - prefetch: !!id, - onResponse: ({ data }) => { - if (!data) return; - dispatch({ - type: "set_form", - form: { area: data.area, count: data.count }, - }); - }, - }); - - const doctorTypes = getAllowedDoctorTypes(specializationsQuery.data?.results); - - const isLastOptionType = - doctorTypes.filter((i) => i.disabled).length === - DOCTOR_SPECIALIZATION.length - 1; - - const headerText = !id ? "Add Staff Capacity" : "Edit Staff Capacity"; - const buttonText = !id - ? `Save ${!isLastOptionType ? "& Add More" : "Staff Capacity"}` - : "Update Staff Capacity"; - - const validateData = () => { - const errors = { ...initForm }; - let invalidForm = false; - Object.keys(state.form).forEach((field) => { - if (!state.form[field]) { - errors[field] = t("field_required"); - invalidForm = true; - } - if (field === "count" && state.form[field] < 0) { - errors[field] = "Staff count cannot be negative"; - invalidForm = true; - } - }); - if (invalidForm) { - dispatch({ type: "set_error", errors }); - return false; - } - dispatch({ type: "set_error", errors }); - return true; - }; - - const handleFormFieldChange: FieldChangeEventHandler = (event) => { - const form = { ...state.form, [event.name]: event.value }; - dispatch({ type: "set_form", form }); - }; - - const handleSubmit = async (e: any) => { - const submitBtnID = e.currentTarget?.id; - e.preventDefault(); - const valid = validateData(); - if (valid) { - setIsLoading(true); - const data = { - area: Number(state.form.area), - count: Number(state.form.count), - }; - const { res } = await (id - ? request(routes.updateDoctor, { - pathParams: { facilityId, id: `${id}` }, - body: data, - }) - : request(routes.createDoctor, { - pathParams: { facilityId }, - body: data, - })); - setIsLoading(false); - if (res?.ok) { - specializationsQuery.refetch(); - dispatch({ type: "set_form", form: initForm }); - if (!id) { - Notification.Success({ msg: "Staff count added successfully" }); - } else { - Notification.Success({ msg: "Staff count updated successfully" }); - } - } - handleUpdate(); - - if (submitBtnID === "save-and-exit") handleClose(); - } - }; - - return ( -
    - {isLoading || loading || specializationsQuery.loading ? ( -
    -
    - - Loading... -
    -
    - ) : ( -
    -
    - - Staff Type - - type.id == state.form.area)?.id} - options={ - id ? doctorTypes : doctorTypes.filter((type) => !type.disabled) - } - optionLabel={(option) => option.text} - optionValue={(option) => option.id} - requiredError={state.errors.area.length !== 0} - onChange={(e) => - handleFormFieldChange({ - name: "area", - value: e || "", - }) - } - disabled={!!id} - /> - -
    -
    - -
    -
    - handleClose()} /> - {!isLastOptionType && headerText === "Add Staff Capacity" && ( - - Save Staff Capacity - - )} - - {buttonText} - -
    -
    - )} -
    - ); -}; diff --git a/src/components/Facility/StaffCountCard.tsx b/src/components/Facility/StaffCountCard.tsx deleted file mode 100644 index 0c0984172b1..00000000000 --- a/src/components/Facility/StaffCountCard.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { useState } from "react"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import ConfirmDialog from "@/components/Common/ConfirmDialog"; -import DialogModal from "@/components/Common/Dialog"; -import { StaffCapacity } from "@/components/Facility/StaffCapacity"; -import { DoctorModal } from "@/components/Facility/models"; -import { DoctorIcon } from "@/components/TeleIcu/Icons/DoctorIcon"; - -import { DOCTOR_SPECIALIZATION } from "@/common/constants"; - -import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; - -interface DoctorsCountProps extends DoctorModal { - facilityId: string; - removeDoctor: (doctorId: number | undefined) => void; - handleUpdate: () => void; -} - -const StaffCountCard = (props: DoctorsCountProps) => { - const specialization = DOCTOR_SPECIALIZATION.find((i) => i.id === props.area); - const [openDeleteDialog, setOpenDeleteDialog] = useState(false); - const [open, setOpen] = useState(false); - const [selectedId, setSelectedId] = useState(-1); - - const handleDeleteSubmit = async () => { - if (!props.area) return; - - const { res } = await request(routes.deleteDoctor, { - pathParams: { facilityId: props.facilityId, area: `${props.area}` }, - }); - - if (res?.ok) { - props.removeDoctor(props.id); - Notification.Success({ - msg: "Staff specialization type deleted successfully", - }); - } - }; - - const handleDeleteClose = () => { - setOpenDeleteDialog(false); - }; - - return ( -
    -
    -
    -
    - -
    -
    -
    - {specialization?.text} -
    -

    {props.count}

    -
    -
    -
    - { - setSelectedId(props.area || 0); - setOpen(true); - }} - authorizeFor={NonReadOnlyUsers} - > - Edit - - setOpenDeleteDialog(true)} - authorizeFor={NonReadOnlyUsers} - > - Delete - -
    - -
    - {open && ( - setOpen(false)} - title="Update Staff Capacity" - > - { - setOpen(false); - }} - handleUpdate={() => { - props.handleUpdate(); - setOpen(false); - }} - id={selectedId} - /> - - )} -
    - ); -}; - -export default StaffCountCard; diff --git a/src/components/Facility/TriageForm.tsx b/src/components/Facility/TriageForm.tsx deleted file mode 100644 index 607adb0172f..00000000000 --- a/src/components/Facility/TriageForm.tsx +++ /dev/null @@ -1,321 +0,0 @@ -import dayjs from "dayjs"; -import { useReducer, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import Card from "@/CAREUI/display/Card"; -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Cancel, Submit } from "@/components/Common/ButtonV2"; -import ConfirmDialog from "@/components/Common/ConfirmDialog"; -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; -import { PatientStatsModel } from "@/components/Facility/models"; -import DateFormField from "@/components/Form/FormFields/DateFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; - -import useAppHistory from "@/hooks/useAppHistory"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import { dateQueryString, scrollTo } from "@/Utils/utils"; - -interface Props extends PatientStatsModel { - facilityId: string; - id?: string; -} - -const initForm: any = { - entry_date: null, - num_patients_visited: "", - num_patients_home_quarantine: "", - num_patients_isolation: "", - num_patient_referred: "", - num_patient_confirmed_positive: "", -}; - -const initialState = { - form: { ...initForm }, - errors: { ...initForm }, -}; - -const triageFormReducer = (state = initialState, action: any) => { - switch (action.type) { - case "set_form": { - return { - ...state, - form: action.form, - }; - } - case "set_error": { - return { - ...state, - errors: action.errors, - }; - } - default: - return state; - } -}; - -export const TriageForm = ({ facilityId, id }: Props) => { - const { t } = useTranslation(); - const { goBack } = useAppHistory(); - const [state, dispatch] = useReducer(triageFormReducer, initialState); - const [isLoading, setIsLoading] = useState(false); - const [openModalForExistingTriage, setOpenModalForExistingTriage] = - useState(false); - const headerText = !id ? "Add Triage" : "Edit Triage"; - const buttonText = !id ? "Save Triage" : "Update Triage"; - - const triageDetailsQuery = useTanStackQueryInstead(routes.getTriageDetails, { - pathParams: { facilityId, id: id! }, - prefetch: !!id, - onResponse: ({ data }) => { - if (!data) return; - dispatch({ - type: "set_form", - form: { - ...data, - entry_date: data.entry_date ? dayjs(data.entry_date).toDate() : null, - }, - }); - }, - }); - - const patientStatsQuery = useTanStackQueryInstead(routes.getTriage, { - pathParams: { facilityId }, - }); - - const patientStatsData = patientStatsQuery.data?.results ?? []; - - const facilityQuery = useTanStackQueryInstead(routes.getAnyFacility, { - pathParams: { id: facilityId }, - }); - const facilityName = facilityQuery.data?.name ?? ""; - - const validateForm = () => { - const errors = { ...initForm }; - let invalidForm = false; - Object.keys(state.form).forEach((field, _) => { - switch (field) { - case "entry_date": - if (!state.form[field]) { - errors[field] = t("field_required"); - invalidForm = true; - } - return; - case "num_patients_visited": - case "num_patients_home_quarantine": - case "num_patients_isolation": - case "num_patient_referred": - case "num_patient_confirmed_positive": - if (state.form[field] != null && state.form[field] < 0) { - errors[field] = "Value must be greater than or equal to 0"; - invalidForm = true; - } - return; - - default: - return; - } - }); - if (invalidForm) { - dispatch({ type: "set_error", errors }); - const firstError = Object.keys(errors).find((e) => errors[e]); - if (firstError) { - scrollTo(firstError); - } - return false; - } - dispatch({ type: "set_error", errors }); - return true; - }; - const isTriageExist = (data: any) => { - if ( - patientStatsData.filter( - (triageData) => triageData.entry_date === data.entry_date, - ).length === 1 - ) { - return true; - } - return false; - }; - - const handleSubmit = async () => { - setOpenModalForExistingTriage(false); - const validForm = validateForm(); - if (validForm) { - const data = { - entry_date: dateQueryString(state.form.entry_date), - num_patients_visited: Number(state.form.num_patients_visited), - num_patients_home_quarantine: Number( - state.form.num_patients_home_quarantine, - ), - num_patients_isolation: Number(state.form.num_patients_isolation), - num_patient_referred: Number(state.form.num_patient_referred), - num_patient_confirmed_positive: Number( - state.form.num_patient_confirmed_positive, - ), - }; - //proceed if the triage does not exist or proceed has allowed to proceed after seeing the modal or it's a edit feature of the same date - if ( - !isTriageExist(data) || - openModalForExistingTriage || - buttonText === "Update Triage" - ) { - setOpenModalForExistingTriage(false); - setIsLoading(true); - const { res } = await request(routes.createTriage, { - pathParams: { facilityId }, - body: data, - }); - setIsLoading(false); - if (res?.ok) { - dispatch({ type: "set_form", form: initForm }); - if (id) { - Notification.Success({ msg: "Triage updated successfully" }); - } else { - Notification.Success({ msg: "Triage created successfully" }); - } - goBack(); - } - } else { - setOpenModalForExistingTriage(true); - } - } - }; - - const handleFormFieldChange = (event: FieldChangeEvent) => { - dispatch({ - type: "set_form", - form: { ...state.form, [event.name]: event.value }, - }); - }; - - if ( - isLoading || - facilityQuery.loading || - triageDetailsQuery.loading || - patientStatsQuery.loading - ) { - return ; - } - - return ( -
    - - - -

    A Triage already exist on this date

    -
    - } - description="A Triage already exist on this date, If you wish to proceed then the existing triage will be over - written!" - variant="danger" - show={openModalForExistingTriage} - onClose={() => setOpenModalForExistingTriage(false)} - className="w-[48rem]" - action="Proceed" - onConfirm={handleSubmit} - /> - -
    - -
    { - e.preventDefault(); - handleSubmit(); - }} - > -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    - goBack()} /> - -
    - -
    -
    - - - ); -}; diff --git a/src/components/Facility/models.tsx b/src/components/Facility/models.tsx index a984efe6283..d25258be12d 100644 --- a/src/components/Facility/models.tsx +++ b/src/components/Facility/models.tsx @@ -67,16 +67,8 @@ export interface FacilityModel { latitude: number; longitude: number; }; - oxygen_capacity?: number; phone_number?: string; - type_b_cylinders?: number; - type_c_cylinders?: number; - type_d_cylinders?: number; middleware_address?: string; - expected_type_b_cylinders?: number; - expected_type_c_cylinders?: number; - expected_type_d_cylinders?: number; - expected_oxygen_requirement?: number; local_body_object?: LocalBodyModel; district_object?: DistrictModel; state_object?: StateModel; @@ -115,20 +107,6 @@ export interface FacilitySpokeRequest { export interface FacilitySpokeErrors {} -export interface CapacityModal { - id?: number; - room_type?: number; - modified_date?: any; - total_capacity?: number; - current_capacity?: number; -} - -export interface DoctorModal { - id?: number; - area?: number; - count?: number; -} - export interface OptionsType { id: number; text: string; @@ -225,17 +203,6 @@ export interface ConsultationModel { has_consents?: (typeof CONSENT_TYPE_CHOICES)[number]["id"][]; } -export interface PatientStatsModel { - id?: string; - entryDate?: string; - num_patients_visited?: number; - num_patients_home_quarantine?: number; - num_patients_isolation?: number; - num_patient_referred?: number; - entry_date?: string; - num_patient_confirmed_positive?: number; -} - export interface DupPatientModel { id: number; gender: string; diff --git a/src/components/Patient/PatientRegister.tsx b/src/components/Patient/PatientRegister.tsx index eb0594baa82..daca5e90a21 100644 --- a/src/components/Patient/PatientRegister.tsx +++ b/src/components/Patient/PatientRegister.tsx @@ -14,13 +14,13 @@ import Loading from "@/components/Common/Loading"; import PageTitle from "@/components/Common/PageTitle"; import Spinner from "@/components/Common/Spinner"; import Error404 from "@/components/ErrorPages/404"; -import { ILocalBodies } from "@/components/ExternalResult/models"; import DuplicatePatientDialog from "@/components/Facility/DuplicatePatientDialog"; import TransferPatientDialog from "@/components/Facility/TransferPatientDialog"; import { DistrictModel, DupPatientModel, FacilityModel, + LocalBodyModel, WardModel, } from "@/components/Facility/models"; import { @@ -205,7 +205,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { const [isLocalbodyLoading, setIsLocalbodyLoading] = useState(false); const [isWardLoading, setIsWardLoading] = useState(false); const [districts, setDistricts] = useState([]); - const [localBody, setLocalBody] = useState([]); + const [localBody, setLocalBody] = useState([]); const [ward, setWard] = useState([]); const [ageInputType, setAgeInputType] = useState< "date_of_birth" | "age" | "alert_for_age" From f84c7df63cd4f89eabceabb6a82003733f5f6997 Mon Sep 17 00:00:00 2001 From: G O Ashwin Praveen <143274955+ashwinpraveengo@users.noreply.github.com> Date: Mon, 16 Dec 2024 11:06:00 +0530 Subject: [PATCH 09/31] Fix alignment issue in timestamp in Created and Last Modified for Patient Dashboard (#9410) --- src/components/Facility/ConsultationDetails/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Facility/ConsultationDetails/index.tsx b/src/components/Facility/ConsultationDetails/index.tsx index 11f24f92968..62f8afdae80 100644 --- a/src/components/Facility/ConsultationDetails/index.tsx +++ b/src/components/Facility/ConsultationDetails/index.tsx @@ -331,7 +331,7 @@ export const ConsultationDetails = (props: any) => {
    -
    +
    Created:   {
    -
    +
    Last Modified:   Date: Mon, 16 Dec 2024 11:09:13 +0530 Subject: [PATCH 10/31] Fix phone number field overflow in search component on firefox (#9378) --- src/components/Form/FormFields/PhoneNumberFormField.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Form/FormFields/PhoneNumberFormField.tsx b/src/components/Form/FormFields/PhoneNumberFormField.tsx index 8b6566de8f7..72a3e0c3076 100644 --- a/src/components/Form/FormFields/PhoneNumberFormField.tsx +++ b/src/components/Form/FormFields/PhoneNumberFormField.tsx @@ -3,6 +3,8 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import React from "react"; import { useTranslation } from "react-i18next"; +import { cn } from "@/lib/utils"; + import CareIcon from "@/CAREUI/icons/CareIcon"; import { @@ -20,7 +22,6 @@ import phoneCodesJson from "@/common/static/countryPhoneAndFlags.json"; import { CountryData, - classNames, formatPhoneNumber as formatPhoneNumberUtil, getCountryCode, humanizeStrings, @@ -138,7 +139,7 @@ const PhoneNumberFormField = React.forwardRef( id={field.id} name={field.name} autoComplete={props.autoComplete ?? "tel"} - className={classNames( + className={cn( "cui-input-base h-full pl-14 tracking-widest sm:leading-6", field.error && "border-danger-500", field.className, From 5d9885bfd5fd8490bbf98aaa803b68b5c4a4d3ba Mon Sep 17 00:00:00 2001 From: Srijan Tripathi <72181144+srijantrpth@users.noreply.github.com> Date: Mon, 16 Dec 2024 11:15:11 +0530 Subject: [PATCH 11/31] Fix: Inconsistency in Title during creation of Resouce Request #9440 (#9442) --- public/locale/en.json | 4 ++-- public/locale/hi.json | 4 ++-- public/locale/kn.json | 4 ++-- public/locale/ml.json | 4 ++-- public/locale/ta.json | 4 ++-- src/components/Resource/ResourceCreate.tsx | 4 ++-- src/components/Resource/ResourceDetails.tsx | 2 +- src/components/Resource/ResourceDetailsUpdate.tsx | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index b9418edd719..2ceaf310fac 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -1249,8 +1249,8 @@ "req_atleast_one_uppercase": "Require at least one upper case", "request-sample-test": "Service Request", "request_consent": "Request Consent", - "request_description": "Description of Request", - "request_description_placeholder": "Type your description here", + "request_reason": "Reason of Request", + "request_reason_placeholder": "Type your description here", "request_sample_test": "Request Sample Test", "request_title": "Request Title", "request_title_placeholder": "Type your title here", diff --git a/public/locale/hi.json b/public/locale/hi.json index 9e6a667ba23..568ce0499f6 100644 --- a/public/locale/hi.json +++ b/public/locale/hi.json @@ -643,8 +643,8 @@ "req_atleast_one_lowercase": "कम से कम एक लोअर केस अक्षर की आवश्यकता है", "req_atleast_one_symbol": "कम से कम एक प्रतीक की आवश्यकता है", "req_atleast_one_uppercase": "कम से कम एक अपर केस की आवश्यकता है", - "request_description": "अनुरोध का विवरण", - "request_description_placeholder": "अपना विवरण यहाँ लिखें", + "request_reason": "अनुरोध का विवरण", + "request_reason_placeholder": "अपना विवरण यहाँ लिखें", "request_title": "शीर्षक का अनुरोध करें", "request_title_placeholder": "अपना शीर्षक यहाँ लिखें", "required": "आवश्यक", diff --git a/public/locale/kn.json b/public/locale/kn.json index faf50da3a23..4907cdd2d8c 100644 --- a/public/locale/kn.json +++ b/public/locale/kn.json @@ -645,8 +645,8 @@ "req_atleast_one_lowercase": "ಕನಿಷ್ಠ ಒಂದು ಸಣ್ಣ ಅಕ್ಷರದ ಅಗತ್ಯವಿದೆ", "req_atleast_one_symbol": "ಕನಿಷ್ಠ ಒಂದು ಚಿಹ್ನೆಯ ಅಗತ್ಯವಿದೆ", "req_atleast_one_uppercase": "ಕನಿಷ್ಠ ಒಂದು ದೊಡ್ಡ ಪ್ರಕರಣದ ಅಗತ್ಯವಿದೆ", - "request_description": "ವಿನಂತಿಯ ವಿವರಣೆ", - "request_description_placeholder": "ನಿಮ್ಮ ವಿವರಣೆಯನ್ನು ಇಲ್ಲಿ ಟೈಪ್ ಮಾಡಿ", + "request_reason": "ವಿನಂತಿಯ ವಿವರಣೆ", + "request_reason_placeholder": "ನಿಮ್ಮ ವಿವರಣೆಯನ್ನು ಇಲ್ಲಿ ಟೈಪ್ ಮಾಡಿ", "request_title": "ವಿನಂತಿ ಶೀರ್ಷಿಕೆ", "request_title_placeholder": "ನಿಮ್ಮ ಶೀರ್ಷಿಕೆಯನ್ನು ಇಲ್ಲಿ ಟೈಪ್ ಮಾಡಿ", "required": "ಅಗತ್ಯವಿದೆ", diff --git a/public/locale/ml.json b/public/locale/ml.json index 33dadcf9fb7..b875a64dd02 100644 --- a/public/locale/ml.json +++ b/public/locale/ml.json @@ -644,8 +644,8 @@ "req_atleast_one_lowercase": "കുറഞ്ഞത് ഒരു ചെറിയ അക്ഷരമെങ്കിലും ആവശ്യമാണ്", "req_atleast_one_symbol": "കുറഞ്ഞത് ഒരു ചിഹ്നമെങ്കിലും ആവശ്യമാണ്", "req_atleast_one_uppercase": "കുറഞ്ഞത് ഒരു വലിയ കേസെങ്കിലും ആവശ്യമാണ്", - "request_description": "അഭ്യർത്ഥനയുടെ വിവരണം", - "request_description_placeholder": "നിങ്ങളുടെ വിവരണം ഇവിടെ ടൈപ്പ് ചെയ്യുക", + "request_reason": "അഭ്യർത്ഥനയുടെ വിവരണം", + "request_reason_placeholder": "നിങ്ങളുടെ വിവരണം ഇവിടെ ടൈപ്പ് ചെയ്യുക", "request_title": "പേര് അഭ്യർത്ഥിക്കുക", "request_title_placeholder": "നിങ്ങളുടെ തലക്കെട്ട് ഇവിടെ ടൈപ്പ് ചെയ്യുക", "required": "ആവശ്യമാണ്", diff --git a/public/locale/ta.json b/public/locale/ta.json index 694efd52e20..cfe12b5fa6a 100644 --- a/public/locale/ta.json +++ b/public/locale/ta.json @@ -643,8 +643,8 @@ "req_atleast_one_lowercase": "குறைந்தபட்சம் ஒரு சிறிய எழுத்து தேவை", "req_atleast_one_symbol": "குறைந்தது ஒரு சின்னம் தேவை", "req_atleast_one_uppercase": "குறைந்தபட்சம் ஒரு பெரிய வழக்கு தேவை", - "request_description": "கோரிக்கையின் விளக்கம்", - "request_description_placeholder": "உங்கள் விளக்கத்தை இங்கே தட்டச்சு செய்யவும்", + "request_reason": "கோரிக்கையின் விளக்கம்", + "request_reason_placeholder": "உங்கள் விளக்கத்தை இங்கே தட்டச்சு செய்யவும்", "request_title": "தலைப்பு கோரிக்கை", "request_title_placeholder": "உங்கள் தலைப்பை இங்கே தட்டச்சு செய்யவும்", "required": "தேவை", diff --git a/src/components/Resource/ResourceCreate.tsx b/src/components/Resource/ResourceCreate.tsx index 4786164aa93..7c3e79cc4cb 100644 --- a/src/components/Resource/ResourceCreate.tsx +++ b/src/components/Resource/ResourceCreate.tsx @@ -309,11 +309,11 @@ export default function ResourceCreate(props: resourceProps) {
    - Description of Request:{" "} + Reason of Request{" "} {data.reason || "--"}
    diff --git a/src/components/Resource/ResourceDetailsUpdate.tsx b/src/components/Resource/ResourceDetailsUpdate.tsx index 46f92ca27db..b4ca02b7b45 100644 --- a/src/components/Resource/ResourceDetailsUpdate.tsx +++ b/src/components/Resource/ResourceDetailsUpdate.tsx @@ -297,7 +297,7 @@ export const ResourceDetailsUpdate = (props: resourceProps) => { placeholder="Type your description here" value={state.form.reason} onChange={handleChange} - label="Description of request*" + label="Reason of Request*" error={state.errors.reason} />
    From 89cefea26ef24565134cab4401d83807506169c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 11:19:37 +0530 Subject: [PATCH 12/31] Bump i18next-browser-languagedetector from 8.0.0 to 8.0.2 (#9370) Bumps [i18next-browser-languagedetector](https://github.com/i18next/i18next-browser-languageDetector) from 8.0.0 to 8.0.2. - [Changelog](https://github.com/i18next/i18next-browser-languageDetector/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/i18next-browser-languageDetector/compare/v8.0.0...v8.0.2) --- updated-dependencies: - dependency-name: i18next-browser-languagedetector dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e57456063b..94a84d3d179 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "events": "^3.3.0", "hi-profiles": "^1.1.0", "i18next": "^23.16.4", - "i18next-browser-languagedetector": "^8.0.0", + "i18next-browser-languagedetector": "^8.0.2", "i18next-http-backend": "^3.0.1", "postcss-loader": "^8.1.1", "qrcode.react": "^4.1.0", @@ -10609,9 +10609,9 @@ } }, "node_modules/i18next-browser-languagedetector": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", - "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.2.tgz", + "integrity": "sha512-shBvPmnIyZeD2VU5jVGIOWP7u9qNG3Lj7mpaiPFpbJ3LVfHZJvVzKR4v1Cb91wAOFpNw442N+LGPzHOHsten2g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2" diff --git a/package.json b/package.json index 3db351e974b..e5eaf3342c9 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "events": "^3.3.0", "hi-profiles": "^1.1.0", "i18next": "^23.16.4", - "i18next-browser-languagedetector": "^8.0.0", + "i18next-browser-languagedetector": "^8.0.2", "i18next-http-backend": "^3.0.1", "postcss-loader": "^8.1.1", "qrcode.react": "^4.1.0", From 96bc802ec57505b4e53e46f4f58514998bdb066e Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:34:59 +0530 Subject: [PATCH 13/31] Fixed Redirection of Critical care updation (#9453) --- src/components/Patient/DailyRounds.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Patient/DailyRounds.tsx b/src/components/Patient/DailyRounds.tsx index f0c78522e40..cf43a5adab9 100644 --- a/src/components/Patient/DailyRounds.tsx +++ b/src/components/Patient/DailyRounds.tsx @@ -411,7 +411,7 @@ export const DailyRounds = (props: any) => { ); } else { navigate( - `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/log_updates/${obj.id}/update`, + `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/log_updates/${obj.id}/critical_care/update`, ); } } From f7b8283decd380a4c5acfd596e9ffe8ef3c7d537 Mon Sep 17 00:00:00 2001 From: Srijan Tripathi <72181144+srijantrpth@users.noreply.github.com> Date: Tue, 17 Dec 2024 09:23:10 +0530 Subject: [PATCH 14/31] Added Custom Headers Logic to Query (#9458) --------- Co-authored-by: rithviknishad --- src/Utils/request/query.ts | 2 +- src/Utils/request/types.ts | 1 + src/Utils/request/utils.ts | 24 +++++++----------------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/Utils/request/query.ts b/src/Utils/request/query.ts index 3431f625728..53fe96878a2 100644 --- a/src/Utils/request/query.ts +++ b/src/Utils/request/query.ts @@ -13,7 +13,7 @@ async function queryRequest( const fetchOptions: RequestInit = { method, - headers: makeHeaders(noAuth ?? false), + headers: makeHeaders(noAuth ?? false, options?.headers), signal: options?.signal, }; diff --git a/src/Utils/request/types.ts b/src/Utils/request/types.ts index 20f095ae6fd..2b4be31d28d 100644 --- a/src/Utils/request/types.ts +++ b/src/Utils/request/types.ts @@ -41,6 +41,7 @@ export interface QueryOptions
    { body?: TBody; silent?: boolean; signal?: AbortSignal; + headers?: HeadersInit; } export interface PaginatedResponse { diff --git a/src/Utils/request/utils.ts b/src/Utils/request/utils.ts index 8fd7bc96bea..03427c17b44 100644 --- a/src/Utils/request/utils.ts +++ b/src/Utils/request/utils.ts @@ -50,33 +50,23 @@ const ensurePathNotMissingReplacements = (path: string) => { } }; -export function makeHeaders(noAuth: boolean) { - const headers = new Headers({ - "Content-Type": "application/json", - Accept: "application/json", - }); +export function makeHeaders(noAuth: boolean, additionalHeaders?: HeadersInit) { + const headers = new Headers(additionalHeaders); + + headers.set("Content-Type", "application/json"); + headers.append("Accept", "application/json"); if (!noAuth) { - const token = getAuthorizationHeader(); + const token = localStorage.getItem(LocalStorageKeys.accessToken); if (token) { - headers.append("Authorization", token); + headers.append("Authorization", `Bearer ${token}`); } } return headers; } -export function getAuthorizationHeader() { - const bearerToken = localStorage.getItem(LocalStorageKeys.accessToken); - - if (bearerToken) { - return `Bearer ${bearerToken}`; - } - - return null; -} - export function mergeRequestOptions( options: RequestOptions, overrides: RequestOptions, From 69527b8bc33a69a15b0c706218d905e9ec07e296 Mon Sep 17 00:00:00 2001 From: Mahendar Chikolla <119734520+Mahendar0701@users.noreply.github.com> Date: Tue, 17 Dec 2024 09:55:04 +0530 Subject: [PATCH 15/31] Fix: Duplicate network requests in Patient Details page (#9297) --- src/components/Facility/PatientNotesList.tsx | 12 +----- .../Patient/PatientDetailsTab/Demography.tsx | 16 ++++--- .../PatientDetailsTab/EncounterHistory.tsx | 42 ++----------------- .../HealthProfileSummary.tsx | 6 +-- .../PatientDetailsTab/ImmunisationRecords.tsx | 7 ++-- .../Patient/PatientDetailsTab/Notes.tsx | 40 ++++-------------- .../PatientDetailsTab/ShiftingHistory.tsx | 5 +-- .../Patient/PatientDetailsTab/index.tsx | 15 +++---- src/components/Patient/PatientHome.tsx | 38 +++++++++-------- 9 files changed, 56 insertions(+), 125 deletions(-) diff --git a/src/components/Facility/PatientNotesList.tsx b/src/components/Facility/PatientNotesList.tsx index dcf84e8b708..8db68395744 100644 --- a/src/components/Facility/PatientNotesList.tsx +++ b/src/components/Facility/PatientNotesList.tsx @@ -58,18 +58,10 @@ const PatientNotesList = (props: PatientNotesProps) => { }; useEffect(() => { - if (reload) { + if (reload || thread) { fetchNotes(); } - }, [reload]); - - useEffect(() => { - fetchNotes(); - }, [thread]); - - useEffect(() => { - setReload(true); - }, []); + }, [reload, thread]); const handleNext = () => { if (state.cPage < state.totalPages) { diff --git a/src/components/Patient/PatientDetailsTab/Demography.tsx b/src/components/Patient/PatientDetailsTab/Demography.tsx index e5bed5abfee..d6e1379cd7e 100644 --- a/src/components/Patient/PatientDetailsTab/Demography.tsx +++ b/src/components/Patient/PatientDetailsTab/Demography.tsx @@ -9,21 +9,21 @@ import AuthorizedChild from "@/CAREUI/misc/AuthorizedChild"; import { Button } from "@/components/ui/button"; +import { InsuranceDetailsCard } from "@/components/Patient/InsuranceDetailsCard"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; +import { parseOccupation } from "@/components/Patient/PatientHome"; +import { AssignedToObjectModel } from "@/components/Patient/models"; + import useAuthUser from "@/hooks/useAuthUser"; import { GENDER_TYPES } from "@/common/constants"; import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; +import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; import { formatName, formatPatientAge } from "@/Utils/utils"; -import { PatientProps } from "."; -import * as Notification from "../../../Utils/Notifications"; -import { InsuranceDetailsCard } from "../InsuranceDetailsCard"; -import { parseOccupation } from "../PatientHome"; -import { AssignedToObjectModel } from "../models"; - export const Demography = (props: PatientProps) => { const { patientData, facilityId, id } = props; const authUser = useAuthUser(); @@ -64,9 +64,7 @@ export const Demography = (props: PatientProps) => { const { data: insuranceDetials } = useTanStackQueryInstead( routes.hcx.policies.list, { - query: { - patient: id, - }, + query: { patient: id }, }, ); diff --git a/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx b/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx index b81009efa74..9ad679f8e9a 100644 --- a/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx +++ b/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx @@ -1,56 +1,20 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import { useTranslation } from "react-i18next"; import PaginatedList from "@/CAREUI/misc/PaginatedList"; import CircularProgress from "@/components/Common/CircularProgress"; -import Loading from "@/components/Common/Loading"; import { ConsultationCard } from "@/components/Facility/ConsultationCard"; import { ConsultationModel } from "@/components/Facility/models"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; -import useAuthUser from "@/hooks/useAuthUser"; - -import { triggerGoal } from "@/Integrations/Plausible"; import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -import { PatientProps } from "."; -import { PatientModel } from "../models"; const EncounterHistory = (props: PatientProps) => { - const { patientData: initialPatientData, facilityId, id } = props; - const [patientData, setPatientData] = - useState(initialPatientData); - const authUser = useAuthUser(); - - useEffect(() => { - setPatientData(initialPatientData); - }, [initialPatientData]); + const { patientData, id, refetch } = props; const { t } = useTranslation(); - const { loading: isLoading, refetch } = useTanStackQueryInstead( - routes.getPatient, - { - pathParams: { - id, - }, - onResponse: ({ res, data }) => { - if (res?.ok && data) { - setPatientData(data); - } - triggerGoal("Patient Profile Viewed", { - facilityId: facilityId, - userId: authUser.id, - }); - }, - }, - ); - - if (isLoading) { - return ; - } - return ( { const { patientData, facilityId, id } = props; diff --git a/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx b/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx index 7ee828868fc..b16059abe46 100644 --- a/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx +++ b/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx @@ -5,18 +5,17 @@ import CareIcon from "@/CAREUI/icons/CareIcon"; import { Button } from "@/components/ui/button"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; +import { PatientModel } from "@/components/Patient/models"; import { UserModel } from "@/components/Users/models"; import useAuthUser from "@/hooks/useAuthUser"; import { ADMIN_USER_TYPES } from "@/common/constants"; +import * as Notification from "@/Utils/Notifications"; import { formatDateTime } from "@/Utils/utils"; -import { PatientProps } from "."; -import * as Notification from "../../../Utils/Notifications"; -import { PatientModel } from "../models"; - export const ImmunisationRecords = (props: PatientProps) => { const { patientData, facilityId, id } = props; diff --git a/src/components/Patient/PatientDetailsTab/Notes.tsx b/src/components/Patient/PatientDetailsTab/Notes.tsx index 646e97d3bd5..4fccf7a1119 100644 --- a/src/components/Patient/PatientDetailsTab/Notes.tsx +++ b/src/components/Patient/PatientDetailsTab/Notes.tsx @@ -1,5 +1,5 @@ import { t } from "i18next"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -11,6 +11,7 @@ import { PatientNotesModel, } from "@/components/Facility/models"; import AutoExpandingTextInputFormField from "@/components/Form/FormFields/AutoExpandingTextInputFormField"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; import useAuthUser from "@/hooks/useAuthUser"; import { useMessageListener } from "@/hooks/useMessageListener"; @@ -18,19 +19,13 @@ import { useMessageListener } from "@/hooks/useMessageListener"; import { PATIENT_NOTES_THREADS } from "@/common/constants"; import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; +import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import { classNames, keysOf } from "@/Utils/utils"; -import * as Notification from "../../../Utils/Notifications"; - -interface PatientNotesProps { - id: string; - facilityId: string; -} - -const PatientNotes = (props: PatientNotesProps) => { - const { id: patientId, facilityId } = props; +const PatientNotes = (props: PatientProps) => { + const { patientData, id: patientId, facilityId } = props; const authUser = useAuthUser(); const [thread, setThread] = useState( @@ -39,7 +34,6 @@ const PatientNotes = (props: PatientNotesProps) => { : PATIENT_NOTES_THREADS.Doctors, ); - const [patientActive, setPatientActive] = useState(true); const [noteField, setNoteField] = useState(""); const [reload, setReload] = useState(false); const [reply_to, setReplyTo] = useState( @@ -84,26 +78,6 @@ const PatientNotes = (props: PatientNotesProps) => { } }; - useEffect(() => { - async function fetchPatientName() { - if (patientId) { - try { - const { data } = await request(routes.getPatient, { - pathParams: { id: patientId }, - }); - if (data) { - setPatientActive(data.is_active ?? true); - } - } catch (error) { - Notification.Error({ - msg: "Failed to fetch patient status", - }); - } - } - } - fetchPatientName(); - }, [patientId]); - useMessageListener((data) => { const message = data?.message; if ( @@ -161,7 +135,7 @@ const PatientNotes = (props: PatientNotesProps) => { errorClassName="hidden" innerClassName="pr-10" placeholder={t("notes_placeholder")} - disabled={!patientActive} + disabled={!patientData.is_active} /> { className="absolute right-2" ghost size="small" - disabled={!patientActive} + disabled={!patientData.is_active} authorizeFor={NonReadOnlyUsers} > diff --git a/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx b/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx index b9f63da5512..6bd1bb5bbb7 100644 --- a/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx +++ b/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx @@ -4,6 +4,8 @@ import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; import ButtonV2 from "@/components/Common/ButtonV2"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; +import { PatientModel } from "@/components/Patient/models"; import { formatFilter } from "@/components/Resource/ResourceCommons"; import ShiftingTable from "@/components/Shifting/ShiftingTable"; @@ -13,9 +15,6 @@ import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import { PatientProps } from "."; -import { PatientModel } from "../models"; - const ShiftingHistory = (props: PatientProps) => { const { patientData, facilityId, id } = props; const { t } = useTranslation(); diff --git a/src/components/Patient/PatientDetailsTab/index.tsx b/src/components/Patient/PatientDetailsTab/index.tsx index 6f4b7ecc982..55c292438ca 100644 --- a/src/components/Patient/PatientDetailsTab/index.tsx +++ b/src/components/Patient/PatientDetailsTab/index.tsx @@ -1,15 +1,16 @@ -import { PatientModel } from "../models"; -import { Demography } from "./Demography"; -import EncounterHistory from "./EncounterHistory"; -import { HealthProfileSummary } from "./HealthProfileSummary"; -import { ImmunisationRecords } from "./ImmunisationRecords"; -import PatientNotes from "./Notes"; -import ShiftingHistory from "./ShiftingHistory"; +import EncounterHistory from "@/components/Patient/PatientDetailsTab//EncounterHistory"; +import { HealthProfileSummary } from "@/components/Patient/PatientDetailsTab//HealthProfileSummary"; +import { ImmunisationRecords } from "@/components/Patient/PatientDetailsTab//ImmunisationRecords"; +import PatientNotes from "@/components/Patient/PatientDetailsTab//Notes"; +import ShiftingHistory from "@/components/Patient/PatientDetailsTab//ShiftingHistory"; +import { Demography } from "@/components/Patient/PatientDetailsTab/Demography"; +import { PatientModel } from "@/components/Patient/models"; export interface PatientProps { facilityId: string; id: string; patientData: PatientModel; + refetch: () => void; } export const patientTabs = [ diff --git a/src/components/Patient/PatientHome.tsx b/src/components/Patient/PatientHome.tsx index 253bd823ac0..1c992445706 100644 --- a/src/components/Patient/PatientHome.tsx +++ b/src/components/Patient/PatientHome.tsx @@ -2,8 +2,22 @@ import { Link, navigate } from "raviger"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; +import Chip from "@/CAREUI/display/Chip"; +import CareIcon from "@/CAREUI/icons/CareIcon"; + +import { Avatar } from "@/components/Common/Avatar"; +import ButtonV2 from "@/components/Common/ButtonV2"; import ConfirmDialog from "@/components/Common/ConfirmDialog"; +import Loading from "@/components/Common/Loading"; +import Page from "@/components/Common/Page"; import UserAutocomplete from "@/components/Common/UserAutocompleteFormField"; +import { patientTabs } from "@/components/Patient/PatientDetailsTab"; +import { isPatientMandatoryDataFilled } from "@/components/Patient/Utils"; +import { + AssignedToObjectModel, + PatientModel, +} from "@/components/Patient/models"; +import { SkillModel, UserBareMinimum } from "@/components/Users/models"; import useAuthUser from "@/hooks/useAuthUser"; @@ -13,16 +27,13 @@ import { OCCUPATION_TYPES, } from "@/common/constants"; +import { triggerGoal } from "@/Integrations/Plausible"; +import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; +import * as Notification from "@/Utils/Notifications"; import dayjs from "@/Utils/dayjs"; import routes from "@/Utils/request/api"; - -import Chip from "../../CAREUI/display/Chip"; -import CareIcon from "../../CAREUI/icons/CareIcon"; -import { triggerGoal } from "../../Integrations/Plausible"; -import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; -import * as Notification from "../../Utils/Notifications"; -import request from "../../Utils/request/request"; -import useTanStackQueryInstead from "../../Utils/request/useQuery"; +import request from "@/Utils/request/request"; +import useTanStackQueryInstead from "@/Utils/request/useQuery"; import { formatDateTime, formatName, @@ -31,15 +42,7 @@ import { isAntenatal, isPostPartum, relativeDate, -} from "../../Utils/utils"; -import { Avatar } from "../Common/Avatar"; -import ButtonV2 from "../Common/ButtonV2"; -import Loading from "../Common/Loading"; -import Page from "../Common/Page"; -import { SkillModel, UserBareMinimum } from "../Users/models"; -import { patientTabs } from "./PatientDetailsTab"; -import { isPatientMandatoryDataFilled } from "./Utils"; -import { AssignedToObjectModel, PatientModel } from "./models"; +} from "@/Utils/utils"; export const parseOccupation = (occupation: string | undefined) => { return OCCUPATION_TYPES.find((i) => i.value === occupation)?.text; @@ -447,6 +450,7 @@ export const PatientHome = (props: { facilityId={facilityId || ""} id={id} patientData={patientData} + refetch={refetch} /> )} From ba80ea9087a7f03c9dfb5f8a3a4767c6874bb3f1 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 17 Dec 2024 06:43:36 +0000 Subject: [PATCH 16/31] Adds `useMutation` compatible utility function and other abstractions (#9463) --- .cursorrules | 2 +- src/App.tsx | 8 ++- src/Utils/request/README.md | 82 +++++++++++++++++++++++- src/Utils/request/errorHandler.ts | 10 +-- src/Utils/request/mutate.ts | 26 ++++++++ src/Utils/request/query.ts | 29 ++++++--- src/Utils/request/queryError.ts | 24 ------- src/Utils/request/types.ts | 37 ++++++++++- src/Utils/request/utils.ts | 19 ++++-- src/components/Facility/FacilityHome.tsx | 12 +--- src/components/Users/UserAvatar.tsx | 8 +-- src/components/Users/UserProfile.tsx | 8 +-- 12 files changed, 194 insertions(+), 71 deletions(-) create mode 100644 src/Utils/request/mutate.ts delete mode 100644 src/Utils/request/queryError.ts diff --git a/.cursorrules b/.cursorrules index 94ebea1bd57..84ed409d44b 100644 --- a/.cursorrules +++ b/.cursorrules @@ -31,5 +31,5 @@ UI and Styling General Guidelines -- Care uses a custom useQuery hook to fetch data from the API. (Docs @ /Utils/request/useQuery) +- Care uses TanStack Query for data fetching from the API along with query and mutate utilities for the queryFn and mutationFn. (Docs @ /Utils/request/README.md) - APIs are defined in the api.tsx file. diff --git a/src/App.tsx b/src/App.tsx index b4d1a1570a9..1d8acbb8e59 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,5 @@ import { + MutationCache, QueryCache, QueryClient, QueryClientProvider, @@ -16,7 +17,7 @@ import AuthUserProvider from "@/Providers/AuthUserProvider"; import HistoryAPIProvider from "@/Providers/HistoryAPIProvider"; import Routers from "@/Routers"; import { FeatureFlagsProvider } from "@/Utils/featureFlags"; -import { handleQueryError } from "@/Utils/request/errorHandler"; +import { handleHttpError } from "@/Utils/request/errorHandler"; import { PubSubProvider } from "./Utils/pubsubContext"; @@ -29,7 +30,10 @@ const queryClient = new QueryClient({ }, }, queryCache: new QueryCache({ - onError: handleQueryError, + onError: handleHttpError, + }), + mutationCache: new MutationCache({ + onError: handleHttpError, }), }); diff --git a/src/Utils/request/README.md b/src/Utils/request/README.md index 3c1279e1554..75dfab6c10f 100644 --- a/src/Utils/request/README.md +++ b/src/Utils/request/README.md @@ -67,10 +67,12 @@ function FacilityDetails({ id }: { id: string }) { - Integrates with our global error handling. ```typescript -interface QueryOptions { +interface APICallOptions { pathParams?: Record; // URL parameters - queryParams?: Record; // Query string parameters + queryParams?: QueryParams; // Query string parameters + body?: TBody; // Request body silent?: boolean; // Suppress error notifications + headers?: HeadersInit; // Additional headers } // Basic usage @@ -100,6 +102,82 @@ are automatically handled. Use the `silent: true` option to suppress error notifications for specific queries. +## Using Mutations with TanStack Query + +For data mutations, we provide a `mutate` utility that works seamlessly with TanStack Query's `useMutation` hook. + +```tsx +import { useMutation } from "@tanstack/react-query"; +import mutate from "@/Utils/request/mutate"; + +function CreatePrescription({ consultationId }: { consultationId: string }) { + const { mutate: createPrescription, isPending } = useMutation({ + mutationFn: mutate(MedicineRoutes.createPrescription, { + pathParams: { consultationId }, + }), + onSuccess: () => { + toast.success("Prescription created successfully"); + }, + }); + + return ( + + ); +} + +// With path parameters and complex payload +function UpdatePatient({ patientId }: { patientId: string }) { + const { mutate: updatePatient } = useMutation({ + mutationFn: mutate(PatientRoutes.update, { + pathParams: { id: patientId }, + silent: true // Optional: suppress error notifications + }) + }); + + const handleSubmit = (data: PatientData) => { + updatePatient(data); + }; + + return ; +} +``` + +### mutate + +`mutate` is our wrapper around the API call functionality that works with TanStack Query's `useMutation`. It: +- Handles request body serialization +- Sets appropriate headers +- Integrates with our global error handling +- Provides TypeScript type safety for your mutation payload + +```typescript +interface APICallOptions { + pathParams?: Record; // URL parameters + queryParams?: QueryParams; // Query string parameters + body?: TBody; // Request body + silent?: boolean; // Suppress error notifications + headers?: HeadersInit; // Additional headers +} + +// Basic usage +useMutation({ + mutationFn: mutate(routes.users.create) +}); + +// With parameters +useMutation({ + mutationFn: mutate(routes.users.update, { + pathParams: { id }, + silent: true // Optional: suppress error notifications + }) +}); +``` + ## Migration Guide & Reference ### Understanding the Transition diff --git a/src/Utils/request/errorHandler.ts b/src/Utils/request/errorHandler.ts index 68d7e4600bb..c5609181f13 100644 --- a/src/Utils/request/errorHandler.ts +++ b/src/Utils/request/errorHandler.ts @@ -1,14 +1,14 @@ import { navigate } from "raviger"; import * as Notifications from "@/Utils/Notifications"; -import { QueryError } from "@/Utils/request/queryError"; +import { HTTPError } from "@/Utils/request/types"; -export function handleQueryError(error: Error) { +export function handleHttpError(error: Error) { if (error.name === "AbortError") { return; } - if (!(error instanceof QueryError)) { + if (!(error instanceof HTTPError)) { Notifications.Error({ msg: error.message || "Something went wrong!" }); return; } @@ -34,7 +34,7 @@ export function handleQueryError(error: Error) { }); } -function isSessionExpired(error: QueryError["cause"]) { +function isSessionExpired(error: HTTPError["cause"]) { return ( // If Authorization header is not valid error?.code === "token_not_valid" || @@ -49,6 +49,6 @@ function handleSessionExpired() { } } -function isBadRequest(error: QueryError) { +function isBadRequest(error: HTTPError) { return error.status === 400 || error.status === 406; } diff --git a/src/Utils/request/mutate.ts b/src/Utils/request/mutate.ts new file mode 100644 index 00000000000..2372920c162 --- /dev/null +++ b/src/Utils/request/mutate.ts @@ -0,0 +1,26 @@ +import { callApi } from "@/Utils/request/query"; +import { APICallOptions, Route } from "@/Utils/request/types"; + +/** + * Creates a TanStack Query compatible mutation function. + * + * Example: + * ```tsx + * const { mutate: createPrescription, isPending } = useMutation({ + * mutationFn: mutate(MedicineRoutes.createPrescription, { + * pathParams: { consultationId }, + * }), + * onSuccess: () => { + * toast.success(t("medication_request_prescribed")); + * }, + * }); + * ``` + */ +export default function mutate( + route: Route, + options?: APICallOptions, +) { + return (variables: TBody) => { + return callApi(route, { ...options, body: variables }); + }; +} diff --git a/src/Utils/request/query.ts b/src/Utils/request/query.ts index 53fe96878a2..dc79bd874ec 100644 --- a/src/Utils/request/query.ts +++ b/src/Utils/request/query.ts @@ -1,13 +1,12 @@ import careConfig from "@careConfig"; -import { QueryError } from "@/Utils/request/queryError"; import { getResponseBody } from "@/Utils/request/request"; -import { QueryOptions, Route } from "@/Utils/request/types"; +import { APICallOptions, HTTPError, Route } from "@/Utils/request/types"; import { makeHeaders, makeUrl } from "@/Utils/request/utils"; -async function queryRequest( +export async function callApi( { path, method, noAuth }: Route, - options?: QueryOptions, + options?: APICallOptions, ): Promise { const url = `${careConfig.apiUrl}${makeUrl(path, options?.queryParams, options?.pathParams)}`; @@ -32,7 +31,7 @@ async function queryRequest( const data = await getResponseBody(res); if (!res.ok) { - throw new QueryError({ + throw new HTTPError({ message: "Request Failed", status: res.status, silent: options?.silent ?? false, @@ -44,13 +43,27 @@ async function queryRequest( } /** - * Creates a TanStack Query compatible request function + * Creates a TanStack Query compatible query function. + * + * Example: + * ```tsx + * const { data, isLoading } = useQuery({ + * queryKey: ["prescription", consultationId], + * queryFn: query(MedicineRoutes.prescription, { + * pathParams: { consultationId }, + * queryParams: { + * limit: 10, + * offset: 0, + * }, + * }), + * }); + * ``` */ export default function query( route: Route, - options?: QueryOptions, + options?: APICallOptions, ) { return ({ signal }: { signal: AbortSignal }) => { - return queryRequest(route, { ...options, signal }); + return callApi(route, { ...options, signal }); }; } diff --git a/src/Utils/request/queryError.ts b/src/Utils/request/queryError.ts deleted file mode 100644 index cdfad312ef4..00000000000 --- a/src/Utils/request/queryError.ts +++ /dev/null @@ -1,24 +0,0 @@ -type QueryErrorCause = Record | undefined; - -export class QueryError extends Error { - status: number; - silent: boolean; - cause?: QueryErrorCause; - - constructor({ - message, - status, - silent, - cause, - }: { - message: string; - status: number; - silent: boolean; - cause?: Record; - }) { - super(message, { cause }); - this.status = status; - this.silent = silent; - this.cause = cause; - } -} diff --git a/src/Utils/request/types.ts b/src/Utils/request/types.ts index 2b4be31d28d..a53a28fb0b0 100644 --- a/src/Utils/request/types.ts +++ b/src/Utils/request/types.ts @@ -35,15 +35,46 @@ export interface RequestOptions { silent?: boolean; } -export interface QueryOptions { - pathParams?: Record; - queryParams?: Record; +export interface APICallOptions { + pathParams?: Record; + queryParams?: QueryParams; body?: TBody; silent?: boolean; signal?: AbortSignal; headers?: HeadersInit; } +type HTTPErrorCause = Record | undefined; + +export class HTTPError extends Error { + status: number; + silent: boolean; + cause?: HTTPErrorCause; + + constructor({ + message, + status, + silent, + cause, + }: { + message: string; + status: number; + silent: boolean; + cause?: Record; + }) { + super(message, { cause }); + this.status = status; + this.silent = silent; + this.cause = cause; + } +} + +declare module "@tanstack/react-query" { + interface Register { + defaultError: HTTPError; + } +} + export interface PaginatedResponse { count: number; next: string | null; diff --git a/src/Utils/request/utils.ts b/src/Utils/request/utils.ts index 03427c17b44..26d69672f53 100644 --- a/src/Utils/request/utils.ts +++ b/src/Utils/request/utils.ts @@ -56,17 +56,24 @@ export function makeHeaders(noAuth: boolean, additionalHeaders?: HeadersInit) { headers.set("Content-Type", "application/json"); headers.append("Accept", "application/json"); - if (!noAuth) { - const token = localStorage.getItem(LocalStorageKeys.accessToken); - - if (token) { - headers.append("Authorization", `Bearer ${token}`); - } + const authorizationHeader = getAuthorizationHeader(); + if (authorizationHeader && !noAuth) { + headers.append("Authorization", authorizationHeader); } return headers; } +export function getAuthorizationHeader() { + const accessToken = localStorage.getItem(LocalStorageKeys.accessToken); + + if (accessToken) { + return `Bearer ${accessToken}`; + } + + return null; +} + export function mergeRequestOptions( options: RequestOptions, overrides: RequestOptions, diff --git a/src/components/Facility/FacilityHome.tsx b/src/components/Facility/FacilityHome.tsx index 1808a1087ee..7881a43123d 100644 --- a/src/components/Facility/FacilityHome.tsx +++ b/src/components/Facility/FacilityHome.tsx @@ -28,11 +28,7 @@ import { FieldLabel } from "@/components/Form/FormFields/FormField"; import useAuthUser from "@/hooks/useAuthUser"; import useSlug from "@/hooks/useSlug"; -import { - FACILITY_FEATURE_TYPES, - LocalStorageKeys, - USER_TYPES, -} from "@/common/constants"; +import { FACILITY_FEATURE_TYPES, USER_TYPES } from "@/common/constants"; import { PLUGIN_Component } from "@/PluginEngine"; import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; @@ -42,6 +38,7 @@ import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import uploadFile from "@/Utils/request/uploadFile"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; +import { getAuthorizationHeader } from "@/Utils/request/utils"; import { sleep } from "@/Utils/utils"; import { patientRegisterAuth } from "../Patient/PatientRegister"; @@ -121,10 +118,7 @@ export const FacilityHome = ({ facilityId }: Props) => { url, formData, "POST", - { - Authorization: - "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken), - }, + { Authorization: getAuthorizationHeader() }, async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000); diff --git a/src/components/Users/UserAvatar.tsx b/src/components/Users/UserAvatar.tsx index db3620b34aa..77b353846bc 100644 --- a/src/components/Users/UserAvatar.tsx +++ b/src/components/Users/UserAvatar.tsx @@ -9,14 +9,13 @@ import Loading from "@/components/Common/Loading"; import useAuthUser from "@/hooks/useAuthUser"; -import { LocalStorageKeys } from "@/common/constants"; - import * as Notification from "@/Utils/Notifications"; import { showAvatarEdit } from "@/Utils/permissions"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import uploadFile from "@/Utils/request/uploadFile"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; +import { getAuthorizationHeader } from "@/Utils/request/utils"; import { formatDisplayName, sleep } from "@/Utils/utils"; export default function UserAvatar({ username }: { username: string }) { @@ -47,10 +46,7 @@ export default function UserAvatar({ username }: { username: string }) { url, formData, "POST", - { - Authorization: - "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken), - }, + { Authorization: getAuthorizationHeader() }, async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000); diff --git a/src/components/Users/UserProfile.tsx b/src/components/Users/UserProfile.tsx index 4dd98635510..786e569c4db 100644 --- a/src/components/Users/UserProfile.tsx +++ b/src/components/Users/UserProfile.tsx @@ -26,7 +26,7 @@ import { import useAuthUser, { useAuthContext } from "@/hooks/useAuthUser"; -import { GENDER_TYPES, LocalStorageKeys } from "@/common/constants"; +import { GENDER_TYPES } from "@/common/constants"; import { validateEmailAddress } from "@/common/validation"; import * as Notification from "@/Utils/Notifications"; @@ -35,6 +35,7 @@ import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import uploadFile from "@/Utils/request/uploadFile"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; +import { getAuthorizationHeader } from "@/Utils/request/utils"; import { dateQueryString, formatDate, @@ -507,10 +508,7 @@ export default function UserProfile() { url, formData, "POST", - { - Authorization: - "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken), - }, + { Authorization: getAuthorizationHeader() }, async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000); From 927c39949f7e4927a20ddb63bb8004d600d5d35b Mon Sep 17 00:00:00 2001 From: Mahendar Chikolla <119734520+Mahendar0701@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:40:17 +0530 Subject: [PATCH 17/31] Search UI for discharge patients (#9320) --- .../Facility/DischargedPatientsList.tsx | 202 ++++++++---------- 1 file changed, 95 insertions(+), 107 deletions(-) diff --git a/src/components/Facility/DischargedPatientsList.tsx b/src/components/Facility/DischargedPatientsList.tsx index 4fb8910f7a1..74bb6d95626 100644 --- a/src/components/Facility/DischargedPatientsList.tsx +++ b/src/components/Facility/DischargedPatientsList.tsx @@ -1,5 +1,5 @@ import { Link, navigate } from "raviger"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import CountBlock from "@/CAREUI/display/Count"; @@ -11,13 +11,11 @@ import PaginatedList from "@/CAREUI/misc/PaginatedList"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; +import SearchByMultipleFields from "@/components/Common/SearchByMultipleFields"; import SortDropdownMenu from "@/components/Common/SortDropdown"; import Tabs from "@/components/Common/Tabs"; import { getDiagnosesByIds } from "@/components/Diagnosis/utils"; import { ICD11DiagnosisModel } from "@/components/Facility/models"; -import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; -import SearchInput from "@/components/Form/SearchInput"; import { DIAGNOSES_FILTER_LABELS, DiagnosesFilterKey, @@ -52,16 +50,79 @@ const DischargedPatientsList = ({ pathParams: { id: facility_external_id }, }); - const { qParams, updateQuery, advancedFilter, FilterBadges, updatePage } = - useFilters({ - limit: 12, - cacheBlacklist: [ - "name", - "patient_no", - "phone_number", - "emergency_phone_number", - ], - }); + const { + qParams, + updateQuery, + advancedFilter, + FilterBadges, + updatePage, + clearSearch, + } = useFilters({ + limit: 12, + cacheBlacklist: [ + "name", + "patient_no", + "phone_number", + "emergency_phone_number", + ], + }); + + const searchOptions = [ + { + key: "name", + label: "Name", + type: "text" as const, + placeholder: "search_by_patient_name", + value: qParams.name || "", + shortcutKey: "n", + }, + { + key: "patient_no", + label: "IP/OP No", + type: "text" as const, + placeholder: "search_by_patient_no", + value: qParams.patient_no || "", + shortcutKey: "u", + }, + { + key: "phone_number", + label: "Phone Number", + type: "phone" as const, + placeholder: "Search_by_phone_number", + value: qParams.phone_number || "", + shortcutKey: "p", + }, + { + key: "emergency_contact_number", + label: "Emergency Contact Phone Number", + type: "phone" as const, + placeholder: "search_by_emergency_phone_number", + value: qParams.emergency_phone_number || "", + shortcutKey: "e", + }, + ]; + + const handleSearch = useCallback( + (key: string, value: string) => { + const isValidPhoneNumber = (val: string) => + val.length >= 13 || val === ""; + + const updatedQuery = { + phone_number: + key === "phone_number" && isValidPhoneNumber(value) + ? value + : undefined, + name: key === "name" ? value : undefined, + patient_no: key === "patient_no" ? value : undefined, + emergency_phone_number: + key === "emergency_contact_number" && isValidPhoneNumber(value) + ? value + : undefined, + }; + updateQuery(updatedQuery); + }, + [updateQuery], + ); useEffect(() => { if (!qParams.phone_number && phone_number.length >= 13) { @@ -200,56 +261,11 @@ const DischargedPatientsList = ({ }); }; - const queryField = (name: string, defaultValue?: T) => { - return { - name, - value: qParams[name] || defaultValue, - onChange: (e: FieldChangeEvent) => updateQuery({ [e.name]: e.value }), - className: "grow w-full mb-2", - }; - }; const [diagnoses, setDiagnoses] = useState([]); const [phone_number, setPhoneNumber] = useState(""); - const [phoneNumberError, setPhoneNumberError] = useState(""); const [emergency_phone_number, setEmergencyPhoneNumber] = useState(""); - const [emergencyPhoneNumberError, setEmergencyPhoneNumberError] = - useState(""); const [count, setCount] = useState(0); - - const setPhoneNum = (phone_number: string) => { - setPhoneNumber(phone_number); - if (phone_number.length >= 13) { - setPhoneNumberError(""); - updateQuery({ phone_number }); - return; - } - - if (phone_number === "+91" || phone_number === "") { - setPhoneNumberError(""); - qParams.phone_number && updateQuery({ phone_number: null }); - return; - } - - setPhoneNumberError("Enter a valid number"); - }; - - const setEmergencyPhoneNum = (emergency_phone_number: string) => { - setEmergencyPhoneNumber(emergency_phone_number); - if (emergency_phone_number.length >= 13) { - setEmergencyPhoneNumberError(""); - updateQuery({ emergency_phone_number }); - return; - } - - if (emergency_phone_number === "+91" || emergency_phone_number === "") { - setEmergencyPhoneNumberError(""); - qParams.emergency_phone_number && - updateQuery({ emergency_phone_number: null }); - return; - } - - setEmergencyPhoneNumberError("Enter a valid number"); - }; + const [isLoading, setIsLoading] = useState(false); return ( } > -
    -
    -
    - -
    -
    -
    -
    -
    - - -
    -
    - setPhoneNum(e.value)} - error={phoneNumberError} - types={["mobile", "landline"]} - /> - setEmergencyPhoneNum(e.value)} - error={emergencyPhoneNumberError} - types={["mobile", "landline"]} - /> -
    -
    +
    +
    +
    +
    setCount(query.data?.count || 0)} + queryCB={(query) => { + setCount(query.data?.count || 0); + setIsLoading(query.loading); + }} initialPage={qParams.page} onPageChange={updatePage} > From 9ac5225a7d1b1f202c49a63f169893dea875e153 Mon Sep 17 00:00:00 2001 From: JavidSumra <112365664+JavidSumra@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:40:38 +0530 Subject: [PATCH 18/31] Fixes UI Bug Issue in Symptom Editor (#9270) --- src/components/Common/DateInputV2.tsx | 1 + .../Form/FormFields/AutocompleteMultiselect.tsx | 8 +++++--- src/components/Form/FormFields/DateFormField.tsx | 5 ++++- src/components/Form/ModelCrudEditor.tsx | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/Common/DateInputV2.tsx b/src/components/Common/DateInputV2.tsx index 20027a004d2..8ca937aed72 100644 --- a/src/components/Common/DateInputV2.tsx +++ b/src/components/Common/DateInputV2.tsx @@ -331,6 +331,7 @@ const DateInputV2: React.FC = ({ data-scribe-ignore className={`cui-input-base cursor-pointer disabled:cursor-not-allowed ${className}`} placeholder={placeholder ?? t("select_date")} + title={placeholder} value={value ? dayjs(value).format(dateFormat) : ""} />
    diff --git a/src/components/Form/FormFields/AutocompleteMultiselect.tsx b/src/components/Form/FormFields/AutocompleteMultiselect.tsx index 3c537dffa32..8dad2f3ff0d 100644 --- a/src/components/Form/FormFields/AutocompleteMultiselect.tsx +++ b/src/components/Form/FormFields/AutocompleteMultiselect.tsx @@ -171,16 +171,18 @@ export const AutocompleteMutliSelect = ( {!props.disabled && ( -
    +
    val.option) ? "-top-5" : ""}`} + > {props.isLoading ? ( ) : ( )}
    diff --git a/src/components/Form/FormFields/DateFormField.tsx b/src/components/Form/FormFields/DateFormField.tsx index e867c24dd51..a3d26fa5554 100644 --- a/src/components/Form/FormFields/DateFormField.tsx +++ b/src/components/Form/FormFields/DateFormField.tsx @@ -37,7 +37,10 @@ const DateFormField = (props: Props) => { return ( ( onClick={() => handleDelete(props.item.id)} className="w-full text-xl text-red-500 hover:text-red-700 disabled:grayscale md:w-auto" > - {" "} + {t("remove")} )} From 2e829994fda14310b1575849a4fb793322f529c4 Mon Sep 17 00:00:00 2001 From: Kamishetty Rishith <119791436+Rishith25@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:46:11 +0530 Subject: [PATCH 19/31] Occupancy bed tooltip fully visible in mobile view (#9235) --- src/components/Common/Sidebar/Sidebar.tsx | 38 +++++++----------- src/components/Facility/FacilityCard.tsx | 37 +++++++++++------ src/components/ui/tooltip.tsx | 48 ++++++++++++++++------- 3 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/components/Common/Sidebar/Sidebar.tsx b/src/components/Common/Sidebar/Sidebar.tsx index 423d0d6f18b..e6d9edbc2dd 100644 --- a/src/components/Common/Sidebar/Sidebar.tsx +++ b/src/components/Common/Sidebar/Sidebar.tsx @@ -6,12 +6,7 @@ import { useTranslation } from "react-i18next"; import CareIcon, { IconName } from "@/CAREUI/icons/CareIcon"; import SlideOver from "@/CAREUI/interactive/SlideOver"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; +import { TooltipComponent, TooltipProvider } from "@/components/ui/tooltip"; import { ShrinkedSidebarItem, @@ -243,24 +238,19 @@ const ToggleShrink = ({ shrinked, toggle }: ToggleShrinkProps) => { const { t } = useTranslation(); return ( - - - - - -

    {shrinked ? t("expand_sidebar") : t("collapse_sidebar")}

    -
    -
    + + +
    ); }; diff --git a/src/components/Facility/FacilityCard.tsx b/src/components/Facility/FacilityCard.tsx index fbebe8a8d0a..2f6ecec204b 100644 --- a/src/components/Facility/FacilityCard.tsx +++ b/src/components/Facility/FacilityCard.tsx @@ -6,6 +6,8 @@ import { useTranslation } from "react-i18next"; import Chip from "@/CAREUI/display/Chip"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { TooltipComponent, TooltipProvider } from "@/components/ui/tooltip"; + import { Avatar } from "@/components/Common/Avatar"; import ButtonV2, { Cancel, Submit } from "@/components/Common/ButtonV2"; import DialogModal from "@/components/Common/Dialog"; @@ -98,19 +100,28 @@ export const FacilityCard = (props: { > {facility.name} -
    0.85 ? "justify-center rounded-md border border-red-600 bg-red-500 p-1 font-bold text-white" : "text-secondary-700"}`} - > - - {t("live_patients_total_beds")} - {" "} - -
    - {t("occupancy")}: {facility.patient_count} /{" "} - {facility.bed_count}{" "} -
    -
    + + +
    + 0.85 + ? "justify-center rounded-md border border-red-600 bg-red-500 p-1 font-bold text-white" + : "text-secondary-700" + }`} + > + +
    + {t("occupancy")}: {facility.patient_count} /{" "} + {facility.bed_count} +
    +
    +
    +
    , +const TooltipContent = TooltipPrimitive.Content; + +const TooltipComponent = React.forwardRef< + React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - -)); -TooltipContent.displayName = TooltipPrimitive.Content.displayName; +>(({ children, content, sideOffset = 4, className }, ref) => { + const [open, setOpen] = React.useState(false); + return ( + + + setOpen(!open)}> + {children} + + + {content} + + + + ); +}); -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; +export { + TooltipComponent, + TooltipTrigger, + TooltipContent, + TooltipProvider, + Tooltip, +}; From 10bfd6cab8447380ece9ffbe7cf3227b1e1f8d21 Mon Sep 17 00:00:00 2001 From: Kamishetty Rishith <119791436+Rishith25@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:47:51 +0530 Subject: [PATCH 20/31] Disallowing out of date range (#9201) --- src/components/Common/DateInputV2.tsx | 274 +++++++++++++++++++------- 1 file changed, 208 insertions(+), 66 deletions(-) diff --git a/src/components/Common/DateInputV2.tsx b/src/components/Common/DateInputV2.tsx index 8ca937aed72..8debee7ac7b 100644 --- a/src/components/Common/DateInputV2.tsx +++ b/src/components/Common/DateInputV2.tsx @@ -89,15 +89,18 @@ const DateInputV2: React.FC = ({ ); break; case "month": - setDatePickerHeaderDate((prev) => - dayjs(prev).subtract(1, "year").toDate(), - ); + setDatePickerHeaderDate((prev) => { + const newDate = dayjs(prev).subtract(1, "year").toDate(); + if (min && newDate < min) { + return new Date(min.getFullYear(), min.getMonth(), 1); + } + return newDate; + }); break; case "year": - setDatePickerHeaderDate((prev) => - dayjs(prev).subtract(1, "year").toDate(), - ); - setYear((prev) => dayjs(prev).subtract(10, "year").toDate()); + if (!min || year.getFullYear() - 10 >= min.getFullYear()) { + setYear((prev) => dayjs(prev).subtract(10, "year").toDate()); + } break; } }; @@ -108,11 +111,18 @@ const DateInputV2: React.FC = ({ setDatePickerHeaderDate((prev) => dayjs(prev).add(1, "month").toDate()); break; case "month": - setDatePickerHeaderDate((prev) => dayjs(prev).add(1, "year").toDate()); + setDatePickerHeaderDate((prev) => { + const newDate = dayjs(prev).add(1, "year").toDate(); + if (max && newDate > max) { + return new Date(max.getFullYear(), max.getMonth(), 1); + } + return newDate; + }); break; case "year": - setDatePickerHeaderDate((prev) => dayjs(prev).add(1, "year").toDate()); - setYear((prev) => dayjs(prev).add(10, "year").toDate()); + if (!max || year.getFullYear() + 10 <= max.getFullYear()) { + setYear((prev) => dayjs(prev).add(10, "year").toDate()); + } break; } }; @@ -209,6 +219,33 @@ const DateInputV2: React.FC = ({ return true; }; + const isMonthWithinConstraints = (month: number) => { + const year = datePickerHeaderDate.getFullYear(); + + if (min && year < min.getFullYear()) return false; + if (max && year > max.getFullYear()) return false; + + const firstDay = new Date(year, month, 1); + const lastDay = new Date(year, month + 1, 0); + if (min && lastDay < min) return false; + if (max && firstDay > max) return false; + + return true; + }; + + const isYearWithinConstraints = (year: number) => { + if (min && year < min.getFullYear()) return false; + if (max && year > max.getFullYear()) return false; + + const yearStart = new Date(year, 0, 1); + const yearEnd = new Date(year, 11, 31); + + if (min && yearEnd < min) return false; + if (max && yearStart > max) return false; + + return true; + }; + const isSelectedMonth = (month: number) => month === datePickerHeaderDate.getMonth(); @@ -216,25 +253,48 @@ const DateInputV2: React.FC = ({ year === datePickerHeaderDate.getFullYear(); const setMonthValue = (month: number) => () => { - setDatePickerHeaderDate( - new Date( + if (isMonthWithinConstraints(month)) { + const lastDayOfMonth = new Date( datePickerHeaderDate.getFullYear(), - month, - datePickerHeaderDate.getDate(), - ), - ); - setType("date"); + month + 1, + 0, + ).getDate(); + const newDate = Math.min(datePickerHeaderDate.getDate(), lastDayOfMonth); + setDatePickerHeaderDate( + new Date(datePickerHeaderDate.getFullYear(), month, newDate), + ); + setType("date"); + } else { + Notification.Error({ + msg: outOfLimitsErrorMessage ?? "Cannot select month out of range", + }); + } }; - + //min and max setting for year const setYearValue = (year: number) => () => { - setDatePickerHeaderDate( - new Date( + if (isYearWithinConstraints(year)) { + const newDate = new Date( year, datePickerHeaderDate.getMonth(), datePickerHeaderDate.getDate(), - ), - ); - setType("date"); + ); + if (min && year === min.getFullYear() && newDate < min) { + setDatePickerHeaderDate( + new Date(min.getFullYear(), min.getMonth(), min.getDate()), + ); + } else if (max && year === max.getFullYear() && newDate > max) { + setDatePickerHeaderDate( + new Date(max.getFullYear(), max.getMonth(), max.getDate()), + ); + } else { + setDatePickerHeaderDate(newDate); + } + setType("date"); + } else { + Notification.Error({ + msg: outOfLimitsErrorMessage ?? "Cannot select year out of range", + }); + } }; useEffect(() => { @@ -372,23 +432,62 @@ const DateInputV2: React.FC = ({
    - + {type === "date" && ( + + )} + {type === "month" && ( + + )} + + {type === "year" && ( + + )}
    {type === "date" && ( @@ -412,23 +511,62 @@ const DateInputV2: React.FC = ({

    - + {type === "date" && ( + + )} + {type === "month" && ( + + )} + + {type === "year" && ( + + )}
    {type === "date" && ( @@ -511,10 +649,12 @@ const DateInputV2: React.FC = ({ key={i} id={`month-${i}`} className={classNames( - "w-1/4 cursor-pointer rounded-lg px-2 py-4 text-center text-sm font-semibold", - value && isSelectedMonth(i) - ? "bg-primary-500 text-white" - : "text-secondary-700 hover:bg-secondary-300", + "w-1/4 rounded-lg px-2 py-4 text-center text-sm font-semibold", + isSelectedMonth(i) + ? "bg-primary-500 text-white cursor-pointer" + : isMonthWithinConstraints(i) + ? "text-secondary-700 hover:bg-secondary-300 cursor-pointer" + : "!text-secondary-400 !cursor-not-allowed", )} onClick={setMonthValue(i)} > @@ -534,16 +674,18 @@ const DateInputV2: React.FC = ({ {Array(12) .fill(null) .map((_, i) => { - const y = year.getFullYear() - 11 + i; + const y = year.getFullYear() - 10 + i; return (
    From f56e6f5eace6562a7252ffacc2790a02c620eca2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:45:57 +0530 Subject: [PATCH 21/31] Bump @sentry/browser from 8.42.0 to 8.45.1 (#9473) Bumps [@sentry/browser](https://github.com/getsentry/sentry-javascript) from 8.42.0 to 8.45.1. - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/8.45.1/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/8.42.0...8.45.1) --- updated-dependencies: - dependency-name: "@sentry/browser" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 60 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index 94a84d3d179..c6076acd00a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toast": "^1.2.2", "@radix-ui/react-tooltip": "^1.1.4", - "@sentry/browser": "^8.42.0", + "@sentry/browser": "^8.45.1", "@tanstack/react-query": "^5.62.3", "@tanstack/react-query-devtools": "^5.62.7", "@yudiel/react-qr-scanner": "^2.0.8", @@ -4796,50 +4796,50 @@ ] }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.42.0.tgz", - "integrity": "sha512-xzgRI0wglKYsPrna574w1t38aftuvo44gjOKFvPNGPnYfiW9y4m+64kUz3JFbtanvOrKPcaITpdYiB4DeJXEbA==", + "version": "8.45.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.45.1.tgz", + "integrity": "sha512-sZwtP3zAzDsjUS7WkMW5VGbvSl7hGKTMc8gAJbpEsrybMxllIP13zzMRwpeFF11RnnvbrZ/FtAeX58Mvj0jahA==", "license": "MIT", "dependencies": { - "@sentry/core": "8.42.0" + "@sentry/core": "8.45.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.42.0.tgz", - "integrity": "sha512-dkIw5Wdukwzngg5gNJ0QcK48LyJaMAnBspqTqZ3ItR01STi6Z+6+/Bt5XgmrvDgRD+FNBinflc5zMmfdFXXhvw==", + "version": "8.45.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.45.1.tgz", + "integrity": "sha512-zCKptzki4SLnG+s8je8dgnppOKFjiiO4GVBc4fh7uL8zjNPBnxW8wK4SrPfAEKVYaHUzkKc5vixwUqcpmfLLGw==", "license": "MIT", "dependencies": { - "@sentry/core": "8.42.0" + "@sentry/core": "8.45.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.42.0.tgz", - "integrity": "sha512-oNcJEBlDfXnRFYC5Mxj5fairyZHNqlnU4g8kPuztB9G5zlsyLgWfPxzcn1ixVQunth2/WZRklDi4o1ZfyHww7w==", + "version": "8.45.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.45.1.tgz", + "integrity": "sha512-cOA9CodNSR9+hmICDaGIDUvWiwxQxeMHk/esbjB8uAW8HG4CYTG3CTYTZmlmou7DuysfMd4JNuFmDFBj+YU5/A==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.42.0", - "@sentry/core": "8.42.0" + "@sentry-internal/browser-utils": "8.45.1", + "@sentry/core": "8.45.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.42.0.tgz", - "integrity": "sha512-XrPErqVhPsPh/oFLVKvz7Wb+Fi2J1zCPLeZCxWqFuPWI2agRyLVu0KvqJyzSpSrRAEJC/XFzuSVILlYlXXSfgA==", + "version": "8.45.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.45.1.tgz", + "integrity": "sha512-qiPg6XwOwkiMMe/8Qf3EhXCqkSlSnWLlorYngIbdkV2klbWjd7vKnqkFJF4PnaS0g7kkZr7nh+MdzpyLyuj2Mw==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "8.42.0", - "@sentry/core": "8.42.0" + "@sentry-internal/replay": "8.45.1", + "@sentry/core": "8.45.1" }, "engines": { "node": ">=14.18" @@ -4898,25 +4898,25 @@ } }, "node_modules/@sentry/browser": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.42.0.tgz", - "integrity": "sha512-lStrEk609KJHwXfDrOgoYVVoFFExixHywxSExk7ZDtwj2YPv6r6Y1gogvgr7dAZj7jWzadHkxZ33l9EOSJBfug==", + "version": "8.45.1", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.45.1.tgz", + "integrity": "sha512-/KvYhQSRg8m9kotG8h9FrfXCWRlebrvdfXKjj1oE9SyZ2LmR8Ze9AcEw1qzsBsa1F1D/a5FQbUJahSoLBkaQPA==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.42.0", - "@sentry-internal/feedback": "8.42.0", - "@sentry-internal/replay": "8.42.0", - "@sentry-internal/replay-canvas": "8.42.0", - "@sentry/core": "8.42.0" + "@sentry-internal/browser-utils": "8.45.1", + "@sentry-internal/feedback": "8.45.1", + "@sentry-internal/replay": "8.45.1", + "@sentry-internal/replay-canvas": "8.45.1", + "@sentry/core": "8.45.1" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.42.0.tgz", - "integrity": "sha512-ac6O3pgoIbU6rpwz6LlwW0wp3/GAHuSI0C5IsTgIY6baN8rOBnlAtG6KrHDDkGmUQ2srxkDJu9n1O6Td3cBCqw==", + "version": "8.45.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.45.1.tgz", + "integrity": "sha512-1fGmkr0paZshh38mD29c4CfkRkgFoYDaAGyDLoGYfTbEph/lU8RHB2HWzN93McqNdMEhl1DRRyqIasUZoPlqSA==", "license": "MIT", "engines": { "node": ">=14.18" diff --git a/package.json b/package.json index e5eaf3342c9..00ec917f6fb 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toast": "^1.2.2", "@radix-ui/react-tooltip": "^1.1.4", - "@sentry/browser": "^8.42.0", + "@sentry/browser": "^8.45.1", "@tanstack/react-query": "^5.62.3", "@tanstack/react-query-devtools": "^5.62.7", "@yudiel/react-qr-scanner": "^2.0.8", From 361885398594491f92ded59c5ae741ca2d0b42cd Mon Sep 17 00:00:00 2001 From: SathishAdithiyaaSV <164901276+SathishAdithiyaaSV@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:56:06 +0530 Subject: [PATCH 22/31] Fix: UI changes in shifting and resources pages (#9437) --- src/components/Resource/ResourceBoard.tsx | 6 +- src/components/Resource/ResourceList.tsx | 78 +++++++++++++---------- src/components/Shifting/ShiftingBoard.tsx | 6 +- src/components/Shifting/ShiftingList.tsx | 76 ++++++++++++---------- 4 files changed, 95 insertions(+), 71 deletions(-) diff --git a/src/components/Resource/ResourceBoard.tsx b/src/components/Resource/ResourceBoard.tsx index 1f8ccafcb5d..39b6f5184e5 100644 --- a/src/components/Resource/ResourceBoard.tsx +++ b/src/components/Resource/ResourceBoard.tsx @@ -93,7 +93,11 @@ export default function BoardView() { currentTab={boardFilter !== ACTIVE ? 1 : 0} />
    - diff --git a/src/components/Resource/ResourceList.tsx b/src/components/Resource/ResourceList.tsx index 2b44599f120..0175c9d63ea 100644 --- a/src/components/Resource/ResourceList.tsx +++ b/src/components/Resource/ResourceList.tsx @@ -9,7 +9,7 @@ import { Button } from "@/components/ui/button"; import { ExportButton } from "@/components/Common/Export"; import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; +import PageTitle from "@/components/Common/PageTitle"; import { ResourceModel } from "@/components/Facility/models"; import SearchInput from "@/components/Form/SearchInput"; import BadgesList from "@/components/Resource/ResourceBadges"; @@ -194,45 +194,55 @@ export default function ListView() { }; return ( - { - const { data } = await request(routes.downloadResourceRequests, { - query: { ...appliedFilters, csv: true }, - }); - return data ?? null; - }} - filenamePrefix="resource_requests" - /> - } - breadcrumbs={false} - options={ - <> -
    -
    - updateQuery({ [e.name]: e.value })} - placeholder={t("search_resource")} - /> -
    +
    +
    +
    + { + const { data } = await request( + routes.downloadResourceRequests, + { + query: { ...appliedFilters, csv: true }, + }, + ); + return data ?? null; + }} + filenamePrefix="resource_requests" + /> + } + breadcrumbs={false} + /> +
    + +
    + updateQuery({ [e.name]: e.value })} + placeholder={t("search_resource")} + className="w-full md:w-60" + /> -
    - advancedFilter.setShow(true)} />
    - - } - > +
    +
    @@ -282,6 +292,6 @@ export default function ListView() { showResourceStatus={true} key={window.location.search} /> - +
    ); } diff --git a/src/components/Shifting/ShiftingBoard.tsx b/src/components/Shifting/ShiftingBoard.tsx index cd9f4300fd4..068820d3311 100644 --- a/src/components/Shifting/ShiftingBoard.tsx +++ b/src/components/Shifting/ShiftingBoard.tsx @@ -124,7 +124,11 @@ export default function BoardView() { />
    - diff --git a/src/components/Shifting/ShiftingList.tsx b/src/components/Shifting/ShiftingList.tsx index 3bf071f1cc2..e9051b1449b 100644 --- a/src/components/Shifting/ShiftingList.tsx +++ b/src/components/Shifting/ShiftingList.tsx @@ -8,7 +8,7 @@ import { Button } from "@/components/ui/button"; import { ExportButton } from "@/components/Common/Export"; import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; +import PageTitle from "@/components/Common/PageTitle"; import SearchInput from "@/components/Form/SearchInput"; import BadgesList from "@/components/Shifting/ShiftingBadges"; import { formatFilter } from "@/components/Shifting/ShiftingCommons"; @@ -49,46 +49,52 @@ export default function ListView() { }); return ( - { - const { data } = await request(routes.downloadShiftRequests, { - query: { ...formatFilter(qParams), csv: true }, - }); - return data ?? null; - }} - filenamePrefix="shift_requests" - /> - } - breadcrumbs={false} - options={ - <> -
    +
    +
    +
    + { + const { data } = await request(routes.downloadShiftRequests, { + query: { ...formatFilter(qParams), csv: true }, + }); + return data ?? null; + }} + filenamePrefix="shift_requests" + /> + } + breadcrumbs={false} + /> +
    +
    + updateQuery({ [e.name]: e.value })} + placeholder={t("search_patient")} + className="w-full md:w-60" + /> -
    - updateQuery({ [e.name]: e.value })} - placeholder={t("search_patient")} - /> -
    - -
    - advancedFilter.setShow(true)} />
    - - } - > +
    +
    +
    @@ -121,6 +127,6 @@ export default function ListView() { {...advancedFilter} key={window.location.search} /> - +
    ); } From a01321bcba18af30bc8031de5a8d410f2ff0dfef Mon Sep 17 00:00:00 2001 From: Raj kumar <150310085+rajku-dev@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:58:09 +0530 Subject: [PATCH 23/31] Create 'copyToClipboard' utility function (#9449) --- public/locale/en.json | 1 + src/Utils/utils.ts | 10 ++++++++ .../Facility/DoctorVideoSlideover.tsx | 23 +++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 2ceaf310fac..ce70849187d 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -549,6 +549,7 @@ "contribute_github": "Contribute on Github", "copied_to_clipboard": "Copied to clipboard", "copilot_thinking": "Copilot is thinking...", + "copy_phone_number": "Copy Phone Number", "could_not_autofill": "We could not autofill any fields from what you said", "countries_travelled": "Countries travelled", "covid_19_cat_gov": "Covid_19 Clinical Category as per Govt. of Kerala guideline (A/B/C)", diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 5588e048bd2..f9e0e14577a 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -3,6 +3,7 @@ import { PatientModel } from "@/components/Patient/models"; import { AREACODES, IN_LANDLINE_AREA_CODES } from "@/common/constants"; import phoneCodesJson from "@/common/static/countryPhoneAndFlags.json"; +import * as Notification from "@/Utils/Notifications"; import dayjs from "@/Utils/dayjs"; interface ApacheParams { @@ -561,3 +562,12 @@ export function omitBy>( Object.entries(obj).filter(([_, value]) => !predicate(value)), ) as Partial; } + +export const copyToClipboard = async (content: string) => { + try { + await navigator.clipboard.writeText(content); + Notification.Success({ msg: "Copied to clipboard" }); + } catch (err) { + Notification.Error({ msg: "Copying is not allowed" }); + } +}; diff --git a/src/components/Facility/DoctorVideoSlideover.tsx b/src/components/Facility/DoctorVideoSlideover.tsx index 61c7a63c17b..98058fd4bfb 100644 --- a/src/components/Facility/DoctorVideoSlideover.tsx +++ b/src/components/Facility/DoctorVideoSlideover.tsx @@ -1,4 +1,5 @@ -import React, { useState } from "react"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; import CareIcon, { IconName } from "@/CAREUI/icons/CareIcon"; import SlideOver from "@/CAREUI/interactive/SlideOver"; @@ -17,6 +18,7 @@ import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; import { classNames, + copyToClipboard, formatName, isUserOnline, relativeTime, @@ -238,6 +240,9 @@ function UserListItem({ user }: { user: UserAnnotatedWithGroup }) { } } + const { t } = useTranslation(); + const [copied, setCopied] = useState(false); + return (
    { + onClick={(e) => { e.stopPropagation(); - await navigator.clipboard.writeText( - user?.alt_phone_number || "", - ); + copyToClipboard(user?.alt_phone_number || ""); + setCopied(true); + setTimeout(() => setCopied(false), 2500); }} > - Copy Phone number + {t("copy_phone_number")} - + {user.alt_phone_number} From 3979b530b8ee309df81dd973435f4b136fd9d43f Mon Sep 17 00:00:00 2001 From: Kamishetty Rishith <119791436+Rishith25@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:43:52 +0530 Subject: [PATCH 24/31] Cypress tests replace cy.wait with cy.intercept or dynamic waits (#8963) --- cypress/e2e/assets_spec/AssetHomepage.cy.ts | 1 - .../e2e/facility_spec/FacilityCreation.cy.ts | 1 - .../e2e/facility_spec/FacilityHomepage.cy.ts | 2 + .../e2e/facility_spec/FacilityInventory.cy.ts | 13 +++- .../PatientConsultationCreation.cy.ts | 5 +- .../PatientConsultationDischarge.cy.ts | 12 ++- .../e2e/patient_spec/PatientHomepage.cy.ts | 1 - .../e2e/patient_spec/PatientLogUpdate.cy.ts | 19 ++++- .../patient_spec/PatientPrescription.cy.ts | 1 - .../patient_spec/PatientRegistration.cy.ts | 8 +- cypress/e2e/users_spec/UsersCreation.cy.ts | 8 +- cypress/e2e/users_spec/UsersManage.cy.ts | 7 +- cypress/pageobject/Asset/AssetHome.ts | 6 +- .../pageobject/Facility/FacilityCreation.ts | 73 +++++++++---------- .../pageobject/Patient/PatientConsultation.ts | 10 ++- cypress/pageobject/Patient/PatientCreation.ts | 58 +++++++++------ .../pageobject/Patient/PatientDischarge.ts | 24 +++++- .../pageobject/Patient/PatientDoctorNotes.ts | 3 +- .../pageobject/Patient/PatientFileupload.ts | 6 +- .../pageobject/Patient/PatientLogupdate.ts | 45 ++++++++++-- .../Patient/PatientMedicalHistory.ts | 2 +- .../pageobject/Patient/PatientPrescription.ts | 13 +++- cypress/pageobject/Patient/PatientTransfer.ts | 2 - cypress/pageobject/Users/ManageUserPage.ts | 18 ++++- cypress/pageobject/Users/UserCreation.ts | 8 ++ cypress/pageobject/Users/UserProfilePage.ts | 8 ++ .../pageobject/utils/advanceFilterHelpers.ts | 8 ++ 27 files changed, 253 insertions(+), 109 deletions(-) diff --git a/cypress/e2e/assets_spec/AssetHomepage.cy.ts b/cypress/e2e/assets_spec/AssetHomepage.cy.ts index e19f885db72..fc195c7a803 100644 --- a/cypress/e2e/assets_spec/AssetHomepage.cy.ts +++ b/cypress/e2e/assets_spec/AssetHomepage.cy.ts @@ -113,7 +113,6 @@ rolesToTest.forEach((role) => { it("Export the list of assets in CSV & Json", () => { if (role === "districtAdmin") { assetHome.selectAssetImportButton("click"); - cy.wait(2000); assetHome.selectJsonExportButton(); assetHome.selectAssetImportButton("click"); assetHome.selectCsvExportButton(); diff --git a/cypress/e2e/facility_spec/FacilityCreation.cy.ts b/cypress/e2e/facility_spec/FacilityCreation.cy.ts index d2893166745..4a07a665896 100644 --- a/cypress/e2e/facility_spec/FacilityCreation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityCreation.cy.ts @@ -65,7 +65,6 @@ describe("Facility Creation with multiple user roles", () => { beforeEach(() => { cy.viewport(1280, 720); cy.restoreLocalStorage(); - cy.awaitUrl("/facility"); }); it("Create a new facility with all fields | Edit Existing Data | Verify its reflection", () => { diff --git a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts index 0aa8518a6d1..c43106ba869 100644 --- a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts @@ -196,7 +196,9 @@ describe("Facility Homepage Function", () => { }); it("Verify the bed capacity badge reflection", () => { + facilityHome.interceptFacilitySearchReq(); facilityHome.typeFacilitySearch(facilityWithNoAvailableBeds); + facilityHome.verifyFacilitySearchReq(); facilityHome.assertFacilityInCard(facilityWithNoAvailableBeds); cy.url().then((url) => { const facilityUrl = url.toString(); diff --git a/cypress/e2e/facility_spec/FacilityInventory.cy.ts b/cypress/e2e/facility_spec/FacilityInventory.cy.ts index b3f77479763..b79998fd5cd 100644 --- a/cypress/e2e/facility_spec/FacilityInventory.cy.ts +++ b/cypress/e2e/facility_spec/FacilityInventory.cy.ts @@ -25,15 +25,20 @@ describe("Inventory Management Section", () => { it("Add New Inventory | Modify data and delete last entry ", () => { // add a new item + facilityPage.interceptManageInventoryItem(); facilityPage.clickManageInventory(); + facilityPage.verifyManageInventoryItem(); facilityPage.fillInventoryDetails("PPE", "Add Stock", "10"); facilityPage.clickAddInventory(); facilityPage.verifySuccessNotification("Inventory created successfully"); + cy.closeNotification(); facilityPage.clickManageInventory(); // modify the new item facilityPage.fillInventoryDetails("PPE", "Use Stock", "5"); facilityPage.clickAddInventory(); - facilityPage.verifySuccessNotification("Inventory created successfully"); + facilityPage.verifySuccessNotification( + "Inventory use stock updated successfully", + ); // verify the new modification facilityPage.verifyPpeQuantity("PPE"); facilityPage.verifyPpeQuantity("5"); @@ -43,7 +48,6 @@ describe("Inventory Management Section", () => { // verify the last entry deletion facilityPage.verifyStockInRow("#row-0", "Added Stock"); facilityPage.verifyStockInRow("#row-1", "Used Stock"); - cy.wait(3000); facilityHome.navigateBack(); facilityPage.verifyPpeQuantity("PPE"); }); @@ -57,9 +61,10 @@ describe("Inventory Management Section", () => { cy.closeNotification(); // Verify Backend minimum badge facilityPage.verifyBadgeWithText(".badge-danger", "Low Stock"); + facilityPage.interceptMinimumQuantity(); // modify with manual minimum badge - facilityPage.clickAddMinimumQuanitity(); - cy.wait(3000); + facilityPage.clickAddMinimumQuantity(); + facilityPage.verifyMinimumQuantity(); cy.get("body").then(($body) => { if ($body.find("#update-minimum-quantity").is(":visible")) { // If the 'update-minimum-quantity' element is visible, click it diff --git a/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts b/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts index a257d127942..2969d2ddb93 100644 --- a/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts +++ b/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts @@ -104,8 +104,9 @@ describe("Patient Consultation in multiple combination", () => { patientPrescription.selectMedicine(medicineOne); patientPrescription.enterDosage("3"); patientPrescription.selectDosageFrequency("Twice daily"); + patientPrescription.interceptPrescriptions(); cy.clickSubmitButton("Submit"); - cy.wait(2000); + patientPrescription.verifyPrescription(); cy.verifyNotification("Medicine prescribed"); patientPrescription.clickReturnToDashboard(); // Verify the data's across the dashboard @@ -376,7 +377,9 @@ describe("Patient Consultation in multiple combination", () => { it("Edit created consultation to existing patient", () => { patientPage.visitPatient("Dummy Patient Thirteen"); + patientConsultationPage.interceptConsultation(); patientConsultationPage.clickEditConsultationButton(); + patientConsultationPage.verifyConsultation(); patientConsultationPage.typePatientIllnessHistory("editted"); patientConsultationPage.selectPatientDiagnosis( diagnosis5, diff --git a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts index b7ef6936804..50af6052581 100644 --- a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts +++ b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts @@ -35,7 +35,9 @@ describe("Patient Discharge based on multiple reason", () => { patientDischarge.clickDischarge(); patientDischarge.selectDischargeReason(patientDischargeReason4); cy.clickSubmitButton("Confirm Discharge"); + patientDischarge.interceptDischargePatient(); cy.clickSubmitButton("Acknowledge & Submit"); + patientDischarge.verifyDischargePatient(); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); // Verify the consultation dashboard reflection @@ -53,7 +55,9 @@ describe("Patient Discharge based on multiple reason", () => { patientDischarge.typeDischargeNote(patientDeathCause); patientDischarge.typeDoctorName(doctorName); cy.clickSubmitButton("Confirm Discharge"); + patientDischarge.interceptDischargePatient(); cy.clickSubmitButton("Acknowledge & Submit"); + patientDischarge.verifyDischargePatient(); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); // Verify the consultation dashboard reflection @@ -76,10 +80,10 @@ describe("Patient Discharge based on multiple reason", () => { patientDischarge.clickClearButton(); // select a non-registered facility and perform the discharge patientDischarge.typeReferringFacility(referringFreetextFacility); - cy.wait(2000); cy.clickSubmitButton("Confirm Discharge"); + patientDischarge.interceptDischargePatient(); cy.clickSubmitButton("Acknowledge & Submit"); - cy.wait(2000); + patientDischarge.verifyDischargePatient(); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); // Verify the consultation dashboard reflection @@ -106,12 +110,12 @@ describe("Patient Discharge based on multiple reason", () => { patientPrescription.selectDosageFrequency("Twice daily"); cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); - cy.wait(2000); cy.closeNotification(); // submit the discharge pop-up cy.clickSubmitButton("Confirm Discharge"); + patientDischarge.interceptDischargePatient(); cy.clickSubmitButton("Acknowledge & Submit"); - cy.wait(2000); + patientDischarge.verifyDischargePatient(); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); // Verify the consultation dashboard reflection diff --git a/cypress/e2e/patient_spec/PatientHomepage.cy.ts b/cypress/e2e/patient_spec/PatientHomepage.cy.ts index 8949fc3e324..8f5ac03a9ef 100644 --- a/cypress/e2e/patient_spec/PatientHomepage.cy.ts +++ b/cypress/e2e/patient_spec/PatientHomepage.cy.ts @@ -161,7 +161,6 @@ describe("Patient Homepage present functionalities", () => { .then((patientOne: string) => { firstPatientPageOne = patientOne.trim(); pageNavigation.navigateToNextPage(); - cy.wait(2000); pageNavigation.verifyCurrentPageNumber(2); cy.get('[data-cy="patient"]') .first() diff --git a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts index ec5aef250dc..da46a6c093e 100644 --- a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts +++ b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts @@ -58,7 +58,9 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.clickSubmitButton("Update Consultation"); cy.verifyNotification("Consultation updated successfully"); cy.closeNotification(); + patientPage.interceptGetPatient(); patientLogupdate.clickLogupdate(); + patientPage.verifyGetPatientResponse(); patientLogupdate.typePhysicalExamination(physicalExamination); patientLogupdate.selectRoundType("Tele-medicine Log"); patientLogupdate.selectPatientCategory(patientCategory); @@ -80,11 +82,15 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { it("Create a new Progress log update for a admitted patient and edit it", () => { patientPage.visitPatient(patientOne); + patientLogupdate.interceptConsultationBed(); patientLogupdate.clickLogupdate(); + patientLogupdate.verifyConsultationBed(); cy.verifyNotification("Please assign a bed to the patient"); patientLogupdate.selectBed(bedOne); cy.closeNotification(); + patientPage.interceptGetPatient(); patientLogupdate.clickLogupdate(); + patientPage.verifyGetPatientResponse(); // Only will be using random non-unique progress note fields patientLogupdate.selectRoundType("Progress Note"); patientLogupdate.selectPatientCategory(patientCategory); @@ -112,15 +118,18 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.verifyNotification("Medicine prescribed"); cy.closeNotification(); // Submit the doctors log update + patientLogupdate.interceptDailyRounds(); cy.clickSubmitButton("Save and Continue"); - cy.wait(2000); + patientLogupdate.verifyDailyRounds(); cy.verifyNotification("Progress Note created successfully"); cy.closeNotification(); // modify the relevant critical care log update patientLogupdate.selectCriticalCareSection("Neurological Monitoring"); cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); cy.get("#left_pupil_light_reaction-option-FIXED").click(); + patientLogupdate.interceptpatchDailyRounds(); cy.clickSubmitButton("Update Details"); + patientLogupdate.verifypatchDailyRounds(); cy.verifyNotification( "Neurological Monitoring details succesfully updated.", ); @@ -156,7 +165,9 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.clickLogupdate(); patientLogupdate.selectRoundType("Detailed Update"); patientLogupdate.selectPatientCategory(patientCategory); + patientLogupdate.interceptDailyRounds(); cy.clickSubmitButton("Save and Continue"); + patientLogupdate.verifyDailyRounds(); cy.verifyNotification("Detailed Update created successfully"); cy.closeNotification(); // Select two Section - First One is Respiratory Support @@ -235,7 +246,9 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.verifyNotification("Please assign a bed to the patient"); patientLogupdate.selectBed(bedThree); cy.closeNotification(); + patientPage.interceptGetPatient(); patientLogupdate.clickLogupdate(); + patientPage.verifyGetPatientResponse(); patientLogupdate.typePhysicalExamination(physicalExamination); patientLogupdate.selectPatientCategory(patientCategory); patientLogupdate.typeOtherDetails(otherExamination); @@ -251,9 +264,11 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.selectRhythm(patientRhythmType); patientLogupdate.typeRhythm(patientRhythm); cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); + patientConsultationPage.interceptConsultation(); cy.clickSubmitButton("Save"); - cy.wait(2000); + patientConsultationPage.verifyConsultation(); cy.verifyNotification("Brief Update created successfully"); + cy.closeNotification(); // Verify the card content cy.get("#basic-information").scrollIntoView(); cy.verifyContentPresence("#encounter-symptoms", [additionalSymptoms]); diff --git a/cypress/e2e/patient_spec/PatientPrescription.cy.ts b/cypress/e2e/patient_spec/PatientPrescription.cy.ts index 61f8067eea0..bc883e7a5fd 100644 --- a/cypress/e2e/patient_spec/PatientPrescription.cy.ts +++ b/cypress/e2e/patient_spec/PatientPrescription.cy.ts @@ -113,7 +113,6 @@ describe("Patient Medicine Administration", () => { cy.closeNotification(); // Administer the medicine in edit form patientPrescription.clickAdministerButton(); - cy.wait(2000); patientPrescription.enterAdministerDosage(medicineBaseDosage); patientPrescription.enterAdministerNotes(medicineAdministerNote); cy.clickSubmitButton("Administer Medicine"); diff --git a/cypress/e2e/patient_spec/PatientRegistration.cy.ts b/cypress/e2e/patient_spec/PatientRegistration.cy.ts index b11d0f8f585..5601f994c53 100644 --- a/cypress/e2e/patient_spec/PatientRegistration.cy.ts +++ b/cypress/e2e/patient_spec/PatientRegistration.cy.ts @@ -117,7 +117,6 @@ describe("Patient Creation with consultation", () => { patientPage.createPatientWithData(newPatientData); // Verify the patient details patientPage.clickCancelButton(); - cy.wait(3000); patientPage.savePatientUrl(); patientPage.verifyPatientDashboardDetails( patientOneGender, @@ -197,11 +196,11 @@ describe("Patient Creation with consultation", () => { patientOneSecondInsurerName, ); patientPage.clickUpdatePatient(); - cy.wait(3000); patientPage.verifyPatientUpdated(); + patientPage.interceptGetPatient(); patientPage.visitPatientUrl(); + patientPage.verifyGetPatientResponse(); // Verify Female Gender change reflection, No Medical History and Insurance Details - cy.wait(5000); patientPage.verifyPatientDashboardDetails( patientOneUpdatedGender, age, @@ -218,7 +217,6 @@ describe("Patient Creation with consultation", () => { cy.get("[data-testid=patient-details]") .contains("Member ID") .scrollIntoView(); - cy.wait(2000); patientInsurance.verifyPatientPolicyDetails( patientOneFirstSubscriberId, patientOneFirstPolicyId, @@ -249,7 +247,7 @@ describe("Patient Creation with consultation", () => { // allow the transfer button of a patient patientTransfer.clickAllowPatientTransferButton(); // Verify the patient error message for the same facility - cy.awaitUrl("/patients"); + cy.visit("/patients"); patientPage.createPatient(); patientPage.selectFacility(patientTransferFacility); patientPage.patientformvisibility(); diff --git a/cypress/e2e/users_spec/UsersCreation.cy.ts b/cypress/e2e/users_spec/UsersCreation.cy.ts index d93707617ff..38ad0c907c4 100644 --- a/cypress/e2e/users_spec/UsersCreation.cy.ts +++ b/cypress/e2e/users_spec/UsersCreation.cy.ts @@ -108,9 +108,9 @@ describe("User Creation", () => { userProfilePage.clearWorkingHours(); userProfilePage.typeWorkingHours(weeklyWorkingHrs); userProfilePage.typeDateOfBirth(dob); - cy.intercept("PATCH", "/api/v1/users/*").as("updateUser"); + userProfilePage.interceptUpdateUsers(); userProfilePage.clickUpdateButton(); - cy.wait("@updateUser").its("response.statusCode").should("eq", 200); + userProfilePage.verifyUpdateUsersResponse(); cy.verifyContentPresence("#contactno-profile-details", [ "+91" + phoneNumber, ]); @@ -158,9 +158,9 @@ describe("User Creation", () => { userCreationPage.selectGender(gender); userCreationPage.selectState(state); userCreationPage.selectDistrict(district); - cy.intercept("POST", "/api/v1/users/add_user/").as("createUser"); + userCreationPage.interceptCreateUser(); userCreationPage.clickSaveUserButton(); - cy.wait("@createUser").its("response.statusCode").should("eq", 201); + userCreationPage.verifyCreateUser(); cy.verifyNotification("User added successfully"); userPage.typeInSearchInput(username); userPage.checkUsernameText(username); diff --git a/cypress/e2e/users_spec/UsersManage.cy.ts b/cypress/e2e/users_spec/UsersManage.cy.ts index 8d7ac8695c6..b1968ed2b4c 100644 --- a/cypress/e2e/users_spec/UsersManage.cy.ts +++ b/cypress/e2e/users_spec/UsersManage.cy.ts @@ -230,14 +230,15 @@ describe("Manage User", () => { userPage.checkUsernameText(usernameforworkinghour); manageUserPage.clickMoreDetailsButton(usernameforworkinghour); manageUserPage.verifyMoreDetailsPage(); + manageUserPage.interceptLinkedSkillTab(); manageUserPage.clickLinkedSkillTab(); - cy.wait(500); + manageUserPage.verifyLinkedSkillResponse(); manageUserPage.verifyLinkedSkillsTabPage(); manageUserPage.selectSkillFromDropdown(linkedskill); + manageUserPage.interceptAddSkill(); manageUserPage.clickAddSkillButton(usernameforworkinghour); - cy.wait(500); + manageUserPage.verifyAddSkillResponse(); manageUserPage.assertSkillInAddedUserSkills(linkedskill); - cy.wait(500); manageUserPage.navigateToProfile(); cy.verifyContentPresence("#username-profile-details", [ usernameforworkinghour, diff --git a/cypress/pageobject/Asset/AssetHome.ts b/cypress/pageobject/Asset/AssetHome.ts index e127b785100..1c3cdd20399 100644 --- a/cypress/pageobject/Asset/AssetHome.ts +++ b/cypress/pageobject/Asset/AssetHome.ts @@ -69,7 +69,7 @@ export class AssetHome { selectAssetImportButton(action: "click" | "verifyNotExist"): void { const selector = "[data-testid=import-asset-button]"; if (action === "click") { - cy.get(selector).click(); + cy.get(selector).scrollIntoView().should("be.visible").click(); } else if (action === "verifyNotExist") { cy.get(selector).should("not.exist"); } @@ -77,13 +77,13 @@ export class AssetHome { selectJsonExportButton() { cy.intercept("GET", "**/api/v1/asset/?**json=true**").as("getJsonexport"); - cy.get("#export-json-option").click(); + cy.get("#export-json-option").should("be.visible").click(); cy.wait("@getJsonexport").its("response.statusCode").should("eq", 200); } selectCsvExportButton() { cy.intercept("GET", "**/api/v1/asset/?**csv=true**").as("getCsvexport"); - cy.get("#export-csv-option").click(); + cy.get("#export-csv-option").should("be.visible").click(); cy.wait("@getCsvexport").its("response.statusCode").should("eq", 200); } diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index 9776433e523..969023c6dc0 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -21,7 +21,7 @@ export interface FacilityData { class FacilityPage { visitCreateFacilityPage() { cy.intercept("GET", "**/facility/create").as("getCreateFacilities"); - cy.visit("/facility/create"); + cy.awaitUrl("/facility/create"); cy.wait("@getCreateFacilities") .its("response.statusCode") .should("eq", 200); @@ -44,8 +44,7 @@ class FacilityPage { } selectWard(ward: string) { - cy.get("div#ward button").click(); - cy.get("[role='option']").contains(ward).click(); + advanceFilters.selectWard(ward); } typeFacilityAddress(address: string, clearBeforeTyping: boolean = false) { @@ -63,6 +62,14 @@ class FacilityPage { cy.verifyAndClickElement("#submit", "Save Facility"); } + interceptFacility() { + cy.intercept("POST", "**/api/v1/facility/").as("postFacility"); + } + + verifyErrorFacility() { + cy.wait("@postFacility").its("response.statusCode").should("eq", 403); + } + verifyFacilityCreatedNotification() { cy.verifyNotification("Facility added successfully"); cy.closeNotification(); @@ -159,8 +166,7 @@ class FacilityPage { cy.get("#facility-location-button").click(); cy.wait("@mapApi").its("response.statusCode").should("eq", 200); cy.get("input#pac-input").type(location).type("{enter}"); - cy.wait(2000); - cy.get("div#map-close").click(); + cy.get("div#map-close").should("be.visible").click(); } fillMiddleWareAddress(url: string) { @@ -202,21 +208,27 @@ class FacilityPage { cy.url().should("include", "/assets?facility="); } + interceptManageInventoryItem() { + cy.intercept("GET", "/api/v1/items/**").as("getItems"); + } + clickManageInventory() { cy.contains("Manage Inventory").click(); } + verifyManageInventoryItem() { + cy.wait("@getItems").its("response.statusCode").should("eq", 200); + } + fillInventoryDetails(name: string, status: string, quantity: string) { - cy.wait(2000); - cy.get("div#id").click(); - cy.get("div#id ul li").contains(name).click(); cy.get("div#isIncoming").click(); cy.get("div#isIncoming ul li").contains(status).click(); + cy.get("div#id").click(); + cy.get("div#id ul li").contains(name).click(); cy.get("[name='quantity']").type(quantity); } fillInventoryMinimumDetails(name: string, quantity: string) { - cy.wait(2000); cy.get("div#id").click(); cy.get("div#id ul li").contains(name).click(); cy.get("[name='quantity']").type(quantity); @@ -262,39 +274,12 @@ class FacilityPage { .should("eq", 201); } - getStateElement() { - return cy.get("#state"); - } - - getDistrictElement() { - return cy.get("#district"); - } - selectStateOnPincode(stateName: string) { - this.getStateElement() - .scrollIntoView() - .wait(2000) - .should("be.visible") - .then(($element) => { - const text = $element.text(); - if (!text.includes(stateName)) { - this.getStateElement().click(); - cy.get("li[role=option]").contains(stateName).click(); - } - }); + advanceFilters.selectState(stateName); } selectDistrictOnPincode(districtName: string) { - this.getDistrictElement().as("district").scrollIntoView().wait(2000); - cy.get("@district") - .should("be.visible") - .then(($element) => { - const text = $element.text(); - if (!text.includes(districtName)) { - this.getDistrictElement().click(); - cy.get("li[role=option]").contains(districtName).click(); - } - }); + advanceFilters.selectDistrict(districtName); } verifyPpeQuantity(text: string) { @@ -317,10 +302,20 @@ class FacilityPage { cy.get(badgeClass).contains(text).should("exist"); } - clickAddMinimumQuanitity() { + interceptMinimumQuantity() { + cy.intercept("GET", "**/api/v1/facility/*/min_quantity/**").as( + "getMinQuantity", + ); + } + + clickAddMinimumQuantity() { cy.get("#add-minimum-quantity").click(); } + verifyMinimumQuantity() { + cy.wait("@getMinQuantity").its("response.statusCode").should("eq", 200); + } + clickUpdateMinimumQuantity() { cy.get("#update-minimum-quantity").first().click(); } diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index edd8ae135a4..8ef4554277f 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -1,6 +1,5 @@ export class PatientConsultationPage { selectConsultationStatus(status: string) { - cy.wait(5000); cy.get("#route_to_facility").scrollIntoView(); cy.get("#route_to_facility").should("be.visible"); cy.clickAndSelectOption("#route_to_facility", status); @@ -110,7 +109,14 @@ export class PatientConsultationPage { "#consultation-buttons", "Edit Consultation Details", ); - cy.wait(3000); + } + + interceptConsultation() { + cy.intercept("GET", "**/api/v1/consultation/*").as("getConsultation"); + } + + verifyConsultation() { + cy.wait("@getConsultation").its("response.statusCode").should("eq", 200); } interceptPatientDetailsAPI(): void { diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts index 635aac3c4d2..bdc65c7d431 100644 --- a/cypress/pageobject/Patient/PatientCreation.ts +++ b/cypress/pageobject/Patient/PatientCreation.ts @@ -45,7 +45,6 @@ export class PatientPage { cy.get("#patient-search").click().type(patientName); // Type the patient name cy.intercept("GET", "**/api/v1/consultation/**").as("getPatient"); cy.get("#patient-name-list").contains(patientName).click(); - cy.wait(2000); cy.wait("@getPatient").its("response.statusCode").should("eq", 200); cy.get("#patient-name-consultation") .should("be.visible") @@ -140,7 +139,9 @@ export class PatientPage { } clickCancelButton() { + cy.intercept("GET", "**/api/v1/patient/*/").as("getPatient"); cy.get("#cancel").click(); + cy.wait("@getPatient"); } selectPatientGender(gender: string) { @@ -181,7 +182,9 @@ export class PatientPage { } visitPatientUrl() { - cy.visit(patient_url); + this.interceptGetPatient(); + cy.awaitUrl(patient_url); + this.verifyGetPatientResponse(); } visitConsultationPage() { @@ -194,6 +197,14 @@ export class PatientPage { cy.wait("@updatePatient").its("response.statusCode").should("eq", 200); } + interceptGetPatient() { + cy.intercept("GET", "**/api/v1/patient/*").as("getPatient"); + } + + verifyGetPatientResponse() { + cy.wait("@getPatient").its("response.statusCode").should("eq", 200); + } + clickCreateConsultationOnPatientPageWithNoConsultation() { cy.get("#create-consultation").should("be.visible").click(); } @@ -221,26 +232,29 @@ export class PatientPage { isPostPartum = false, ) { cy.url().should("include", "/facility/"); - cy.get("[data-testid=patient-dashboard]").then(($dashboard) => { - expect($dashboard).to.contain(gender); - expect($dashboard).to.contain(age); - expect($dashboard).to.contain(patientName); - expect($dashboard).to.contain(phoneNumber); - expect($dashboard).to.contain(emergencyPhoneNumber); - //expect($dashboard).to.contain(yearOfBirth); //Commented out because new proposed UI does not have DOB. Can change later. - expect($dashboard).to.contain(bloodGroup); - expect($dashboard).to.contain(occupation); - socioeconomicStatus && expect($dashboard).to.contain(socioeconomicStatus); - domesticHealthcareSupport && - expect($dashboard).to.contain(domesticHealthcareSupport); - - if (isAntenatal) { - expect($dashboard).to.contain("Antenatal"); - } - if (isPostPartum) { - expect($dashboard).to.contain("Post-partum"); - } - }); + cy.get("[data-testid=patient-dashboard]") + .should("be.visible") + .then(($dashboard) => { + expect($dashboard).to.contain(gender); + expect($dashboard).to.contain(age); + expect($dashboard).to.contain(patientName); + expect($dashboard).to.contain(phoneNumber); + expect($dashboard).to.contain(emergencyPhoneNumber); + expect($dashboard).to.contain(yearOfBirth); + expect($dashboard).to.contain(bloodGroup); + expect($dashboard).to.contain(occupation); + socioeconomicStatus && + expect($dashboard).to.contain(socioeconomicStatus); + domesticHealthcareSupport && + expect($dashboard).to.contain(domesticHealthcareSupport); + + if (isAntenatal) { + expect($dashboard).to.contain("Antenatal"); + } + if (isPostPartum) { + expect($dashboard).to.contain("Post-partum"); + } + }); } verifyPatientLocationDetails( diff --git a/cypress/pageobject/Patient/PatientDischarge.ts b/cypress/pageobject/Patient/PatientDischarge.ts index 70a6d550887..58805255088 100644 --- a/cypress/pageobject/Patient/PatientDischarge.ts +++ b/cypress/pageobject/Patient/PatientDischarge.ts @@ -6,7 +6,19 @@ class PatientDischarge { } selectDischargeReason(reason: string) { - cy.clickAndSelectOption("#discharge_reason", reason); + if (reason == "Recovered") { + cy.intercept("GET", "**/api/v1/consultation/*/prescriptions/*").as( + "getPrescriptions", + ); + cy.clickAndSelectOption("#discharge_reason", reason); + cy.wait("@getPrescriptions").its("response.statusCode").should("eq", 200); + } else if (reason == "Referred") { + cy.intercept("GET", "**/api/v1/getallfacilities/**").as("getFacilities"); + cy.clickAndSelectOption("#discharge_reason", reason); + cy.wait("@getFacilities").its("response.statusCode").should("eq", 200); + } else { + cy.clickAndSelectOption("#discharge_reason", reason); + } } typeDischargeNote(note: string) { @@ -24,6 +36,16 @@ class PatientDischarge { typeDoctorName(doctorName: string) { cy.get("#death_confirmed_by").type(doctorName); } + + interceptDischargePatient() { + cy.intercept("POST", "**/api/v1/consultation/*/discharge_patient/").as( + "postDischarge", + ); + } + + verifyDischargePatient() { + cy.wait("@postDischarge").its("response.statusCode").should("eq", 200); + } } export default PatientDischarge; diff --git a/cypress/pageobject/Patient/PatientDoctorNotes.ts b/cypress/pageobject/Patient/PatientDoctorNotes.ts index 157f35d47d9..f1ac6b87bc5 100644 --- a/cypress/pageobject/Patient/PatientDoctorNotes.ts +++ b/cypress/pageobject/Patient/PatientDoctorNotes.ts @@ -5,14 +5,15 @@ export class PatientDoctorNotes { } addDiscussionNotes(notes: string) { - cy.wait(2000); cy.get("#discussion_notes_textarea").scrollIntoView(); cy.get("#discussion_notes_textarea").click().type(notes); } selectNurseDiscussion() { cy.get("#patient-note-tab-Nurses").scrollIntoView(); + cy.intercept("GET", "/api/v1/patient/*/notes/*").as("getPatientNotes"); cy.get("#patient-note-tab-Nurses").click(); + cy.wait("@getPatientNotes").its("response.statusCode").should("eq", 200); } verifyDiscussionMessage(text: string) { diff --git a/cypress/pageobject/Patient/PatientFileupload.ts b/cypress/pageobject/Patient/PatientFileupload.ts index c70170a744d..140d5ca993b 100644 --- a/cypress/pageobject/Patient/PatientFileupload.ts +++ b/cypress/pageobject/Patient/PatientFileupload.ts @@ -23,9 +23,9 @@ export class PatientFileUpload { cy.wait(2000); cy.get("#start-recording").click(); cy.wait(2000); - cy.get("#stop-recording").click(); - cy.wait(1000); - cy.get("#save-recording").click(); + cy.get("#stop-recording").should("be.enabled").click(); + cy.wait(2000); + cy.get("#save-recording").should("be.enabled").click(); } clickUploadAudioFile() { diff --git a/cypress/pageobject/Patient/PatientLogupdate.ts b/cypress/pageobject/Patient/PatientLogupdate.ts index 45c1924e1a3..bbe7c157e15 100644 --- a/cypress/pageobject/Patient/PatientLogupdate.ts +++ b/cypress/pageobject/Patient/PatientLogupdate.ts @@ -2,7 +2,14 @@ class PatientLogupdate { clickLogupdate() { cy.get("#log-update").scrollIntoView(); cy.verifyAndClickElement("#log-update", "Log Update"); - cy.wait(2000); + } + + interceptConsultationBed() { + cy.intercept("GET", "**/api/v1/consultationbed/*").as("getBed"); + } + + verifyConsultationBed() { + cy.wait("@getBed").its("response.statusCode").should("eq", 200); } clickSwitchBed() { @@ -15,8 +22,13 @@ class PatientLogupdate { selectBed(bed: string) { cy.typeAndSelectOption("input[name='bed']", bed); + cy.intercept("POST", "**/api/v1/consultationbed/").as( + "postConsultationBed", + ); cy.get("#update-switchbed").click(); - cy.wait(2000); + cy.wait("@postConsultationBed") + .its("response.statusCode") + .should("eq", 201); } selectPatientCategory(category: string) { @@ -74,23 +86,46 @@ class PatientLogupdate { cy.get("#rhythm_detail").click().type(rhythm); } + interceptDailyRounds() { + cy.intercept("GET", "**/api/v1/consultation/*/daily_rounds/*/").as( + "getDailyRounds", + ); + } + + verifyDailyRounds() { + cy.wait("@getDailyRounds").its("response.statusCode").should("eq", 200); + } + + interceptpatchDailyRounds() { + cy.intercept("PATCH", "**/api/v1/consultation/*/daily_rounds/*/").as( + "patchDailyRounds", + ); + } + + verifypatchDailyRounds() { + cy.wait("@patchDailyRounds").its("response.statusCode").should("eq", 200); + } + clickLogUpdateViewDetails(element: string, patientCategory: string) { cy.get(element).scrollIntoView(); cy.verifyContentPresence(element, [patientCategory]); + this.interceptDailyRounds(); cy.get(element).first().contains("View Details").click(); - cy.wait(3000); + this.verifyDailyRounds(); } clickLogUpdateUpdateLog(element: string, patientCategory: string) { cy.get(element).scrollIntoView(); cy.verifyContentPresence(element, [patientCategory]); + this.interceptDailyRounds(); cy.get(element).first().contains("Update Log").click(); - cy.wait(3000); + this.verifyDailyRounds(); } clickUpdateDetail() { + this.interceptDailyRounds(); cy.verifyAndClickElement("#consultation-preview", "Update Log"); - cy.wait(3000); + this.verifyDailyRounds(); } clearIntoElementById(elementId) { diff --git a/cypress/pageobject/Patient/PatientMedicalHistory.ts b/cypress/pageobject/Patient/PatientMedicalHistory.ts index bf2296b4471..94c06790fbf 100644 --- a/cypress/pageobject/Patient/PatientMedicalHistory.ts +++ b/cypress/pageobject/Patient/PatientMedicalHistory.ts @@ -34,7 +34,7 @@ class PatientMedicalHistory { patientSymptoms7: string, ) { cy.get("a").contains("Health Profile").click(); - cy.wait(2000); + cy.url().should("include", "/health-profile"); cy.get("[data-test-id=patient-health-profile]").then(($dashboard) => { cy.url().should("include", "/facility/"); expect($dashboard).to.contain(patientPresentHealth); diff --git a/cypress/pageobject/Patient/PatientPrescription.ts b/cypress/pageobject/Patient/PatientPrescription.ts index d801b360aba..89b14efc7b7 100644 --- a/cypress/pageobject/Patient/PatientPrescription.ts +++ b/cypress/pageobject/Patient/PatientPrescription.ts @@ -61,8 +61,7 @@ export class PatientPrescription { } enterDiscontinueReason(reason: string) { - cy.wait(2000); - cy.get("#discontinuedReason").type(reason); + cy.get("#discontinuedReason").should("be.visible").type(reason); } enterAdministerDosage(dosage: string) { @@ -81,6 +80,16 @@ export class PatientPrescription { cy.clickAndSelectOption("#frequency", frequency); } + interceptPrescriptions() { + cy.intercept("GET", "**/api/v1/consultation/*/prescriptions/*").as( + "getPrescriptions", + ); + } + + verifyPrescription() { + cy.wait("@getPrescriptions").its("response.statusCode").should("eq", 200); + } + clickReturnToDashboard() { cy.verifyAndClickElement( "[data-testid='return-to-patient-dashboard']", diff --git a/cypress/pageobject/Patient/PatientTransfer.ts b/cypress/pageobject/Patient/PatientTransfer.ts index 0bdd55e9880..5ad49b40b5f 100644 --- a/cypress/pageobject/Patient/PatientTransfer.ts +++ b/cypress/pageobject/Patient/PatientTransfer.ts @@ -19,13 +19,11 @@ class PatientTransfer { clickTransferSubmitButton() { cy.get("#submit-transferpatient").click(); - cy.wait(2000); } clickConsultationCancelButton() { cy.get("#cancel").scrollIntoView(); cy.get("#cancel").click(); - cy.wait(2000); } clickAllowPatientTransferButton() { diff --git a/cypress/pageobject/Users/ManageUserPage.ts b/cypress/pageobject/Users/ManageUserPage.ts index 24c056a70eb..027357a0321 100644 --- a/cypress/pageobject/Users/ManageUserPage.ts +++ b/cypress/pageobject/Users/ManageUserPage.ts @@ -8,7 +8,9 @@ export class ManageUserPage { } selectSkillFromDropdown(skill: string) { + cy.intercept("GET", "/api/v1/skill/*").as("getSkills"); cy.typeAndSelectOption("input[name='skill']", skill); + cy.wait("@getSkills").its("response.statusCode").should("eq", 200); } assertLinkedFacility(facilityName: string) { @@ -213,6 +215,14 @@ export class ManageUserPage { cy.get("#facility-patients").click(); } + interceptLinkedSkillTab() { + cy.intercept("GET", "**/api/v1/users/*/skill").as("getUserSkill"); + } + + verifyLinkedSkillResponse() { + cy.wait("@getUserSkill").its("response.statusCode").should("eq", 200); + } + clickLinkedSkillTab() { cy.get("#skills").click(); } @@ -361,9 +371,15 @@ export class ManageUserPage { clickAddSkillButton(username: string) { cy.intercept("GET", `**/api/v1/users/${username}/skill/**`).as("getSkills"); cy.get("#add-skill-button").click(); - cy.wait("@getSkills").its("response.statusCode").should("eq", 200); } + interceptAddSkill() { + cy.intercept("GET", "**/api/v1/users/*/skill").as("getUserSkills"); + } + + verifyAddSkillResponse() { + cy.wait("@getUserSkills").its("response.statusCode").should("eq", 200); + } assertSkillInAlreadyLinkedSkills(skillName: string) { cy.get("#already-linked-skills") .contains(skillName) diff --git a/cypress/pageobject/Users/UserCreation.ts b/cypress/pageobject/Users/UserCreation.ts index 26eaa088e23..527cd82fa1e 100644 --- a/cypress/pageobject/Users/UserCreation.ts +++ b/cypress/pageobject/Users/UserCreation.ts @@ -48,4 +48,12 @@ export class UserCreationPage { clickSaveUserButton() { cy.clickSubmitButton("Submit"); } + + interceptCreateUser() { + cy.intercept("POST", "/api/v1/users/add_user/").as("createUser"); + } + + verifyCreateUser() { + cy.wait("@createUser").its("response.statusCode").should("eq", 201); + } } diff --git a/cypress/pageobject/Users/UserProfilePage.ts b/cypress/pageobject/Users/UserProfilePage.ts index 882be0b7b9b..50959bb7cf7 100644 --- a/cypress/pageobject/Users/UserProfilePage.ts +++ b/cypress/pageobject/Users/UserProfilePage.ts @@ -11,6 +11,14 @@ export default class UserProfilePage { cy.get("#video_connect_link").click().clear().type(link); } + interceptUpdateUsers() { + cy.intercept("PATCH", "/api/v1/users/*").as("updateUser"); + } + + verifyUpdateUsersResponse() { + cy.wait("@updateUser").its("response.statusCode").should("eq", 200); + } + clickUpdateButton() { cy.clickSubmitButton("Update"); } diff --git a/cypress/pageobject/utils/advanceFilterHelpers.ts b/cypress/pageobject/utils/advanceFilterHelpers.ts index 22925fc2c23..613f4af2f23 100644 --- a/cypress/pageobject/utils/advanceFilterHelpers.ts +++ b/cypress/pageobject/utils/advanceFilterHelpers.ts @@ -4,17 +4,25 @@ export const advanceFilters = { }, selectState(state: string) { + cy.wait(200); cy.clickAndSelectOption("#state", state); }, selectDistrict(district: string) { + cy.wait(200); cy.clickAndSelectOption("#district", district); }, selectLocalBody(localBody: string) { + cy.wait(200); cy.clickAndSelectOption("#local_body", localBody); }, + selectWard(ward: string) { + cy.wait(200); + cy.clickAndSelectOption("#ward", ward); + }, + applySelectedFilter() { cy.verifyAndClickElement("#apply-filter", "Apply"); }, From 4a560f4b79aad1cbb462eed29c7a091963205c6f Mon Sep 17 00:00:00 2001 From: Mohamed amaan <121436543+modamaan@users.noreply.github.com> Date: Wed, 18 Dec 2024 19:10:51 +0530 Subject: [PATCH 25/31] FIXED: The APPROVAL LETTER is not wrapped with the component (#9479) --- public/locale/en.json | 6 + src/components/Resource/ResourceDetails.tsx | 346 ++++++++++---------- 2 files changed, 185 insertions(+), 167 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index ce70849187d..b9d5c60539c 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -323,6 +323,7 @@ "ambulance_driver_name": "Name of ambulance driver", "ambulance_number": "Ambulance No", "ambulance_phone_number": "Phone number of Ambulance", + "and_the_status_of_request_is": "and the status of request is", "antenatal": "Antenatal", "any_id": "Enter any ID linked with your ABHA number", "any_id_description": "Currently we support: Aadhaar Number / Mobile Number", @@ -1211,6 +1212,8 @@ "provisional": "Provisional", "qualification": "Qualification", "qualification_required": "Qualification is required", + "quantity_approved": "QUANTITY APPROVED", + "quantity_requested": "Quantity Requested", "raise_consent_request": "Raise a consent request to fetch patient records over ABDM", "ration_card__APL": "APL", "ration_card__BPL": "BPL", @@ -1263,6 +1266,7 @@ "reset_password_note_self": "Enter your current password, then create and confirm your new password", "resource": "Resource", "resource_approving_facility": "Resource approving facility", + "resource_details": "Resource details", "resource_origin_facility": "Origin Facility", "resource_request": "Resource Request", "resource_status": "Resource Status", @@ -1404,7 +1408,9 @@ "target_dosage": "Target Dosage", "test_type": "Type of test done", "tested_on": "Tested on", + "the_request_for_resources_placed_by_yourself_is": "The request for resource (details below) placed by yourself is", "third_party_software_licenses": "Third Party Software Licenses", + "title_of_request": "Title of Request", "titrate_dosage": "Titrate Dosage", "to_be_conducted": "To be conducted", "total_amount": "Total Amount", diff --git a/src/components/Resource/ResourceDetails.tsx b/src/components/Resource/ResourceDetails.tsx index 5aefdf394a1..c7d83536c31 100644 --- a/src/components/Resource/ResourceDetails.tsx +++ b/src/components/Resource/ResourceDetails.tsx @@ -1,9 +1,12 @@ import { navigate } from "raviger"; import { useState } from "react"; +import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import PrintPreview from "@/CAREUI/misc/PrintPreview"; + +import { Button } from "@/components/ui/button"; -import ButtonV2 from "@/components/Common/ButtonV2"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; import CommentSection from "@/components/Resource/ResourceCommentSection"; @@ -14,6 +17,7 @@ import { classNames, formatDateTime, formatName } from "@/Utils/utils"; export default function ResourceDetails(props: { id: string }) { const [isPrintMode, setIsPrintMode] = useState(false); + const { t } = useTranslation(); const { data, loading } = useTanStackQueryInstead(routes.getResourceDetails, { pathParams: { id: props.id }, onResponse: ({ res, data }) => { @@ -63,12 +67,15 @@ export default function ResourceDetails(props: { id: string }) {
    {" "} - Date and Time:{" "} + {t("date_and_time")}:{" "} {formatDateTime(data.created_date)}
    - Unique Id: + + {" "} + {t("unique_id")}:{" "} + {data.id}
    @@ -96,50 +103,50 @@ export default function ResourceDetails(props: { id: string }) { data.status === "ON HOLD" ? (
    - The request for resource (details below) placed by yourself is{" "} + {t("the_request_for_resources_placed_by_yourself_is")}{" "} {data.status}
    ) : data.status === "APPROVED" ? (
    - The request for resource (details below) placed by yourself is{" "} + {t("the_request_for_resources_placed_by_yourself_is")}{" "} {data.status}
    ) : (
    - The request for resource (details below) placed by yourself is{" "} + {t("the_request_for_resources_placed_by_yourself_is")}{" "} APPROVED - and the status of request is{" "} + {t("and_the_status_of_request_is")}{" "} {data.status}
    )}
    - Title of Request:{" "} + {t("title_of_request")}:{" "} {data.title || "--"}
    - Reason of Request{" "} + {t("request_reason")}:{" "} {data.reason || "--"}
    - Quantity Requested:{" "} + {t("quantity_requested")}:{" "} {data.requested_quantity}
    - QUANTITY APPROVED:{" "} + {t("quantity_approved")}:{" "} {data.assigned_quantity}
    @@ -188,186 +195,191 @@ export default function ResourceDetails(props: { id: string }) { } return ( - +
    {isPrintMode ? (
    -
    - window.print()}> - Print - Approval Letter - - setIsPrintMode(false)} variant="secondary"> - Close - -
    - {ApprovalLetter(data)} + + {ApprovalLetter(data)} +
    ) : ( -
    -
    - setIsPrintMode(true)}> - Approval - Letter - -
    - {data.assigned_to_object && ( -
    -
    -
    -

    - - Assigned to: {formatName(data.assigned_to_object)} -{" "} - {data.assigned_to_object.user_type} - -

    -
    -
    + +
    +
    +
    - )} -
    -
    -
    {data.title || "--"}
    - - Update Status/Details - -
    - -
    -
    - Status: - - {data.status} - -
    -
    - - Category:{" "} - - {data.category || "--"} -
    -
    - - Subcategory:{" "} - - {data.sub_category || "--"} -
    -
    - - Required Quantity:{" "} - - {data.requested_quantity || "--"} -
    -
    - - Contact person at the current facility:{" "} - - {data.refering_facility_contact_name || "--"} -
    -
    - - Approved Quantity:{" "} - - {data.assigned_quantity} + {data.assigned_to_object && ( +
    +
    +
    +

    + + Assigned to: {formatName(data.assigned_to_object)} -{" "} + {data.assigned_to_object.user_type} + +

    +
    +
    -
    - - Contact person number:{" "} - - {data.refering_facility_contact_number ? ( - - {data.refering_facility_contact_number} + )} +
    + -
    - - {" "} - Is emergency:{" "} - - - {" "} - {data.emergency ? "yes" : "no"} - +
    -
    -
    Reason:
    -
    {data.reason || "--"}
    +
    +
    + + Status:{" "} + + + {data.status} + +
    +
    + + Category:{" "} + + {data.category || "--"} +
    +
    + + Subcategory:{" "} + + {data.sub_category || "--"} +
    +
    + + Required Quantity:{" "} + + {data.requested_quantity || "--"} +
    +
    + + Contact person at the current facility:{" "} + + {data.refering_facility_contact_name || "--"} +
    +
    + + Approved Quantity:{" "} + + {data.assigned_quantity} +
    +
    + + Contact person number:{" "} + + {data.refering_facility_contact_number ? ( + + {data.refering_facility_contact_number} + + ) : ( + "--" + )} +
    +
    + + {" "} + Is emergency:{" "} + + + {" "} + {data.emergency ? "yes" : "no"} + +
    + +
    +
    Reason:
    +
    {data.reason || "--"}
    +
    -
    -

    Audit Log

    +

    Audit Log

    -
    -
    -
    - Created -
    -
    -
    - {data.created_by_object && formatName(data.created_by_object)} +
    +
    +
    + Created
    -
    - {data.created_date && formatDateTime(data.created_date)} +
    +
    + {data.created_by_object && + formatName(data.created_by_object)} +
    +
    + {data.created_date && formatDateTime(data.created_date)} +
    -
    -
    -
    - Last Edited -
    -
    -
    - {formatName(data.last_edited_by_object)} +
    +
    + Last Edited
    -
    - {data.modified_date && formatDateTime(data.modified_date)} +
    +
    + {formatName(data.last_edited_by_object)} +
    +
    + {data.modified_date && formatDateTime(data.modified_date)} +
    -
    -
    -
    -

    Origin Facility

    - - {showFacilityCard(data.origin_facility_object)} -
    -
    -

    Resource Approving Facility

    +
    +
    +

    Origin Facility

    - {showFacilityCard(data.approving_facility_object)} -
    - {data.assigned_facility_object && ( + {showFacilityCard(data.origin_facility_object)} +
    -

    Request Fulfilling Facility

    +

    Resource Approving Facility

    - {showFacilityCard(data.assigned_facility_object)} + {showFacilityCard(data.approving_facility_object)}
    - )} -
    -
    -

    Comments

    - + {data.assigned_facility_object && ( +
    +

    Request Fulfilling Facility

    + + {showFacilityCard(data.assigned_facility_object)} +
    + )} +
    +
    +

    Comments

    + +
    -
    + )} - +
    ); } From 1d50f53c3fb66570d323c2e59739673d9a1c0d99 Mon Sep 17 00:00:00 2001 From: Shaurya Gupta Date: Wed, 18 Dec 2024 21:26:38 +0530 Subject: [PATCH 26/31] Fix avatar upload stuck state and update header after changing avatar (#9427) --- src/Utils/request/uploadFile.ts | 69 +++++++++++++---------- src/components/Common/AvatarEditModal.tsx | 27 +++++---- src/components/Users/UserAvatar.tsx | 29 ++++++---- 3 files changed, 73 insertions(+), 52 deletions(-) diff --git a/src/Utils/request/uploadFile.ts b/src/Utils/request/uploadFile.ts index 005eeaf92aa..ea603e1754f 100644 --- a/src/Utils/request/uploadFile.ts +++ b/src/Utils/request/uploadFile.ts @@ -3,7 +3,7 @@ import { Dispatch, SetStateAction } from "react"; import * as Notification from "@/Utils/Notifications"; import { handleUploadPercentage } from "@/Utils/request/utils"; -const uploadFile = ( +const uploadFile = async ( url: string, file: File | FormData, reqMethod: string, @@ -11,41 +11,52 @@ const uploadFile = ( onLoad: (xhr: XMLHttpRequest) => void, setUploadPercent: Dispatch> | null, onError: () => void, -) => { - const xhr = new XMLHttpRequest(); - xhr.open(reqMethod, url); +): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open(reqMethod, url); - Object.entries(headers).forEach(([key, value]) => { - xhr.setRequestHeader(key, value); - }); + Object.entries(headers).forEach(([key, value]) => { + xhr.setRequestHeader(key, value); + }); - xhr.onload = () => { - onLoad(xhr); - if (400 <= xhr.status && xhr.status <= 499) { - const error = JSON.parse(xhr.responseText); - if (typeof error === "object" && !Array.isArray(error)) { - Object.values(error).forEach((msg) => { - Notification.Error({ msg: msg || "Something went wrong!" }); - }); + xhr.onload = () => { + onLoad(xhr); + if (400 <= xhr.status && xhr.status <= 499) { + let error; + try { + error = JSON.parse(xhr.responseText); + } catch { + error = xhr.responseText; + } + if (typeof error === "object" && !Array.isArray(error)) { + Object.values(error).forEach((msg) => { + Notification.Error({ msg: msg || "Something went wrong!" }); + }); + } else { + Notification.Error({ msg: error || "Something went wrong!" }); + } + reject(new Error("Client error")); } else { - Notification.Error({ msg: error || "Something went wrong!" }); + resolve(); } + }; + + if (setUploadPercent != null) { + xhr.upload.onprogress = (event: ProgressEvent) => { + handleUploadPercentage(event, setUploadPercent); + }; } - }; - if (setUploadPercent != null) { - xhr.upload.onprogress = (event: ProgressEvent) => { - handleUploadPercentage(event, setUploadPercent); + xhr.onerror = () => { + Notification.Error({ + msg: "Network Failure. Please check your internet connectivity.", + }); + onError(); + reject(new Error("Network error")); }; - } - xhr.onerror = () => { - Notification.Error({ - msg: "Network Failure. Please check your internet connectivity.", - }); - onError(); - }; - xhr.send(file); + xhr.send(file); + }); }; - export default uploadFile; diff --git a/src/components/Common/AvatarEditModal.tsx b/src/components/Common/AvatarEditModal.tsx index bcc61819fde..dc044264c4d 100644 --- a/src/components/Common/AvatarEditModal.tsx +++ b/src/components/Common/AvatarEditModal.tsx @@ -114,20 +114,25 @@ const AvatarEditModal = ({ }; const uploadAvatar = async () => { - if (!selectedFile) { - closeModal(); - return; - } + try { + if (!selectedFile) { + closeModal(); + return; + } - setIsProcessing(true); - setIsCaptureImgBeingUploaded(true); - await handleUpload(selectedFile, () => { - setSelectedFile(undefined); - setPreview(undefined); - setPreviewImage(null); + setIsProcessing(true); + setIsCaptureImgBeingUploaded(true); + await handleUpload(selectedFile, () => { + setSelectedFile(undefined); + setPreview(undefined); + setPreviewImage(null); + setIsCaptureImgBeingUploaded(false); + setIsProcessing(false); + }); + } finally { setIsCaptureImgBeingUploaded(false); setIsProcessing(false); - }); + } }; const deleteAvatar = async () => { diff --git a/src/components/Users/UserAvatar.tsx b/src/components/Users/UserAvatar.tsx index 77b353846bc..9930a2e35b7 100644 --- a/src/components/Users/UserAvatar.tsx +++ b/src/components/Users/UserAvatar.tsx @@ -18,20 +18,25 @@ import useTanStackQueryInstead from "@/Utils/request/useQuery"; import { getAuthorizationHeader } from "@/Utils/request/utils"; import { formatDisplayName, sleep } from "@/Utils/utils"; -export default function UserAvatar({ username }: { username: string }) { +export default function UserAvatar({ + username, + refetchUserData, +}: { + username: string; + refetchUserData?: () => void; +}) { const { t } = useTranslation(); const [editAvatar, setEditAvatar] = useState(false); const authUser = useAuthUser(); - const { - data: userData, - loading: isLoading, - refetch: refetchUserData, - } = useTanStackQueryInstead(routes.getUserDetails, { - pathParams: { - username: username, + const { data: userData, loading: isLoading } = useTanStackQueryInstead( + routes.getUserDetails, + { + pathParams: { + username: username, + }, }, - }); + ); if (isLoading || !userData) { return ; @@ -42,7 +47,7 @@ export default function UserAvatar({ username }: { username: string }) { formData.append("profile_picture", file); const url = `${careConfig.apiUrl}/api/v1/users/${userData.username}/profile_picture/`; - uploadFile( + await uploadFile( url, formData, "POST", @@ -50,7 +55,7 @@ export default function UserAvatar({ username }: { username: string }) { async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000); - refetchUserData(); + refetchUserData?.(); Notification.Success({ msg: t("avatar_updated_success") }); setEditAvatar(false); } @@ -68,7 +73,7 @@ export default function UserAvatar({ username }: { username: string }) { }); if (res?.ok) { Notification.Success({ msg: "Profile picture deleted" }); - await refetchUserData(); + refetchUserData?.(); setEditAvatar(false); } else { onError(); From d113b564da89c6aad0188e47c497f4717c0d3df9 Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Thu, 19 Dec 2024 08:04:07 +0530 Subject: [PATCH 27/31] Fixed Flaky Test in cypress develop branch (#9492) --- .../e2e/patient_spec/PatientLogUpdate.cy.ts | 19 +++- .../patient_spec/PatientRegistration.cy.ts | 67 +++-------- .../pageobject/Facility/FacilityCreation.ts | 5 +- cypress/pageobject/Hcx/HcxClaims.ts | 2 +- .../pageobject/Patient/PatientConsultation.ts | 2 +- cypress/pageobject/Patient/PatientCreation.ts | 25 +---- .../pageobject/Patient/PatientLogupdate.ts | 98 ++++++++++------- .../pageobject/utils/advanceFilterHelpers.ts | 8 +- cypress/pageobject/utils/constants.ts | 104 +++++++++++++----- cypress/support/commands.ts | 27 +++-- cypress/support/index.ts | 3 +- 11 files changed, 202 insertions(+), 158 deletions(-) diff --git a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts index da46a6c093e..963f62a76e0 100644 --- a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts +++ b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts @@ -13,6 +13,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { const patientInvestigation = new PatientInvestigation(); const patientPrescription = new PatientPrescription(); const patientCategory = "Moderate"; + const patientModifiedCategory = "Critical"; const additionalSymptoms = "Fever"; const physicalExamination = "physical examination details"; const otherExamination = "Other"; @@ -150,6 +151,9 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { ]); // verify the edit functionality patientLogupdate.clickUpdateDetail(); + patientLogupdate.verifyPatientCategory(patientCategory); + patientLogupdate.verifyRoundType("Progress Note"); + patientLogupdate.selectPatientCategory(patientModifiedCategory); patientLogupdate.typeSystolic(patientModifiedSystolic); patientLogupdate.typeDiastolic(patientModifiedDiastolic); cy.clickSubmitButton("Continue"); @@ -249,8 +253,9 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientPage.interceptGetPatient(); patientLogupdate.clickLogupdate(); patientPage.verifyGetPatientResponse(); - patientLogupdate.typePhysicalExamination(physicalExamination); + patientLogupdate.verifyRoundType("Brief Update"); patientLogupdate.selectPatientCategory(patientCategory); + patientLogupdate.typePhysicalExamination(physicalExamination); patientLogupdate.typeOtherDetails(otherExamination); patientLogupdate.selectSymptomsDate("01012024"); patientLogupdate.typeAndMultiSelectSymptoms("fe", ["Fever"]); @@ -282,11 +287,13 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.verifyNotification("Consultation updated successfully"); cy.closeNotification(); patientLogupdate.clickLogupdate(); + patientLogupdate.verifyRoundType("Brief Update"); // Verify the default round type + patientLogupdate.selectRoundType("Brief Update"); + patientLogupdate.selectPatientCategory(patientCategory); patientLogupdate.typePhysicalExamination(physicalExamination); patientLogupdate.typeOtherDetails(otherExamination); patientLogupdate.selectSymptomsDate("01012024"); patientLogupdate.typeAndMultiSelectSymptoms("fe", ["Fever"]); - patientLogupdate.selectPatientCategory(patientCategory); patientLogupdate.typeSystolic(patientSystolic); patientLogupdate.typeDiastolic(patientDiastolic); patientLogupdate.typePulse(patientPulse); @@ -318,10 +325,10 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientRhythm, ]); patientLogupdate.clickUpdateDetail(); - patientLogupdate.clearIntoElementById("#systolic"); - patientLogupdate.typeSystolic(patientModifiedSystolic); - patientLogupdate.clearIntoElementById("#diastolic"); - patientLogupdate.typeDiastolic(patientModifiedDiastolic); + patientLogupdate.verifyPatientCategory(patientCategory); + patientLogupdate.verifyRoundType("Brief Update"); + patientLogupdate.typeSystolic(patientModifiedSystolic, true); + patientLogupdate.typeDiastolic(patientModifiedDiastolic, true); cy.clickSubmitButton("Continue"); cy.verifyNotification("Brief Update updated successfully"); cy.contains("button", "Log Updates").click(); diff --git a/cypress/e2e/patient_spec/PatientRegistration.cy.ts b/cypress/e2e/patient_spec/PatientRegistration.cy.ts index 5601f994c53..a8b1e47bb4d 100644 --- a/cypress/e2e/patient_spec/PatientRegistration.cy.ts +++ b/cypress/e2e/patient_spec/PatientRegistration.cy.ts @@ -1,3 +1,5 @@ +import { PatientConsultationPage } from "pageobject/Patient/PatientConsultation"; + import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientData, @@ -6,7 +8,11 @@ import { import PatientInsurance from "../../pageobject/Patient/PatientInsurance"; import PatientMedicalHistory from "../../pageobject/Patient/PatientMedicalHistory"; import PatientTransfer from "../../pageobject/Patient/PatientTransfer"; -import { generatePhoneNumber } from "../../pageobject/utils/constants"; +import { + generatePatientName, + generatePhoneNumber, + generateRandomAddress, +} from "../../pageobject/utils/constants"; const yearOfBirth = "2001"; @@ -15,38 +21,21 @@ const calculateAge = () => { return currentYear - parseInt(yearOfBirth); }; -const getRelativeDateString = (deltaDays = 0) => { - const date = new Date(); - if (deltaDays) { - date.setDate(date.getDate() + deltaDays); - } - return date - .toLocaleDateString("en-IN", { - day: "2-digit", - month: "2-digit", - year: "numeric", - }) - .replace(/\//g, ""); -}; - describe("Patient Creation with consultation", () => { const loginPage = new LoginPage(); const patientPage = new PatientPage(); const patientTransfer = new PatientTransfer(); const patientInsurance = new PatientInsurance(); const patientMedicalHistory = new PatientMedicalHistory(); + const patientConsultationPage = new PatientConsultationPage(); const phone_number = generatePhoneNumber(); const age = calculateAge(); const patientFacility = "Dummy Facility 40"; const patientDateOfBirth = "01012001"; - const patientMenstruationStartDate = getRelativeDateString(-10); - const patientDateOfDelivery = getRelativeDateString(-20); - const patientOneName = "Great Napolean 14"; + const patientOneName = generatePatientName(); const patientOneGender = "Male"; const patientOneUpdatedGender = "Female"; - const patientOneAddress = `149/J, 3rd Block, - Aluva - Ernakulam, Kerala - 682001`; + const patientOneAddress = generateRandomAddress(true); const patientOnePincode = "682001"; const patientOneState = "Kerala"; const patientOneDistrict = "Ernakulam"; @@ -115,13 +104,11 @@ describe("Patient Creation with consultation", () => { it("Create a new patient with all field in registration form and no consultation", () => { patientPage.createPatientWithData(newPatientData); - // Verify the patient details patientPage.clickCancelButton(); - patientPage.savePatientUrl(); + // Verify the patient details patientPage.verifyPatientDashboardDetails( patientOneGender, age, - patientOneName, phone_number, phone_number, yearOfBirth, @@ -149,21 +136,15 @@ describe("Patient Creation with consultation", () => { patientPage.verifyPatientNameList(patientOneName); }); - it("Edit the patient details with no consultation and verify", () => { - patientPage.interceptFacilities(); - patientPage.visitUpdatePatientUrl(); - patientPage.verifyStatusCode(); - patientPage.patientformvisibility(); - // change the gender to female and input data to related changed field - cy.wait(3000); + it("Edit the patient details and verify its reflection", () => { + const patientName = "Dummy Patient Two"; + patientPage.visitPatient(patientName); + patientConsultationPage.clickPatientDetails(); + patientPage.clickPatientUpdateDetails(); patientPage.selectPatientGender(patientOneUpdatedGender); patientPage.typePatientDateOfBirth(patientDateOfBirth); - patientPage.clickPatientAntenatalStatusYes(); - patientPage.typeLastMenstruationStartDate(patientMenstruationStartDate); - patientPage.clickPatientPostPartumStatusYes(); - patientPage.typeDateOfDelivery(patientDateOfDelivery); patientPage.selectPatientBloodGroup(patientOneUpdatedBloodGroup); - // Edit the patient consultation , select none medical history and multiple health ID + // select none medical history and add multiple health ID patientMedicalHistory.clickNoneMedicialHistory(); patientInsurance.clickAddInsruanceDetails(); patientInsurance.typePatientInsuranceDetail( @@ -197,20 +178,6 @@ describe("Patient Creation with consultation", () => { ); patientPage.clickUpdatePatient(); patientPage.verifyPatientUpdated(); - patientPage.interceptGetPatient(); - patientPage.visitPatientUrl(); - patientPage.verifyGetPatientResponse(); - // Verify Female Gender change reflection, No Medical History and Insurance Details - patientPage.verifyPatientDashboardDetails( - patientOneUpdatedGender, - age, - patientOneName, - phone_number, - phone_number, - yearOfBirth, - patientOneUpdatedBloodGroup, - patientOccupation, - ); // Verify No medical history patientMedicalHistory.verifyNoSymptosPresent("Diabetes"); // verify insurance details and dedicatd page diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index 969023c6dc0..f03fa65ce8b 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -55,7 +55,10 @@ class FacilityPage { phoneNumber: string, clearBeforeTyping: boolean = false, ) { - cy.typeIntoField("#phone_number", phoneNumber, { clearBeforeTyping }); + cy.typeIntoField("#phone_number", phoneNumber, { + clearBeforeTyping, + skipVerification: true, + }); } clickSaveFacilityButton() { diff --git a/cypress/pageobject/Hcx/HcxClaims.ts b/cypress/pageobject/Hcx/HcxClaims.ts index b93862e6d13..883303d1af6 100644 --- a/cypress/pageobject/Hcx/HcxClaims.ts +++ b/cypress/pageobject/Hcx/HcxClaims.ts @@ -3,7 +3,7 @@ export class HcxClaims { cy.get("#select-insurance-policy", { timeout: 10000 }) .should("be.visible") .and("not.be.disabled"); - cy.clickAndSelectOption("#select-insurance-policy", policy); + cy.clickAndSelectOption("#select-insurance-policy", policy, true); } verifyPolicyEligibility() { diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index 8ef4554277f..1306432bd03 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -65,7 +65,7 @@ export class PatientConsultationPage { } clickPatientDetails() { - cy.verifyAndClickElement("#consultationpage-header", "Patient Details"); + cy.verifyAndClickElement("#patient-details", "Patient Details"); } typePatientIllnessHistory(history: string) { diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts index bdc65c7d431..a74e088eeb8 100644 --- a/cypress/pageobject/Patient/PatientCreation.ts +++ b/cypress/pageobject/Patient/PatientCreation.ts @@ -3,7 +3,6 @@ import FacilityPage from "pageobject/Facility/FacilityCreation"; import PatientMedicalHistory from "./PatientMedicalHistory"; -let patient_url = ""; const facilityPage = new FacilityPage(); const patientMedicalHistory = new PatientMedicalHistory(); @@ -96,7 +95,7 @@ export class PatientPage { } typePatientAge(age: string) { - cy.clickAndSelectOption("#patientAge", "Age"); + cy.clickAndSelectOption("#patientAge", "Age", true); cy.clickSubmitButton("Confirm"); cy.get("#age").clear().type(age); } @@ -175,22 +174,6 @@ export class PatientPage { cy.url().should("include", "/patient"); } - savePatientUrl() { - cy.url().then((url) => { - patient_url = url; - }); - } - - visitPatientUrl() { - this.interceptGetPatient(); - cy.awaitUrl(patient_url); - this.verifyGetPatientResponse(); - } - - visitConsultationPage() { - cy.visit(patient_url + "/consultation"); - } - clickUpdatePatient() { cy.intercept("PUT", "**/api/v1/patient/**").as("updatePatient"); cy.get("button").get("[data-testid=submit-button]").click(); @@ -220,7 +203,6 @@ export class PatientPage { verifyPatientDashboardDetails( gender: string, age: number, - patientName: string, phoneNumber: string, emergencyPhoneNumber: string, yearOfBirth: string, @@ -237,7 +219,6 @@ export class PatientPage { .then(($dashboard) => { expect($dashboard).to.contain(gender); expect($dashboard).to.contain(age); - expect($dashboard).to.contain(patientName); expect($dashboard).to.contain(phoneNumber); expect($dashboard).to.contain(emergencyPhoneNumber); expect($dashboard).to.contain(yearOfBirth); @@ -276,10 +257,6 @@ export class PatientPage { }); } - visitUpdatePatientUrl() { - cy.visit(patient_url + "/update"); - } - clickPatientUpdateDetails() { cy.verifyAndClickElement("#update-patient-details", "Edit Profile"); } diff --git a/cypress/pageobject/Patient/PatientLogupdate.ts b/cypress/pageobject/Patient/PatientLogupdate.ts index bbe7c157e15..bcaf6695d96 100644 --- a/cypress/pageobject/Patient/PatientLogupdate.ts +++ b/cypress/pageobject/Patient/PatientLogupdate.ts @@ -20,6 +20,12 @@ class PatientLogupdate { cy.clickAndSelectOption("#rounds_type", roundType); } + verifyRoundType(roundType: string) { + cy.get("#rounds_type", { timeout: 10000 }) + .should("be.visible") + .should("contain.text", roundType); + } + selectBed(bed: string) { cy.typeAndSelectOption("input[name='bed']", bed); cy.intercept("POST", "**/api/v1/consultationbed/").as( @@ -35,13 +41,23 @@ class PatientLogupdate { cy.clickAndSelectOption("#patientCategory", category); } - typePhysicalExamination(examination: string) { - cy.get("#physical_examination_info").click().type(examination); - cy.get("#physical_examination_info").should("contain", examination); + verifyPatientCategory(category: string) { + cy.get("#patientCategory", { timeout: 10000 }) + .should("be.visible") + .should("contain.text", category); + } + + typePhysicalExamination( + examination: string, + clearBeforeTyping: boolean = false, + ) { + cy.typeIntoField("#physical_examination_info", examination, { + clearBeforeTyping, + }); } - typeOtherDetails(details: string) { - cy.get("#other_details").click().type(details); + typeOtherDetails(details: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#other_details", details, { clearBeforeTyping }); } typeAndMultiSelectSymptoms(input: string, symptoms: string[]) { @@ -54,36 +70,36 @@ class PatientLogupdate { cy.get("#add-symptom").click(); } - typeSystolic(systolic: string) { - cy.get("#systolic").click().type(systolic); + typeSystolic(systolic: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#systolic", systolic, { clearBeforeTyping }); } - typeDiastolic(diastolic: string) { - cy.get("#diastolic").click().type(diastolic); + typeDiastolic(diastolic: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#diastolic", diastolic, { clearBeforeTyping }); } - typePulse(pulse: string) { - cy.get("#pulse").click().type(pulse); + typePulse(pulse: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#pulse", pulse, { clearBeforeTyping }); } - typeTemperature(temperature: string) { - cy.get("#temperature").click().type(temperature); + typeTemperature(temperature: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#temperature", temperature, { clearBeforeTyping }); } - typeRespiratory(respiratory: string) { - cy.get("#resp").click().type(respiratory); + typeRespiratory(respiratory: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#resp", respiratory, { clearBeforeTyping }); } - typeSpo2(spo: string) { - cy.get("#ventilator_spo2").click().type(spo); + typeSpo2(spo: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#ventilator_spo2", spo, { clearBeforeTyping }); } selectRhythm(rhythm: string) { cy.clickAndSelectOption("#rhythm", rhythm); } - typeRhythm(rhythm: string) { - cy.get("#rhythm_detail").click().type(rhythm); + typeRhythm(rhythm: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#rhythm_detail", rhythm, { clearBeforeTyping }); } interceptDailyRounds() { @@ -128,10 +144,6 @@ class PatientLogupdate { this.verifyDailyRounds(); } - clearIntoElementById(elementId) { - cy.get(elementId).click().clear(); - } - clickVitals() { cy.get("#consultation_tab_nav").scrollIntoView(); cy.verifyAndClickElement("#consultation_tab_nav", "Vitals"); @@ -141,8 +153,8 @@ class PatientLogupdate { cy.get("#bilateral_air_entry-option-false").click(); } - typeEtco2(etco2: string) { - cy.get("#etco2-range-input").type(etco2); + typeEtco2(etco2: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#etco2-range-input", etco2, { clearBeforeTyping }); } selectOxygenSupport() { @@ -153,36 +165,48 @@ class PatientLogupdate { cy.get("#ventilator_oxygen_modality-option-NON_REBREATHING_MASK").click(); } - typeOxygenFlowRate(flowRate: string) { - cy.get("#oxygen_flow_rate-range-input").type(flowRate); + typeOxygenFlowRate(flowRate: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#oxygen_flow_rate-range-input", flowRate, { + clearBeforeTyping, + }); } - typeVentilatorSpo2(spo2: string) { - cy.get("#ventilator_spo2-range-input").type(spo2); + typeVentilatorSpo2(spo2: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#ventilator_spo2-range-input", spo2, { + clearBeforeTyping, + }); } selectCriticalCareSection(sectionName: string) { cy.contains("button", sectionName).click(); } - typeBloodSugar(bloodSugar: string) { - cy.get("#blood_sugar_level-range-input").type(bloodSugar); + typeBloodSugar(bloodSugar: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#blood_sugar_level-range-input", bloodSugar, { + clearBeforeTyping, + }); } - typeInsulinDosage(insulinDosage: string) { - cy.get("#insulin_intake_dose-range-input").type(insulinDosage); + typeInsulinDosage(insulinDosage: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#insulin_intake_dose-range-input", insulinDosage, { + clearBeforeTyping, + }); } clickGoBackConsultation() { cy.get("#back-to-consultation").click(); } - typeFluidBalance(fluid: string) { - cy.get("#dialysis_fluid_balance-range-input").type(fluid); + typeFluidBalance(fluid: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#dialysis_fluid_balance-range-input", fluid, { + clearBeforeTyping, + }); } - typeNetBalance(netBalance: string) { - cy.get("#dialysis_net_balance-range-input").type(netBalance); + typeNetBalance(netBalance: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#dialysis_net_balance-range-input", netBalance, { + clearBeforeTyping, + }); } } export default PatientLogupdate; diff --git a/cypress/pageobject/utils/advanceFilterHelpers.ts b/cypress/pageobject/utils/advanceFilterHelpers.ts index 613f4af2f23..14e3ab41bda 100644 --- a/cypress/pageobject/utils/advanceFilterHelpers.ts +++ b/cypress/pageobject/utils/advanceFilterHelpers.ts @@ -4,22 +4,22 @@ export const advanceFilters = { }, selectState(state: string) { - cy.wait(200); + cy.wait(1000); cy.clickAndSelectOption("#state", state); }, selectDistrict(district: string) { - cy.wait(200); + cy.wait(1000); cy.clickAndSelectOption("#district", district); }, selectLocalBody(localBody: string) { - cy.wait(200); + cy.wait(1000); cy.clickAndSelectOption("#local_body", localBody); }, selectWard(ward: string) { - cy.wait(200); + cy.wait(1000); cy.clickAndSelectOption("#ward", ward); }, diff --git a/cypress/pageobject/utils/constants.ts b/cypress/pageobject/utils/constants.ts index 90baf3b6d4b..e14e3720231 100644 --- a/cypress/pageobject/utils/constants.ts +++ b/cypress/pageobject/utils/constants.ts @@ -1,7 +1,17 @@ -function generatePhoneNumber(): string { +function unbiasedRandom(max: number): number { const array = new Uint32Array(1); - window.crypto.getRandomValues(array); - const randomNum = (array[0] % 900000000) + 100000000; + let randomValue; + + do { + window.crypto.getRandomValues(array); + randomValue = array[0]; + } while (randomValue > Math.floor(0xffffffff / max) * max); + + return randomValue % max; +} + +function generatePhoneNumber(): string { + const randomNum = unbiasedRandom(900000000) + 100000000; // Ensure 9-digit range return "9" + randomNum.toString(); } @@ -31,9 +41,9 @@ function generateFacilityName(): string { "Ernakulam", ]; const identifiers = [ - () => Math.floor(Math.random() * 100), // Numeric IDs - () => `Zone-${Math.floor(Math.random() * 10)}`, // Zone IDs - () => `Block-${String.fromCharCode(65 + Math.floor(Math.random() * 26))}`, // Alphabetic Blocks + () => unbiasedRandom(100), // Numeric IDs + () => `Zone-${unbiasedRandom(10)}`, // Zone IDs + () => `Block-${String.fromCharCode(65 + unbiasedRandom(26))}`, // Alphabetic Blocks ]; const suffixes = [ "Meta", @@ -46,21 +56,18 @@ function generateFacilityName(): string { "Hospital", ]; - const randomPrefix = prefixes[Math.floor(Math.random() * prefixes.length)]; - const randomLocation = - locations[Math.floor(Math.random() * locations.length)]; - const randomIdentifier = - identifiers[Math.floor(Math.random() * identifiers.length)](); - const randomSuffix = suffixes[Math.floor(Math.random() * suffixes.length)]; + const randomPrefix = prefixes[unbiasedRandom(prefixes.length)]; + const randomLocation = locations[unbiasedRandom(locations.length)]; + const randomIdentifier = identifiers[unbiasedRandom(identifiers.length)](); + const randomSuffix = suffixes[unbiasedRandom(suffixes.length)]; - // Randomize the format of the name const formats = [ `${randomPrefix} ${randomLocation}-${randomIdentifier} ${randomSuffix}`, `${randomLocation} ${randomPrefix} ${randomSuffix}`, `${randomPrefix} ${randomLocation} ${randomSuffix}`, ]; - return formats[Math.floor(Math.random() * formats.length)]; + return formats[unbiasedRandom(formats.length)]; } function generateRandomAddress(multiline: boolean = false): string { @@ -89,17 +96,14 @@ function generateRandomAddress(multiline: boolean = false): string { ]; const districts = ["Kochi", "Ernakulam"]; const states = ["Kerala"]; - const pincode = Math.floor(682000 + Math.random() * 1000).toString(); // Generate random pincodes in the 682XXX range. + const pincode = (682000 + unbiasedRandom(1000)).toString(); - const randomLocality = - localities[Math.floor(Math.random() * localities.length)]; + const randomLocality = localities[unbiasedRandom(localities.length)]; const randomNeighborhood = - neighborhoods[Math.floor(Math.random() * neighborhoods.length)]; - const randomDistrict = - districts[Math.floor(Math.random() * districts.length)]; - const randomState = states[Math.floor(Math.random() * states.length)]; + neighborhoods[unbiasedRandom(neighborhoods.length)]; + const randomDistrict = districts[unbiasedRandom(districts.length)]; + const randomState = states[unbiasedRandom(states.length)]; - // Create address components const addressParts = [ randomNeighborhood, randomLocality, @@ -108,15 +112,65 @@ function generateRandomAddress(multiline: boolean = false): string { `Pincode: ${pincode}`, ]; - // Return address as single line or multiline - // If 'multiline' is false, return address as a single line - // If 'multiline' is true, return address with each component on a new line return multiline ? addressParts.join("\n") : addressParts.join(", "); } +function generatePatientName(): string { + const firstNames = [ + "John", + "Jane", + "Michael", + "Sarah", + "David", + "Emma", + "James", + "Olivia", + "Robert", + "Sophia", + "William", + "Isabella", + "Benjamin", + "Mia", + "Daniel", + "Charlotte", + "Lucas", + "Amelia", + "Ethan", + "Harper", + ]; + const lastNames = [ + "Smith", + "Johnson", + "Williams", + "Brown", + "Jones", + "Miller", + "Davis", + "Garcia", + "Rodriguez", + "Wilson", + "Martinez", + "Hernandez", + "Lopez", + "Gonzalez", + "Perez", + "Taylor", + "Anderson", + "Thomas", + "Jackson", + "White", + ]; + + const randomFirstName = firstNames[unbiasedRandom(firstNames.length)]; + const randomLastName = lastNames[unbiasedRandom(lastNames.length)]; + + return `${randomFirstName} ${randomLastName}`; +} + export { generatePhoneNumber, generateEmergencyPhoneNumber, generateFacilityName, generateRandomAddress, + generatePatientName, }; diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index f5bbcf42290..54bc3be2666 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -133,12 +133,12 @@ Cypress.Commands.add("clickCancelButton", (buttonText = "Cancel") => { Cypress.Commands.add( "typeAndSelectOption", - (element: string, referance: string) => { + (element: string, reference: string) => { cy.get(element) .click() - .type(referance) + .type(reference) .then(() => { - cy.get("[role='option']").contains(referance).click(); + cy.get("[role='option']").contains(reference).click(); }); }, ); @@ -175,11 +175,17 @@ Cypress.Commands.add( Cypress.Commands.add( "clickAndSelectOption", - (element: string, reference: string) => { + (element: string, reference: string, skipVerification: boolean = false) => { cy.get(element) .click() .then(() => { cy.get("[role='option']").contains(reference).click(); + }) + .then(() => { + // Skip verification if skipVerification is true + if (!skipVerification) { + cy.get(element).should("contain", reference); + } }); }, ); @@ -247,15 +253,20 @@ Cypress.Commands.add( ( selector: string, value: string, - options: { clearBeforeTyping?: boolean } = {}, + options: { clearBeforeTyping?: boolean; skipVerification?: boolean } = {}, ) => { - const { clearBeforeTyping = false } = options; + const { clearBeforeTyping = false, skipVerification = false } = options; const inputField = cy.get(selector); if (clearBeforeTyping) { - inputField.clear(); // Clear the input field + inputField.clear(); // Clear the input field if specified } - inputField.click().type(value); // Click and type the new value + inputField.scrollIntoView().should("be.visible").click().type(value); + + // Conditionally skip verification based on the skipVerification flag + if (!skipVerification) { + inputField.should("have.value", value); // Verify the value if skipVerification is false + } }, ); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index fa01326698c..59620bf8a6d 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -34,6 +34,7 @@ declare global { clickAndSelectOption( element: string, reference: string, + skipVerification?: boolean, ): Chainable; verifyAndClickElement( element: string, @@ -49,7 +50,7 @@ declare global { typeIntoField( selector: string, value: string, - options?: { clearBeforeTyping?: boolean }, + options?: { clearBeforeTyping?: boolean; skipVerification?: boolean }, ): Chainable; } } From c2ec59afdc4d8712cee1b3516a6f36fee1752308 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:59:33 +0530 Subject: [PATCH 28/31] Bump cypress from 13.15.2 to 13.17.0 (#9482) Bumps [cypress](https://github.com/cypress-io/cypress) from 13.15.2 to 13.17.0. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v13.15.2...v13.17.0) --- updated-dependencies: - dependency-name: cypress dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6076acd00a..f0f24443f22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "clsx": "^2.1.1", "cmdk": "^1.0.4", "cross-env": "^7.0.3", - "cypress": "^13.15.2", + "cypress": "^13.17.0", "dayjs": "^1.11.13", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", @@ -7807,10 +7807,11 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "13.15.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.2.tgz", - "integrity": "sha512-ARbnUorjcCM3XiPwgHKuqsyr5W9Qn+pIIBPaoilnoBkLdSC2oLQjV1BUpnmc7KR+b7Avah3Ly2RMFnfxr96E/A==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.17.0.tgz", + "integrity": "sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@cypress/request": "^3.0.6", "@cypress/xvfb": "^1.2.4", diff --git a/package.json b/package.json index 00ec917f6fb..90923b11a53 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "clsx": "^2.1.1", "cmdk": "^1.0.4", "cross-env": "^7.0.3", - "cypress": "^13.15.2", + "cypress": "^13.17.0", "dayjs": "^1.11.13", "echarts": "^5.5.1", "echarts-for-react": "^3.0.2", From c1890ede160c58e7da768e2a377ab32d03b4d382 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:59:54 +0530 Subject: [PATCH 29/31] Bump @radix-ui/react-tooltip from 1.1.4 to 1.1.6 (#9481) Bumps [@radix-ui/react-tooltip](https://github.com/radix-ui/primitives) from 1.1.4 to 1.1.6. - [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md) - [Commits](https://github.com/radix-ui/primitives/commits) --- updated-dependencies: - dependency-name: "@radix-ui/react-tooltip" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 241 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 2 +- 2 files changed, 229 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index f0f24443f22..8b5bb49563a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@radix-ui/react-scroll-area": "^1.2.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toast": "^1.2.2", - "@radix-ui/react-tooltip": "^1.1.4", + "@radix-ui/react-tooltip": "^1.1.6", "@sentry/browser": "^8.45.1", "@tanstack/react-query": "^5.62.3", "@tanstack/react-query-devtools": "^5.62.7", @@ -4235,23 +4235,238 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.4.tgz", - "integrity": "sha512-QpObUH/ZlpaO4YgHSaYzrLO2VuO+ZBFFgGzjMUPwtiYnAzzNNDPJeEGRrT7qNOrWm/Jr08M1vlp+vTHtnSQ0Uw==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.6.tgz", + "integrity": "sha512-TLB5D8QLExS1uDn7+wH/bjEmRurNMTzNrtq7IjaS4kjion9NtzsTGkvR5+i7yc9q01Pi2KMM2cN3f8UG4IvvXA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.3", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.2", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-popper": "1.2.1", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1", "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.0" + "@radix-ui/react-visually-hidden": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz", + "integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", + "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz", + "integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", + "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz", + "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" }, "peerDependencies": { "@types/react": "*", diff --git a/package.json b/package.json index 90923b11a53..a340f49fdac 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@radix-ui/react-scroll-area": "^1.2.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toast": "^1.2.2", - "@radix-ui/react-tooltip": "^1.1.4", + "@radix-ui/react-tooltip": "^1.1.6", "@sentry/browser": "^8.45.1", "@tanstack/react-query": "^5.62.3", "@tanstack/react-query-devtools": "^5.62.7", From bb2c1bce16bf5ca9a769317ee9c145617c7393b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 18:08:25 +0530 Subject: [PATCH 30/31] Bump browserslist from 4.24.2 to 4.24.3 (#9495) Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.24.2 to 4.24.3. - [Release notes](https://github.com/browserslist/browserslist/releases) - [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md) - [Commits](https://github.com/browserslist/browserslist/compare/4.24.2...4.24.3) --- updated-dependencies: - dependency-name: browserslist dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 32 ++++++++++++++++---------------- package.json | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b5bb49563a..703faf0230a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "@yudiel/react-qr-scanner": "^2.0.8", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", - "browserslist": "^4.24.2", + "browserslist": "^4.24.3", "browserslist-useragent-regexp": "^4.1.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -7254,9 +7254,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", "funding": [ { "type": "opencollective", @@ -7273,9 +7273,9 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { @@ -7399,9 +7399,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", "funding": [ { "type": "opencollective", @@ -8777,9 +8777,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.41", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", - "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", + "version": "1.5.74", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz", + "integrity": "sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -14700,9 +14700,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "license": "MIT" }, "node_modules/node-source-walk": { diff --git a/package.json b/package.json index a340f49fdac..972f14d614b 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "@yudiel/react-qr-scanner": "^2.0.8", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", - "browserslist": "^4.24.2", + "browserslist": "^4.24.3", "browserslist-useragent-regexp": "^4.1.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", From 213e1147eeace45e4d0770634da8835376585575 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 18:35:26 +0530 Subject: [PATCH 31/31] Bump @radix-ui/react-dialog from 1.1.2 to 1.1.4 (#9496) Bumps [@radix-ui/react-dialog](https://github.com/radix-ui/primitives) from 1.1.2 to 1.1.4. - [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md) - [Commits](https://github.com/radix-ui/primitives/commits) --- updated-dependencies: - dependency-name: "@radix-ui/react-dialog" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 256 +++++++++++++++++++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 218 insertions(+), 40 deletions(-) diff --git a/package-lock.json b/package-lock.json index 703faf0230a..e2b5c5e311b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@hello-pangea/dnd": "^17.0.0", "@pnotify/core": "^5.2.0", "@pnotify/mobile": "^5.2.0", - "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-label": "^2.1.0", @@ -3718,24 +3718,73 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz", - "integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz", + "integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==", + "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.3", "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.1", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.2", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.6.0" + "react-remove-scroll": "^2.6.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", + "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -3752,6 +3801,145 @@ } } }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz", + "integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", + "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", + "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", @@ -10998,15 +11186,6 @@ "node": ">= 0.10" } }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/is-alphabetical": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", @@ -16119,20 +16298,20 @@ } }, "node_modules/react-remove-scroll-bar": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", - "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", "dependencies": { - "react-style-singleton": "^2.2.1", + "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "engines": { "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -16141,21 +16320,20 @@ } }, "node_modules/react-style-singleton": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", - "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", - "invariant": "^2.2.4", "tslib": "^2.0.0" }, "engines": { "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -19074,9 +19252,9 @@ } }, "node_modules/use-callback-ref": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", - "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -19085,8 +19263,8 @@ "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { diff --git a/package.json b/package.json index 972f14d614b..fb8510950b7 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@hello-pangea/dnd": "^17.0.0", "@pnotify/core": "^5.2.0", "@pnotify/mobile": "^5.2.0", - "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-label": "^2.1.0",