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/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/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/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/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 53e18580f56..56a50bc8558 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",
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/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/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/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/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/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;
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("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("icmr_specimen_referral_form")}
-
-
-
- )
- }
- >
-
-
-
-
-
- {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) => (
-
- ))}
-
- >
- );
-}
-
-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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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 (
-
- );
-}
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 (
-
-
-
- );
-};
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"}
-
-
-
-
-
-
- {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" && (
-
- showUpdateStatus(item)}
- className="w-full rounded border border-secondary-400 bg-primary-500 px-4 py-2 text-center text-sm font-semibold text-white shadow hover:bg-primary-700"
- >
- UPDATE SAMPLE TEST STATUS
-
-
- )}
-
-
navigate(`/sample/${item.id}`)}
- className="mt-2 w-full rounded border border-secondary-400 bg-white px-4 py-2 text-center text-sm font-semibold text-secondary-800 shadow hover:bg-secondary-400"
- >
- Sample Details
-
-
-
-
-
- );
- });
- }
-
- 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 || "" : "",
- ),
- ]}
- />
-
-
-
- );
-}
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
- />
-
-
-
- {t("upload")}
-
-
-
- {t("discard")}
-
-
- {!!fileUpload.progress && (
-
- )}
-
- ) : (
-
-
-
- {t("choose_file")}
-
-
-
- )}
- >
- )}
-
-
-
- );
-};
-
-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/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) => {
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",