diff --git a/cypress/e2e/assets_spec/asset_homepage.cy.ts b/cypress/e2e/assets_spec/asset_homepage.cy.ts index e1fcf278442..61f7d8a52c0 100644 --- a/cypress/e2e/assets_spec/asset_homepage.cy.ts +++ b/cypress/e2e/assets_spec/asset_homepage.cy.ts @@ -90,7 +90,7 @@ describe("Asset Tab", () => { assetPage.selectImportOption(); assetPage.selectImportFacility("Dummy Facility 1"); assetPage.importAssetFile(); - assetPage.selectImportLocation("Camera Loc"); + assetPage.selectImportLocation("Camera Locations"); assetPage.clickImportAsset(); }); diff --git a/cypress/e2e/assets_spec/assets_manage.cy.ts b/cypress/e2e/assets_spec/assets_manage.cy.ts index 34c554b374e..8b440f68761 100644 --- a/cypress/e2e/assets_spec/assets_manage.cy.ts +++ b/cypress/e2e/assets_spec/assets_manage.cy.ts @@ -5,6 +5,12 @@ import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import { AssetFilters } from "../../pageobject/Asset/AssetFilters"; +function addDaysToDate(numberOfDays: number) { + const inputDate = new Date(); + inputDate.setDate(inputDate.getDate() + numberOfDays); + return inputDate.toISOString().split("T")[0]; +} + describe("Asset", () => { const assetPage = new AssetPage(); const loginPage = new LoginPage(); @@ -26,6 +32,33 @@ describe("Asset", () => { cy.awaitUrl("/assets"); }); + it("Verify Asset Warranty Expiry Label", () => { + assetSearchPage.typeSearchKeyword(assetname); + assetSearchPage.pressEnter(); + assetSearchPage.verifyBadgeContent(assetname); + assetSearchPage.clickAssetByName(assetname); + assetPage.clickupdatedetailbutton(); + assetPage.scrollintoWarrantyDetails(); + assetPage.enterWarrantyExpiryDate(addDaysToDate(100)); // greater than 3 months + assetPage.clickassetupdatebutton(); + assetPage.verifyWarrantyExpiryLabel(""); + assetPage.clickupdatedetailbutton(); + assetPage.scrollintoWarrantyDetails(); + assetPage.enterWarrantyExpiryDate(addDaysToDate(80)); // less than 3 months + assetPage.clickassetupdatebutton(); + assetPage.verifyWarrantyExpiryLabel("3 months"); + assetPage.clickupdatedetailbutton(); + assetPage.scrollintoWarrantyDetails(); + assetPage.enterWarrantyExpiryDate(addDaysToDate(20)); // less than 1 month + assetPage.clickassetupdatebutton(); + assetPage.verifyWarrantyExpiryLabel("1 month"); + assetPage.clickupdatedetailbutton(); + assetPage.scrollintoWarrantyDetails(); + assetPage.enterWarrantyExpiryDate(addDaysToDate(100)); // check for greater than 3 months again to verify the label is removed + assetPage.clickassetupdatebutton(); + assetPage.verifyWarrantyExpiryLabel(""); + }); + it("Create & Edit a service history and verify reflection", () => { assetSearchPage.typeSearchKeyword(assetname); assetSearchPage.pressEnter(); diff --git a/cypress/e2e/patient_spec/patient_crud.cy.ts b/cypress/e2e/patient_spec/patient_crud.cy.ts index fcfd97039f7..4fef861aeab 100644 --- a/cypress/e2e/patient_spec/patient_crud.cy.ts +++ b/cypress/e2e/patient_spec/patient_crud.cy.ts @@ -130,12 +130,27 @@ describe("Patient Creation with consultation", () => { patientConsultationPage.interceptMediaBase(); patientConsultationPage.selectMedicinebox(); patientConsultationPage.waitForMediabaseStatusCode(); - patientConsultationPage.prescribeMedicine(); + patientConsultationPage.prescribefirstMedicine(); patientConsultationPage.enterDosage("3"); patientConsultationPage.selectDosageFrequency("Twice daily"); patientConsultationPage.submitPrescriptionAndReturn(); }); + it("Edit created consultation to existing patient", () => { + updatePatientPage.visitUpdatedPatient(); + patientConsultationPage.visitEditConsultationPage(); + patientConsultationPage.fillIllnessHistory("editted"); + patientConsultationPage.selectConsultationStatus( + "Referred from other hospital" + ); + patientConsultationPage.updateSymptoms("FEVER"); + patientConsultationPage.setSymptomsDate("01082023"); + patientConsultationPage.updateConsultation(); + patientConsultationPage.verifySuccessNotification( + "Consultation updated successfully" + ); + }); + afterEach(() => { cy.saveLocalStorage(); }); diff --git a/cypress/e2e/patient_spec/patient_manage.cy.ts b/cypress/e2e/patient_spec/patient_manage.cy.ts new file mode 100644 index 00000000000..e8d381286aa --- /dev/null +++ b/cypress/e2e/patient_spec/patient_manage.cy.ts @@ -0,0 +1,78 @@ +import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; +import LoginPage from "../../pageobject/Login/LoginPage"; +import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; +import { PatientPage } from "../../pageobject/Patient/PatientCreation"; + +describe("Patient", () => { + const loginPage = new LoginPage(); + const patientPage = new PatientPage(); + const patientConsultationPage = new PatientConsultationPage(); + + before(() => { + loginPage.loginAsDisctrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + cy.awaitUrl("/patients"); + }); + + // it("Create Patient shift requests.", () => { + // patientPage.visitPatient(); + // patientConsultationPage.visitShiftRequestPage(); + // patientConsultationPage.enterPatientShiftDetails( + // "Test User", + // phone_number, + // "Dummy Shifting", + // "Reason" + // ); + // patientConsultationPage.createShiftRequest(); + // patientConsultationPage.verifySuccessNotification( + // "Shift request created successfully" + // ); + // }); + // commented out the shifting request, as logic need to be re-visited + + it("Post doctor notes for an already created patient", () => { + patientPage.visitPatient(); + patientConsultationPage.visitDoctorNotesPage(); + patientConsultationPage.addDoctorsNotes("Test Doctor Notes"); + patientConsultationPage.postDoctorNotes(); + patientConsultationPage.verifySuccessNotification( + "Note added successfully" + ); + }); + + it("Edit prescription for an already created patient", () => { + patientPage.visitPatient(); + patientConsultationPage.visitEditPrescriptionPage(); + patientConsultationPage.clickAddPrescription(); + patientConsultationPage.interceptMediaBase(); + patientConsultationPage.selectMedicinebox(); + patientConsultationPage.waitForMediabaseStatusCode(); + patientConsultationPage.prescribesecondMedicine(); + patientConsultationPage.enterDosage("4"); + patientConsultationPage.selectDosageFrequency("Twice daily"); + patientConsultationPage.submitPrescription(); + }); + + it("Upload consultations file ", () => { + patientPage.visitPatient(); + patientConsultationPage.visitFilesPage(); + patientConsultationPage.uploadFile(); + patientConsultationPage.clickUploadFile(); + }); + + it("Discharge a patient", () => { + patientPage.visitPatient(); + patientConsultationPage.clickDischargePatient(); + patientConsultationPage.selectDischargeReason("Recovered"); + patientConsultationPage.addDischargeNotes("Discharge notes"); + patientConsultationPage.confirmDischarge(); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/e2e/users_spec/user_homepage.cy.ts b/cypress/e2e/users_spec/user_homepage.cy.ts new file mode 100644 index 00000000000..40a55bad1e8 --- /dev/null +++ b/cypress/e2e/users_spec/user_homepage.cy.ts @@ -0,0 +1,39 @@ +/// + +import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; +import LoginPage from "../../pageobject/Login/LoginPage"; +import { UserPage } from "../../pageobject/Users/UserSearch"; + +describe("Asset Tab", () => { + const userPage = new UserPage(); + const usernameToTest = "devdoctor"; + const currentuser = "devdistrictadmin"; + const loginPage = new LoginPage(); + before(() => { + loginPage.loginAsDisctrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + cy.awaitUrl("/users"); + }); + + it("Search by username", () => { + userPage.checkSearchInputVisibility(); + userPage.typeInSearchInput(usernameToTest); + userPage.checkUrlForUsername(usernameToTest); + userPage.checkUsernameText(usernameToTest); + userPage.checkUsernameBadgeVisibility(true); + userPage.clearSearchInput(); + userPage.checkUsernameBadgeVisibility(false); + userPage.typeInSearchInput(usernameToTest); + userPage.checkUsernameText(usernameToTest); + userPage.clickRemoveIcon(); + userPage.checkUsernameBadgeVisibility(false); + userPage.checkUsernameText(currentuser); + }); + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/pageobject/Asset/AssetCreation.ts b/cypress/pageobject/Asset/AssetCreation.ts index 45356a1a4e7..93bbc87c9ab 100644 --- a/cypress/pageobject/Asset/AssetCreation.ts +++ b/cypress/pageobject/Asset/AssetCreation.ts @@ -150,7 +150,7 @@ export class AssetPage { configureVitalAsset(hostName: string, localIp: string) { cy.get("[data-testid=asset-configure-button]").click(); - cy.get("#middlewareHostname").type(hostName); + cy.get("#middleware_hostname").type(hostName); cy.get("#localipAddress").type(localIp); } @@ -285,16 +285,39 @@ export class AssetPage { cy.get("#notes").scrollIntoView(); } - enterAssetNotes(text) { + enterAssetNotes(text: string) { cy.get("#notes").click().clear(); cy.get("#notes").click().type(text); } - enterAssetservicedate(text) { + enterAssetservicedate(text: string) { cy.get("input[name='last_serviced_on']").click(); cy.get("#date-input").click().type(text); } + scrollintoWarrantyDetails() { + cy.get("#warranty-details").scrollIntoView(); + } + + enterWarrantyExpiryDate(text: string) { + cy.get("#WarrantyAMCExpiry").click(); + cy.get("#WarrantyAMCExpiry").click().type(text); + } + + verifyWarrantyExpiryLabel(duration: string) { + if (duration === "") { + cy.get("#warranty-amc-expired-red").should("not.exist"); + cy.get("#warranty-amc-expiring-soon-orange").should("not.exist"); + cy.get("#warranty-amc-expiring-soon-yellow").should("not.exist"); + } else if (duration === "expired") { + cy.get("#warranty-amc-expired-red").should("be.visible"); + } else if (duration === "1 month") { + cy.get("#warranty-amc-expiring-soon-orange").should("be.visible"); + } else if (duration === "3 months") { + cy.get("#warranty-amc-expiring-soon-yellow").should("be.visible"); + } + } + clickassetupdatebutton() { cy.get("#submit").click(); } diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index 2eb6550cb8b..bf301641898 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -1,5 +1,7 @@ export class PatientConsultationPage { selectConsultationStatus(status: string) { + cy.get("#consultation_status").scrollIntoView(); + cy.get("#consultation_status").should("be.visible"); cy.get("#consultation_status") .click() .then(() => { @@ -83,10 +85,18 @@ export class PatientConsultationPage { cy.intercept("GET", "**/api/v1/medibase/**").as("getMediaBase"); } - prescribeMedicine() { + prescribefirstMedicine() { cy.get("div#medicine_object input[placeholder='Select'][role='combobox']") .click() - .type("dolo{enter}"); + .type("dolo") + .type("{downarrow}{enter}"); + } + + prescribesecondMedicine() { + cy.get("div#medicine_object input[placeholder='Select'][role='combobox']") + .click() + .type("dolo") + .type("{downarrow}{downarrow}{enter}"); } selectMedicinebox() { @@ -95,6 +105,23 @@ export class PatientConsultationPage { ).click(); } + visitFilesPage() { + cy.get("a").contains("Files").click(); + } + + uploadFile() { + cy.get("#file_upload_patient").selectFile( + "cypress/fixtures/sampleAsset.xlsx", + { force: true } + ); + } + + clickUploadFile() { + cy.intercept("POST", "**/api/v1/files/").as("uploadFile"); + cy.get("#upload_file_button").click(); + cy.wait("@uploadFile").its("response.statusCode").should("eq", 201); + } + waitForMediabaseStatusCode() { cy.wait("@getMediaBase").its("response.statusCode").should("eq", 200); } @@ -119,4 +146,119 @@ export class PatientConsultationPage { cy.get("[data-testid='return-to-patient-dashboard']").click(); cy.wait("@submitPrescription").its("response.statusCode").should("eq", 201); } + + visitEditConsultationPage() { + cy.get("#view_consulation_updates").click(); + cy.get("button").contains("Edit Consultation Details").click(); + } + + setSymptomsDate(date: string) { + cy.get("#symptoms_onset_date") + .click() + .then(() => { + cy.get("[placeholder='DD/MM/YYYY']").type(date); + }); + } + + updateConsultation() { + cy.intercept("PUT", "**/api/v1/consultation/**").as("updateConsultation"); + cy.get("#submit").contains("Update Consultation").click(); + cy.wait("@updateConsultation").its("response.statusCode").should("eq", 200); + } + + verifySuccessNotification(message: string) { + cy.verifyNotification(message); + } + + updateSymptoms(symptoms: string) { + this.selectSymptoms(symptoms); + cy.get("#symptoms").click(); + } + + visitShiftRequestPage() { + cy.get("#create_shift_request").click(); + } + + enterPatientShiftDetails( + name: string, + phone_number: string, + facilityName: string, + reason: string + ) { + cy.get("#refering_facility_contact_name").type(name); + cy.get("#refering_facility_contact_number").type(phone_number); + cy.get("input[name='assigned_facility']") + .type(facilityName) + .then(() => { + cy.get("[role='option']").first().click(); + }); + cy.get("#reason").type(reason); + } + + createShiftRequest() { + cy.intercept("POST", "**/api/v1/shift/").as("createShiftRequest"); + cy.get("#submit").click(); + cy.wait("@createShiftRequest").its("response.statusCode").should("eq", 201); + } + + visitDoctorNotesPage() { + cy.get("#patient_doctor_notes").click(); + } + + addDoctorsNotes(notes: string) { + cy.get("#doctor_notes_textarea").type(notes); + } + + postDoctorNotes() { + cy.intercept("POST", "**/api/v1/patient/*/notes").as("postDoctorNotes"); + cy.get("#submit").contains("Post Your Note").click(); + cy.wait("@postDoctorNotes").its("response.statusCode").should("eq", 201); + } + + clickDischargePatient() { + cy.get("#discharge_patient_from_care").click(); + } + + selectDischargeReason(reason: string) { + cy.get("#discharge_reason") + .click() + .then(() => { + cy.get("[role='option']").contains(reason).click(); + }); + } + + addDischargeNotes(notes: string) { + cy.get("#discharge_notes").type(notes); + } + + confirmDischarge() { + cy.intercept("POST", "**/api/v1/consultation/*/discharge_patient/").as( + "dischargePatient" + ); + cy.get("#submit").contains("Confirm Discharge").click(); + cy.wait("@dischargePatient").its("response.statusCode").should("eq", 200); + } + + discontinuePreviousPrescription() { + cy.intercept( + "POST", + "**/api/v1/consultation/*/prescriptions/*/discontinue/" + ).as("deletePrescription"); + cy.get("button").contains("Discontinue").click(); + cy.get("#submit").contains("Discontinue").click(); + cy.wait("@deletePrescription").its("response.statusCode").should("eq", 200); + } + + visitEditPrescriptionPage() { + cy.get("#consultation_tab_nav").contains("Medicines").click(); + cy.get("a[href='prescriptions']").first().click(); + } + + submitPrescription() { + cy.intercept("POST", "**/api/v1/consultation/*/prescriptions/").as( + "submitPrescription" + ); + cy.get("#submit").contains("Submit").click(); + cy.wait("@submitPrescription").its("response.statusCode").should("eq", 201); + } } diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts index 4fcd43dc490..47bf9c913ad 100644 --- a/cypress/pageobject/Patient/PatientCreation.ts +++ b/cypress/pageobject/Patient/PatientCreation.ts @@ -10,6 +10,12 @@ export class PatientPage { cy.wait("@getFacilities").its("response.statusCode").should("eq", 200); } + visitPatient() { + cy.intercept("GET", "**/api/v1/consultation/**").as("getPatient"); + cy.get("[data-cy='patient']").first().click(); + cy.wait("@getPatient").its("response.statusCode").should("eq", 200); + } + selectFacility(facilityName: string) { cy.get("input[name='facilities']") .type(facilityName) diff --git a/cypress/pageobject/Users/UserSearch.ts b/cypress/pageobject/Users/UserSearch.ts new file mode 100644 index 00000000000..311a4b87c3a --- /dev/null +++ b/cypress/pageobject/Users/UserSearch.ts @@ -0,0 +1,37 @@ +// UserPage.ts +export class UserPage { + // Element selectors + searchByUsernameInput = "#search-by-username"; + usernameText = "#username"; + usernameBadge = "[data-testid='Username']"; + removeIcon = "#removeicon"; + + checkSearchInputVisibility() { + cy.get(this.searchByUsernameInput).should("be.visible"); + } + + typeInSearchInput(text: string) { + cy.get(this.searchByUsernameInput).click().type(text); + } + + clearSearchInput() { + cy.get(this.searchByUsernameInput).click().clear(); + } + + checkUrlForUsername(username: string) { + cy.url().should("include", `username=${username}`); + } + + checkUsernameText(username: string) { + cy.get(this.usernameText).should("have.text", username); + } + + checkUsernameBadgeVisibility(shouldBeVisible: boolean) { + const assertion = shouldBeVisible ? "be.visible" : "not.be.visible"; + cy.get(this.usernameBadge).should(assertion); + } + + clickRemoveIcon() { + cy.get(this.removeIcon).click(); + } +} diff --git a/package-lock.json b/package-lock.json index 6697b3e7021..a2f8d202145 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "events": "^3.3.0", "i18next": "^23.2.7", "i18next-browser-languagedetector": "^7.1.0", - "lodash": "^4.17.21", + "lodash-es": "^4.17.21", "postcss-loader": "^7.3.3", "qrcode.react": "^3.1.0", "raviger": "^4.1.2", @@ -73,7 +73,7 @@ "@types/cypress": "^1.1.3", "@types/echarts": "^4.9.18", "@types/google.maps": "^3.53.4", - "@types/lodash": "^4.14.195", + "@types/lodash-es": "^4.17.9", "@types/lodash.get": "^4.4.7", "@types/node": "^20.4.0", "@types/prop-types": "*", @@ -5483,6 +5483,15 @@ "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==", "dev": true }, + "node_modules/@types/lodash-es": { + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.9.tgz", + "integrity": "sha512-ZTcmhiI3NNU7dEvWLZJkzG6ao49zOIjEgIE0RgV7wbPxU0f2xT3VSAHw2gmst8swH6V0YkLRGp4qPlX/6I90MQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/lodash.get": { "version": "4.4.7", "resolved": "https://registry.npmjs.org/@types/lodash.get/-/lodash.get-4.4.7.tgz", @@ -12454,6 +12463,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.castarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", diff --git a/package.json b/package.json index 6114fdf7496..ed884f49881 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "events": "^3.3.0", "i18next": "^23.2.7", "i18next-browser-languagedetector": "^7.1.0", - "lodash": "^4.17.21", + "lodash-es": "^4.17.21", "postcss-loader": "^7.3.3", "qrcode.react": "^3.1.0", "raviger": "^4.1.2", @@ -113,7 +113,7 @@ "@types/cypress": "^1.1.3", "@types/echarts": "^4.9.18", "@types/google.maps": "^3.53.4", - "@types/lodash": "^4.14.195", + "@types/lodash-es": "^4.17.9", "@types/lodash.get": "^4.4.7", "@types/node": "^20.4.0", "@types/prop-types": "*", diff --git a/public/config.json b/public/config.json index 5e67902d4fe..444362cfb20 100644 --- a/public/config.json +++ b/public/config.json @@ -5,12 +5,12 @@ "site_url": "care.coronasafe.in", "analytics_server_url": "https://plausible.10bedicu.in", "header_logo": { - "light":"https://cdn.coronasafe.network/header_logo.png", - "dark":"https://cdn.coronasafe.network/header_logo.png" + "light": "https://cdn.coronasafe.network/header_logo.png", + "dark": "https://cdn.coronasafe.network/header_logo.png" }, "main_logo": { - "light":"https://cdn.coronasafe.network/light-logo.svg", - "dark":"https://cdn.coronasafe.network/black-logo.svg" + "light": "https://cdn.coronasafe.network/light-logo.svg", + "dark": "https://cdn.coronasafe.network/black-logo.svg" }, "gmaps_api_key": "AIzaSyDsBAc3y7deI5ZO3NtK5GuzKwtUzQNJNUk", "gov_data_api_key": "579b464db66ec23bdd000001cdd3946e44ce4aad7209ff7b23ac571b", @@ -22,6 +22,5 @@ "kasp_full_string": "Karunya Arogya Suraksha Padhathi", "sample_format_asset_import": "https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=11JaEhNHdyCHth4YQs_44YaRlP77Rrqe81VSEfg1glko&exportFormat=xlsx", "sample_format_external_result_import": "https://docs.google.com/spreadsheets/d/17VfgryA6OYSYgtQZeXU9mp7kNvLySeEawvnLBO_1nuE/export?format=csv&id=17VfgryA6OYSYgtQZeXU9mp7kNvLySeEawvnLBO_1nuE", - "enable_abdm": true, - "jwt_token_refresh_interval": 300000 + "enable_abdm": true } \ No newline at end of file diff --git a/src/CAREUI/display/Chip.tsx b/src/CAREUI/display/Chip.tsx index abc21711551..7bcbd6078e4 100644 --- a/src/CAREUI/display/Chip.tsx +++ b/src/CAREUI/display/Chip.tsx @@ -11,6 +11,7 @@ interface Props { text: string; tooltip?: string; className?: string; + id?: string; } export default function Chip({ @@ -21,6 +22,7 @@ export default function Chip({ }: Props) { return ( { > {`${name}: ${value}`} diff --git a/src/CAREUI/misc/PaginatedList.tsx b/src/CAREUI/misc/PaginatedList.tsx index 28ee17650ad..3b699177d9e 100644 --- a/src/CAREUI/misc/PaginatedList.tsx +++ b/src/CAREUI/misc/PaginatedList.tsx @@ -30,7 +30,7 @@ function useContextualized() { return ctx as PaginatedListContext; } -interface Props extends QueryOptions { +interface Props extends QueryOptions> { route: QueryRoute>; perPage?: number; children: (ctx: PaginatedListContext) => JSX.Element | JSX.Element[]; diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index e51494f6bac..0b08b4b9a42 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -499,6 +499,7 @@ export const TELEMEDICINE_ACTIONS = [ { id: 60, text: "COMPLETE", desc: "Complete" }, { id: 70, text: "REVIEW", desc: "Review" }, { id: 80, text: "NOT_REACHABLE", desc: "Not Reachable" }, + { id: 90, text: "DISCHARGE_RECOMMENDED", desc: "Discharge Recommended" }, ]; export const FRONTLINE_WORKER = [ diff --git a/src/Common/hooks/useAsyncOptions.ts b/src/Common/hooks/useAsyncOptions.ts index f0a1c895430..2f3f68d5c3a 100644 --- a/src/Common/hooks/useAsyncOptions.ts +++ b/src/Common/hooks/useAsyncOptions.ts @@ -1,4 +1,4 @@ -import { debounce } from "lodash"; +import { debounce } from "lodash-es"; import { useMemo, useState } from "react"; import { useDispatch } from "react-redux"; diff --git a/src/Components/ABDM/ABHAProfileModal.tsx b/src/Components/ABDM/ABHAProfileModal.tsx index 0d6b7d9b90b..cc16fd45b8d 100644 --- a/src/Components/ABDM/ABHAProfileModal.tsx +++ b/src/Components/ABDM/ABHAProfileModal.tsx @@ -5,9 +5,9 @@ import CareIcon from "../../CAREUI/icons/CareIcon"; import DialogModal from "../Common/Dialog"; import QRCode from "qrcode.react"; import { formatDateTime } from "../../Utils/utils"; -import { getAbhaCard } from "../../Redux/actions"; -import { useDispatch } from "react-redux"; import { useRef } from "react"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; interface IProps { patientId?: string; @@ -18,21 +18,24 @@ interface IProps { const ABHAProfileModal = ({ patientId, show, onClose, abha }: IProps) => { const printRef = useRef(null); - const dispatch = useDispatch(); const downloadAbhaCard = async (type: "pdf" | "png") => { if (!patientId) return; - const response = await dispatch(getAbhaCard(patientId, type)); + const { res, data } = await request(routes.abha.getAbhaCard, { + body: { + patient: patientId, + type: type, + }, + }); - if (response.status === 200 && response.data) { + if (res?.status === 200 && data) { if (type === "png") { const downloadLink = document.createElement("a"); - downloadLink.href = - "data:application/octet-stream;base64," + response.data; + downloadLink.href = "data:application/octet-stream;base64," + data; downloadLink.download = "abha.png"; downloadLink.click(); } else { - const htmlPopup = ``; + const htmlPopup = ``; const printWindow = window.open("", "PDF"); printWindow?.document.write(htmlPopup); diff --git a/src/Components/ABDM/ConfigureHealthFacility.tsx b/src/Components/ABDM/ConfigureHealthFacility.tsx index 025a3f0e862..16e6bf90ea4 100644 --- a/src/Components/ABDM/ConfigureHealthFacility.tsx +++ b/src/Components/ABDM/ConfigureHealthFacility.tsx @@ -1,12 +1,13 @@ -import { lazy, useCallback, useEffect, useReducer, useState } from "react"; -import { useDispatch } from "react-redux"; - -import { healthFacilityActions } from "../../Redux/actions"; +import { lazy, useReducer, useState } from "react"; import * as Notification from "../../Utils/Notifications.js"; import { navigate } from "raviger"; import { Cancel, Submit } from "../Common/components/ButtonV2"; import TextFormField from "../Form/FormFields/TextFormField"; import { classNames } from "../../Utils/utils"; +import useQuery from "../../Utils/request/useQuery"; +import routes from "../../Redux/api"; +import request from "../../Utils/request/request"; +import { FieldChangeEvent } from "../Form/FormFields/Utils.js"; const Loading = lazy(() => import("../Common/Loading")); const initForm = { @@ -40,32 +41,26 @@ const FormReducer = (state = initialState, action: any) => { export const ConfigureHealthFacility = (props: any) => { const [state, dispatch] = useReducer(FormReducer, initialState); const { facilityId } = props; - const dispatchAction: any = useDispatch(); const [isLoading, setIsLoading] = useState(false); - const fetchData = useCallback(async () => { - if (facilityId) { - setIsLoading(true); - const res = await dispatchAction(healthFacilityActions.read(facilityId)); - - if (res?.status === 200 && res?.data) { - const formData = { - ...state.form, - hf_id: res.data.hf_id, - health_facility: res.data, - }; - dispatch({ type: "set_form", form: formData }); + const { loading } = useQuery(routes.abha.getHealthFacility, { + pathParams: { facility_id: facilityId }, + silent: true, + onResponse(res) { + if (res.data) { + dispatch({ + type: "set_form", + form: { + ...state.form, + health_facility: res.data, + hf_id: res.data.hf_id, + }, + }); } + }, + }); - setIsLoading(false); - } - }, [dispatchAction, facilityId]); - - useEffect(() => { - fetchData(); - }, [dispatch, fetchData]); - - const handleSubmit = async (e: any) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); @@ -78,27 +73,43 @@ export const ConfigureHealthFacility = (props: any) => { return; } - let res = null; + let response = null; + let responseData = null; if (state.form.health_facility) { - res = await dispatchAction( - healthFacilityActions.partialUpdate(facilityId, { - hf_id: state.form.hf_id, - }) + const { res, data } = await request( + routes.abha.partialUpdateHealthFacility, + { + pathParams: { + facility_id: facilityId, + }, + body: { + hf_id: state.form.hf_id, + }, + } ); + response = res; + responseData = data; } else if (state.form.hf_id === state.form.health_facility?.hf_id) { - res = await dispatchAction( - healthFacilityActions.registerService(facilityId) + const { res, data } = await request( + routes.abha.registerHealthFacilityAsService, + { + pathParams: { + facility_id: facilityId, + }, + } ); + response = res; + responseData = data; - if (res?.status === 200 && res?.data) { - if (res.data?.registered) { + if (response?.status === 200 && responseData) { + if (responseData?.registered) { dispatch({ type: "set_form", form: { ...state.form, health_facility: { ...state.form?.health_facility, - registered: res.data.registered, + registered: responseData.registered, }, }, }); @@ -112,43 +123,45 @@ export const ConfigureHealthFacility = (props: any) => { }); return; } else { - res = await dispatchAction( - healthFacilityActions.create({ + const { res, data } = await request(routes.abha.createHealthFacility, { + body: { facility: facilityId, hf_id: state.form.hf_id, - }) - ); + }, + }); + response = res; + responseData = data; } setIsLoading(false); - if (res && res.data) { + if (response && responseData) { Notification.Success({ msg: "Health Facility config updated successfully", }); navigate(`/facility/${facilityId}`); } else { - if (res?.data) + if (responseData) Notification.Error({ - msg: "Something went wrong: " + (res.data.detail || ""), + msg: "Something went wrong: " + (responseData.detail || ""), }); } setIsLoading(false); }; - const handleChange = (e: any) => { + const handleChange = (e: FieldChangeEvent) => { dispatch({ type: "set_form", form: { ...state.form, [e.name]: e.value }, }); }; - if (isLoading) { + if (loading || isLoading) { return ; } return (
-
handleSubmit(e)}> +
{ } required value={state.form.hf_id} - onChange={(e) => handleChange(e)} + onChange={handleChange} error={state.errors?.hf_id} />
-
+
navigate(`/facility/${facilityId}`)} /> { - const dispatch = useDispatch(); - const [qrValue, setQrValue] = useState(""); const [authMethods, setAuthMethods] = useState([]); const [selectedAuthMethod, setSelectedAuthMethod] = useState(""); @@ -187,23 +173,23 @@ const ScanABHAQRSection = ({ try { const abha = JSON.parse(value); - const res = await dispatch(linkViaQR(abha, patientId)); + const { res, data } = await request(routes.abha.linkViaQR, { + body: { ...abha, patientId }, + }); if (res?.status === 200 || res?.status === 202) { Notify.Success({ msg: "Request sent successfully" }); onSuccess?.({ - ...res.data, + ...data, abha_profile: { - ...res.data?.abha_profile, - healthIdNumber: res.data?.abha_profile?.abha_number, - healthId: res.data?.abha_profile?.health_id, + ...data?.abha_profile, + healthIdNumber: data?.abha_profile?.abha_number, + healthId: data?.abha_profile?.health_id, mobile: abha?.mobile, monthOfBirth: - res.data?.abha_profile?.date_of_birth?.split("-")[1], - dayOfBirth: - res.data?.abha_profile?.date_of_birth?.split("-")[2], - yearOfBirth: - res.data?.abha_profile?.date_of_birth?.split("-")[0], + data?.abha_profile?.date_of_birth?.split("-")[1], + dayOfBirth: data?.abha_profile?.date_of_birth?.split("-")[2], + yearOfBirth: data?.abha_profile?.date_of_birth?.split("-")[0], }, }); } else { @@ -256,29 +242,55 @@ const ScanABHAQRSection = ({ disabled={otp.length !== 6} onClick={async () => { let response = null; + let Rdata = null; + let Rerror = null; switch (selectedAuthMethod) { case "MOBILE_OTP": - response = await dispatch( - confirmWithMobileOtp(txnId, otp, patientId) - ); + { + const { res, data, error } = await request( + routes.abha.confirmWithMobileOtp, + { + body: { + otp: otp, + txnId: txnId, + patientId: patientId, + }, + } + ); + response = res; + Rdata = data; + Rerror = error; + } break; case "AADHAAR_OTP": - response = await dispatch( - confirmWithAadhaarOtp(txnId, otp, patientId) - ); + { + const { res, data, error } = await request( + routes.abha.confirmWithAadhaarOtp, + { + body: { + otp: otp, + txnId: txnId, + patientId: patientId, + }, + } + ); + response = res; + Rdata = data; + Rerror = error; + } break; } - if (response.status === 200) { - onSuccess?.(response.data); + if (response?.status === 200) { + onSuccess?.(Rdata); Notify.Success({ msg: "ABHA Number linked successfully", }); } else { Notify.Error({ - msg: response?.message ?? "Something went wrong!", + msg: Rerror ?? "Something went wrong!", }); } }} @@ -290,13 +302,14 @@ const ScanABHAQRSection = ({ {authMethods.map((method) => ( { - const response = await dispatch( - initiateAbdmAuthentication(method, qrValue) + const { res, data } = await request( + routes.abha.initiateAbdmAuthentication, + { body: { authMethod: method, healthid: qrValue } } ); - if (response.status === 200 && response?.data?.txnId) { + if (res?.status === 200 && data?.txnId) { setSelectedAuthMethod(method); - setTxnId(response.data.txnId); + setTxnId(data.txnId); } }} > @@ -308,11 +321,18 @@ const ScanABHAQRSection = ({ { - const response = await dispatch(searchByHealthId(qrValue)); - - if (response.status === 200 && response?.data?.authMethods) { + const { res, data } = await request( + routes.abha.searchByHealthId, + { + body: { + healthId: qrValue, + }, + } + ); + + if (res?.status === 200 && data?.authMethods) { setAuthMethods( - response.data.authMethods?.filter?.((method: string) => + data.authMethods?.filter?.((method: string) => supportedAuthMethods.find( (supported) => supported === method ) @@ -339,8 +359,6 @@ const VerifyAadhaarSection = ({ onVerified, onSignin, }: VerifyAadhaarSectionProps) => { - const dispatch = useDispatch(); - const [aadhaarNumber, setAadhaarNumber] = useState(""); const [aadhaarNumberError, setAadhaarNumberError] = useState(); @@ -382,17 +400,22 @@ const VerifyAadhaarSection = ({ if (!validateAadhaar()) return; setIsSendingOtp(true); - const res = await dispatch(generateAadhaarOtp(aadhaarNumber)); + + const { res, data } = await request(routes.abha.generateAadhaarOtp, { + body: { + aadhaar: aadhaarNumber, + }, + }); setIsSendingOtp(false); - if (res.status === 200 && res.data) { - const { txnId } = res.data; + if (res?.status === 200 && data) { + const { txnId } = data; setTxnId(txnId); Notify.Success({ msg: "OTP has been sent to the mobile number registered with the Aadhar number.", }); } else { - Notify.Error({ msg: JSON.stringify(res.data) }); + Notify.Error({ msg: JSON.stringify(data) }); } }; @@ -400,16 +423,20 @@ const VerifyAadhaarSection = ({ if (!validateAadhaar() || !txnId) return; setIsSendingOtp(true); - const res = await dispatch(resentAadhaarOtp(txnId)); + const { res, data } = await request(routes.abha.generateAadhaarOtp, { + body: { + txnId: txnId, + }, + }); setIsSendingOtp(false); - if (res.status === 200 && res.data.txnId) { - setTxnId(res.data.txnId); + if (res?.status === 200 && data?.txnId) { + setTxnId(data.txnId); Notify.Success({ msg: "OTP has been resent to the mobile number registered with the Aadhar number.", }); } else { - Notify.Error({ msg: JSON.stringify(res.data) }); + Notify.Error({ msg: JSON.stringify(data) }); } }; @@ -430,11 +457,16 @@ const VerifyAadhaarSection = ({ if (!validateOtp() || !txnId) return; setIsVerifyingOtp(true); - const res = await dispatch(verifyAadhaarOtp(txnId, otp)); + const { res, data } = await request(routes.abha.verifyAadhaarOtp, { + body: { + otp: otp, + txnId: txnId, + }, + }); setIsVerifyingOtp(false); - if (res.status === 200 && res.data.txnId) { - setTxnId(res.data.txnId); + if (res?.status === 200 && data?.txnId) { + setTxnId(data.txnId); Notify.Success({ msg: "OTP verified" }); setIsVerified(true); } else { @@ -563,8 +595,6 @@ const VerifyMobileSection = ({ onVerified, patientMobile, }: VerifyMobileSectionProps) => { - const dispatch = useDispatch(); - const [mobile, setMobile] = useState(() => patientMobile || ""); const [mobileError, setMobileError] = useState(); @@ -602,11 +632,16 @@ const VerifyMobileSection = ({ setOtpDispatched(false); setIsSendingOtp(true); - const res = await dispatch(checkAndGenerateMobileOtp(txnId, mobile)); + const { res, data } = await request(routes.abha.checkAndGenerateMobileOtp, { + body: { + mobile: mobile, + txnId: txnId, + }, + }); setIsSendingOtp(false); - if (res.status === 200 && res.data) { - const { txnId, mobileLinked } = res.data; + if (res?.status === 200 && data) { + const { txnId, mobileLinked } = data; setTxnId(txnId); if (mobileLinked) { @@ -621,7 +656,7 @@ const VerifyMobileSection = ({ }); } } else { - Notify.Error({ msg: JSON.stringify(res.data) }); + Notify.Error({ msg: JSON.stringify(data) }); } }; @@ -642,11 +677,16 @@ const VerifyMobileSection = ({ if (!validateOtp()) return; setIsVerifyingOtp(true); - const res = await dispatch(verifyMobileOtp(txnId, otp)); + const { res, data } = await request(routes.abha.verifyMobileOtp, { + body: { + txnId: txnId, + otp: otp, + }, + }); setIsVerifyingOtp(false); - if (res.status === 200 && res.data.txnId) { - setTxnId(res.data.txnId); + if (res?.status === 200 && data?.txnId) { + setTxnId(data.txnId); Notify.Success({ msg: "OTP verified" }); setIsVerified(true); } else { @@ -718,21 +758,24 @@ const CreateHealthIDSection = ({ onCreateSuccess, patientId, }: CreateHealthIDSectionProps) => { - const dispatch = useDispatch(); const [healthId, setHealthId] = useState(""); const [isCreating, setIsCreating] = useState(false); const [isHealthIdInputInFocus, setIsHealthIdInputInFocus] = useState(false); const handleCreateHealthId = async () => { setIsCreating(true); - const res = await dispatch( - createHealthId({ txnId: transactionId, patientId, healthId }) - ); - if (res.status === 200) { + const { res, data } = await request(routes.abha.createHealthId, { + body: { + healthId: healthId, + txnId: transactionId, + patientId: patientId, + }, + }); + if (res?.status === 200) { Notify.Success({ msg: "Abha Address created" }); - onCreateSuccess(res.data); + onCreateSuccess(data); } else { - Notify.Error({ msg: JSON.stringify(res.data) }); + Notify.Error({ msg: JSON.stringify(data) }); } setIsCreating(false); }; diff --git a/src/Components/ABDM/LinkCareContextModal.tsx b/src/Components/ABDM/LinkCareContextModal.tsx index fc0b488954d..36749ff3d23 100644 --- a/src/Components/ABDM/LinkCareContextModal.tsx +++ b/src/Components/ABDM/LinkCareContextModal.tsx @@ -5,9 +5,9 @@ import DateFormField from "../Form/FormFields/DateFormField"; import DialogModal from "../Common/Dialog"; import { PatientModel } from "../Patient/models"; import TextFormField from "../Form/FormFields/TextFormField"; -import { linkCareContext } from "../../Redux/actions"; -import { useDispatch } from "react-redux"; import { useState } from "react"; +import routes from "../../Redux/api.js"; +import request from "../../Utils/request/request.js"; interface IProps { consultationId: string; @@ -25,8 +25,6 @@ const LinkCareContextModal = ({ const [acceptedDisclaimer, setAcceptedDisclaimer] = useState(false); const [isLinkingCareContext, setIsLinkingCareContext] = useState(false); - const dispatch = useDispatch(); - return ( { setIsLinkingCareContext(true); - const res = await dispatch( - linkCareContext(consultationId, { + const { res } = await request(routes.abha.linkCareContext, { + body: { + consultation: consultationId, name: patient?.abha_number_object?.name, gender: patient?.abha_number_object?.gender, dob: patient?.abha_number_object?.date_of_birth, - }) - ); - - if (res.status === 202) { + }, + reattempts: 0, + }); + if (res?.status === 202) { Notification.Success({ msg: "Care Context sucessfully linked!", }); diff --git a/src/Components/ABDM/models.ts b/src/Components/ABDM/models.ts index b01579fba88..f992cc9df4f 100644 --- a/src/Components/ABDM/models.ts +++ b/src/Components/ABDM/models.ts @@ -17,3 +17,84 @@ export interface ICreateHealthIdResponse { healthId?: string; healthIdNumber: string; } + +export interface IHealthFacility { + id: string; + registered: boolean; + external_id: string; + created_date: string; + modified_date: string; + hf_id: string; + facility: string; + detail?: string; +} + +export interface ILinkABHANumber { + abha_profile: { + abha_number: string; + health_id: string; + date_of_birth: string; + }; +} + +export interface IConfirmMobileOtp { + otp: string; + txnId: string; + patientId?: string; + message?: string; +} + +export interface IHealthId { + authMethods?: string[]; +} + +export interface IAadhaarOtp { + txnId: string; +} + +export interface ICheckAndGenerateMobileOtp { + mobileLinked: boolean; + txnId: string; +} + +export interface IAadhaarOtpTBody { + aadhaar?: string; + txnId?: string; +} + +export interface IVerifyAadhaarOtpTBody { + consultation?: string; + name?: string; + gender?: "M" | "F" | "O"; + dob?: string; + otp?: string; + txnId?: string; +} + +export interface IGenerateMobileOtpTBody { + mobile: string; + txnId: string; +} + +export interface ISearchByHealthIdTBody { + healthId: string; +} + +export interface IinitiateAbdmAuthenticationTBody { + authMethod: string; + healthid: string; +} + +export interface IgetAbhaCardTBody { + patient: string; + type: "pdf" | "png"; +} + +export interface IcreateHealthFacilityTBody { + facility: string; + hf_id: string; +} + +export interface IpartialUpdateHealthFacilityTBody { + hf_id: string; +} diff --git a/src/Components/Assets/AssetFilter.tsx b/src/Components/Assets/AssetFilter.tsx index 4dca7dfecdb..8b250088d1a 100644 --- a/src/Components/Assets/AssetFilter.tsx +++ b/src/Components/Assets/AssetFilter.tsx @@ -1,19 +1,14 @@ import { useState, useEffect, useCallback } from "react"; -import { useAbortableEffect, statusType } from "../../Common/utils"; import { navigate, useQueryParams } from "raviger"; import { FacilitySelect } from "../Common/FacilitySelect"; import { FacilityModel } from "../Facility/models"; -import { useDispatch } from "react-redux"; -import { - getFacilityAssetLocation, - getPermittedFacility, -} from "../../Redux/actions"; -import * as Notification from "../../Utils/Notifications.js"; import { LocationSelect } from "../Common/LocationSelect"; import { AssetClass, AssetLocationObject } from "./AssetTypes"; import { FieldLabel } from "../Form/FormFields/FormField"; import { SelectFormField } from "../Form/FormFields/SelectFormField"; import FiltersSlideover from "../../CAREUI/interactive/FiltersSlideover"; +import routes from "../../Redux/api"; +import useQuery from "../../Utils/request/useQuery"; import DateRangeFormField from "../Form/FormFields/DateRangeFormField"; import dayjs from "dayjs"; import { FieldChangeEvent } from "../Form/FormFields/Utils"; @@ -35,7 +30,6 @@ const getDate = (value: any) => function AssetFilter(props: any) { const { filter, onChange, closeFilter } = props; - const dispatch: any = useDispatch(); const [facility, setFacility] = useState({ name: "" }); const [location, setLocation] = useState(initialLocation); @@ -46,7 +40,7 @@ function AssetFilter(props: any) { const [asset_class, setAssetClass] = useState( filter.asset_class || "" ); - const [facilityId, setFacilityId] = useState(filter.facility); + const [facilityId, setFacilityId] = useState(filter.facility); const [locationId, setLocationId] = useState(filter.location); const [warrantyExpiry, setWarrantyExpiry] = useState({ before: filter.warranty_amc_end_of_validity_before || null, @@ -54,8 +48,31 @@ function AssetFilter(props: any) { }); const [qParams, _] = useQueryParams(); + useQuery(routes.getPermittedFacility, { + pathParams: { id: facilityId }, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data) { + setFacility(data); + } + }, + prefetch: !!facilityId, + }); + + useQuery(routes.getFacilityAssetLocation, { + pathParams: { + facilityId: String(facilityId), + locationId: String(locationId), + }, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data) { + setLocation(data); + } + }, + prefetch: !!(facilityId && locationId), + }); + useEffect(() => { - setFacilityId(facility?.id ? facility?.id : ""); + setFacilityId(facility?.id ? `${facility?.id}` : ""); setLocationId( facility?.id === qParams.facility ? qParams.location ?? "" : "" ); @@ -75,48 +92,6 @@ function AssetFilter(props: any) { else navigate("/assets"); }, [qParams]); - const fetchFacility = useCallback( - async (status: statusType) => { - if (facilityId) { - const facilityData: any = await dispatch( - getPermittedFacility(facilityId) - ); - if (!status.aborted) { - setFacility(facilityData?.data); - } - } - }, - [filter.facility] - ); - - const fetchLocation = useCallback( - async (status: statusType) => { - if (locationId && facilityId) { - const [locationData]: any = await Promise.all([ - dispatch( - getFacilityAssetLocation(String(facilityId), String(locationId)) - ), - ]); - if (!status.aborted && locationData !== undefined) { - if (!locationData.data) - Notification.Error({ - msg: "Something went wrong..!", - }); - else { - setLocation(locationData.data); - } - } - } else { - setLocation(initialLocation); - } - }, - [filter.location] - ); - - useAbortableEffect((status: statusType) => { - filter.facility && fetchFacility(status); - filter.location && fetchLocation(status); - }, []); const applyFilter = () => { const data = { facility: facilityId, diff --git a/src/Components/Assets/AssetImportModal.tsx b/src/Components/Assets/AssetImportModal.tsx index 54ac25e2ac8..f8ab7cbc65f 100644 --- a/src/Components/Assets/AssetImportModal.tsx +++ b/src/Components/Assets/AssetImportModal.tsx @@ -5,8 +5,6 @@ import { FacilityModel } from "../Facility/models"; import { AssetData } from "./AssetTypes"; import * as Notification from "../../Utils/Notifications.js"; import { Cancel, Submit } from "../Common/components/ButtonV2"; -import { listFacilityAssetLocation } from "../../Redux/actions"; -import { useDispatch } from "react-redux"; import { Link } from "raviger"; import readXlsxFile from "read-excel-file"; import { @@ -16,6 +14,8 @@ import { import { parseCsvFile } from "../../Utils/utils"; import useConfig from "../../Common/hooks/useConfig"; import DialogModal from "../Common/Dialog"; +import useQuery from "../../Utils/request/useQuery"; +import routes from "../../Redux/api"; import { SelectFormField } from "../Form/FormFields/SelectFormField"; interface Props { @@ -34,7 +34,6 @@ const AssetImportModal = ({ open, onClose, facility }: Props) => { location: "", }); const [locations, setLocations] = useState([]); - const dispatchAction: any = useDispatch(); const { sample_format_asset_import } = useConfig(); const [locationsLoading, setLocationsLoading] = useState(false); @@ -43,18 +42,14 @@ const AssetImportModal = ({ open, onClose, facility }: Props) => { setSelectedFile(undefined); onClose && onClose(); }; - - useEffect(() => { - setLocationsLoading(true); - dispatchAction( - listFacilityAssetLocation({}, { facility_external_id: facility.id }) - ).then(({ data }: any) => { - setLocationsLoading(false); - if (data.count > 0) { + useQuery(routes.listFacilityAssetLocation, { + pathParams: { facility_external_id: `${facility.id}` }, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data) { setLocations(data.results); } - }); - }, []); + }, + }); useEffect(() => { const readFile = async () => { @@ -362,6 +357,7 @@ const AssetImportModal = ({ open, onClose, facility }: Props) => { {isImporting ? ( diff --git a/src/Components/Assets/AssetManage.tsx b/src/Components/Assets/AssetManage.tsx index e6d1836e27b..23098bff22f 100644 --- a/src/Components/Assets/AssetManage.tsx +++ b/src/Components/Assets/AssetManage.tsx @@ -1,4 +1,4 @@ -import { useState, useCallback, useEffect, ReactElement, lazy } from "react"; +import { useState, useEffect, ReactElement, lazy } from "react"; import { AssetClass, assetClassProps, @@ -6,14 +6,6 @@ import { AssetService, AssetTransaction, } from "./AssetTypes"; -import { statusType, useAbortableEffect } from "../../Common/utils"; -import { useDispatch } from "react-redux"; -import { - deleteAsset, - getAsset, - listAssetService, - listAssetTransaction, -} from "../../Redux/actions"; import Pagination from "../Common/Pagination"; import { navigate } from "raviger"; import QRCode from "qrcode.react"; @@ -36,6 +28,9 @@ import RelativeDateUserMention from "../Common/RelativeDateUserMention"; import { AssetServiceEditModal } from "./AssetServiceEditModal"; import { warrantyAmcValidityChip } from "./AssetsList"; import Page from "../Common/components/Page"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; +import useQuery from "../../Utils/request/useQuery"; interface AssetManageProps { assetId: string; @@ -51,80 +46,60 @@ const checkAuthority = (type: string, cutoff: string) => { const AssetManage = (props: AssetManageProps) => { const { t } = useTranslation(); const { assetId, facilityId } = props; - const [asset, setAsset] = useState(); const [isPrintMode, setIsPrintMode] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [offset, setOffset] = useState(0); const [totalCount, setTotalCount] = useState(0); - const [transactions, setTransactions] = useState([]); const [transactionDetails, setTransactionDetails] = useState< ReactElement | ReactElement[] >(); - const [services, setServices] = useState([]); const [servicesDetails, setServiceDetails] = useState< ReactElement | ReactElement[] >(); - const [isLoading, setIsLoading] = useState(false); - const dispatch = useDispatch(); const limit = 14; const authUser = useAuthUser(); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [serviceEditData, setServiceEditData] = useState< AssetService & { open: boolean; viewOnly?: boolean } >(); + const [transactionFilter, setTransactionFilter] = useState({}); - const fetchData = useCallback( - async (status: statusType) => { - setIsLoading(true); - const assetData = await dispatch(getAsset(assetId)); - if (!status.aborted) { - setIsLoading(false); - if (assetData?.data) { - setAsset(assetData.data); - - const transactionFilter = assetData.qr_code_id - ? { qr_code_id: assetData.qr_code_id } - : { external_id: assetId }; - - const [transactionsData, servicesData] = await Promise.all([ - dispatch( - listAssetTransaction({ - ...transactionFilter, - limit, - offset, - }) - ), - dispatch(listAssetService({}, assetId)), - ]); - - if (transactionsData?.data) { - setTransactions(transactionsData.data.results); - setTotalCount(transactionsData.data.count); - } else { - Notification.Error({ - msg: "Error fetching transactions", - }); - } - if (servicesData?.data) { - setServices(servicesData.data.results); - } else { - Notification.Error({ - msg: "Error fetching service logs", - }); - } - } else { - navigate("/not-found"); - } + const { data: asset, loading } = useQuery(routes.getAsset, { + pathParams: { + external_id: assetId, + }, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data) { + setTransactionFilter( + data.qr_code_id + ? { qr_code_id: data.qr_code_id } + : { external_id: assetId } + ); } }, - [dispatch, assetId, offset] - ); + }); - useAbortableEffect( - (status: statusType) => { - fetchData(status); + const { data: transactions } = useQuery(routes.listAssetTransaction, { + prefetch: !!asset, + query: { + ...transactionFilter, + limit, + offset, }, - [dispatch, fetchData] + onResponse: ({ res, data }) => { + if (res?.status === 200 && data) { + setTotalCount(data.count); + } + }, + }); + + const { data: services, refetch: serviceRefetch } = useQuery( + routes.listAssetService, + { + pathParams: { + asset_external_id: assetId, + }, + } ); const handlePagination = (page: number, limit: number) => { @@ -158,7 +133,7 @@ const AssetManage = (props: AssetManageProps) => { const populateTableRows = (txns: AssetTransaction[]) => { if (txns.length > 0) { setTransactionDetails( - transactions.map((transaction: AssetTransaction) => ( + transactions?.results.map((transaction: AssetTransaction) => ( @@ -201,7 +176,7 @@ const AssetManage = (props: AssetManageProps) => { const populateServiceTableRows = (txns: AssetService[]) => { if (txns.length > 0) { setServiceDetails( - services.map((service: AssetService) => ( + services?.results.map((service: AssetService) => ( @@ -276,14 +251,14 @@ const AssetManage = (props: AssetManageProps) => { }; useEffect(() => { - populateTableRows(transactions); + if (transactions) populateTableRows(transactions.results); }, [transactions]); useEffect(() => { - populateServiceTableRows(services); + if (services) populateServiceTableRows(services?.results); }, [services]); - if (isLoading) return ; + if (loading) return ; if (isPrintMode) return ; const assetClassProp = @@ -324,13 +299,17 @@ const AssetManage = (props: AssetManageProps) => { const handleDelete = async () => { if (asset) { - const response = await dispatch(deleteAsset(asset.id)); - if (response && response.status === 204) { - Notification.Success({ - msg: "Asset deleted successfully", - }); - navigate("/assets"); - } + await request(routes.deleteAsset, { + pathParams: { + external_id: asset.id, + }, + onResponse: () => { + Notification.Success({ + msg: "Asset deleted successfully", + }); + navigate("/assets"); + }, + }); } }; @@ -595,7 +574,7 @@ const AssetManage = (props: AssetManageProps) => { handleClose={() => setServiceEditData({ ...serviceEditData, open: false }) } - handleUpdate={() => fetchData({ aborted: false })} + handleUpdate={() => serviceRefetch()} show={serviceEditData.open} viewOnly={serviceEditData.viewOnly} /> diff --git a/src/Components/Assets/AssetServiceEditModal.tsx b/src/Components/Assets/AssetServiceEditModal.tsx index 690524e471b..3964dfe0770 100644 --- a/src/Components/Assets/AssetServiceEditModal.tsx +++ b/src/Components/Assets/AssetServiceEditModal.tsx @@ -1,6 +1,4 @@ import { useEffect, useState } from "react"; -import { useDispatch } from "react-redux"; -import { updateAssetService } from "../../Redux/actions"; import * as Notification from "../../Utils/Notifications.js"; import ButtonV2, { Cancel, Submit } from "../Common/components/ButtonV2"; import DialogModal from "../Common/Dialog"; @@ -9,6 +7,8 @@ import dayjs from "dayjs"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; import { formatDate, formatDateTime } from "../../Utils/utils"; import CareIcon from "../../CAREUI/icons/CareIcon"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; import DateFormField from "../Form/FormFields/DateFormField"; import { t } from "i18next"; @@ -24,23 +24,25 @@ export const AssetServiceEditModal = (props: { serviced_on: props.service_record?.serviced_on, note: props.service_record?.note, }); - const dispatchAction: any = useDispatch(); const [isLoading, setIsLoading] = useState(false); const [editRecord, setEditRecord] = useState(); const handleSubmit = async (e: any) => { e.preventDefault(); setIsLoading(true); - const data = { + const body = { serviced_on: form.serviced_on, note: form.note, }; - - const res = await dispatchAction( - updateAssetService(props.asset?.id ?? "", props.service_record.id, data) - ); + const { data } = await request(routes.updateAssetService, { + pathParams: { + asset_external_id: props.asset?.id ?? "", + external_id: props.service_record.id, + }, + body: body, + }); setIsLoading(false); - if (res?.data) { + if (data) { Notification.Success({ msg: "Asset service record updated successfully", }); diff --git a/src/Components/Assets/AssetType/HL7Monitor.tsx b/src/Components/Assets/AssetType/HL7Monitor.tsx index 55f4d0c258e..b4fefbc90b2 100644 --- a/src/Components/Assets/AssetType/HL7Monitor.tsx +++ b/src/Components/Assets/AssetType/HL7Monitor.tsx @@ -1,10 +1,5 @@ import { SyntheticEvent, useEffect, useState } from "react"; import { AssetData } from "../AssetTypes"; -import { useDispatch } from "react-redux"; -import { - partialUpdateAsset, - getPermittedFacility, -} from "../../../Redux/actions"; import * as Notification from "../../../Utils/Notifications.js"; import MonitorConfigure from "../configure/MonitorConfigure"; import Loading from "../../Common/Loading"; @@ -16,6 +11,9 @@ import TextFormField from "../../Form/FormFields/TextFormField"; import HL7PatientVitalsMonitor from "../../VitalsMonitor/HL7PatientVitalsMonitor"; import VentilatorPatientVitalsMonitor from "../../VitalsMonitor/VentilatorPatientVitalsMonitor"; import useAuthUser from "../../../Common/hooks/useAuthUser"; +import request from "../../../Utils/request/request"; +import routes from "../../../Redux/api"; +import useQuery from "../../../Utils/request/useQuery"; interface HL7MonitorProps { assetId: string; @@ -33,19 +31,14 @@ const HL7Monitor = (props: HL7MonitorProps) => { const [localipAddress, setLocalIPAddress] = useState(""); const [ipadrdress_error, setIpAddress_error] = useState(""); const authUser = useAuthUser(); - const dispatch = useDispatch(); - - useEffect(() => { - const fetchFacility = async () => { - const res = await dispatch(getPermittedFacility(facilityId)); - - if (res.status === 200 && res.data) { - setFacilityMiddlewareHostname(res.data.middleware_address); + const { data: facility, loading } = useQuery(routes.getPermittedFacility, { + pathParams: { id: facilityId }, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data && data.middleware_address) { + setFacilityMiddlewareHostname(data.middleware_address); } - }; - - if (facilityId) fetchFacility(); - }, [dispatch, facilityId]); + }, + }); useEffect(() => { setAssetType(asset?.asset_class); @@ -65,26 +58,28 @@ const HL7Monitor = (props: HL7MonitorProps) => { local_ip_address: localipAddress, }, }; - const res: any = await Promise.resolve( - dispatch(partialUpdateAsset(assetId, data)) - ); + const { res } = await request(routes.partialUpdateAsset, { + pathParams: { external_id: assetId }, + body: data, + }); if (res?.status === 200) { Notification.Success({ msg: "Asset Configured Successfully", }); } else { Notification.Error({ - msg: "Something went wrong..!", + msg: "Something went wrong!", }); } } else { - setIpAddress_error("Please Enter a Valid IP address !!"); + setIpAddress_error("IP address is invalid"); } }; - const middleware = middlewareHostname || facilityMiddlewareHostname; + const fallbackMiddleware = + asset?.location_object?.middleware_address || facilityMiddlewareHostname; - if (isLoading) return ; + if (isLoading || loading || !facility) return ; return (
@@ -93,11 +88,29 @@ const HL7Monitor = (props: HL7MonitorProps) => {

Connection

-
+
+

Middleware Hostname

+ {!middlewareHostname && ( +
+ + + Middleware hostname sourced from{" "} + {asset?.location_object?.middleware_address + ? "asset location" + : "asset facility"} + +
+ )} +
+ } + placeholder={fallbackMiddleware} value={middlewareHostname} onChange={(e) => setMiddlewareHostname(e.value)} errorClassName="hidden" @@ -127,12 +140,16 @@ const HL7Monitor = (props: HL7MonitorProps) => { {assetType === "HL7MONITOR" && ( )} {assetType === "VENTILATOR" && ( )}
diff --git a/src/Components/Assets/AssetType/ONVIFCamera.tsx b/src/Components/Assets/AssetType/ONVIFCamera.tsx index 4720c876010..eb6ebb9abfd 100644 --- a/src/Components/Assets/AssetType/ONVIFCamera.tsx +++ b/src/Components/Assets/AssetType/ONVIFCamera.tsx @@ -1,11 +1,5 @@ import { useEffect, useState } from "react"; import { AssetData } from "../AssetTypes"; -import { useDispatch } from "react-redux"; -import { - partialUpdateAsset, - createAssetBed, - getPermittedFacility, -} from "../../../Redux/actions"; import * as Notification from "../../../Utils/Notifications.js"; import { BedModel } from "../../Facility/models"; import axios from "axios"; @@ -18,6 +12,13 @@ import { Submit } from "../../Common/components/ButtonV2"; import { SyntheticEvent } from "react"; import useAuthUser from "../../../Common/hooks/useAuthUser"; +import request from "../../../Utils/request/request"; +import routes from "../../../Redux/api"; +import useQuery from "../../../Utils/request/useQuery"; + +import CareIcon from "../../../CAREUI/icons/CareIcon"; + + interface Props { assetId: string; facilityId: string; @@ -43,19 +44,15 @@ const ONVIFCamera = ({ assetId, facilityId, asset, onUpdated }: Props) => { const [refreshPresetsHash, setRefreshPresetsHash] = useState( Number(new Date()) ); - const dispatch = useDispatch(); + const { data: facility, loading } = useQuery(routes.getPermittedFacility, { + pathParams: { id: facilityId }, + }); const authUser = useAuthUser(); useEffect(() => { - const fetchFacility = async () => { - const res = await dispatch(getPermittedFacility(facilityId)); - - if (res.status === 200 && res.data) { - setFacilityMiddlewareHostname(res.data.middleware_address); - } - }; - - if (facilityId) fetchFacility(); - }, [dispatch, facilityId]); + if (facility?.middleware_address) { + setFacilityMiddlewareHostname(facility.middleware_address); + } + }, [facility, facilityId]); useEffect(() => { if (asset) { @@ -83,18 +80,19 @@ const ONVIFCamera = ({ assetId, facilityId, asset, onUpdated }: Props) => { camera_access_key: `${username}:${password}:${streamUuid}`, }, }; - const res: any = await Promise.resolve( - dispatch(partialUpdateAsset(assetId, data)) - ); + const { res } = await request(routes.partialUpdateAsset, { + pathParams: { external_id: assetId }, + body: data, + }); if (res?.status === 200) { Notification.Success({ msg: "Asset Configured Successfully" }); onUpdated?.(); } else { - Notification.Error({ msg: "Something went wrong..!" }); + Notification.Error({ msg: "Something went wrong!" }); } setLoadingSetConfiguration(false); } else { - setIpAddress_error("Please Enter a Valid Camera address !!"); + setIpAddress_error("IP address is invalid"); } }; @@ -110,15 +108,14 @@ const ONVIFCamera = ({ assetId, facilityId, asset, onUpdated }: Props) => { const presetData = await axios.get( `https://${facilityMiddlewareHostname}/status?hostname=${config.hostname}&port=${config.port}&username=${config.username}&password=${config.password}` ); - const res: any = await Promise.resolve( - dispatch( - createAssetBed( - { meta: { ...data, ...presetData.data } }, - assetId, - bed?.id as string - ) - ) - ); + + const { res } = await request(routes.createAssetBed, { + body: { + meta: { ...data, ...presetData.data }, + asset: assetId, + bed: bed?.id as string, + }, + }); if (res?.status === 201) { Notification.Success({ msg: "Preset Added Successfully", @@ -138,8 +135,11 @@ const ONVIFCamera = ({ assetId, facilityId, asset, onUpdated }: Props) => { } setLoadingAddPreset(false); }; + + if (isLoading || loading || !facility) return ; - if (isLoading) return ; + const fallbackMiddleware = + asset?.location_object?.middleware_address || facilityMiddlewareHostname; return (
@@ -148,8 +148,26 @@ const ONVIFCamera = ({ assetId, facilityId, asset, onUpdated }: Props) => {
+

Middleware Hostname

+ {!middlewareHostname && ( +
+ + + Middleware hostname sourced from{" "} + {asset?.location_object?.middleware_address + ? "asset location" + : "asset facility"} + +
+ )} +
+ } + placeholder={fallbackMiddleware} value={middlewareHostname} onChange={({ value }) => setMiddlewareHostname(value)} /> diff --git a/src/Components/Assets/AssetTypes.tsx b/src/Components/Assets/AssetTypes.tsx index 52c7e45003c..8b96b6beeb7 100644 --- a/src/Components/Assets/AssetTypes.tsx +++ b/src/Components/Assets/AssetTypes.tsx @@ -91,6 +91,8 @@ export interface AssetData { }; } +export type AssetUpdate = Partial; + export interface AssetsResponse { count: number; next?: string; @@ -137,8 +139,12 @@ export interface AssetBedModel { created_date: string; modified_date: string; meta: Record; + asset?: string; + bed?: string; } +export type AssetBedBody = Partial; + export interface AssetServiceEdit { id: string; asset_service: AssetService; @@ -166,3 +172,9 @@ export interface PatientAssetBed { patient?: PatientModel; meta?: Record; } + +export interface AssetServiceUpdate { + external_id: string; + serviced_on: string; + note: string; +} diff --git a/src/Components/Assets/AssetsList.tsx b/src/Components/Assets/AssetsList.tsx index 46b4da5283d..4bcb2698a9a 100644 --- a/src/Components/Assets/AssetsList.tsx +++ b/src/Components/Assets/AssetsList.tsx @@ -1,15 +1,8 @@ -import { useDispatch } from "react-redux"; import QrReader from "react-qr-reader"; -import { statusType, useAbortableEffect } from "../../Common/utils"; import * as Notification from "../../Utils/Notifications.js"; -import { - getAnyFacility, - listAssets, - getFacilityAssetLocation, - getAsset, -} from "../../Redux/actions"; +import { listAssets } from "../../Redux/actions"; import { assetClassProps, AssetData } from "./AssetTypes"; -import { useState, useCallback, useEffect, lazy } from "react"; +import { useState, useEffect, lazy } from "react"; import { Link, navigate } from "raviger"; import AssetFilter from "./AssetFilter"; import { parseQueryParams } from "../../Utils/primitives"; @@ -28,6 +21,9 @@ import AssetImportModal from "./AssetImportModal"; import Page from "../Common/components/Page"; import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover"; import { useTranslation } from "react-i18next"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; +import useQuery from "../../Utils/request/useQuery"; const Loading = lazy(() => import("../Common/Loading")); @@ -52,66 +48,45 @@ const AssetsList = () => { const [status, setStatus] = useState(); const [facilityName, setFacilityName] = useState(); const [asset_class, setAssetClass] = useState(); - const [locationName, setLocationName] = useState(); const [importAssetModalOpen, setImportAssetModalOpen] = useState(false); - const dispatch: any = useDispatch(); const assetsExist = assets.length > 0 && Object.keys(assets[0]).length > 0; const [showFacilityDialog, setShowFacilityDialog] = useState(false); const [selectedFacility, setSelectedFacility] = useState({ name: "", }); + const params = { + limit: resultsPerPage, + page: qParams.page, + offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage, + search_text: qParams.search || "", + facility: qParams.facility || "", + asset_type: qParams.asset_type || "", + asset_class: qParams.asset_class || "", + location: qParams.facility ? qParams.location || "" : "", + status: qParams.status || "", + }; - const fetchData = useCallback( - async (status: statusType) => { - setIsLoading(true); - const params = { - limit: resultsPerPage, - page: qParams.page, - offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage, - search_text: qParams.search || "", - facility: qParams.facility || "", - asset_type: qParams.asset_type || "", - asset_class: qParams.asset_class || "", - location: qParams.facility ? qParams.location || "" : "", - status: qParams.status || "", - warranty_amc_end_of_validity_before: - qParams.warranty_amc_end_of_validity_before || "", - warranty_amc_end_of_validity_after: - qParams.warranty_amc_end_of_validity_after || "", - }; - const { data } = await dispatch(listAssets(params)); - if (!status.aborted) { - setIsLoading(false); - if (!data) - Notification.Error({ - msg: "Something went wrong..!", - }); - else { - setAssets(data.results); - setTotalCount(data.count); - if (qParams.facility) { - const fetchFacility = await dispatch( - getAnyFacility(qParams.facility) - ); - setSelectedFacility(fetchFacility.data as FacilityModel); - } - } + useQuery(routes.listAssets, { + query: params, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data) { + setAssets(data.results); + setTotalCount(data.count); } }, - [ - resultsPerPage, - qParams.page, - qParams.search, - qParams.facility, - qParams.asset_type, - qParams.asset_class, - qParams.location, - qParams.status, - qParams.warranty_amc_end_of_validity_before, - qParams.warranty_amc_end_of_validity_after, - dispatch, - ] - ); + }); + + useQuery(routes.getAnyFacility, { + pathParams: { id: qParams.facility }, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data) { + setFacility(data); + setSelectedFacility(data); + setFacilityName(data.name); + } + }, + prefetch: !!qParams.facility, + }); useEffect(() => { setAssetType(qParams.asset_type); @@ -125,56 +100,13 @@ const AssetsList = () => { setAssetClass(qParams.asset_class); }, [qParams.asset_class]); - useAbortableEffect( - (status: statusType) => { - fetchData(status); + const { data: location } = useQuery(routes.getFacilityAssetLocation, { + pathParams: { + facility_external_id: String(qParams.facility), + external_id: String(qParams.location), }, - [dispatch, fetchData] - ); - useEffect(() => { - async function fetchFacilityName() { - if (!qParams.facility) return setFacilityName(""); - const res = await dispatch(getAnyFacility(qParams.facility, "facility")); - setFacilityName(res?.data?.name); - } - fetchFacilityName(); - }, [dispatch, qParams.facility]); - - const fetchFacility = useCallback( - async (status: statusType) => { - if (!qParams.facility) return setFacility(undefined); - setIsLoading(true); - const res = await dispatch(getAnyFacility(qParams.facility)); - if (!status.aborted) { - setFacility(res?.data); - setIsLoading(false); - } - }, - [dispatch, qParams.facility] - ); - const fetchLocationName = useCallback( - async (status: statusType) => { - if (!qParams.location || !qParams.facility) - return setLocationName(undefined); - setIsLoading(true); - const res = await dispatch( - getFacilityAssetLocation(qParams.facility, qParams.location) - ); - if (!status.aborted) { - setLocationName(res?.data?.name); - setIsLoading(false); - } - }, - [dispatch, qParams.facility, qParams.location] - ); - - useAbortableEffect( - (status: statusType) => { - fetchFacility(status); - fetchLocationName(status); - }, - [fetchFacility, fetchLocationName] - ); + prefetch: !!(qParams.facility && qParams.location), + }); const getAssetIdFromQR = async (assetUrl: string) => { try { @@ -184,8 +116,10 @@ const AssetsList = () => { // QR Maybe searchParams "asset" or "assetQR" const assetId = params.asset || params.assetQR; if (assetId) { - const { data } = await dispatch(listAssets({ qr_code_id: assetId })); - return data.results[0].id; + const { data } = await request(routes.listAssets, { + query: { qr_code_id: assetId }, + }); + return data?.results[0].id; } } catch (err) { console.log(err); @@ -193,11 +127,13 @@ const AssetsList = () => { }; const checkValidAssetId = async (assetId: string) => { - const assetData = await dispatch(getAsset(assetId)); + const { data: assetData } = await request(routes.getAsset, { + pathParams: { id: assetId }, + }); try { - if (assetData.data) { + if (assetData) { navigate( - `/facility/${assetData.data.location_object.facility.id}/assets/${assetId}` + `/facility/${assetData.location_object.facility.id}/assets/${assetId}` ); } } catch (err) { @@ -434,7 +370,7 @@ const AssetsList = () => { value("Asset Type", "asset_type", asset_type ?? ""), value("Asset Class", "asset_class", asset_class ?? ""), value("Status", "status", status?.replace(/_/g, " ") ?? ""), - value("Location", "location", locationName ?? ""), + value("Location", "location", location?.name ?? ""), value( "Warranty AMC End Of Validity Before", "warranty_amc_end_of_validity_before", @@ -516,6 +452,7 @@ export const warrantyAmcValidityChip = ( if (warrantyAmcEndDate < today) { return ( ) => { - dispatch(createAssetBed({}, assetId, bedId)); +const saveLink = async (assetId: string, bedId: string) => { + await request(routes.createAssetBed, { + body: { + asset: assetId, + bed: bedId, + }, + }); Notification.Success({ msg: "AssetBed Link created successfully" }); }; -const update_Link = ( +const update_Link = async ( assetbedId: string, assetId: string, - bed: BedModel, - assetBed: any, - dispatch: Dispatch + bed: BedModel ) => { - dispatch( - partialUpdateAssetBed( - { - asset: assetId, - bed: bed.id, - }, - assetbedId - ) - ); + await request(routes.partialUpdateAssetBed, { + pathParams: { external_id: assetbedId }, + body: { + asset: assetId, + bed: bed.id ?? "", + }, + }); Notification.Success({ msg: "AssetBed Link updated successfully" }); }; export default function MonitorConfigure({ asset }: { asset: AssetData }) { const [bed, setBed] = useState({}); const [updateLink, setUpdateLink] = useState(false); - const [assetBed, setAssetBed] = useState(); - const dispatch: any = useDispatch(); - - const getAssetBeds = async (id: string) => { - const assetBeds = await dispatch(listAssetBeds({ asset: id })); - if (assetBeds.data?.results?.length > 0) { - setUpdateLink(true); - setAssetBed(assetBeds.data.results[0]); - setBed(assetBeds.data.results[0].bed_object); - } else { - setUpdateLink(false); - } - }; - - useEffect(() => { - if (asset.id) { - getAssetBeds(asset.id); - } - }, [asset]); + const { data: assetBed } = useQuery(routes.listAssetBeds, { + query: { asset: asset.id }, + onResponse: ({ res, data }) => { + if (res?.status === 200 && data && data.results.length > 0) { + setBed(data.results[0].bed_object); + setUpdateLink(true); + } + }, + }); return ( diff --git a/src/Components/Common/Export.tsx b/src/Components/Common/Export.tsx index 3595b3c84a0..f991c476aac 100644 --- a/src/Components/Common/Export.tsx +++ b/src/Components/Common/Export.tsx @@ -44,7 +44,7 @@ export const ExportMenu = ({ } + icon={} className="tooltip border-primary-500 bg-white text-primary-500 hover:bg-primary-100 enabled:border" > {exportItems.map((item) => ( diff --git a/src/Components/Common/Uptime.tsx b/src/Components/Common/Uptime.tsx index ce60e7b7f7e..6f6966b9053 100644 --- a/src/Components/Common/Uptime.tsx +++ b/src/Components/Common/Uptime.tsx @@ -4,7 +4,7 @@ import { listAssetAvailability } from "../../Redux/actions"; import { useDispatch } from "react-redux"; import * as Notification from "../../Utils/Notifications.js"; import { AssetStatus, AssetUptimeRecord } from "../Assets/AssetTypes"; -import { reverse } from "lodash"; +import { reverse } from "lodash-es"; import { classNames } from "../../Utils/utils"; import dayjs from "../../Utils/dayjs"; diff --git a/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res b/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res index 35d137e0414..dfe0e5cc3dc 100644 --- a/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res +++ b/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res @@ -68,12 +68,12 @@ let reducer = (state, action) => { | SetConsciousnessLevel(consciousnessLevel) => { ...state, dirty: true, - consciousnessLevel: consciousnessLevel, + consciousnessLevel, } | SetConsciousnessLevelDetails(consciousnessLevelDetails) => { ...state, dirty: true, - consciousnessLevelDetails: consciousnessLevelDetails, + consciousnessLevelDetails, } | SetLeftPupilSize(leftPupilSize) => { ...state, @@ -83,17 +83,17 @@ let reducer = (state, action) => { | SetLeftPupilSizeDetails(leftPupilSizeDetails) => { ...state, dirty: true, - leftPupilSizeDetails: leftPupilSizeDetails, + leftPupilSizeDetails, } | SetLeftPupilLightReaction(leftPupilLightReaction) => { ...state, dirty: true, - leftPupilLightReaction: leftPupilLightReaction, + leftPupilLightReaction, } | SetLeftPupilLightReactionDetails(leftPupilLightReactionDetails) => { ...state, dirty: true, - leftPupilLightReactionDetails: leftPupilLightReactionDetails, + leftPupilLightReactionDetails, } | SetRightPupilSize(rightPupilSize) => { ...state, @@ -103,17 +103,17 @@ let reducer = (state, action) => { | SetRightPupilSizeDetails(rightPupilSizeDetails) => { ...state, dirty: true, - rightPupilSizeDetails: rightPupilSizeDetails, + rightPupilSizeDetails, } | SetRightPupilLightReaction(rightPupilLightReaction) => { ...state, dirty: true, - rightPupilLightReaction: rightPupilLightReaction, + rightPupilLightReaction, } | SetRightPupilLightReactionDetails(rightPupilLightReactionDetails) => { ...state, dirty: true, - rightPupilLightReactionDetails: rightPupilLightReactionDetails, + rightPupilLightReactionDetails, } | SetGlasgowEyeOpen(glasgowEyeOpen) => {...state, glasgowEyeOpen: Some(glasgowEyeOpen)} | SetGlasgowVerbalResponse(glasgowVerbalResponse) => { @@ -129,22 +129,22 @@ let reducer = (state, action) => { | SetLimbResponseUpperExtremityRight(limbResponseUpperExtremityRight) => { ...state, dirty: true, - limbResponseUpperExtremityRight: limbResponseUpperExtremityRight, + limbResponseUpperExtremityRight, } | SetLimbResponseUpperExtremityLeft(limbResponseUpperExtremityLeft) => { ...state, dirty: true, - limbResponseUpperExtremityLeft: limbResponseUpperExtremityLeft, + limbResponseUpperExtremityLeft, } | SetLimbResponseLowerExtremityRight(limbResponseLowerExtremityRight) => { ...state, dirty: true, - limbResponseLowerExtremityRight: limbResponseLowerExtremityRight, + limbResponseLowerExtremityRight, } | SetLimbResponseLowerExtremityLeft(limbResponseLowerExtremityLeft) => { ...state, dirty: true, - limbResponseLowerExtremityLeft: limbResponseLowerExtremityLeft, + limbResponseLowerExtremityLeft, } | SetSaving => {...state, saving: true} @@ -265,7 +265,7 @@ let renderConsciousnessLevel = ( ) => {
{str("Level Of Consciousness")}
-
+
{Js.Array.map(consciousnessLevel => { onInputChange(consciousnessLevel)} /> - }, [Alert, Drowsy, Stuporous, Comatose, CannotBeAssessed])->React.array} + }, [ + Unresponsive, + Alert, + RespondsToPain, + RespondsToVoice, + AgitatedOrConfused, + OnsetOfAgitationAndConfusion, + ])->React.array}
- {ReactUtils.nullUnless( - onInputDetailsChange(event)} - />, - input === NeurologicalMonitoring.CannotBeAssessed, - )}
} diff --git a/src/Components/CriticalCareRecording/NeurologicalMonitoring/DailyRound__NeurologicalMonitoring.res b/src/Components/CriticalCareRecording/NeurologicalMonitoring/DailyRound__NeurologicalMonitoring.res index f476fd36c46..7dd295ecb51 100644 --- a/src/Components/CriticalCareRecording/NeurologicalMonitoring/DailyRound__NeurologicalMonitoring.res +++ b/src/Components/CriticalCareRecording/NeurologicalMonitoring/DailyRound__NeurologicalMonitoring.res @@ -16,10 +16,6 @@ let make = ( NeurologicalMonitoring.consciousnessLevel(neurologicalMonitoring), ), )} - {renderOptionalDescription( - "Consciousness Level Reaction Description", - NeurologicalMonitoring.consciousnessLevelDetails(neurologicalMonitoring), - )}
{title("Left Pupil")} diff --git a/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res b/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res index f42ca5c140d..0fae710ce36 100644 --- a/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res +++ b/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res @@ -1,4 +1,11 @@ -type consciousnessLevel = Alert | Drowsy | Stuporous | Comatose | CannotBeAssessed | Unknown +type consciousnessLevel = + | Unresponsive + | RespondsToPain + | RespondsToVoice + | Alert + | AgitatedOrConfused + | OnsetOfAgitationAndConfusion + | Unknown type lightReaction = Brisk | Sluggish | Fixed | CannotBeAssessed | Unknown type limpResponse = Strong | Moderate | Weak | Flexion | Extension | NONE_ | Unknown @@ -68,11 +75,12 @@ let make = ( let makeConsciousnessLevel = consciousnessLevel => { switch consciousnessLevel { + | "UNRESPONSIVE" => Unresponsive + | "RESPONDS_TO_PAIN" => RespondsToPain + | "RESPONDS_TO_VOICE" => RespondsToVoice | "ALERT" => Alert - | "DROWSY" => Drowsy - | "STUPOROUS" => Stuporous - | "COMATOSE" => Comatose - | "CANNOT_BE_ASSESSED" => CannotBeAssessed + | "AGITATED_OR_CONFUSED" => AgitatedOrConfused + | "ONSET_OF_AGITATION_AND_CONFUSION" => OnsetOfAgitationAndConfusion | "UNKNOWN" | _ => Unknown @@ -81,11 +89,12 @@ let makeConsciousnessLevel = consciousnessLevel => { let encodeConConsciousnessLevel = consciousnessLevel => { switch consciousnessLevel { + | Unresponsive => "UNRESPONSIVE" + | RespondsToPain => "RESPONDS_TO_PAIN" + | RespondsToVoice => "RESPONDS_TO_VOICE" | Alert => "ALERT" - | Drowsy => "DROWSY" - | Stuporous => "STUPOROUS" - | Comatose => "COMATOSE" - | CannotBeAssessed => "CANNOT_BE_ASSESSED" + | AgitatedOrConfused => "AGITATED_OR_CONFUSED" + | OnsetOfAgitationAndConfusion => "ONSET_OF_AGITATION_AND_CONFUSION" | Unknown => "UNKNOWN" } } @@ -150,11 +159,12 @@ let lightReactionToString = lightReaction => { let consciousnessLevelToString = consciousnessLevel => { switch consciousnessLevel { + | Unresponsive => "Unresponsive" + | RespondsToPain => "Responds to Pain" + | RespondsToVoice => "Responds to Voice" | Alert => "Alert" - | Drowsy => "Drowsy" - | Stuporous => "Stuporous" - | Comatose => "Comatose" - | CannotBeAssessed => "Cannot be assessed" + | AgitatedOrConfused => "Agitated or Confused" + | OnsetOfAgitationAndConfusion => "Onset of Agitation and Confusion" | Unknown => "Unknown" } } diff --git a/src/Components/ExternalResult/ExternalResultUpload.tsx b/src/Components/ExternalResult/ExternalResultUpload.tsx index 5f39cb213a4..20a2cec3341 100644 --- a/src/Components/ExternalResult/ExternalResultUpload.tsx +++ b/src/Components/ExternalResult/ExternalResultUpload.tsx @@ -1,22 +1,22 @@ -import _ from "lodash"; +import _ from "lodash-es"; import { navigate } from "raviger"; import { lazy, useState } from "react"; import CSVReader from "react-csv-reader"; -import { useDispatch } from "react-redux"; import useConfig from "../../Common/hooks/useConfig"; -import { externalResultUploadCsv } from "../../Redux/actions"; import * as Notification from "../../Utils/Notifications.js"; const PageTitle = lazy(() => import("../Common/PageTitle")); import { useTranslation } from "react-i18next"; import { Cancel, Submit } from "../Common/components/ButtonV2"; import useAppHistory from "../../Common/hooks/useAppHistory"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; +import { IExternalResult } from "./models"; export default function ExternalResultUpload() { const { sample_format_external_result_import } = useConfig(); - const dispatch: any = useDispatch(); // for disabling save button once clicked const [loading, setLoading] = useState(false); - const [csvData, setCsvData] = useState(new Array()); + const [csvData, setCsvData] = useState(new Array()); const [errors, setErrors] = useState([]); const handleForce = (data: any) => { setCsvData(data); @@ -32,26 +32,35 @@ export default function ExternalResultUpload() { header.toLowerCase().replace(/\W/g, "_"), }; - const handleSubmit = (e: any) => { + const handleSubmit = async (e: any) => { e.preventDefault(); setLoading(true); const valid = true; - if (csvData.length !== 0) { - const data = { - sample_tests: csvData, - }; + if (csvData.length !== 0) { if (valid) { setErrors([]); - dispatch(externalResultUploadCsv(data)).then((resp: any) => { - if (resp && resp.status === 202) { + + try { + const { res, data } = await request(routes.externalResultUploadCsv, { + body: { + sample_tests: csvData, + }, + }); + + if (res && res.status === 202) { setLoading(false); navigate("/external_results"); } else { - setErrors(resp.data.map((err: any) => Object.entries(err))); + if (data) { + setErrors(data.map((err: any) => Object.entries(err))); + } setLoading(false); } - }); + } catch (error) { + console.error("An error occurred:", error); + setLoading(false); + } } else { setLoading(false); } @@ -117,7 +126,7 @@ export default function ExternalResultUpload() {
{index + 1}
{data.name}
-
+
{errors && errors.length !== 0 ? errors.map((error: any) => { return ( diff --git a/src/Components/ExternalResult/ListFilter.tsx b/src/Components/ExternalResult/ListFilter.tsx index 91b75e535d2..75358196ffd 100644 --- a/src/Components/ExternalResult/ListFilter.tsx +++ b/src/Components/ExternalResult/ListFilter.tsx @@ -1,6 +1,4 @@ -import { useEffect, useState } from "react"; -import { getAllLocalBodyByDistrict } from "../../Redux/actions"; -import { useDispatch } from "react-redux"; +import { useState } from "react"; import useMergeState from "../../Common/hooks/useMergeState"; import { navigate } from "raviger"; import { useTranslation } from "react-i18next"; @@ -11,6 +9,9 @@ import DateRangeFormField from "../Form/FormFields/DateRangeFormField"; import dayjs from "dayjs"; import { dateQueryString } from "../../Utils/utils"; import useAuthUser from "../../Common/hooks/useAuthUser"; +import useQuery from "../../Utils/request/useQuery"; +import routes from "../../Redux/api"; +import Loading from "../Common/Loading"; const clearFilterState = { created_date_before: "", @@ -29,10 +30,8 @@ export default function ListFilter(props: any) { const { filter, onChange, closeFilter, dataList } = props; const [wardList, setWardList] = useState([]); const [lsgList, setLsgList] = useState([]); - const [wards, setWards] = useState([]); const [selectedLsgs, setSelectedLsgs] = useState([]); - const dispatch: any = useDispatch(); const authUser = useAuthUser(); const [filterState, setFilterState] = useMergeState({ created_date_before: filter.created_date_before || null, @@ -45,6 +44,57 @@ export default function ListFilter(props: any) { }); const { t } = useTranslation(); + const { loading } = useQuery(routes.getAllLocalBodyByDistrict, { + pathParams: { id: String(authUser.district) }, + onResponse: ({ res, data }) => { + if (res && data) { + let allWards: any[] = []; + let allLsgs: any[] = []; + if (res && data) { + data.forEach((local: any) => { + allLsgs = [...allLsgs, { id: local.id, name: local.name }]; + if (local.wards) { + local.wards.forEach((ward: any) => { + allWards = [ + ...allWards, + { + id: ward.id, + name: ward.number + ": " + ward.name, + panchayath: local.name, + number: ward.number, + local_body_id: local.id, + }, + ]; + }); + } + }); + } + + sortByName(allWards); + sortByName(allLsgs); + setWardList(allWards || []); + setLsgList(allLsgs || []); + const filteredWard = filter?.wards?.split(",").map(Number); + const selectedWards: any = + filteredWard && allWards + ? allWards.filter(({ id }: { id: number }) => { + return filteredWard.includes(id); + }) + : []; + setWards(selectedWards); + + const filteredLsgs = filter?.local_bodies?.split(",").map(Number); + const selectedLsgs: any = + filteredLsgs && allLsgs + ? allLsgs.filter(({ id }: { id: number }) => { + return filteredLsgs.includes(id); + }) + : []; + setSelectedLsgs(selectedLsgs); + } + }, + }); + const handleDateRangeChange = ( startDateId: string, endDateId: string, @@ -118,59 +168,10 @@ export default function ListFilter(props: any) { }); }; - useEffect(() => { - async function getWardList() { - const id = authUser.district; - const res = await dispatch(getAllLocalBodyByDistrict({ id })); - let allWards: any[] = []; - let allLsgs: any[] = []; - res?.data?.forEach((local: any) => { - allLsgs = [...allLsgs, { id: local.id, name: local.name }]; - if (local.wards) { - local.wards.forEach((ward: any) => { - allWards = [ - ...allWards, - { - id: ward.id, - name: ward.number + ": " + ward.name, - panchayath: local.name, - number: ward.number, - local_body_id: local.id, - }, - ]; - }); - } - }); - sortByName(allWards); - sortByName(allLsgs); - setWardList(allWards || []); - setLsgList(allLsgs || []); - const filteredWard = filter?.wards?.split(",").map(Number); - const selectedWards: any = - filteredWard && allWards - ? allWards.filter(({ id }: { id: number }) => { - return filteredWard.includes(id); - }) - : []; - setWards(selectedWards); - - const filteredLsgs = filter?.local_bodies?.split(",").map(Number); - const selectedLsgs: any = - filteredLsgs && allLsgs - ? allLsgs.filter(({ id }: { id: number }) => { - return filteredLsgs.includes(id); - }) - : []; - setSelectedLsgs(selectedLsgs); - } - getWardList(); - }, []); - const filterWards = () => { const selectedLsgIds: any = selectedLsgs.map((e) => { return e.id; }); - const selectedwards: any = selectedLsgIds.length === 0 ? wardList @@ -183,13 +184,15 @@ export default function ListFilter(props: any) { const handleChange = (event: any) => { const { name, value } = event.target; - const filterData: any = { ...filterState }; filterData[name] = value; - setFilterState(filterData); }; + if (loading) { + ; + } + return ( import("../Common/Loading")); export default function ResultItem(props: any) { - const dispatch: any = useDispatch(); - const initialData: any = {}; - const [data, setData] = useState(initialData); - const [isLoading, setIsLoading] = useState(true); const [showDeleteAlert, setShowDeleteAlert] = useState(false); const { t } = useTranslation(); - const fetchData = useCallback( - async (status: statusType) => { - setIsLoading(true); - const res = await dispatch(externalResult({ id: props.id })); - if (!status.aborted) { - if (res && res.data) { - setData(res.data); - } - setIsLoading(false); - } - }, - [props.id, dispatch] - ); + const { data: resultItemData, loading } = useQuery(routes.externalResult, { + pathParams: { id: props.id }, + }); const handleDelete = async () => { - const res = await dispatch(deleteExternalResult(props.id)); - if (res?.status === 204) { - Notification.Success({ - msg: t("record_has_been_deleted_successfully"), + if (showDeleteAlert) { + const { res, data } = await request(routes.deleteExternalResult, { + pathParams: { id: props.id }, }); - } else { - Notification.Error({ - msg: - t("error_while_deleting_record") + ": " + (res?.data?.detail || ""), - }); - } - setShowDeleteAlert(false); - navigate("/external_results"); + if (res?.status === 204) { + Notification.Success({ + msg: t("record_has_been_deleted_successfully"), + }); + } else { + Notification.Error({ + msg: t("error_while_deleting_record") + ": " + (data?.detail || ""), + }); + } + setShowDeleteAlert(false); + navigate("/external_results"); + } }; - useAbortableEffect( - (status: statusType) => { - fetchData(status); - }, - [fetchData] - ); - - if (isLoading) { + if (loading || !resultItemData) { return ; } @@ -69,14 +50,18 @@ export default function ResultItem(props: any) { variant="danger" action={t("delete")} show={showDeleteAlert} - onConfirm={() => handleDelete()} + onConfirm={() => { + handleDelete(); + }} onClose={() => setShowDeleteAlert(false)} />
diff --git a/src/Components/ExternalResult/ResultList.tsx b/src/Components/ExternalResult/ResultList.tsx index 74fbf8430b0..d148b26e3f5 100644 --- a/src/Components/ExternalResult/ResultList.tsx +++ b/src/Components/ExternalResult/ResultList.tsx @@ -1,12 +1,10 @@ import ButtonV2 from "../Common/components/ButtonV2"; import { navigate } from "raviger"; -import { lazy, useEffect, useState } from "react"; -import { useDispatch } from "react-redux"; +import { lazy, useState } from "react"; import { externalResultList } from "../../Redux/actions"; import ListFilter from "./ListFilter"; import FacilitiesSelectDialogue from "./FacilitiesSelectDialogue"; import { FacilityModel } from "../Facility/models"; -import { parsePhoneNumber } from "../../Utils/utils"; import SearchInput from "../Form/SearchInput"; import useFilters from "../../Common/hooks/useFilters"; import CareIcon from "../../CAREUI/icons/CareIcon"; @@ -15,14 +13,12 @@ import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; import CountBlock from "../../CAREUI/display/Count"; import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover"; import Page from "../Common/components/Page"; - +import routes from "../../Redux/api"; +import useQuery from "../../Utils/request/useQuery"; +import { parsePhoneNumber } from "../../Utils/utils"; const Loading = lazy(() => import("../Common/Loading")); export default function ResultList() { - const dispatch: any = useDispatch(); - const [data, setData] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [totalCount, setTotalCount] = useState(0); const { qParams, updateQuery, @@ -57,61 +53,31 @@ export default function ResultList() { setPhoneNumberError("Enter a valid number"); }; + const params = { + page: qParams.page || 1, + name: qParams.name || "", + mobile_number: qParams.mobile_number + ? parsePhoneNumber(qParams.mobile_number) ?? "" + : "", + wards: qParams.wards || undefined, + local_bodies: qParams.local_bodies || undefined, + created_date_before: qParams.created_date_before || undefined, + created_date_after: qParams.created_date_after || undefined, + result_date_before: qParams.result_date_before || undefined, + result_date_after: qParams.result_date_after || undefined, + sample_collection_date_after: + qParams.sample_collection_date_after || undefined, + sample_collection_date_before: + qParams.sample_collection_date_before || undefined, + offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage, + srf_id: qParams.srf_id || undefined, + }; - let manageResults: any = null; - useEffect(() => { - setIsLoading(true); - const params = { - page: qParams.page || 1, - name: qParams.name || "", - mobile_number: qParams.mobile_number - ? parsePhoneNumber(qParams.mobile_number) ?? "" - : "", - wards: qParams.wards || undefined, - local_bodies: qParams.local_bodies || undefined, - created_date_before: qParams.created_date_before || undefined, - created_date_after: qParams.created_date_after || undefined, - result_date_before: qParams.result_date_before || undefined, - result_date_after: qParams.result_date_after || undefined, - sample_collection_date_after: - qParams.sample_collection_date_after || undefined, - sample_collection_date_before: - qParams.sample_collection_date_before || undefined, - offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage, - srf_id: qParams.srf_id || undefined, - }; - - dispatch(externalResultList(params, "externalResultList")) - .then((res: any) => { - if (res && res.data) { - setData(res.data.results); - setTotalCount(res.data.count); - setIsLoading(false); - } - }) - .catch(() => { - setIsLoading(false); - }); + const { data, loading } = useQuery(routes.externalResultList, { + query: params, + }); - if (!params.mobile_number) { - setPhoneNum("+91"); - } - }, [ - dispatch, - qParams.name, - qParams.page, - qParams.mobile_number, - qParams.wards, - qParams.created_date_before, - qParams.created_date_after, - qParams.result_date_before, - qParams.result_date_after, - qParams.sample_collection_date_after, - qParams.sample_collection_date_before, - qParams.local_bodies, - qParams.srf_id, - dataList, - ]); + let manageResults: any = null; const removeLSGFilter = (paramKey: any, id: any) => { const updatedLsgList = dataList.lsgList.filter((x: any) => x.id !== id); @@ -158,8 +124,8 @@ export default function ResultList() { }; let resultList: any[] = []; - if (data && data.length) { - resultList = data.map((result: any) => { + if (data?.results.length) { + resultList = data.results.map((result: any) => { const resultUrl = `/external_results/${result.id}`; return ( @@ -173,7 +139,7 @@ export default function ResultList() { className="group inline-flex space-x-2 text-sm leading-5" >

- {result.name} - {result.age} {result.age_in} + {`${result.name}`} - {result.age} {result.age_in}

@@ -214,7 +180,7 @@ export default function ResultList() { }); } - if (isLoading || !data) { + if (loading) { manageResults = ( @@ -222,9 +188,9 @@ export default function ResultList() { ); - } else if (data && data.length) { + } else if (data?.results.length) { manageResults = <>{resultList}; - } else if (data && data.length === 0) { + } else if (data?.results.length === 0) { manageResults = ( @@ -286,8 +252,8 @@ export default function ResultList() {
@@ -358,7 +324,7 @@ export default function ResultList() {
- + import("../Common/Loading")); @@ -63,79 +57,70 @@ export default function UpdateResult(props: any) { const { id } = props; const { goBack } = useAppHistory(); - const dispatchAction: any = useDispatch(); const [state, dispatch] = useReducer(FormReducer, initialState); - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(true); const [isLocalbodyLoading, setIsLocalbodyLoading] = useState(false); const [isWardLoading, setIsWardLoading] = useState(false); const [localBody, setLocalBody] = useState(initialLocalbodies); const [ward, setWard] = useState(initialLocalbodies); - const fetchData = useCallback( - async (status: statusType) => { - setIsLoading(true); - const res = await dispatchAction(externalResult({ id: id })); - if (!status.aborted) { - if (res && res.data) { - const form = { ...state.form }; - form["name"] = res.data.name; - form["age"] = res.data.age; - form["age_in"] = res.data.age_in; - form["srf_id"] = res.data.srf_id; - form["address"] = res.data.address; - form["district"] = res.data.district_object.name; - form["local_body"] = String(res.data.local_body); - form["ward"] = String(res.data.ward); - form["patient_created"] = String(res.data.patient_created); + const { loading } = useQuery(routes.externalResult, { + pathParams: { id }, + onResponse: async ({ res, data }) => { + if (res && data) { + const form = { ...state.form }; + form["name"] = data.name; + form["age"] = data.age; + form["age_in"] = data.age_in; + form["srf_id"] = data.srf_id; + form["address"] = data.address; + form["district"] = data.district_object.name; + form["local_body"] = String(data.local_body); + form["ward"] = String(data.ward); + form["patient_created"] = String(data.patient_created); - dispatch({ type: "set_form", form }); + dispatch({ type: "set_form", form }); - Promise.all([ - fetchLocalBody(res.data.district), - fetchWards(res.data.local_body), - ]); - } + Promise.all([ + fetchLocalBody(data.district), + fetchWards(data.local_body), + ]); setIsLoading(false); } }, - [props.id, dispatchAction] - ); + }); - const fetchLocalBody = useCallback( - async (id: string) => { - if (Number(id) > 0) { - setIsLocalbodyLoading(true); - const localBodyList = await dispatchAction( - getLocalbodyByDistrict({ id }) - ); + const fetchLocalBody = async (id: number) => { + if (Number(id) > 0) { + setIsLocalbodyLoading(true); + const { res, data } = await request(routes.getLocalbodyByDistrict, { + pathParams: { id: String(id) }, + }); + if (res && data) { setIsLocalbodyLoading(false); - setLocalBody([...initialLocalbodies, ...localBodyList.data]); - } else { - setLocalBody(initialLocalbodies); + setLocalBody([...initialLocalbodies, ...data]); } - }, - [dispatchAction] - ); + } else { + setLocalBody(initialLocalbodies); + } + }; const fetchWards = useCallback( - async (id: string) => { + async (id: number) => { if (Number(id) > 0) { setIsWardLoading(true); - const wardList = await dispatchAction(getWardByLocalBody({ id })); + const { res, data } = await request(routes.getWardByLocalBody, { + pathParams: { id: String(id) }, + }); + if (res && data) { + setWard([...initialWard, ...data.results]); + } setIsWardLoading(false); - setWard([...initialWard, ...wardList.data.results]); } else { setWard(initialLocalbodies); } }, - [dispatchAction] - ); - - useAbortableEffect( - (status: statusType) => { - fetchData(status); - }, - [fetchData] + [props.id] ); const validateForm = () => { @@ -195,15 +180,20 @@ export default function UpdateResult(props: any) { const validForm = validateForm(); if (validForm) { setIsLoading(true); - const data = { + const rdata = { address: state.form.address ? state.form.address : undefined, local_body: state.form.local_body ? state.form.local_body : undefined, ward: state.form.ward, patient_created: state.form.patient_created === "true", }; - const res = await dispatchAction(partialUpdateExternalResult(id, data)); + + const { res, data } = await request(routes.partialUpdateExternalResult, { + pathParams: { id }, + body: rdata, + }); + setIsLoading(false); - if (res && res.data) { + if (res && data) { dispatch({ type: "set_form", form: initForm }); Notification.Success({ msg: "External Result updated successfully", @@ -213,7 +203,7 @@ export default function UpdateResult(props: any) { } }; - if (isLoading) { + if (isLoading || loading) { return ; } @@ -262,10 +252,7 @@ export default function UpdateResult(props: any) { options={localBody} optionLabel={(localBody) => localBody.name} optionValue={(localBody) => localBody.id} - onChange={(e) => [ - handleChange(e), - fetchWards(String(e.value)), - ]} + onChange={(e) => [handleChange(e), fetchWards(e.value)]} error={state.errors.local_body} /> )} diff --git a/src/Components/ExternalResult/models.ts b/src/Components/ExternalResult/models.ts new file mode 100644 index 00000000000..8ccaba04d05 --- /dev/null +++ b/src/Components/ExternalResult/models.ts @@ -0,0 +1,72 @@ +export interface IExternalResultUploadCsv { + sample_tests: any[]; +} + +export interface IExternalResult { + id: number; + name: string; + age: number; + age_in: string; + test_type: string; + result: string; + result_date: string; + patient_created: boolean; + gender: string; + source: string; + is_repeat: boolean; + mobile_number: string; + patient_status: string; + sample_type: string; + sample_collection_date: string; + patient_category: string; + srf_id: string; + district_object: { + id: number; + name: string; + state: number; + }; + district: number; + ward: number; + local_body: number; + address: string; + ward_object: { + id: number; + number: number; + name: string; + }; + local_body_object: { + id: number; + name: string; + }; +} + +export interface ILocalBodies { + id: number; + name: string; + state: number; + number: number; + body_type: number; + localbody_code: string; + district: number; +} + +export interface IDeleteExternalResult { + detail: string; +} + +export interface IPartialUpdateExternalResult { + address: string; + ward: number; + local_body: number; + patient_created: boolean; +} + +export interface ILocalBodyByDistrict { + id: number; + name: string; + state: number; +} + +export interface IExternalResultCsv { + sample_tests: Partial[]; +} diff --git a/src/Components/Facility/AddLocationForm.tsx b/src/Components/Facility/AddLocationForm.tsx index f0dd7893aca..e71b68cc95c 100644 --- a/src/Components/Facility/AddLocationForm.tsx +++ b/src/Components/Facility/AddLocationForm.tsx @@ -25,12 +25,14 @@ export const AddLocationForm = (props: LocationFormProps) => { const dispatchAction: any = useDispatch(); const [isLoading, setIsLoading] = useState(false); const [name, setName] = useState(""); + const [middlewareAddress, setMiddlewareAddress] = useState(""); const [description, setDescription] = useState(""); const [facilityName, setFacilityName] = useState(""); const [locationName, setLocationName] = useState(""); const [errors, setErrors] = useState({ name: "", description: "", + middlewareAddress: "", }); const headerText = !locationId ? "Add Location" : "Update Location"; const buttonText = !locationId ? "Add Location" : "Update Location"; @@ -51,6 +53,7 @@ export const AddLocationForm = (props: LocationFormProps) => { setName(res?.data?.name || ""); setLocationName(res?.data?.name || ""); setDescription(res?.data?.description || ""); + setMiddlewareAddress(res?.data?.middleware_address || ""); } setIsLoading(false); } @@ -62,6 +65,7 @@ export const AddLocationForm = (props: LocationFormProps) => { const error = { name: "", description: "", + middlewareAddress: "", }; if (name.trim().length === 0) { @@ -69,6 +73,16 @@ export const AddLocationForm = (props: LocationFormProps) => { formValid = false; } + if ( + middlewareAddress && + middlewareAddress.match( + /^(?!https?:\/\/)[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*\.[a-zA-Z]{2,}$/ + ) === null + ) { + error.middlewareAddress = "Invalid Middleware Address"; + formValid = false; + } + setErrors(error); return formValid; }; @@ -83,6 +97,7 @@ export const AddLocationForm = (props: LocationFormProps) => { const data = { name, description, + middleware_address: middlewareAddress, }; const res = await dispatchAction( @@ -157,8 +172,18 @@ export const AddLocationForm = (props: LocationFormProps) => { error={errors.description} />
+
+ setMiddlewareAddress(e.value)} + error={errors.middlewareAddress} + /> +
-
+
navigate(`/facility/${facilityId}/location`, { diff --git a/src/Components/Facility/ConsultationCard.tsx b/src/Components/Facility/ConsultationCard.tsx index f6b4484b477..4859b981e8f 100644 --- a/src/Components/Facility/ConsultationCard.tsx +++ b/src/Components/Facility/ConsultationCard.tsx @@ -131,6 +131,7 @@ export const ConsultationCard = (props: ConsultationProps) => {
navigate( diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index 3d3271b16d5..d21200543c3 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -309,6 +309,7 @@ export const ConsultationDetails = (props: any) => { ) : ( navigate( `/facility/${patientData.facility}/patient/${patientData.id}/shift/new` @@ -352,6 +353,7 @@ export const ConsultationDetails = (props: any) => { Patient Details @@ -450,6 +452,7 @@ export const ConsultationDetails = (props: any) => { setOpenDischargeDialog(true)} disabled={!!consultationData.discharge_date} > @@ -496,7 +499,10 @@ export const ConsultationDetails = (props: any) => {
-
-
+
{data.map((x: any, i: any) => { return (
{ const LOC_OPTIONS = [ { id: 0, value: "Unknown" }, { id: 5, value: "Alert" }, - { id: 10, value: "Drowsy" }, - { id: 15, value: "Stuporous" }, - { id: 20, value: "Comatose" }, - { id: 25, value: "Cannot Be Assessed" }, + { id: 10, value: "Responds to Voice" }, + { id: 15, value: "Responds to Pain" }, + { id: 20, value: "Unresponsive" }, + { id: 25, value: "Agitated or Confused" }, + { id: 30, value: "Onset of Agitation and Confusion" }, ]; const REACTION_OPTIONS = [ @@ -297,16 +295,13 @@ export const NeurologicalTable = (props: any) => {
Level Of Consciousness
-
+
{locData.map((x: any, i: any) => (
-
+
{x.date}
@@ -376,10 +371,7 @@ export const NeurologicalTable = (props: any) => { Total
-
+
{glasgowData.map((x: any, i: any) => { return (
import("../Common/Loading")); const initForm = { @@ -22,6 +19,7 @@ const initForm = { ward: 0, middleware_address: "", }; + const initialState = { form: { ...initForm }, errors: {}, @@ -46,44 +44,33 @@ const FormReducer = (state = initialState, action: any) => { } }; -export const FacilityConfigure = (props: any) => { +interface IProps { + facilityId: string; +} + +export const FacilityConfigure = (props: IProps) => { const [state, dispatch] = useReducer(FormReducer, initialState); const { facilityId } = props; - const dispatchAction: any = useDispatch(); const [isLoading, setIsLoading] = useState(false); - const fetchData = useCallback( - async (status: statusType) => { - if (facilityId) { - setIsLoading(true); - const res = await dispatchAction(getPermittedFacility(facilityId)); - if (!status.aborted && res.data) { - const formData = { - name: res.data.name, - state: res.data.state, - district: res.data.district, - local_body: res.data.local_body, - ward: res.data.ward, - middleware_address: res.data.middleware_address, - }; - dispatch({ type: "set_form", form: formData }); - } else { - navigate(`/facility/${facilityId}`); - } - setIsLoading(false); + const { loading } = useQuery(routes.getPermittedFacility, { + pathParams: { id: facilityId }, + onResponse: (res) => { + if (res.data) { + const formData = { + name: res.data.name, + state: res.data.state, + district: res.data.district, + local_body: res.data.local_body, + ward: res.data.ward, + middleware_address: res.data.middleware_address, + }; + dispatch({ type: "set_form", form: formData }); } }, - [dispatchAction, facilityId] - ); + }); - useAbortableEffect( - (status: statusType) => { - fetchData(status); - }, - [dispatch, fetchData] - ); - - const handleSubmit = async (e: any) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); if (!state.form.middleware_address) { @@ -108,35 +95,39 @@ export const FacilityConfigure = (props: any) => { setIsLoading(false); return; } - const data: any = { + + const data = { ...state.form, middleware_address: state.form.middleware_address, }; - const res = await dispatchAction(partialUpdateFacility(facilityId, data)); + const { res, error } = await request(routes.partialUpdateFacility, { + pathParams: { id: facilityId }, + body: data, + }); + setIsLoading(false); - if (res && res.data) { + if (res?.ok) { Notification.Success({ msg: "Facility updated successfully", }); navigate(`/facility/${facilityId}`); } else { - if (res?.data) - Notification.Error({ - msg: "Something went wrong: " + (res.data.detail || ""), - }); + Notification.Error({ + msg: error?.detail ?? "Something went wrong", + }); } setIsLoading(false); }; - const handleChange = (e: any) => { + const handleChange = (e: FieldChangeEvent) => { dispatch({ type: "set_form", form: { ...state.form, [e.name]: e.value }, }); }; - if (isLoading) { + if (isLoading || loading) { return ; } @@ -146,22 +137,23 @@ export const FacilityConfigure = (props: any) => { crumbsReplacements={{ [facilityId]: { name: state.form.name }, }} - className="mx-auto max-w-3xl" + className="w-full overflow-x-hidden" >
- handleSubmit(e)}> +
handleChange(e)} + onChange={handleChange} error={state.errors?.middleware_address} />
-
+
navigate(`/facility/${facilityId}`)} />
diff --git a/src/Components/Facility/Investigations/InvestigationTable.tsx b/src/Components/Facility/Investigations/InvestigationTable.tsx index 8149e18496b..54e7e50bdc7 100644 --- a/src/Components/Facility/Investigations/InvestigationTable.tsx +++ b/src/Components/Facility/Investigations/InvestigationTable.tsx @@ -2,7 +2,6 @@ import ButtonV2 from "../../Common/components/ButtonV2"; import CareIcon from "../../../CAREUI/icons/CareIcon"; import { SelectFormField } from "../../Form/FormFields/SelectFormField"; import TextFormField from "../../Form/FormFields/TextFormField"; -import _ from "lodash"; import { classNames } from "../../../Utils/utils"; import { useState } from "react"; diff --git a/src/Components/Facility/Investigations/Reports/index.tsx b/src/Components/Facility/Investigations/Reports/index.tsx index ab5380c62ca..9b3c29d40f8 100644 --- a/src/Components/Facility/Investigations/Reports/index.tsx +++ b/src/Components/Facility/Investigations/Reports/index.tsx @@ -1,5 +1,5 @@ import * as Notification from "../../../../Utils/Notifications"; - +import _ from "lodash-es"; import { Group, InvestigationType } from ".."; import { getPatient, @@ -17,7 +17,6 @@ import { InvestigationResponse } from "./types"; import Loading from "../../../Common/Loading"; import Page from "../../../Common/components/Page"; import ReportTable from "./ReportTable"; -import _ from "lodash"; import { useDispatch } from "react-redux"; import { useRef } from "react"; diff --git a/src/Components/Facility/Investigations/Reports/utils.tsx b/src/Components/Facility/Investigations/Reports/utils.tsx index 485a3e1d5f4..e57f3c42c53 100644 --- a/src/Components/Facility/Investigations/Reports/utils.tsx +++ b/src/Components/Facility/Investigations/Reports/utils.tsx @@ -1,4 +1,4 @@ -import _ from "lodash"; +import _ from "lodash-es"; import { InvestigationResponse } from "./types"; export const transformData = _.memoize((data: InvestigationResponse) => { diff --git a/src/Components/Facility/Investigations/ShowInvestigation.tsx b/src/Components/Facility/Investigations/ShowInvestigation.tsx index 4c2826f6eea..00196bb6678 100644 --- a/src/Components/Facility/Investigations/ShowInvestigation.tsx +++ b/src/Components/Facility/Investigations/ShowInvestigation.tsx @@ -8,8 +8,8 @@ import { } from "../../../Redux/actions"; import PageTitle from "../../Common/PageTitle"; import InvestigationTable from "./InvestigationTable"; - -import _ from "lodash"; +import _ from "lodash-es"; +import { set } from "lodash-es"; import { navigate } from "raviger"; import * as Notification from "../../../Utils/Notifications.js"; @@ -110,7 +110,7 @@ export default function ShowInvestigation(props: any) { const handleValueChange = (value: any, name: string) => { const changedFields = { ...state.changedFields }; - _.set(changedFields, name, value); + set(changedFields, name, value); dispatch({ type: "set_changed_fields", changedFields }); }; diff --git a/src/Components/Facility/Investigations/Table.tsx b/src/Components/Facility/Investigations/Table.tsx index 4d6ce4c2340..4bd7e841543 100644 --- a/src/Components/Facility/Investigations/Table.tsx +++ b/src/Components/Facility/Investigations/Table.tsx @@ -1,7 +1,7 @@ import { FieldChangeEvent } from "../../Form/FormFields/Utils"; import { SelectFormField } from "../../Form/FormFields/SelectFormField"; import TextFormField from "../../Form/FormFields/TextFormField"; -import _ from "lodash"; +import { set } from "lodash-es"; import { useState } from "react"; const TestRow = ({ data, value, onChange, i }: any) => { @@ -59,7 +59,7 @@ export const TestTable = ({ title, data, state, dispatch }: any) => { const handleValueChange = (value: any, name: string) => { const form = { ...state }; - _.set(form, name, value); + set(form, name, value); dispatch({ type: "set_form", form }); }; diff --git a/src/Components/Facility/LegacyFacilityCNS.tsx b/src/Components/Facility/LegacyFacilityCNS.tsx index b3a933b9a9f..5b0005c9daf 100644 --- a/src/Components/Facility/LegacyFacilityCNS.tsx +++ b/src/Components/Facility/LegacyFacilityCNS.tsx @@ -16,7 +16,7 @@ import Pagination from "../Common/Pagination"; import { PatientModel } from "../Patient/models"; import { FacilityModel } from "./models"; import AutocompleteFormField from "../Form/FormFields/Autocomplete"; -import { uniqBy } from "lodash"; +import { uniqBy } from "lodash-es"; import DialogModal from "../Common/Dialog"; import { LegacyMonitorCard } from "./LegacyMonitorCard"; diff --git a/src/Components/Facility/LocationManagement.tsx b/src/Components/Facility/LocationManagement.tsx index 38dcfc1f389..c018a7c222b 100644 --- a/src/Components/Facility/LocationManagement.tsx +++ b/src/Components/Facility/LocationManagement.tsx @@ -65,12 +65,24 @@ export default function LocationManagement({ facilityId }: Props) { ); } -const Location = ({ name, description, id }: LocationModel) => ( +const Location = ({ + name, + description, + middleware_address, + id, +}: LocationModel) => (
-
-

{name}

-

{description}

+
+

+ {name} +

+ {description || "-"} +

+

+

+ {middleware_address} +

diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index de2c6af698a..a9861a4869c 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -28,7 +28,6 @@ export interface WardModel { export interface FacilityModel { id?: number; name?: string; - district?: number; read_cover_image_url?: string; facility_type?: string; address?: string; @@ -53,6 +52,10 @@ export interface FacilityModel { ward_object?: WardModel; modified_date?: string; created_date?: string; + state: number; + district: number; + local_body: number; + ward: number; } export interface CapacityModal { @@ -186,6 +189,7 @@ export interface LocationModel { id?: string; name?: string; description?: string; + middleware_address?: string; facility?: { name: string; }; diff --git a/src/Components/Form/AutoCompleteAsync.tsx b/src/Components/Form/AutoCompleteAsync.tsx index 5f33c6388c5..db2d1e888df 100644 --- a/src/Components/Form/AutoCompleteAsync.tsx +++ b/src/Components/Form/AutoCompleteAsync.tsx @@ -1,6 +1,6 @@ import { useEffect, useState, useMemo } from "react"; import { Combobox } from "@headlessui/react"; -import { debounce } from "lodash"; +import { debounce } from "lodash-es"; import { DropdownTransition } from "../Common/components/HelperComponents"; import CareIcon from "../../CAREUI/icons/CareIcon"; import { diff --git a/src/Components/Form/Form.tsx b/src/Components/Form/Form.tsx index e934c4ffe0e..66383616034 100644 --- a/src/Components/Form/Form.tsx +++ b/src/Components/Form/Form.tsx @@ -1,4 +1,4 @@ -import { isEmpty, omitBy } from "lodash"; +import { isEmpty, omitBy } from "lodash-es"; import { useEffect, useMemo, useState } from "react"; import { classNames } from "../../Utils/utils"; import { Cancel, Submit } from "../Common/components/ButtonV2"; diff --git a/src/Components/Notifications/NotificationsList.tsx b/src/Components/Notifications/NotificationsList.tsx index 5e3aa65b3ec..5f124516a14 100644 --- a/src/Components/Notifications/NotificationsList.tsx +++ b/src/Components/Notifications/NotificationsList.tsx @@ -353,15 +353,17 @@ export default function NotificationsList({ manageResults = ( <> {data - .filter((notification: any) => showUnread ? notification.read_at === null : true) - .map((result: any) => ( - - ))} + .filter((notification: any) => + showUnread ? notification.read_at === null : true + ) + .map((result: any) => ( + + ))} {isLoading && (
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx index a84ad4a3e8b..ff749aed29e 100644 --- a/src/Components/Patient/DailyRounds.tsx +++ b/src/Components/Patient/DailyRounds.tsx @@ -1,40 +1,40 @@ import { navigate } from "raviger"; -import { useCallback, useState, useEffect, lazy } from "react"; +import dayjs from "dayjs"; +import { lazy, useCallback, useEffect, useState } from "react"; import { useDispatch } from "react-redux"; import { - TELEMEDICINE_ACTIONS, + PATIENT_CATEGORIES, REVIEW_AT_CHOICES, RHYTHM_CHOICES, - PATIENT_CATEGORIES, + TELEMEDICINE_ACTIONS, } from "../../Common/constants"; +import useAppHistory from "../../Common/hooks/useAppHistory"; import { statusType, useAbortableEffect } from "../../Common/utils"; import { createDailyReport, getConsultationDailyRoundsDetails, getDailyReport, - updateDailyReport, getPatient, + updateDailyReport, } from "../../Redux/actions"; +import { DraftSection, useAutoSaveReducer } from "../../Utils/AutoSave"; import * as Notification from "../../Utils/Notifications"; import { formatDateTime } from "../../Utils/utils"; -import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; -import { Cancel, Submit } from "../Common/components/ButtonV2"; -import useAppHistory from "../../Common/hooks/useAppHistory"; -import { DraftSection, useAutoSaveReducer } from "../../Utils/AutoSave"; -import Page from "../Common/components/Page"; -import { FieldChangeEvent } from "../Form/FormFields/Utils"; -import TextFormField from "../Form/FormFields/TextFormField"; -import { SelectFormField } from "../Form/FormFields/SelectFormField"; -import PatientCategorySelect from "./PatientCategorySelect"; -import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField"; -import { SymptomsSelect } from "../Common/SymptomsSelect"; -import RangeAutocompleteFormField from "../Form/FormFields/RangeAutocompleteFormField"; import BloodPressureFormField, { meanArterialPressure, } from "../Common/BloodPressureFormField"; +import { SymptomsSelect } from "../Common/SymptomsSelect"; import TemperatureFormField from "../Common/TemperatureFormField"; -import dayjs from "dayjs"; +import { Cancel, Submit } from "../Common/components/ButtonV2"; +import Page from "../Common/components/Page"; +import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField"; +import RangeAutocompleteFormField from "../Form/FormFields/RangeAutocompleteFormField"; +import { SelectFormField } from "../Form/FormFields/SelectFormField"; +import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; +import TextFormField from "../Form/FormFields/TextFormField"; +import { FieldChangeEvent } from "../Form/FormFields/Utils"; +import PatientCategorySelect from "./PatientCategorySelect"; const Loading = lazy(() => import("../Common/Loading")); const initForm: any = { @@ -44,8 +44,7 @@ const initForm: any = { other_details: "", patient_category: "", current_health: 0, - recommend_discharge: false, - action: null, + actions: null, review_interval: 0, admitted_to: "", taken_at: null, @@ -274,7 +273,6 @@ export const DailyRounds = (props: any) => { physical_examination_info: state.form.physical_examination_info, other_details: state.form.other_details, consultation: consultationId, - recommend_discharge: JSON.parse(state.form.recommend_discharge), action: prevAction, review_interval: Number(prevReviewInterval), }; @@ -516,12 +514,6 @@ export const DailyRounds = (props: any) => { }} /> - - {state.form.rounds_type === "NORMAL" && ( <>

Vitals

diff --git a/src/Components/Patient/FileUpload.tsx b/src/Components/Patient/FileUpload.tsx index 2b0b068b0ef..f4d02404b7f 100644 --- a/src/Components/Patient/FileUpload.tsx +++ b/src/Components/Patient/FileUpload.tsx @@ -1523,6 +1523,7 @@ export const FileUpload = (props: FileUploadProps) => { {t("choose_file")} { Open Camera handleUpload({ status })} diff --git a/src/Components/Patient/ManagePatients.tsx b/src/Components/Patient/ManagePatients.tsx index 6e83eb9bc91..aa3a837647d 100644 --- a/src/Components/Patient/ManagePatients.tsx +++ b/src/Components/Patient/ManagePatients.tsx @@ -815,7 +815,7 @@ export const PatientManager = () => { }} className="mr-5 w-full lg:w-fit" > - + Export ) : ( diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index 701b76b5e3a..2d297642abb 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -5,23 +5,24 @@ import { DISCHARGE_REASONS, PATIENT_CATEGORIES, RESPIRATORY_SUPPORT, + TELEMEDICINE_ACTIONS, } from "../../Common/constants"; import { ConsultationModel, PatientCategory } from "../Facility/models"; -import ABHAProfileModal from "../ABDM/ABHAProfileModal"; -import Beds from "../Facility/Consultations/Beds"; -import ButtonV2 from "../Common/components/ButtonV2"; -import CareIcon from "../../CAREUI/icons/CareIcon"; -import DialogModal from "../Common/Dialog"; import { Link } from "raviger"; +import { useState } from "react"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import useConfig from "../../Common/hooks/useConfig"; +import { getDimensionOrDash } from "../../Common/utils"; +import dayjs from "../../Utils/dayjs"; +import { formatDate, formatDateTime } from "../../Utils/utils.js"; +import ABHAProfileModal from "../ABDM/ABHAProfileModal"; import LinkABHANumberModal from "../ABDM/LinkABHANumberModal"; import LinkCareContextModal from "../ABDM/LinkCareContextModal"; +import DialogModal from "../Common/Dialog"; +import ButtonV2 from "../Common/components/ButtonV2"; +import Beds from "../Facility/Consultations/Beds"; import { PatientModel } from "./models"; -import { getDimensionOrDash } from "../../Common/utils"; -import useConfig from "../../Common/hooks/useConfig"; -import { useState } from "react"; -import { formatAge, formatDate, formatDateTime } from "../../Utils/utils.js"; -import dayjs from "../../Utils/dayjs"; export default function PatientInfoCard(props: { patient: PatientModel; @@ -170,29 +171,44 @@ export default function PatientInfoCard(props: { Discharged from CARE

)} -

- {formatAge(patient.age, patient.date_of_birth, true)} - - {patient.gender} - {consultation?.suggestion === "DC" && ( - <> - - - - Domiciliary Care - - - )} - {consultation?.is_readmission && ( - <> - - - - Readmitted - - - )} -

+
+
+ {patient.action && patient.action != 10 && ( +
+
+ + {" "} + { + TELEMEDICINE_ACTIONS.find( + (i) => i.id === patient.action + )?.desc + } + +
+
+ )} +
+
+ Age: {patient.age} years +
+
+
+
+ Gender: {patient.gender} +
+
+ {consultation?.suggestion === "DC" && ( +
+
+
+ Domiciliary Care + +
+
+
+ )} +
+
{[ ["Blood Group", patient.blood_group, patient.blood_group], diff --git a/src/Components/Patient/PatientNotes.tsx b/src/Components/Patient/PatientNotes.tsx index 68a5ab4dc5d..c105619678b 100644 --- a/src/Components/Patient/PatientNotes.tsx +++ b/src/Components/Patient/PatientNotes.tsx @@ -114,6 +114,7 @@ const PatientNotes = (props: PatientNotesProps) => { />

Add new notes