diff --git a/.env b/.env
index fcabed6db34..38fd950b0d8 100644
--- a/.env
+++ b/.env
@@ -1,11 +1,10 @@
# Whitelabelling envs
-REACT_APP_TITLE="CARE"
-REACT_APP_META_DESCRIPTION="CoronaSafe Network is an open-source public utility designed by a multi-disciplinary team of innovators and volunteers. CoronaSafe Care is a Digital Public Good recognised by United Nations."
+REACT_APP_TITLE=CARE
+REACT_APP_META_DESCRIPTION=CoronaSafe Network is an open-source public utility designed by a multi-disciplinary team of innovators and volunteers. CoronaSafe Care is a Digital Public Good recognised by United Nations.
REACT_APP_COVER_IMAGE=https://cdn.coronasafe.network/care_logo.svg
REACT_APP_COVER_IMAGE_ALT=https://cdn.coronasafe.network/care_logo.svg
-REACT_APP_CONFIG=""
-REACT_PUBLIC_URL="https://care.coronasafe.in"
+REACT_PUBLIC_URL=https://care.coronasafe.in
# Dev envs
ESLINT_NO_DEV_ERRORS=true
diff --git a/.envrc b/.envrc
new file mode 100644
index 00000000000..fc7d890f90a
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+test -f .env.local && dotenv .env.local
\ No newline at end of file
diff --git a/.github/workflows/cypress.yaml b/.github/workflows/cypress.yaml
index e98f5b01e7d..f04045d0c72 100644
--- a/.github/workflows/cypress.yaml
+++ b/.github/workflows/cypress.yaml
@@ -14,6 +14,10 @@ jobs:
permissions: write-all
if: github.repository == 'coronasafe/care_fe'
runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ containers: [1,2,3,4,5,6,7,8]
steps:
- name: Checkout 📥
uses: actions/checkout@v3
@@ -24,20 +28,26 @@ jobs:
repository: coronasafe/care
path: care
- - name: Run docker compose up on care 🐳
- run: cd care && touch .env && make docker_config_file=docker-compose.pre-built.yaml up && cd .. && sleep 60s
- # Voluntarily kept 60 seconds delay to wait for migrations to complete.
-
- - name: Run Django collectstatic and load dummy data on care 🐍
+ - name: Start care docker containers 🐳
+ run: |
+ cd care
+ make docker_config_file=docker-compose.pre-built.yaml up
+ while docker compose exec backend bash -c "python manage.py showmigrations 2>/dev/null | cat | grep -q '\[ \]'"; do
+ >&2 echo "Migrations are not yet applied - sleeping"
+ sleep 5
+ done
+ echo "Migrations are applied"
+ cd ..
+
+ - name: Load dummy data into care backend 📂
run: |
- docker exec care python manage.py load_dummy_data
+ cd care
+ docker compose exec backend bash -c "python manage.py load_dummy_data"
+ cd ..
- name: Check care is up ♻
run: curl -o /dev/null -s -w "%{http_code}\n" http://localhost:9000
- - name: Change api proxy url 📝
- run: 'sed --in-place "s^target: .*,^target: \"http://localhost:9000\",^g" vite.config.ts'
-
- name: Install dependencies 📦
run: npm install
@@ -54,38 +64,14 @@ jobs:
wait-on-timeout: 300
browser: chrome
record: true
+ parallel: true
env:
+ CARE_API: http://localhost:9000
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_OPTIONS: --max_old_space_size=4096
-
- - name: Remove cypress passed label on failure 🏷️
- uses: actions-ecosystem/action-remove-labels@v1
- if: failure()
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- labels: cypress passed
-
- - name: Add cypress passed label on success 🏷️
- uses: actions-ecosystem/action-add-labels@v1
- if: success()
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- labels: cypress passed
-
- - name: Remove cypress failed label on success 🏷️
- uses: actions-ecosystem/action-remove-labels@v1
- if: success()
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- labels: cypress failed
-
- - name: Add cypress failed label on failure 🏷️
- uses: actions-ecosystem/action-add-labels@v1
- if: failure()
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- labels: cypress failed
+ COMMIT_INFO_MESSAGE: ${{github.event.pull_request.title}}
+ COMMIT_INFO_SHA: ${{github.event.pull_request.head.sha}}
- name: Upload cypress screenshots on failure 📸
uses: actions/upload-artifact@v3
@@ -94,10 +80,3 @@ jobs:
name: cypress-screenshots
path: cypress/screenshots
- # Test run video was always captured, so this action uses "always()" condition
- - name: Upload cypress videos 📹
- uses: actions/upload-artifact@v3
- if: always()
- with:
- name: cypress-videos
- path: cypress/videos
diff --git a/.gitignore b/.gitignore
index b97356ed20f..4ca589aab39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,6 +54,7 @@ public/build-meta.json
# Using NPM
yarn.lock
pnpm-lock.yaml
+bun.lockb
# Cypress
cypress/downloads
diff --git a/cypress.config.ts b/cypress.config.ts
index 014eb1f4d07..66915f8a11b 100644
--- a/cypress.config.ts
+++ b/cypress.config.ts
@@ -19,7 +19,6 @@ export default defineConfig({
return null;
},
});
-
return config;
},
baseUrl: "http://localhost:4000",
diff --git a/cypress/e2e/assets_spec/asset_homepage.cy.ts b/cypress/e2e/assets_spec/asset_homepage.cy.ts
new file mode 100644
index 00000000000..8bc24c7370f
--- /dev/null
+++ b/cypress/e2e/assets_spec/asset_homepage.cy.ts
@@ -0,0 +1,114 @@
+///
+
+import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress";
+import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch";
+import { AssetQRScanPage } from "../../pageobject/Asset/AssetQRScan";
+import { AssetPagination } from "../../pageobject/Asset/AssetPagination";
+import { AssetFilters } from "../../pageobject/Asset/AssetFilters";
+import { AssetPage } from "../../pageobject/Asset/AssetCreation";
+import LoginPage from "../../pageobject/Login/LoginPage";
+import { v4 as uuidv4 } from "uuid";
+
+describe("Asset Tab", () => {
+ const assetSearchPage = new AssetSearchPage();
+ const assetQRScanPage = new AssetQRScanPage();
+ const assetPagination = new AssetPagination();
+ const assetFilters = new AssetFilters();
+ const assetPage = new AssetPage();
+ const loginPage = new LoginPage();
+ const assetName = "Dummy Camera 10";
+ const qrCode = uuidv4();
+ const serialNumber = Math.floor(Math.random() * 10 ** 10).toString();
+
+ before(() => {
+ loginPage.loginAsDisctrictAdmin();
+ cy.saveLocalStorage();
+ });
+
+ beforeEach(() => {
+ cy.restoreLocalStorage();
+ cy.awaitUrl("/assets");
+ });
+
+ // search for a element
+
+ it("Search Asset Name/QR_ID/Serial_number", () => {
+ assetSearchPage.typeSearchKeyword(assetName);
+ assetSearchPage.pressEnter();
+ assetSearchPage.verifyBadgeContent(assetName);
+ assetSearchPage.clickAssetByName(assetName);
+ assetSearchPage.clickUpdateButton();
+ assetSearchPage.clearAndTypeQRCode(qrCode);
+ assetSearchPage.clearAndTypeSerialNumber(serialNumber);
+ assetSearchPage.clickAssetSubmitButton();
+ assetSearchPage.visitAssetsPage();
+ assetSearchPage.typeSearchKeyword(qrCode);
+ assetSearchPage.pressEnter();
+ assetSearchPage.verifyAssetListContains(assetName);
+ assetSearchPage.verifyBadgeContent(qrCode);
+ assetSearchPage.typeSearchKeyword(serialNumber);
+ assetSearchPage.verifyAssetListContains(assetName);
+ assetSearchPage.verifyBadgeContent(serialNumber);
+ });
+
+ // scan a asset qr code
+
+ it("Scan Asset QR", () => {
+ assetQRScanPage.scanAssetQR();
+ });
+
+ // filter the asset and verify the badges are there
+
+ it("Filter Asset", () => {
+ assetFilters.filterAssets(
+ "Dummy Facility 1",
+ "INTERNAL",
+ "ACTIVE",
+ "ONVIF Camera",
+ "Camera Loc"
+ );
+ assetFilters.clickadvancefilter();
+ assetFilters.clickslideoverbackbutton(); // to verify the back button doesn't clear applied filters
+ assetFilters.assertFacilityText("Dummy Facility 1");
+ assetFilters.assertAssetTypeText("INTERNAL");
+ assetFilters.assertAssetClassText("ONVIF");
+ assetFilters.assertStatusText("ACTIVE");
+ assetFilters.assertLocationText("Camera Locations");
+ assetFilters.clickadvancefilter();
+ assetFilters.clearFilters();
+ });
+
+ // Verify the pagination in the page
+
+ it("Next/Previous Page", () => {
+ assetPagination.navigateToNextPage();
+ assetPagination.navigateToPreviousPage();
+ });
+
+ it("Import new asset", () => {
+ assetPage.selectassetimportbutton();
+ assetPage.selectImportOption();
+ assetPage.selectImportFacility("Dummy Facility 1");
+ assetPage.importAssetFile();
+ assetPage.selectImportLocation("Camera Locations");
+ assetPage.clickImportAsset();
+ assetPage.verifySuccessNotification("Assets imported successfully");
+ });
+
+ it("verify imported asset", () => {
+ assetSearchPage.typeSearchKeyword("New Test Asset");
+ assetSearchPage.pressEnter();
+ assetSearchPage.verifyAssetIsPresent("New Test Asset");
+ });
+
+ it("Export asset", () => {
+ assetPage.selectassetimportbutton();
+ assetPage.selectjsonexportbutton();
+ assetPage.selectassetimportbutton();
+ assetPage.selectcsvexportbutton();
+ });
+
+ afterEach(() => {
+ cy.saveLocalStorage();
+ });
+});
diff --git a/cypress/e2e/assets_spec/asset_tab.cy.ts b/cypress/e2e/assets_spec/asset_tab.cy.ts
deleted file mode 100644
index 0abf11fcaf0..00000000000
--- a/cypress/e2e/assets_spec/asset_tab.cy.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-///
-
-import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress";
-import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch";
-import { AssetQRScanPage } from "../../pageobject/Asset/AssetQRScan";
-import { AssetPagination } from "../../pageobject/Asset/AssetPagination";
-import { AssetFilters } from "../../pageobject/Asset/AssetFilters";
-
-describe("Asset Tab", () => {
- const assetSearchPage = new AssetSearchPage();
- const assetQRScanPage = new AssetQRScanPage();
- const assetPagination = new AssetPagination();
- const assetFilters = new AssetFilters();
-
- before(() => {
- cy.loginByApi("devdistrictadmin", "Coronasafe@123");
- cy.saveLocalStorage();
- });
-
- beforeEach(() => {
- cy.restoreLocalStorage();
- cy.awaitUrl("/assets");
- });
-
- // search for a element
-
- it("Search Asset Name", () => {
- const initialUrl = cy.url();
- assetSearchPage.typeSearchKeyword("dummy camera 30");
- assetSearchPage.pressEnter();
- assetSearchPage.verifyUrlChanged(initialUrl);
- });
-
- // scan a asset qr code
-
- it("Scan Asset QR", () => {
- assetQRScanPage.scanAssetQR();
- });
-
- // filter the asset and verify the badges are there
-
- it("Filter Asset", () => {
- assetFilters.filterAssets(
- "Dummy Facility 1",
- "INTERNAL",
- "ACTIVE",
- "ONVIF Camera"
- );
- });
-
- // Verify the pagination in the page
-
- it("Next/Previous Page", () => {
- assetPagination.navigateToNextPage();
- assetPagination.navigateToPreviousPage();
- });
-
- afterEach(() => {
- cy.saveLocalStorage();
- });
-});
diff --git a/cypress/e2e/assets_spec/assets_creation.cy.ts b/cypress/e2e/assets_spec/assets_creation.cy.ts
new file mode 100644
index 00000000000..3e7b24eeca6
--- /dev/null
+++ b/cypress/e2e/assets_spec/assets_creation.cy.ts
@@ -0,0 +1,178 @@
+///
+import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress";
+import { AssetPage } from "../../pageobject/Asset/AssetCreation";
+import { v4 as uuidv4 } from "uuid";
+import LoginPage from "../../pageobject/Login/LoginPage";
+import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch";
+
+describe("Asset", () => {
+ const assetPage = new AssetPage();
+ const assetSearchPage = new AssetSearchPage();
+ const loginPage = new LoginPage();
+ const phone_number = "9999999999";
+ const serialNumber = Math.floor(Math.random() * 10 ** 10).toString();
+
+ before(() => {
+ loginPage.loginAsDisctrictAdmin();
+ cy.saveLocalStorage();
+ });
+
+ beforeEach(() => {
+ cy.restoreLocalStorage();
+ cy.awaitUrl("/assets");
+ });
+
+ it("Verify asset creation fields throws error if empty", () => {
+ assetPage.createAsset();
+ assetPage.selectFacility("Dummy Facility 1");
+ assetPage.clickCreateAsset();
+
+ assetPage.verifyEmptyAssetNameError();
+ assetPage.verifyEmptyAssetTypeError();
+ assetPage.verifyEmptyLocationError();
+ assetPage.verifyEmptyStatusError();
+ assetPage.verifyEmptyPhoneError();
+ });
+
+ //Create an asset
+
+ it("Create an Asset", () => {
+ assetPage.createAsset();
+ assetPage.selectFacility("Dummy Facility 1");
+ assetPage.selectLocation("Camera Loc");
+ assetPage.selectAssetType("Internal");
+ assetPage.selectAssetClass("ONVIF Camera");
+
+ const qr_id_1 = uuidv4();
+
+ assetPage.enterAssetDetails(
+ "New Test Asset 1",
+ "Test Description",
+ "Working",
+ qr_id_1,
+ "Manufacturer's Name",
+ "2025-12-25",
+ "Customer Support's Name",
+ phone_number,
+ "email@support.com",
+ "Vendor's Name",
+ serialNumber,
+ "25122021",
+ "Test note for asset creation!"
+ );
+
+ assetPage.clickCreateAddMore();
+ assetPage.verifySuccessNotification("Asset created successfully");
+
+ const qr_id_2 = uuidv4();
+
+ assetPage.selectLocation("Camera Loc");
+ assetPage.selectAssetType("Internal");
+ assetPage.selectAssetClass("ONVIF Camera");
+ assetPage.enterAssetDetails(
+ "New Test Asset 2",
+ "Test Description",
+ "Working",
+ qr_id_2,
+ "Manufacturer's Name",
+ "2025-12-25",
+ "Customer Support's Name",
+ phone_number,
+ "email@support.com",
+ "Vendor's Name",
+ serialNumber,
+ "25122021",
+ "Test note for asset creation!"
+ );
+
+ assetPage.interceptAssetCreation();
+ assetPage.clickCreateAsset();
+ assetPage.verifyAssetCreation();
+ assetPage.verifySuccessNotification("Asset created successfully");
+
+ assetSearchPage.typeSearchKeyword("New Test Asset 2");
+ assetSearchPage.pressEnter();
+ assetSearchPage.verifyAssetIsPresent("New Test Asset 2");
+ });
+
+ it("Edit an Asset", () => {
+ assetPage.openCreatedAsset();
+
+ const qr_id = uuidv4();
+
+ assetPage.editAssetDetails(
+ "New Test Asset Edited",
+ "Test Description Edited",
+ qr_id,
+ "Manufacturer's Name Edited",
+ "Customer Support's Name Edited",
+ "Vendor's Name Edited",
+ "Test note for asset creation edited!",
+ "25122021"
+ );
+
+ assetPage.clickUpdateAsset();
+
+ assetPage.verifySuccessNotification("Asset updated successfully");
+ });
+
+ it("Verify Editted Asset", () => {
+ assetSearchPage.typeSearchKeyword("New Test Asset Edited");
+ assetSearchPage.pressEnter();
+ assetSearchPage.verifyAssetIsPresent("New Test Asset Edited");
+ });
+
+ it("Configure an asset", () => {
+ assetPage.openCreatedAsset();
+ assetPage.spyAssetConfigureApi();
+ assetPage.configureAsset(
+ "Host name",
+ "192.168.1.64",
+ "remote_user",
+ "2jCkrCRSeahzKEU",
+ "d5694af2-21e2-4a39-9bad-2fb98d9818bd"
+ );
+ assetPage.clickConfigureAsset();
+ assetPage.verifyAssetConfiguration(200);
+ });
+
+ it("Add an vital monitor asset and configure it", () => {
+ assetPage.createAsset();
+ assetPage.selectFacility("Dummy Facility 1");
+ assetPage.selectLocation("Camera Loc");
+ assetPage.selectAssetType("Internal");
+ assetPage.selectAssetClass("HL7 Vitals Monitor");
+
+ const qr_id_1 = uuidv4();
+
+ assetPage.enterAssetDetails(
+ "New Test Asset Vital",
+ "Test Description",
+ "Working",
+ qr_id_1,
+ "Manufacturer's Name",
+ "2025-12-25",
+ "Customer Support's Name",
+ phone_number,
+ "email@support.com",
+ "Vendor's Name",
+ serialNumber,
+ "25122021",
+ "Test note for asset creation!"
+ );
+ assetPage.interceptAssetCreation();
+ assetPage.clickCreateAsset();
+ assetPage.verifyAssetCreation();
+
+ assetSearchPage.typeSearchKeyword("New Test Asset Vital");
+ assetSearchPage.pressEnter();
+
+ assetPage.openCreatedAsset();
+ assetPage.configureVitalAsset("Host name", "192.168.1.64");
+ assetPage.clickConfigureVital();
+ });
+
+ afterEach(() => {
+ cy.saveLocalStorage();
+ });
+});
diff --git a/cypress/e2e/assets_spec/assets_manage.cy.ts b/cypress/e2e/assets_spec/assets_manage.cy.ts
index d04a7733c0d..1f89facd0a3 100644
--- a/cypress/e2e/assets_spec/assets_manage.cy.ts
+++ b/cypress/e2e/assets_spec/assets_manage.cy.ts
@@ -1,15 +1,17 @@
-///
+import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress";
import { AssetPage } from "../../pageobject/Asset/AssetCreation";
-import { v4 as uuidv4 } from "uuid";
import LoginPage from "../../pageobject/Login/LoginPage";
import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch";
+import FacilityPage from "../../pageobject/Facility/FacilityCreation";
+import { AssetFilters } from "../../pageobject/Asset/AssetFilters";
describe("Asset", () => {
const assetPage = new AssetPage();
- const assetSearchPage = new AssetSearchPage();
const loginPage = new LoginPage();
- const phone_number = "9999999999";
- const serialNumber = Math.floor(Math.random() * 10 ** 10).toString();
+ const facilityPage = new FacilityPage();
+ const assetSearchPage = new AssetSearchPage();
+ const assetFilters = new AssetFilters();
+ const fillFacilityName = "Dummy Facility 1";
before(() => {
loginPage.loginAsDisctrictAdmin();
@@ -21,102 +23,28 @@ describe("Asset", () => {
cy.awaitUrl("/assets");
});
- it("Verify asset creation fields throws error if empty", () => {
- assetPage.createAsset();
- assetPage.selectFacility("Dummy Facility 1");
- assetPage.clickCreateAsset();
-
- assetPage.verifyEmptyAssetNameError();
- assetPage.verifyEmptyAssetTypeError();
- assetPage.verifyEmptyLocationError();
- assetPage.verifyEmptyStatusError();
- assetPage.verifyEmptyPhoneError();
- });
-
- //Create an asset
-
- it("Create an Asset", () => {
- assetPage.createAsset();
- assetPage.selectFacility("Dummy Facility 1");
- assetPage.selectLocation("Camera Loc");
- assetPage.selectAssetType("Internal");
- assetPage.selectAssetClass("ONVIF Camera");
-
- const qr_id_1 = uuidv4();
-
- assetPage.enterAssetDetails(
- "New Test Asset 1",
- "Test Description",
- "Working",
- qr_id_1,
- "Manufacturer's Name",
- "2025-12-25",
- "Customer Support's Name",
- phone_number,
- "email@support.com",
- "Vendor's Name",
- serialNumber,
- "25122021",
- "Test note for asset creation!"
- );
-
- assetPage.clickCreateAddMore();
- assetPage.verifySuccessNotification("Asset created successfully");
-
- const qr_id_2 = uuidv4();
-
- assetPage.selectLocation("Camera Loc");
- assetPage.selectAssetType("Internal");
- assetPage.selectAssetClass("ONVIF Camera");
- assetPage.enterAssetDetails(
- "New Test Asset 2",
- "Test Description",
- "Working",
- qr_id_2,
- "Manufacturer's Name",
- "2025-12-25",
- "Customer Support's Name",
- phone_number,
- "email@support.com",
- "Vendor's Name",
- serialNumber,
- "25122021",
- "Test note for asset creation!"
- );
-
- assetPage.clickCreateAsset();
- assetPage.verifySuccessNotification("Asset created successfully");
-
- assetSearchPage.typeSearchKeyword("New Test Asset 2");
- assetSearchPage.pressEnter();
- assetSearchPage.verifyAssetIsPresent("New Test Asset 2");
- });
-
- it("Edit an Asset", () => {
- assetPage.openCreatedAsset();
-
- const qr_id = uuidv4();
-
- assetPage.editAssetDetails(
- "New Test Asset Edited",
- "Test Description Edited",
- qr_id,
- "Manufacturer's Name Edited",
- "Customer Support's Name Edited",
- "Vendor's Name Edited",
- "Test note for asset creation edited!"
- );
-
- assetPage.clickUpdateAsset();
-
- assetPage.verifySuccessNotification("Asset updated successfully");
- });
-
it("Delete an Asset", () => {
assetPage.openCreatedAsset();
+ assetPage.interceptDeleteAssetApi();
assetPage.deleteAsset();
+ assetPage.verifyDeleteStatus();
+ });
- assetPage.verifySuccessNotification("Asset deleted successfully");
+ it("Verify Facility Asset Page Redirection", () => {
+ cy.visit("/facility");
+ assetSearchPage.typeSearchKeyword(fillFacilityName);
+ assetSearchPage.pressEnter();
+ facilityPage.verifyFacilityBadgeContent(fillFacilityName);
+ facilityPage.visitAlreadyCreatedFacility();
+ facilityPage.clickManageFacilityDropdown();
+ facilityPage.clickCreateAssetFacilityOption();
+ facilityPage.verifyfacilitycreateassetredirection();
+ facilityPage.verifyassetfacilitybackredirection();
+ facilityPage.clickManageFacilityDropdown();
+ facilityPage.clickviewAssetFacilityOption();
+ facilityPage.verifyfacilityviewassetredirection();
+ assetFilters.assertFacilityText(fillFacilityName);
+ facilityPage.verifyassetfacilitybackredirection();
});
afterEach(() => {
diff --git a/cypress/e2e/facility_spec/facility.cy.ts b/cypress/e2e/facility_spec/facility.cy.ts
index f2e555bb58a..f2ff847c9d9 100644
--- a/cypress/e2e/facility_spec/facility.cy.ts
+++ b/cypress/e2e/facility_spec/facility.cy.ts
@@ -1,12 +1,15 @@
// FacilityCreation
+import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress";
import FacilityPage from "../../pageobject/Facility/FacilityCreation";
+import LoginPage from "../../pageobject/Login/LoginPage";
describe("Facility Creation", () => {
let facilityUrl: string;
const facilityPage = new FacilityPage();
+ const loginPage = new LoginPage();
before(() => {
- cy.loginByApi("devdistrictadmin", "Coronasafe@123");
+ loginPage.loginAsDisctrictAdmin();
cy.saveLocalStorage();
});
@@ -36,14 +39,9 @@ describe("Facility Creation", () => {
facilityPage.selectAreaOfSpecialization("General Medicine");
facilityPage.fillDoctorCount("5");
facilityPage.saveAndExitDoctorForm();
-
- cy.url().then((initialUrl) => {
- cy.get("button#save-and-exit").should("not.exist");
- cy.url()
- .should("not.equal", initialUrl)
- .then((newUrl) => {
- facilityUrl = newUrl;
- });
+ facilityPage.verifyfacilitynewurl();
+ cy.url().then((newUrl) => {
+ facilityUrl = newUrl;
});
});
@@ -51,6 +49,7 @@ describe("Facility Creation", () => {
facilityPage.visitUpdateFacilityPage(facilityUrl);
facilityPage.clickManageFacilityDropdown();
facilityPage.clickUpdateFacilityOption();
+ facilityPage.clickUpdateFacilityType();
facilityPage.fillFacilityName("cypress facility updated");
facilityPage.fillAddress("Cypress Facility Updated Address");
facilityPage.fillOxygenCapacity("100");
@@ -61,6 +60,22 @@ describe("Facility Creation", () => {
cy.url().should("not.include", "/update");
});
+ it("Configure the existing facility", () => {
+ facilityPage.visitUpdateFacilityPage(facilityUrl);
+ facilityPage.clickManageFacilityDropdown();
+ facilityPage.clickConfigureFacilityOption();
+ facilityPage.fillMiddleWareAddress("dev_middleware.coronasafe.live");
+ facilityPage.clickupdateMiddleWare();
+ facilityPage.verifySuccessNotification("Facility updated successfully");
+ });
+
+ it("Delete a facility", () => {
+ facilityPage.visitUpdateFacilityPage(facilityUrl);
+ facilityPage.clickManageFacilityDropdown();
+ facilityPage.clickDeleteFacilityOption();
+ facilityPage.confirmDeleteFacility();
+ });
+
afterEach(() => {
cy.saveLocalStorage();
});
diff --git a/cypress/e2e/facility_spec/inventory.cy.ts b/cypress/e2e/facility_spec/inventory.cy.ts
index 91c6d36466f..c28035dd885 100644
--- a/cypress/e2e/facility_spec/inventory.cy.ts
+++ b/cypress/e2e/facility_spec/inventory.cy.ts
@@ -1,8 +1,13 @@
import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress";
+import FacilityPage from "../../pageobject/Facility/FacilityCreation";
+import LoginPage from "../../pageobject/Login/LoginPage";
describe("Inventory Management Section", () => {
+ const facilityPage = new FacilityPage();
+ const loginPage = new LoginPage();
+
before(() => {
- cy.loginByApi("devdistrictadmin", "Coronasafe@123");
+ loginPage.loginAsDisctrictAdmin();
cy.saveLocalStorage();
});
@@ -10,23 +15,16 @@ describe("Inventory Management Section", () => {
cy.restoreLocalStorage();
cy.awaitUrl("/");
cy.viewport(1280, 720);
- cy.intercept("GET", "**/api/v1/facility/**").as("getFacilities");
- cy.get("[id='facility-details']").first().click();
- cy.wait("@getFacilities").its("response.statusCode").should("eq", 200);
- cy.get("#manage-facility-dropdown button").should("be.visible");
- cy.get("[id='manage-facility-dropdown']").scrollIntoView().click();
- cy.get("[id=inventory-management]").click();
});
it("Adds Inventory", () => {
- cy.contains("Manage Inventory").click();
- cy.get("div#id").click();
- cy.get("div#id ul li").contains("Liquid Oxygen").click();
- cy.get("div#isIncoming").click();
- cy.get("div#isIncoming ul li").contains("Add Stock").click();
- cy.get("[name='quantity']").type("120");
- cy.get("button").contains("Add/Update Inventory").click();
- cy.verifyNotification("Inventory created successfully");
+ facilityPage.visitAlreadyCreatedFacility();
+ facilityPage.clickManageFacilityDropdown();
+ facilityPage.clickInventoryManagementOption();
+ facilityPage.clickManageInventory();
+ facilityPage.fillInventoryDetails("Liquid Oxygen", "Add Stock", "120");
+ facilityPage.clickAddInventory();
+ facilityPage.verifySuccessNotification("Inventory created successfully");
});
afterEach(() => {
diff --git a/cypress/e2e/patient_spec/patient_crud.cy.ts b/cypress/e2e/patient_spec/patient_crud.cy.ts
index ff8ffaefcfc..b55732fa440 100644
--- a/cypress/e2e/patient_spec/patient_crud.cy.ts
+++ b/cypress/e2e/patient_spec/patient_crud.cy.ts
@@ -1,12 +1,13 @@
import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress";
-
-const username = "devdistrictadmin";
-const password = "Coronasafe@123";
-const phone_number = "9" + Math.floor(100000000 + Math.random() * 900000000);
-const emergency_phone_number =
- "9" + Math.floor(100000000 + Math.random() * 900000000);
+import LoginPage from "../../pageobject/Login/LoginPage";
+import { PatientPage } from "../../pageobject/Patient/PatientCreation";
+import { UpdatePatientPage } from "../../pageobject/Patient/PatientUpdate";
+import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation";
+import {
+ emergency_phone_number,
+ phone_number,
+} from "../../pageobject/constants";
const yearOfBirth = "2023";
-let patient_url = "";
const calculateAge = () => {
const currentYear = new Date().getFullYear();
@@ -14,8 +15,13 @@ const calculateAge = () => {
};
describe("Patient Creation with consultation", () => {
+ const loginPage = new LoginPage();
+ const patientPage = new PatientPage();
+ const updatePatientPage = new UpdatePatientPage();
+ const patientConsultationPage = new PatientConsultationPage();
+
before(() => {
- cy.loginByApi(username, password);
+ loginPage.loginAsDisctrictAdmin();
cy.saveLocalStorage();
});
@@ -25,199 +31,106 @@ describe("Patient Creation with consultation", () => {
});
it("Create a new patient with no consultation", () => {
- cy.get("#add-patient-details").should("be.visible");
- cy.get("#add-patient-details").click();
- cy.get("input[name='facilities']")
- .type("cypress facility")
- .then(() => {
- cy.get("[role='option']").first().click();
- });
- cy.get("button").should("contain", "Select");
- cy.get("button").get("#submit").click();
- cy.get("#phone_number-div").type(phone_number);
- cy.get("#emergency_phone_number-div").type(emergency_phone_number);
- cy.get("#date_of_birth").should("be.visible").click();
- cy.get("#date-input").click().type("01082023");
- cy.get("[data-testid=name] input").type("Test E2E User");
- cy.get("[data-testid=Gender] button")
- .click()
- .then(() => {
- cy.get("[role='option']").contains("Male").click();
- });
- cy.get("[data-testid=current-address] textarea").type(
- "Test Patient Address"
+ patientPage.createPatient();
+ patientPage.selectFacility("dummy facility");
+ patientPage.enterPatientDetails(
+ phone_number,
+ emergency_phone_number,
+ "Test E2E User",
+ "Male",
+ "Test Patient Address",
+ "682001",
+ "1: PAZHAMTHOTTAM",
+ "O+",
+ "01012001"
);
- cy.get("[data-testid=permanent-address] input").check();
- cy.get("#pincode").type("682001");
- cy.get("[data-testid=localbody] button")
- .click()
- .then(() => {
- cy.get("[role='option']").first().click();
- });
- cy.get("[data-testid=ward-respective-lsgi] button")
- .click()
- .then(() => {
- cy.get("[role='option']").contains("1: PAZHAMTHOTTAM").click();
- });
- cy.get("[name=medical_history_check_1]").check();
- cy.get("[data-testid=blood-group] button")
- .click()
- .then(() => {
- cy.get("[role='option']").contains("O+").click();
- });
- cy.get("button[data-testid='submit-button']").click();
+ patientPage.clickCreatePatient();
- cy.get("h2").should("contain", "Create Consultation");
- cy.url().should("include", "/patient");
- cy.url().then((url) => {
- cy.log(url);
- patient_url = url.split("/").slice(0, -1).join("/");
- cy.log(patient_url);
- });
+ patientPage.verifyPatientIsCreated();
+ patientPage.saveCreatedPatientUrl();
});
it("Patient Detail verification post registration", () => {
- cy.log(patient_url);
- cy.awaitUrl(patient_url);
- cy.url().should("include", "/facility/");
- cy.get("[data-testid=patient-dashboard]").should("contain", calculateAge());
- cy.get("[data-testid=patient-dashboard]").should(
- "contain",
- "Test E2E User"
+ patientPage.interceptFacilities();
+ patientPage.visitCreatedPatient();
+ patientPage.verifyStatusCode();
+ const age = calculateAge();
+ patientPage.verifyPatientDetails(
+ age,
+ "Test E2E User",
+ phone_number,
+ emergency_phone_number,
+ yearOfBirth,
+ "O+"
);
- cy.get("[data-testid=patient-dashboard]").should("contain", phone_number);
- cy.get("[data-testid=patient-dashboard]").should(
- "contain",
- emergency_phone_number
- );
- cy.get("[data-testid=patient-dashboard]").should("contain", yearOfBirth);
- cy.get("[data-testid=patient-dashboard]").should("contain", "O+");
});
it("Edit the patient details", () => {
- cy.intercept("GET", "**/facility/*/patient/**").as("getFacilities");
- cy.awaitUrl(patient_url + "/update");
- cy.wait("@getFacilities").its("response.statusCode").should("eq", 200);
- cy.wait(10000);
- cy.get("#address").scrollIntoView();
- cy.get("#address").should("be.visible");
- cy.get("#address").type("Test Patient Address Edited");
- cy.get("[data-testid=name] input").clear();
- cy.get("[data-testid=name] input").type("Test E2E User Edited");
- cy.get("#phone_number-div").clear();
- cy.get("#phone_number-div").type("+91").type(phone_number);
- cy.get("#emergency_phone_number-div").clear();
- cy.get("#emergency_phone_number-div")
- .type("+91")
- .type(emergency_phone_number);
- cy.get("#present_health").type("Severe Cough");
- cy.get("#ongoing_medication").type("Paracetamol");
- cy.get("#allergies").type("Dust");
- cy.get("[name=medical_history_check_1]").uncheck();
- cy.get("[name=medical_history_check_2]").check();
- cy.get("#medical_history_2").type("2 months ago");
- cy.get("[name=medical_history_check_3]").check();
- cy.get("#medical_history_3").type("1 month ago");
- cy.get("button").get("[data-testid=add-insurance-button]").click();
- cy.get("#subscriber_id").type("SUB123");
- cy.get("#policy_id").type("P123");
- cy.get("#insurer_id").type("GICOFINDIA");
- cy.get("#insurer_name").type("GICOFINDIA");
- cy.get("[data-testid=blood-group] button")
- .click()
- .then(() => {
- cy.get("[role='option']").contains("O+").click();
- });
- cy.get("button[data-testid='submit-button']").click();
- cy.url().should("include", "/patient");
- cy.url().then((url) => {
- cy.log(url);
- patient_url = url.split("/").slice(0, -1).join("/");
- cy.log(patient_url);
- });
+ patientPage.interceptFacilities();
+ patientPage.visitUpdatePatientUrl();
+ patientPage.verifyStatusCode();
+ updatePatientPage.enterPatientDetails(
+ "Test E2E User Edited",
+ "O+",
+ phone_number,
+ emergency_phone_number,
+ "Test Patient Address Edited",
+ "Severe Cough",
+ "Paracetamol",
+ "Dust",
+ ["2 months ago", "1 month ago"],
+ "SUB123",
+ "P123",
+ "GICOFINDIA",
+ "GICOFINDIA"
+ );
+ updatePatientPage.clickUpdatePatient();
+
+ updatePatientPage.verifyPatientUpdated();
+ updatePatientPage.saveUpdatedPatientUrl();
});
it("Patient Detail verification post edit", () => {
- cy.log(patient_url);
- cy.awaitUrl(patient_url);
- cy.url().should("include", "/facility/");
- cy.get("[data-testid=patient-dashboard]").should(
- "contain",
- "Test E2E User Edited"
- );
- cy.get("[data-testid=patient-dashboard]").should("contain", phone_number);
- const patientDetails_values: string[] = [
+ patientPage.interceptFacilities();
+ updatePatientPage.visitUpdatedPatient();
+ patientPage.verifyStatusCode();
+
+ updatePatientPage.verifyPatientDetails(
+ "Test E2E User Edited",
+ phone_number,
"Severe Cough",
"Paracetamol",
- "Dust",
- "Diabetes",
- "2 months ago",
- "Heart Disease",
- "1 month ago",
- ];
-
- patientDetails_values.forEach((value) => {
- cy.get("[data-testid=patient-details]").should("contain", value);
- });
+ "Dust"
+ );
});
it("Create a New consultation to existing patient", () => {
- cy.intercept("GET", "**/api/v1/patient/**").as("getFacilities");
- cy.visit(patient_url + "/consultation");
- cy.wait("@getFacilities").its("response.statusCode").should("eq", 200);
- cy.get("#history_of_present_illness").scrollIntoView;
- cy.get("#history_of_present_illness").should("be.visible");
- cy.get("#history_of_present_illness").click().type("histroy");
- cy.get("#consultation_status")
- .click()
- .then(() => {
- cy.get("[role='option']").contains("Out-patient (walk in)").click();
- });
- cy.get("#symptoms")
- .click()
- .then(() => {
- cy.get("[role='option']").contains("ASYMPTOMATIC").click();
- });
- cy.get("#symptoms").click();
+ patientPage.interceptFacilities();
+ updatePatientPage.visitConsultationPage();
+ patientPage.verifyStatusCode();
+ patientConsultationPage.fillIllnessHistory("history");
+ patientConsultationPage.selectConsultationStatus("Out-patient (walk in)");
+ patientConsultationPage.selectSymptoms("ASYMPTOMATIC");
+
+ patientConsultationPage.enterConsultationDetails(
+ "Examination details and Clinical conditions",
+ "70",
+ "170",
+ "IP007",
+ "generalnote",
+ "Dev Doctor"
+ );
+ patientConsultationPage.submitConsultation();
- cy.get("#examination_details")
- .click()
- .type("Examination details and Clinical conditions");
- cy.get("#weight").click().type("70");
- cy.get("#height").click().type("170");
- cy.get("#patient_no").type("IP007");
- cy.get(
- "#icd11_diagnoses_object input[placeholder='Select'][role='combobox']"
- )
- .click()
- .type("1A");
- cy.wait(1000);
- cy.get("#icd11_diagnoses_object [role='option']")
- .contains("1A03 Intestinal infections due to Escherichia coli")
- .click();
- cy.get("#consultation_notes").click().type("generalnote");
- cy.get("#verified_by").click().type("generalnote");
- cy.get("#submit").click();
// Below code for the prescription module only present while creating a new consultation
- cy.contains("button", "Add Prescription Medication")
- .should("be.visible")
- .click();
- cy.intercept("GET", "**/api/v1/medibase/**").as("getFacilities");
- cy.get(
- "div#medicine_object input[placeholder='Select'][role='combobox']"
- ).click();
- cy.wait("@getFacilities").its("response.statusCode").should("eq", 200);
- cy.get("div#medicine_object input[placeholder='Select'][role='combobox']")
- .click()
- .type("dolo{enter}");
- cy.get("#dosage").type("3", { force: true });
- cy.get("#frequency")
- .click()
- .then(() => {
- cy.get("div#frequency [role='option']").contains("Twice daily").click();
- });
- cy.get("button#submit").should("be.visible").click();
- cy.get("[data-testid='return-to-patient-dashboard']").click();
+ patientConsultationPage.clickAddPrescription();
+ patientConsultationPage.interceptMediaBase();
+ patientConsultationPage.selectMedicinebox();
+ patientConsultationPage.waitForMediabaseStatusCode();
+ patientConsultationPage.prescribeMedicine();
+ patientConsultationPage.enterDosage("3");
+ patientConsultationPage.selectDosageFrequency("Twice daily");
+ patientConsultationPage.submitPrescriptionAndReturn();
});
afterEach(() => {
diff --git a/cypress/e2e/resource_spec/resources.cy.ts b/cypress/e2e/resource_spec/resources.cy.ts
index 099e782277a..acf179db120 100644
--- a/cypress/e2e/resource_spec/resources.cy.ts
+++ b/cypress/e2e/resource_spec/resources.cy.ts
@@ -1,8 +1,17 @@
import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress";
+import LoginPage from "../../pageobject/Login/LoginPage";
+import ResourcePage from "../../pageobject/Resource/ResourcePage";
+import FacilityPage from "../../pageobject/Facility/FacilityCreation";
describe("Resource Page", () => {
+ let createdResource: string;
+ const loginPage = new LoginPage();
+ const resourcePage = new ResourcePage();
+ const facilityPage = new FacilityPage();
+ const phone_number = "9999999999";
+
before(() => {
- cy.loginByApi("devdistrictadmin", "Coronasafe@123");
+ loginPage.loginAsDisctrictAdmin();
cy.saveLocalStorage();
});
@@ -11,36 +20,65 @@ describe("Resource Page", () => {
cy.awaitUrl("/resource");
});
- it("checks if all download button works", () => {
- cy.get("svg.care-svg-icon__baseline.care-l-export").each(($button) => {
- cy.intercept(/\/api\/v1\/resource/).as("resource_download");
- cy.wrap($button).click({ force: true });
- cy.wait("@resource_download").then((interception) => {
- expect(interception.response.statusCode).to.equal(200);
- });
- });
+ it("Checks if all download button works", () => {
+ resourcePage.verifyDownloadButtonWorks();
});
- it("switch between active/completed", () => {
- cy.intercept(/\/api\/v1\/resource/).as("resource");
- cy.contains("Completed").click();
- cy.wait("@resource").then((interception) => {
- expect(interception.response.statusCode).to.equal(200);
- });
- cy.contains("Active").should("have.class", "text-primary-500");
- cy.contains("Completed").should("have.class", "text-white");
- cy.intercept(/\/api\/v1\/resource/).as("resource");
- cy.contains("Active").click();
- cy.wait("@resource").then((interception) => {
- expect(interception.response.statusCode).to.equal(200);
+ it("Switch between active/completed", () => {
+ resourcePage.spyResourceApi();
+ resourcePage.clickCompletedResources();
+ resourcePage.verifyCompletedResources();
+ resourcePage.spyResourceApi();
+ resourcePage.clickActiveResources();
+ resourcePage.verifyActiveResources();
+ });
+
+ it("Switch between list view and board view", () => {
+ resourcePage.clickListViewButton();
+ resourcePage.clickBoardViewButton();
+ });
+
+ it("Create a resource request", () => {
+ cy.visit("/facility");
+ cy.get("#search").click().type("dummy facility 1");
+ cy.intercept("GET", "**/api/v1/facility/**").as("loadFacilities");
+ cy.get("#facility-details").click();
+ cy.wait("@loadFacilities").its("response.statusCode").should("eq", 200);
+ facilityPage.clickManageFacilityDropdown();
+ facilityPage.clickResourceRequestOption();
+ facilityPage.fillResourceRequestDetails(
+ "Test User",
+ phone_number,
+ "Dummy",
+ "Test title",
+ "10",
+ "Test description"
+ );
+ facilityPage.clickSubmitRequestButton();
+ facilityPage.verifySuccessNotification(
+ "Resource request created successfully"
+ );
+ facilityPage.verifyresourcenewurl();
+ cy.url().then((url) => {
+ createdResource = url;
});
- cy.contains("Active").should("have.class", "text-white");
- cy.contains("Completed").should("have.class", "text-primary-500");
});
- it("switch between list view and board view", () => {
- cy.contains("List View").click();
- cy.contains("Board View").click();
+ it("Update the status of resource", () => {
+ cy.visit(createdResource);
+ resourcePage.clickUpdateStatus();
+ resourcePage.updateStatus("APPROVED");
+ resourcePage.clickSubmitButton();
+ resourcePage.verifySuccessNotification(
+ "Resource request updated successfully"
+ );
+ });
+
+ it("Post comment for a resource", () => {
+ cy.visit(createdResource);
+ resourcePage.addCommentForResource("Test comment");
+ resourcePage.clickPostCommentButton();
+ resourcePage.verifySuccessNotification("Comment added successfully");
});
afterEach(() => {
diff --git a/cypress/fixtures/sampleAsset.xlsx b/cypress/fixtures/sampleAsset.xlsx
new file mode 100644
index 00000000000..f8e234ce447
Binary files /dev/null and b/cypress/fixtures/sampleAsset.xlsx differ
diff --git a/cypress/pageobject/Asset/AssetCreation.ts b/cypress/pageobject/Asset/AssetCreation.ts
index d24c93d0197..b939c31405f 100644
--- a/cypress/pageobject/Asset/AssetCreation.ts
+++ b/cypress/pageobject/Asset/AssetCreation.ts
@@ -1,4 +1,5 @@
// assetPage.ts
+import { cy, expect } from "local-cypress";
export class AssetPage {
createAsset() {
@@ -74,6 +75,14 @@ export class AssetPage {
cy.get("[data-testid=asset-notes-input] textarea").type(notes);
}
+ interceptAssetCreation() {
+ cy.intercept("POST", "**/api/v1/asset/").as("createAsset");
+ }
+
+ verifyAssetCreation() {
+ cy.wait("@createAsset").its("response.statusCode").should("eq", 201);
+ }
+
clickCreateAsset() {
cy.get("#submit").contains("Create Asset").click();
}
@@ -87,7 +96,9 @@ export class AssetPage {
}
openCreatedAsset() {
+ cy.intercept("GET", "**/api/v1/asset/**").as("getAsset");
cy.get("[data-testid=created-asset-list]").first().click();
+ cy.wait("@getAsset").its("response.statusCode").should("eq", 200);
}
editAssetDetails(
@@ -97,7 +108,8 @@ export class AssetPage {
manufacturer: string,
supportName: string,
vendorName: string,
- notes: string
+ notes: string,
+ lastServicedOn: string
) {
cy.get("[data-testid=asset-update-button]").click();
cy.get("[data-testid=asset-name-input] input").clear().type(name);
@@ -114,18 +126,71 @@ export class AssetPage {
cy.get("[data-testid=asset-vendor-name-input] input")
.clear()
.type(vendorName);
+ cy.get(
+ "[data-testid=asset-last-serviced-on-input] input[type='text']"
+ ).click();
+ cy.get("#date-input").click().type(lastServicedOn);
cy.get("[data-testid=asset-notes-input] textarea").clear().type(notes);
}
+ configureAsset(
+ hostName: string,
+ localIp: string,
+ userName: string,
+ password: string,
+ streamUuid: string
+ ) {
+ cy.get("[data-testid=asset-configure-button]").click();
+ cy.get("[name=middleware_hostname]").type(hostName);
+ cy.get("[name=camera_address]").type(localIp);
+ cy.get("[name=username]").type(userName);
+ cy.get("[name=password]").type(password);
+ cy.get("[name=stream_uuid]").type(streamUuid);
+ }
+
+ configureVitalAsset(hostName: string, localIp: string) {
+ cy.get("[data-testid=asset-configure-button]").click();
+ cy.get("#middlewareHostname").type(hostName);
+ cy.get("#localipAddress").type(localIp);
+ }
+
+ spyAssetConfigureApi() {
+ cy.intercept(/\/api\/v1\/asset/).as("asset");
+ }
+
+ verifyAssetConfiguration(statusCode: number) {
+ cy.wait("@asset").then((interception) => {
+ expect(interception.response.statusCode).to.equal(statusCode);
+ });
+ }
+
+ clickConfigureAsset() {
+ cy.get("#submit").contains("Set Configuration").click();
+ }
+
+ clickConfigureVital() {
+ cy.intercept("PATCH", "**/api/v1/asset/**").as("postConfiguration");
+ cy.get("#submit").contains("Save Configuration").click();
+ cy.wait("@postConfiguration").its("response.statusCode").should("eq", 200);
+ }
+
clickUpdateAsset() {
cy.get("#submit").contains("Update").click();
}
+ interceptDeleteAssetApi() {
+ cy.intercept("DELETE", "**/api/v1/asset/**").as("deleteAsset");
+ }
+
deleteAsset() {
cy.get("[data-testid=asset-delete-button]").click();
cy.get("#submit").contains("Confirm").click();
}
+ verifyDeleteStatus() {
+ cy.wait("@deleteAsset").its("response.statusCode").should("eq", 204);
+ }
+
verifyEmptyAssetNameError() {
cy.get("[data-testid=asset-name-input] span").should(
"contain",
@@ -160,4 +225,55 @@ export class AssetPage {
"Please enter valid phone number"
);
}
+
+ selectImportFacility(facilityName: string) {
+ cy.get("input[name='facilities']")
+ .type(facilityName)
+ .then(() => {
+ cy.get("[role='option']").contains(facilityName).click();
+ });
+ }
+
+ selectassetimportbutton() {
+ cy.get("[data-testid=import-asset-button]").click();
+ }
+
+ selectjsonexportbutton() {
+ cy.intercept("GET", "**/api/v1/asset/?json=true**").as("getJsonexport");
+ cy.get("#export-json-option").click();
+ cy.wait("@getJsonexport").then(({ request, response }) => {
+ expect(response.statusCode).to.eq(200);
+ expect(request.url).to.include("json=true");
+ });
+ }
+
+ selectcsvexportbutton() {
+ cy.intercept("GET", "**/api/v1/asset/?csv=true**").as("getCsvexport");
+ cy.get("#export-csv-option").click();
+ cy.wait("@getCsvexport").then(({ request, response }) => {
+ expect(response.statusCode).to.eq(200);
+ expect(request.url).to.include("csv=true");
+ });
+ }
+
+ selectImportOption() {
+ cy.get(".import-assets-button").click();
+ }
+
+ importAssetFile() {
+ cy.get("[data-testid=import-asset-file]")
+ .selectFile("cypress/fixtures/sampleAsset.xlsx", { force: true })
+ .wait(100);
+ }
+
+ selectImportLocation(locationName: string) {
+ cy.get("[data-testid=select-import-location]").click();
+ cy.get("li[role=option]").contains(locationName).click();
+ }
+
+ clickImportAsset() {
+ cy.intercept("POST", "**/api/v1/asset/").as("importAsset");
+ cy.get("#submit").contains("Import").click();
+ cy.wait("@importAsset").its("response.statusCode").should("eq", 201);
+ }
}
diff --git a/cypress/pageobject/Asset/AssetFilters.ts b/cypress/pageobject/Asset/AssetFilters.ts
index 57cc893bdb7..a16b61f4fc5 100644
--- a/cypress/pageobject/Asset/AssetFilters.ts
+++ b/cypress/pageobject/Asset/AssetFilters.ts
@@ -3,7 +3,8 @@ export class AssetFilters {
facilityName: string,
assetType: string,
assetStatus: string,
- assetClass: string
+ assetClass: string,
+ assetLocation: string
) {
cy.contains("Advanced Filters").click();
cy.get("input[name='Facilities']")
@@ -27,6 +28,42 @@ export class AssetFilters {
.then(() => {
cy.get("[role='option']").contains(assetClass).click();
});
+ cy.get("#Facilities-location")
+ .click()
+ .type(assetLocation)
+ .then(() => {
+ cy.get("[role='option']").contains(assetLocation).click();
+ });
cy.contains("Apply").click();
}
+ clearFilters() {
+ cy.intercept("GET", "**/api/v1/asset/**").as("clearAssets");
+ cy.get("#clear-filter").click();
+ cy.wait("@clearAssets").its("response.statusCode").should("eq", 200);
+ cy.url().should("match", /\/assets$/);
+ }
+ clickadvancefilter() {
+ cy.intercept("GET", "**/api/v1/getallfacilities/**").as("advancefilter");
+ cy.get("#advanced-filter").click();
+ cy.wait("@advancefilter").its("response.statusCode").should("eq", 200);
+ }
+ clickslideoverbackbutton() {
+ cy.get("#close-slide-over").click();
+ }
+ // Assertions
+ assertFacilityText(text) {
+ cy.get("[data-testid=Facility]").should("contain", text);
+ }
+ assertAssetTypeText(text) {
+ cy.get("[data-testid='Asset Type']").should("contain", text);
+ }
+ assertAssetClassText(text) {
+ cy.get("[data-testid='Asset Class']").should("contain", text);
+ }
+ assertStatusText(text) {
+ cy.get("[data-testid=Status]").should("contain", text);
+ }
+ assertLocationText(text) {
+ cy.get("[data-testid=Location]").should("contain", text);
+ }
}
diff --git a/cypress/pageobject/Asset/AssetSearch.ts b/cypress/pageobject/Asset/AssetSearch.ts
index 315a414a62b..b1ccb2f71c9 100644
--- a/cypress/pageobject/Asset/AssetSearch.ts
+++ b/cypress/pageobject/Asset/AssetSearch.ts
@@ -1,16 +1,24 @@
export class AssetSearchPage {
typeSearchKeyword(keyword: string) {
- cy.get("[name='search']").type(keyword);
+ cy.get("#search").click().clear();
+ cy.get("#search").click().type(keyword);
}
pressEnter() {
cy.get("[name='search']").type("{enter}");
}
- verifyUrlChanged(initialUrl: string) {
- cy.url().should((currentUrl) => {
- expect(currentUrl).not.to.equal(initialUrl);
- });
+ clickAssetByName(assetName: string) {
+ cy.intercept("GET", "**/api/v1/asset/**").as("clearAssets");
+ cy.get("[data-testid='created-asset-list']").contains(assetName).click();
+ cy.wait("@clearAssets").its("response.statusCode").should("eq", 200);
+ }
+
+ verifyBadgeContent(expectedText: string) {
+ cy.get("[data-testid='Name/Serial No./QR ID']").should(
+ "contain",
+ expectedText
+ );
}
verifyAssetIsPresent(assetName: string) {
@@ -18,4 +26,35 @@ export class AssetSearchPage {
.first()
.should("contain", assetName);
}
+
+ clickUpdateButton() {
+ cy.get("[data-testid='asset-update-button']").contains("Update").click();
+ }
+
+ clearAndTypeQRCode(qrCode: string) {
+ cy.get("#qr_code_id").clear();
+ cy.get("#qr_code_id").click().type(qrCode);
+ }
+
+ clearAndTypeSerialNumber(serialNumber: string) {
+ cy.get("#serial-number").clear();
+ cy.get("#serial-number").click().type(serialNumber);
+ }
+
+ clickAssetSubmitButton() {
+ cy.intercept("GET", "**/api/v1/asset/**").as("getAssets");
+ cy.get("#submit").click();
+ cy.wait("@getAssets").its("response.statusCode").should("eq", 200);
+ }
+
+ visitAssetsPage() {
+ cy.visit("/assets");
+ }
+
+ verifyAssetListContains(dummyCameraText: string) {
+ cy.get("[data-testid='created-asset-list']").should(
+ "contain",
+ dummyCameraText
+ );
+ }
}
diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts
index ab958a49810..0c12d4655fd 100644
--- a/cypress/pageobject/Facility/FacilityCreation.ts
+++ b/cypress/pageobject/Facility/FacilityCreation.ts
@@ -1,7 +1,13 @@
// FacilityPage.ts
+import { cy } from "local-cypress";
+
class FacilityPage {
visitCreateFacilityPage() {
+ cy.intercept("GET", "**/facility/create").as("getCreateFacilities");
cy.visit("/facility/create");
+ cy.wait("@getCreateFacilities")
+ .its("response.statusCode")
+ .should("eq", 200);
}
visitUpdateFacilityPage(url: string) {
@@ -11,6 +17,14 @@ class FacilityPage {
cy.get("#manage-facility-dropdown button").should("be.visible");
}
+ clickUpdateFacilityType() {
+ cy.get("#facility_type")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").contains("Request Approving Center").click();
+ });
+ }
+
fillFacilityName(name: string) {
cy.get("#name").clear().type(name);
}
@@ -86,10 +100,13 @@ class FacilityPage {
}
saveAndExitDoctorForm() {
+ cy.intercept("GET", "**/api/v1/facility/**").as("createFacilities");
cy.get("button#save-and-exit").click();
+ cy.wait("@createFacilities").its("response.statusCode").should("eq", 200);
}
clickManageFacilityDropdown() {
+ cy.get("#manage-facility-dropdown button").scrollIntoView();
cy.get("#manage-facility-dropdown button")
.contains("Manage Facility")
.click();
@@ -99,6 +116,45 @@ class FacilityPage {
cy.get("#update-facility").contains("Update Facility").click();
}
+ clickConfigureFacilityOption() {
+ cy.get("#configure-facility").contains("Configure Facility").click();
+ }
+
+ clickCreateAssetFacilityOption() {
+ cy.get("#create-assets").contains("Create Asset").click();
+ }
+
+ clickviewAssetFacilityOption() {
+ cy.get("#view-assets").contains("View Assets").click();
+ }
+
+ clickInventoryManagementOption() {
+ cy.get("#inventory-management", { timeout: 10000 }).should("be.visible");
+ cy.get("#inventory-management").click();
+ }
+
+ clickResourceRequestOption() {
+ cy.get("#resource-request").contains("Resource Request").click();
+ }
+
+ clickDeleteFacilityOption() {
+ cy.get("#delete-facility").contains("Delete Facility").click();
+ }
+
+ verifyfacilitynewurl() {
+ cy.url().should("match", /facility\/[a-z\d-]+/);
+ }
+
+ verifyresourcenewurl() {
+ cy.url().should("match", /resource\/[a-z\d-]+/);
+ }
+
+ confirmDeleteFacility() {
+ cy.intercept("DELETE", "**/api/v1/facility/**").as("deleteFacility");
+ cy.get("#submit").contains("Delete").click();
+ cy.wait("@deleteFacility").its("response.statusCode").should("eq", 403);
+ }
+
selectLocation(location: string) {
cy.get("span > svg.care-svg-icon__baseline.care-l-map-marker").click();
cy.intercept("https://maps.googleapis.com/maps/api/mapsjs/*").as("mapApi");
@@ -106,6 +162,101 @@ class FacilityPage {
cy.get("input#pac-input").type(location).type("{enter}");
cy.get("div#map-close").click();
}
+
+ fillMiddleWareAddress(url: string) {
+ cy.get("#middleware_address").type(url);
+ }
+
+ clickupdateMiddleWare() {
+ cy.intercept("PATCH", "**/api/v1/facility/**").as("updateMiddleWare");
+ cy.get("button#submit").first().click();
+ cy.wait("@updateMiddleWare").its("response.statusCode").should("eq", 200);
+ }
+
+ verifySuccessNotification(message: string) {
+ cy.verifyNotification(message);
+ }
+
+ visitAlreadyCreatedFacility() {
+ cy.intercept("GET", "**/api/v1/facility/**").as("getFacilities");
+ cy.get("[id='facility-details']").first().click();
+ cy.wait("@getFacilities").its("response.statusCode").should("eq", 200);
+ }
+
+ verifyFacilityBadgeContent(expectedText: string) {
+ cy.get("[data-testid='Facility/District Name']").should(
+ "contain",
+ expectedText
+ );
+ }
+
+ verifyfacilitycreateassetredirection() {
+ cy.intercept("GET", "**/api/v1/facility/**").as("getNewAssets");
+ cy.url().should("include", "/assets/new");
+ cy.wait("@getNewAssets").its("response.statusCode").should("eq", 200);
+ }
+
+ verifyassetfacilitybackredirection() {
+ cy.intercept("GET", "**/api/v1/facility/**").as("getManagePage");
+ cy.go("back");
+ cy.wait("@getManagePage").its("response.statusCode").should("eq", 200);
+ cy.get("#manage-facility-dropdown").scrollIntoView();
+ cy.get("#manage-facility-dropdown").should("exist");
+ }
+
+ verifyfacilityviewassetredirection() {
+ cy.intercept("GET", "**api/v1/getallfacilities/**").as("getViewAssets");
+ cy.url().should("include", "/assets?facility=");
+ cy.wait("@getViewAssets").its("response.statusCode").should("eq", 200);
+ }
+
+ clickManageInventory() {
+ cy.contains("Manage Inventory").click();
+ }
+
+ fillInventoryDetails(name: string, status: string, quantity: string) {
+ cy.get("div#id").click();
+ cy.get("div#id ul li").contains(name).click();
+ cy.get("div#isIncoming").click();
+ cy.get("div#isIncoming ul li").contains(status).click();
+ cy.get("[name='quantity']").type(quantity);
+ }
+
+ clickAddInventory() {
+ cy.intercept("POST", "**/api/v1/facility/*/inventory/").as(
+ "createInventory"
+ );
+ cy.get("button").contains("Add/Update Inventory").click();
+ cy.wait("@createInventory").its("response.statusCode").should("eq", 201);
+ }
+
+ fillResourceRequestDetails(
+ name: string,
+ phone_number: string,
+ facility: string,
+ title: string,
+ quantity: string,
+ description: string
+ ) {
+ cy.get("#refering_facility_contact_name").type(name);
+ cy.get("#refering_facility_contact_number").type(phone_number);
+ cy.get("[name='approving_facility']")
+ .type(facility)
+ .then(() => {
+ cy.get("[role='option']").first().click();
+ });
+ cy.get("#title").type(title);
+ cy.get("#requested_quantity").type(quantity);
+ cy.get("#reason").type(description);
+ }
+
+ clickSubmitRequestButton() {
+ cy.intercept("POST", "**/api/v1/resource/").as("createResourceRequest");
+ cy.get("button").contains("Submit").click();
+ cy.wait("@createResourceRequest")
+ .its("response.statusCode")
+ .should("eq", 201);
+ }
}
export default FacilityPage;
diff --git a/cypress/pageobject/Login/LoginPage.ts b/cypress/pageobject/Login/LoginPage.ts
index e75524ad3f4..f691d5f9e15 100644
--- a/cypress/pageobject/Login/LoginPage.ts
+++ b/cypress/pageobject/Login/LoginPage.ts
@@ -1,4 +1,6 @@
// LoginPage.ts
+import { cy } from "local-cypress";
+
class LoginPage {
loginAsDisctrictAdmin(): void {
cy.loginByApi("devdistrictadmin", "Coronasafe@123");
diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts
new file mode 100644
index 00000000000..c0ba0c260d8
--- /dev/null
+++ b/cypress/pageobject/Patient/PatientConsultation.ts
@@ -0,0 +1,113 @@
+export class PatientConsultationPage {
+ selectConsultationStatus(status: string) {
+ cy.get("#consultation_status")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").contains(status).click();
+ });
+ }
+
+ selectSymptoms(symptoms: string) {
+ cy.get("#symptoms")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").contains(symptoms).click();
+ });
+ }
+
+ fillIllnessHistory(history: string) {
+ cy.get("#history_of_present_illness").scrollIntoView();
+ cy.get("#history_of_present_illness").should("be.visible");
+ cy.get("#history_of_present_illness").click().type(history);
+ }
+
+ enterConsultationDetails(
+ examinationDetails: string,
+ weight: string,
+ height: string,
+ ipNumber: string,
+ consulationNotes: string,
+ verificationBy: string
+ ) {
+ cy.get("#symptoms").click();
+ cy.get("#examination_details").click().type(examinationDetails);
+ cy.get("#weight").click().type(height);
+ cy.get("#height").click().type(weight);
+ cy.get("#patient_no").type(ipNumber);
+ cy.intercept("GET", "**/icd/**").as("getIcdResults");
+ cy.get(
+ "#icd11_diagnoses_object input[placeholder='Select'][role='combobox']"
+ )
+ .click()
+ .type("1A");
+ cy.get("#icd11_diagnoses_object [role='option']")
+ .contains("1A03 Intestinal infections due to Escherichia coli")
+ .click();
+ cy.get("label[for='icd11_diagnoses_object']").click();
+ cy.wait("@getIcdResults").its("response.statusCode").should("eq", 200);
+
+ cy.get("#icd11_principal_diagnosis [role='combobox']").click().type("1A");
+ cy.get("#icd11_principal_diagnosis [role='option']")
+ .contains("1A03 Intestinal infections due to Escherichia coli")
+ .click();
+
+ cy.get("#consultation_notes").click().type(consulationNotes);
+ cy.get("#verified_by")
+ .click()
+ .type(verificationBy)
+ .then(() => {
+ cy.get("[role='option']").contains("Dev Doctor").click();
+ });
+ }
+
+ submitConsultation() {
+ cy.get("#submit").click();
+ }
+
+ clickAddPrescription() {
+ cy.contains("button", "Add Prescription Medication")
+ .should("be.visible")
+ .click();
+ }
+
+ interceptMediaBase() {
+ cy.intercept("GET", "**/api/v1/medibase/**").as("getMediaBase");
+ }
+
+ prescribeMedicine() {
+ cy.get("div#medicine_object input[placeholder='Select'][role='combobox']")
+ .click()
+ .type("dolo{enter}");
+ }
+
+ selectMedicinebox() {
+ cy.get(
+ "div#medicine_object input[placeholder='Select'][role='combobox']"
+ ).click();
+ }
+
+ waitForMediabaseStatusCode() {
+ cy.wait("@getMediaBase").its("response.statusCode").should("eq", 200);
+ }
+
+ enterDosage(doseAmount: string) {
+ cy.get("#dosage").type(doseAmount, { force: true });
+ }
+
+ selectDosageFrequency(frequency: string) {
+ cy.get("#frequency")
+ .click()
+ .then(() => {
+ cy.get("div#frequency [role='option']").contains(frequency).click();
+ });
+ }
+
+ submitPrescriptionAndReturn() {
+ cy.intercept("POST", "**/api/v1/consultation/*/prescriptions/").as(
+ "submitPrescription"
+ );
+ cy.get("button#submit").should("be.visible").click();
+ cy.get("[data-testid='return-to-patient-dashboard']").click();
+ cy.wait("@submitPrescription").its("response.statusCode").should("eq", 201);
+ }
+}
diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts
new file mode 100644
index 00000000000..9b8df4a287e
--- /dev/null
+++ b/cypress/pageobject/Patient/PatientCreation.ts
@@ -0,0 +1,127 @@
+// PatientPage.ts
+
+let patient_url = "";
+
+export class PatientPage {
+ createPatient() {
+ cy.intercept("GET", "**/api/v1/facility/**").as("getFacilities");
+ cy.get("#add-patient-details").should("be.visible");
+ cy.get("#add-patient-details").click();
+ cy.wait("@getFacilities").its("response.statusCode").should("eq", 200);
+ }
+
+ selectFacility(facilityName: string) {
+ cy.get("input[name='facilities']")
+ .type(facilityName)
+ .then(() => {
+ cy.get("[role='option']").first().click();
+ });
+ cy.get("button").should("contain", "Select");
+ cy.get("button").get("#submit").click();
+ }
+
+ interceptCreatePatientAPI() {
+ cy.intercept("GET", "**/facility/*/patient/**").as("createPatient");
+ }
+
+ verifyCreatedPatientResponse() {
+ cy.wait("@createPatient").its("response.statusCode").should("eq", 200);
+ }
+
+ enterPatientDetails(
+ phoneNumber: string,
+ emergencyPhoneNumber: string,
+ patientName: string,
+ gender: string,
+ address: string,
+ pincode: string,
+ wardName: string,
+ bloodGroup: string,
+ dateOfBirth: string
+ ) {
+ cy.get("#phone_number-div").type(phoneNumber);
+ cy.get("#emergency_phone_number-div").type(emergencyPhoneNumber);
+ cy.get("#date_of_birth").should("be.visible").click();
+ cy.get("#date-input").click().type(dateOfBirth);
+ cy.get("[data-testid=name] input").type(patientName);
+ cy.get("[data-testid=Gender] button")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").contains(gender).click();
+ });
+ cy.get("[data-testid=current-address] textarea").type(address);
+ cy.get("[data-testid=permanent-address] input").check();
+ cy.get("#pincode").type(pincode);
+ cy.get("[data-testid=localbody] button")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").first().click();
+ });
+ cy.get("[data-testid=ward-respective-lsgi] button")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").contains(wardName).click();
+ });
+ cy.get("[name=medical_history_check_1]").check();
+ cy.get("[data-testid=blood-group] button")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").contains(bloodGroup).click();
+ });
+ }
+
+ clickCreatePatient() {
+ cy.intercept("POST", "**/api/v1/patient/").as("createPatient");
+ cy.get("button[data-testid='submit-button']").click();
+ cy.wait("@createPatient").its("response.statusCode").should("eq", 201);
+ }
+
+ verifyPatientIsCreated() {
+ cy.get("h2").should("contain", "Create Consultation");
+ cy.url().should("include", "/patient");
+ }
+
+ saveCreatedPatientUrl() {
+ cy.url().then((url) => {
+ cy.log(url);
+ patient_url = url.split("/").slice(0, -1).join("/");
+ cy.log(patient_url);
+ });
+ }
+
+ visitCreatedPatient() {
+ cy.awaitUrl(patient_url);
+ }
+
+ verifyPatientDetails(
+ age: number,
+ patientName: string,
+ phoneNumber: string,
+ emergencyPhoneNumber: string,
+ yearOfBirth: string,
+ bloodGroup: string
+ ) {
+ cy.url().should("include", "/facility/");
+ cy.get("[data-testid=patient-dashboard]").should("contain", age);
+ cy.get("[data-testid=patient-dashboard]").should("contain", patientName);
+ cy.get("[data-testid=patient-dashboard]").should("contain", phoneNumber);
+ cy.get("[data-testid=patient-dashboard]").should(
+ "contain",
+ emergencyPhoneNumber
+ );
+ cy.get("[data-testid=patient-dashboard]").should("contain", yearOfBirth);
+ cy.get("[data-testid=patient-dashboard]").should("contain", bloodGroup);
+ }
+
+ visitUpdatePatientUrl() {
+ cy.awaitUrl(patient_url + "/update");
+ }
+
+ interceptFacilities() {
+ cy.intercept("GET", "**/facility/*/patient/**").as("getFacilities");
+ }
+
+ verifyStatusCode() {
+ cy.wait("@getFacilities").its("response.statusCode").should("eq", 200);
+ }
+}
diff --git a/cypress/pageobject/Patient/PatientUpdate.ts b/cypress/pageobject/Patient/PatientUpdate.ts
new file mode 100644
index 00000000000..b26ef678679
--- /dev/null
+++ b/cypress/pageobject/Patient/PatientUpdate.ts
@@ -0,0 +1,97 @@
+let patient_url = "";
+
+export class UpdatePatientPage {
+ enterPatientDetails(
+ patientName: string,
+ bloodGroup: string,
+ phoneNumber: string,
+ emergencyPhoneNumber: string,
+ address: string,
+ currentHealthCondition: string,
+ ongoingMedication: string,
+ allergies: string,
+ medicalHistory: string[],
+ subscriberId: string,
+ policyId: string,
+ insuranceId: string,
+ insuranceName: string
+ ) {
+ cy.wait(10000);
+ cy.get("#address").scrollIntoView();
+ cy.get("#address").should("be.visible");
+ cy.get("#address").type(address);
+ cy.get("[data-testid=name] input").clear();
+ cy.get("[data-testid=name] input").type(patientName);
+ cy.get("#phone_number-div").clear();
+ cy.get("#phone_number-div").type("+91").type(phoneNumber);
+ cy.get("#emergency_phone_number-div").clear();
+ cy.get("#emergency_phone_number-div")
+ .type("+91")
+ .type(emergencyPhoneNumber);
+ cy.get("#present_health").type(currentHealthCondition);
+ cy.get("#ongoing_medication").type(ongoingMedication);
+ cy.get("#allergies").type(allergies);
+ cy.get("[name=medical_history_check_1]").uncheck();
+ cy.get("[name=medical_history_check_2]").check();
+ cy.get("#medical_history_2").type(medicalHistory[0]);
+ cy.get("[name=medical_history_check_3]").check();
+ cy.get("#medical_history_3").type(medicalHistory[1]);
+ cy.get("button").get("[data-testid=add-insurance-button]").click();
+ cy.get("#subscriber_id").type(subscriberId);
+ cy.get("#policy_id").type(policyId);
+ cy.get("#insurer_id").type(insuranceId);
+ cy.get("#insurer_name").type(insuranceName);
+ cy.get("[data-testid=blood-group] button")
+ .click()
+ .then(() => {
+ cy.get("[role='option']").contains(bloodGroup).click();
+ });
+ }
+
+ clickUpdatePatient() {
+ cy.intercept("PUT", "**/api/v1/patient/**").as("updatePatient");
+ cy.get("button").get("[data-testid=submit-button]").click();
+ cy.wait("@updatePatient").its("response.statusCode").should("eq", 200);
+ }
+
+ verifyPatientUpdated() {
+ cy.url().should("include", "/patient");
+ }
+
+ saveUpdatedPatientUrl() {
+ cy.url().then((url) => {
+ cy.log(url);
+ patient_url = url.split("/").slice(0, -1).join("/");
+ cy.log(patient_url);
+ });
+ }
+
+ visitUpdatedPatient() {
+ cy.awaitUrl(patient_url);
+ }
+
+ verifyPatientDetails(
+ patientName: string,
+ phoneNumber: string,
+ presentHealth: string,
+ ongoingMedication: string,
+ allergies: string
+ ) {
+ cy.url().should("include", "/facility/");
+ cy.get("[data-testid=patient-dashboard]").should("contain", patientName);
+ cy.get("[data-testid=patient-dashboard]").should("contain", phoneNumber);
+ cy.get("[data-testid=patient-present-health]").should(
+ "contain",
+ presentHealth
+ );
+ cy.get("[data-testid=patient-ongoing-medication]").should(
+ "contain",
+ ongoingMedication
+ );
+ cy.get("[data-testid=patient-allergies]").should("contain", allergies);
+ }
+
+ visitConsultationPage() {
+ cy.visit(patient_url + "/consultation");
+ }
+}
diff --git a/cypress/pageobject/Resource/ResourcePage.ts b/cypress/pageobject/Resource/ResourcePage.ts
new file mode 100644
index 00000000000..f7feac925bf
--- /dev/null
+++ b/cypress/pageobject/Resource/ResourcePage.ts
@@ -0,0 +1,79 @@
+// ResoucrePage.ts
+class ResourcePage {
+ verifyDownloadButtonWorks() {
+ cy.get("svg.care-svg-icon__baseline.care-l-export").each(($button) => {
+ cy.intercept(/\/api\/v1\/resource/).as("resource_download");
+ cy.wrap($button).click({ force: true });
+ cy.wait("@resource_download").then((interception) => {
+ expect(interception.response.statusCode).to.equal(200);
+ });
+ });
+ }
+
+ spyResourceApi() {
+ cy.intercept(/\/api\/v1\/resource/).as("resource");
+ }
+
+ clickCompletedResources() {
+ cy.contains("Completed").click();
+ }
+
+ verifyCompletedResources() {
+ cy.wait("@resource").then((interception) => {
+ expect(interception.response.statusCode).to.equal(200);
+ });
+ cy.contains("Active").should("have.class", "text-primary-500");
+ cy.contains("Completed").should("have.class", "text-white");
+ }
+
+ clickActiveResources() {
+ cy.contains("Active").click();
+ }
+
+ verifyActiveResources() {
+ cy.wait("@resource").then((interception) => {
+ expect(interception.response.statusCode).to.equal(200);
+ });
+ cy.contains("Active").should("have.class", "text-white");
+ cy.contains("Completed").should("have.class", "text-primary-500");
+ }
+
+ clickListViewButton() {
+ cy.contains("List View").click();
+ }
+
+ clickBoardViewButton() {
+ cy.contains("Board View").click();
+ }
+
+ clickUpdateStatus() {
+ cy.get("[data-testid='update-status']").click();
+ }
+
+ updateStatus(status: string) {
+ cy.get("#status").click();
+ cy.get("[role='option']").contains(status).click();
+ }
+
+ clickSubmitButton() {
+ cy.intercept("PUT", "**/api/v1/resource/**/").as("updateResource");
+ cy.get("#submit").contains("Submit").click();
+ cy.wait("@updateResource").its("response.statusCode").should("eq", 200);
+ }
+
+ verifySuccessNotification(message: string) {
+ cy.verifyNotification(message);
+ }
+
+ addCommentForResource(comment: string) {
+ cy.get("#comment").type(comment);
+ }
+
+ clickPostCommentButton() {
+ cy.intercept("POST", "**/api/v1/resource/*/comment/").as("postComment");
+ cy.contains("Post Your Comment").click();
+ cy.wait("@postComment").its("response.statusCode").should("eq", 201);
+ }
+}
+
+export default ResourcePage;
diff --git a/cypress/pageobject/constants.ts b/cypress/pageobject/constants.ts
new file mode 100644
index 00000000000..72e0d31c662
--- /dev/null
+++ b/cypress/pageobject/constants.ts
@@ -0,0 +1,4 @@
+export const phone_number =
+ "9" + Math.floor(100000000 + Math.random() * 900000000);
+export const emergency_phone_number =
+ "9" + Math.floor(100000000 + Math.random() * 900000000);
diff --git a/package-lock.json b/package-lock.json
index dda8ac9dd79..6f655932fd7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32,7 +32,6 @@
"events": "^3.3.0",
"i18next": "^23.2.7",
"i18next-browser-languagedetector": "^7.1.0",
- "libphonenumber-js": "^1.10.37",
"lodash": "^4.17.21",
"postcss-loader": "^7.3.3",
"qrcode.react": "^3.1.0",
@@ -11127,9 +11126,9 @@
}
},
"node_modules/is-core-module": {
- "version": "2.12.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
- "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+ "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
"dev": true,
"dependencies": {
"has": "^1.0.3"
@@ -12079,11 +12078,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/libphonenumber-js": {
- "version": "1.10.37",
- "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.37.tgz",
- "integrity": "sha512-Z10PCaOCiAxbUxLyR31DNeeNugSVP6iv/m7UrSKS5JHziEMApJtgku4e9Q69pzzSC9LnQiM09sqsGf2ticZnMw=="
- },
"node_modules/lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -13742,8 +13736,6 @@
},
"node_modules/npm/node_modules/@colors/colors": {
"version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
- "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -13754,8 +13746,6 @@
},
"node_modules/npm/node_modules/@isaacs/cliui": {
"version": "8.0.2",
- "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
- "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -13773,8 +13763,6 @@
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -13787,16 +13775,12 @@
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": {
"version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
- "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -13814,8 +13798,6 @@
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": {
"version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14068,8 +14050,6 @@
},
"node_modules/npm/node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
- "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
- "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14154,8 +14134,6 @@
},
"node_modules/npm/node_modules/agent-base": {
"version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14182,8 +14160,6 @@
},
"node_modules/npm/node_modules/aggregate-error": {
"version": "3.1.0",
- "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
- "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14197,8 +14173,6 @@
},
"node_modules/npm/node_modules/ansi-regex": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14208,8 +14182,6 @@
},
"node_modules/npm/node_modules/ansi-styles": {
"version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14225,8 +14197,6 @@
},
"node_modules/npm/node_modules/aproba": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
- "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
"dev": true,
"inBundle": true,
"license": "ISC"
@@ -14252,16 +14222,12 @@
},
"node_modules/npm/node_modules/balanced-match": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/base64-js": {
"version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
@@ -14306,10 +14272,7 @@
},
"node_modules/npm/node_modules/brace-expansion": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
- "inBundle": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -14385,8 +14348,6 @@
},
"node_modules/npm/node_modules/chownr": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
- "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -14423,8 +14384,6 @@
},
"node_modules/npm/node_modules/clean-stack": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14462,8 +14421,6 @@
},
"node_modules/npm/node_modules/clone": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14482,8 +14439,6 @@
},
"node_modules/npm/node_modules/color-convert": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14496,8 +14451,6 @@
},
"node_modules/npm/node_modules/color-name": {
"version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"inBundle": true,
"license": "MIT"
@@ -14532,24 +14485,18 @@
},
"node_modules/npm/node_modules/concat-map": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/console-control-strings": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
- "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/cross-spawn": {
"version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14581,8 +14528,6 @@
},
"node_modules/npm/node_modules/cssesc": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
- "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14595,8 +14540,6 @@
},
"node_modules/npm/node_modules/debug": {
"version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14614,16 +14557,12 @@
},
"node_modules/npm/node_modules/debug/node_modules/ms": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/defaults": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
- "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14636,8 +14575,6 @@
},
"node_modules/npm/node_modules/delegates": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
- "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"dev": true,
"inBundle": true,
"license": "MIT"
@@ -14662,16 +14599,12 @@
},
"node_modules/npm/node_modules/eastasianwidth": {
"version": "0.2.0",
- "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/emoji-regex": {
"version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"inBundle": true,
"license": "MIT"
@@ -14712,8 +14645,6 @@
},
"node_modules/npm/node_modules/events": {
"version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14738,8 +14669,6 @@
},
"node_modules/npm/node_modules/foreground-child": {
"version": "3.1.1",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
- "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -14768,16 +14697,12 @@
},
"node_modules/npm/node_modules/fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/function-bind": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true,
"inBundle": true,
"license": "MIT"
@@ -14831,8 +14756,6 @@
},
"node_modules/npm/node_modules/has": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14845,8 +14768,6 @@
},
"node_modules/npm/node_modules/has-unicode": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
- "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"dev": true,
"inBundle": true,
"license": "ISC"
@@ -14885,8 +14806,6 @@
},
"node_modules/npm/node_modules/https-proxy-agent": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
- "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14954,8 +14873,6 @@
},
"node_modules/npm/node_modules/imurmurhash": {
"version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14965,8 +14882,6 @@
},
"node_modules/npm/node_modules/indent-string": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -14976,8 +14891,6 @@
},
"node_modules/npm/node_modules/inflight": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -14988,8 +14901,6 @@
},
"node_modules/npm/node_modules/inherits": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true,
"inBundle": true,
"license": "ISC"
@@ -15023,8 +14934,6 @@
},
"node_modules/npm/node_modules/ip": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
- "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
"dev": true,
"inBundle": true,
"license": "MIT"
@@ -15064,8 +14973,6 @@
},
"node_modules/npm/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -15081,8 +14988,6 @@
},
"node_modules/npm/node_modules/isexe": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true,
"inBundle": true,
"license": "ISC"
@@ -15349,8 +15254,6 @@
},
"node_modules/npm/node_modules/minimatch": {
"version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15364,6 +15267,15 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/npm/node_modules/minimatch/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/npm/node_modules/minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
@@ -15389,8 +15301,6 @@
},
"node_modules/npm/node_modules/minipass-collect/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15432,8 +15342,6 @@
},
"node_modules/npm/node_modules/minipass-flush/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15456,8 +15364,6 @@
},
"node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15482,8 +15388,6 @@
},
"node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15508,8 +15412,6 @@
},
"node_modules/npm/node_modules/minipass-sized/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15522,8 +15424,6 @@
},
"node_modules/npm/node_modules/minizlib": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
- "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -15537,8 +15437,6 @@
},
"node_modules/npm/node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15551,8 +15449,6 @@
},
"node_modules/npm/node_modules/mkdirp": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -15633,8 +15529,6 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": {
"version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -15664,8 +15558,6 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/glob": {
"version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15686,8 +15578,6 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/minimatch": {
"version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15730,8 +15620,6 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": {
"version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -15746,8 +15634,6 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/signal-exit": {
"version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true,
"inBundle": true,
"license": "ISC"
@@ -15938,8 +15824,6 @@
},
"node_modules/npm/node_modules/once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -15949,8 +15833,6 @@
},
"node_modules/npm/node_modules/p-map": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
- "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16012,8 +15894,6 @@
},
"node_modules/npm/node_modules/path-is-absolute": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16023,8 +15903,6 @@
},
"node_modules/npm/node_modules/path-key": {
"version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16081,8 +15959,6 @@
},
"node_modules/npm/node_modules/process": {
"version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16222,8 +16098,6 @@
},
"node_modules/npm/node_modules/rimraf": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16239,8 +16113,6 @@
},
"node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": {
"version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16251,8 +16123,6 @@
},
"node_modules/npm/node_modules/rimraf/node_modules/glob": {
"version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16273,8 +16143,6 @@
},
"node_modules/npm/node_modules/rimraf/node_modules/minimatch": {
"version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16287,8 +16155,6 @@
},
"node_modules/npm/node_modules/safe-buffer": {
"version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true,
"funding": [
{
@@ -16316,8 +16182,6 @@
},
"node_modules/npm/node_modules/semver": {
"version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16333,8 +16197,6 @@
},
"node_modules/npm/node_modules/semver/node_modules/lru-cache": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16347,16 +16209,12 @@
},
"node_modules/npm/node_modules/set-blocking": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/shebang-command": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16369,8 +16227,6 @@
},
"node_modules/npm/node_modules/shebang-regex": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16380,8 +16236,6 @@
},
"node_modules/npm/node_modules/signal-exit": {
"version": "4.0.2",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz",
- "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16449,8 +16303,6 @@
},
"node_modules/npm/node_modules/spdx-correct": {
"version": "3.2.0",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
- "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
"dev": true,
"inBundle": true,
"license": "Apache-2.0",
@@ -16461,16 +16313,12 @@
},
"node_modules/npm/node_modules/spdx-exceptions": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
- "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true,
"inBundle": true,
"license": "CC-BY-3.0"
},
"node_modules/npm/node_modules/spdx-expression-parse": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
- "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16481,8 +16329,6 @@
},
"node_modules/npm/node_modules/spdx-license-ids": {
"version": "3.0.13",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
- "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
"dev": true,
"inBundle": true,
"license": "CC0-1.0"
@@ -16501,8 +16347,6 @@
},
"node_modules/npm/node_modules/string_decoder": {
"version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16512,8 +16356,6 @@
},
"node_modules/npm/node_modules/string-width": {
"version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16529,8 +16371,6 @@
"node_modules/npm/node_modules/string-width-cjs": {
"name": "string-width",
"version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16545,8 +16385,6 @@
},
"node_modules/npm/node_modules/strip-ansi": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16560,8 +16398,6 @@
"node_modules/npm/node_modules/strip-ansi-cjs": {
"name": "strip-ansi",
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16605,8 +16441,6 @@
},
"node_modules/npm/node_modules/tar/node_modules/fs-minipass": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
- "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16619,8 +16453,6 @@
},
"node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -16800,8 +16632,6 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16814,8 +16644,6 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "6.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
- "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16828,16 +16656,12 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": {
"version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": {
"version": "5.1.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
- "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -16855,8 +16679,6 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": {
"version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -19114,12 +18936,12 @@
"integrity": "sha512-PdjHqho8+kI7AIC3DlLgD99H8zzHphzpIhyv2skVtWaSJGK819+ZqWMC3mHEtSjlcFoYaLXliNt8sb6Taa2Mpg=="
},
"node_modules/resolve": {
- "version": "1.22.2",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
- "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+ "version": "1.22.4",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+ "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
"dev": true,
"dependencies": {
- "is-core-module": "^2.11.0",
+ "is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
diff --git a/package.json b/package.json
index 2e894f22288..8ade8c604be 100644
--- a/package.json
+++ b/package.json
@@ -72,7 +72,6 @@
"events": "^3.3.0",
"i18next": "^23.2.7",
"i18next-browser-languagedetector": "^7.1.0",
- "libphonenumber-js": "^1.10.37",
"lodash": "^4.17.21",
"postcss-loader": "^7.3.3",
"qrcode.react": "^3.1.0",
diff --git a/src/CAREUI/interactive/SlideOver.tsx b/src/CAREUI/interactive/SlideOver.tsx
index 3eae13869cb..34e1c615f94 100644
--- a/src/CAREUI/interactive/SlideOver.tsx
+++ b/src/CAREUI/interactive/SlideOver.tsx
@@ -109,6 +109,7 @@ export default function SlideOver({
>
navigate(`/facility/${facilityId}`)} />
-
+
diff --git a/src/Components/Assets/AssetFilter.tsx b/src/Components/Assets/AssetFilter.tsx
index b0a870d0e31..4fc4ff6d7f2 100644
--- a/src/Components/Assets/AssetFilter.tsx
+++ b/src/Components/Assets/AssetFilter.tsx
@@ -108,9 +108,9 @@ function AssetFilter(props: any) {
const applyFilter = () => {
const data = {
facility: facilityId,
- asset_type: asset_type,
- asset_class: asset_class,
- status: asset_status,
+ asset_type: asset_type ?? "",
+ asset_class: asset_class ?? "",
+ status: asset_status ?? "",
location: locationId,
};
onChange(data);
@@ -148,7 +148,7 @@ function AssetFilter(props: any) {
Location
handleLocationSelect((selectedId as string) || "")
}
diff --git a/src/Components/Assets/AssetImportModal.tsx b/src/Components/Assets/AssetImportModal.tsx
index b5b0110096a..548df2901ec 100644
--- a/src/Components/Assets/AssetImportModal.tsx
+++ b/src/Components/Assets/AssetImportModal.tsx
@@ -220,7 +220,7 @@ const AssetImportModal = ({ open, onClose, facility }: Props) => {
-
+
{
-
{asset?.description}
+
+ {asset?.description}
+
{[
@@ -402,19 +416,6 @@ const AssetManage = (props: AssetManageProps) => {
icon: "location-pin-alt",
content: asset?.location_object.name,
},
- {
- label: "Asset Type",
- icon: "apps",
- content:
- asset?.asset_type === "INTERNAL"
- ? "Internal Asset"
- : "External Asset",
- },
- {
- label: "Asset Class",
- icon: assetClassProp.icon,
- content: assetClassProp.name,
- },
{
label: "Asset QR Code ID",
icon: "qrcode-scan",
@@ -451,7 +452,8 @@ const AssetManage = (props: AssetManageProps) => {
)
}
id="configure-asset"
- authorizeFor={NonReadOnlyUsers}
+ data-testid="asset-configure-button"
+ authorizeFor={AuthorizeFor(["DistrictAdmin", "StateAdmin"])}
>
{t("configure")}
@@ -584,7 +586,7 @@ const AssetManage = (props: AssetManageProps) => {
viewOnly={serviceEditData.viewOnly}
/>
)}
-
+
);
};
diff --git a/src/Components/Assets/AssetType/ONVIFCamera.tsx b/src/Components/Assets/AssetType/ONVIFCamera.tsx
index ec11761abf6..0f26c4924ae 100644
--- a/src/Components/Assets/AssetType/ONVIFCamera.tsx
+++ b/src/Components/Assets/AssetType/ONVIFCamera.tsx
@@ -42,6 +42,7 @@ const ONVIFCamera = (props: ONVIFCameraProps) => {
const [refreshPresetsHash, setRefreshPresetsHash] = useState(
Number(new Date())
);
+ const [refreshHash, setRefreshHash] = useState(Number(new Date()));
const dispatch = useDispatch();
useEffect(() => {
@@ -89,7 +90,7 @@ const ONVIFCamera = (props: ONVIFCameraProps) => {
Notification.Success({
msg: "Asset Configured Successfully",
});
- window.location.reload();
+ setRefreshHash(Number(new Date()));
} else {
Notification.Error({
msg: "Something went wrong..!",
@@ -200,6 +201,7 @@ const ONVIFCamera = (props: ONVIFCameraProps) => {
{assetType === "ONVIF" ? (
{
+ if (isCopied) {
+ const timeout = setTimeout(() => {
+ setIsCopied(false);
+ }, 2000);
+ return () => clearTimeout(timeout);
+ }
+ }, [isCopied]);
+
return (
{asset.manufacturer}
-
-
+
+
{Object.keys(details).map((key) => (
{key}
-
+
{details[key as keyof typeof details] || "--"}
+ {key === "Serial Number" && (
+
+ )}
))}
+
diff --git a/src/Components/Assets/AssetsList.tsx b/src/Components/Assets/AssetsList.tsx
index 5b820f93e29..d91468166ac 100644
--- a/src/Components/Assets/AssetsList.tsx
+++ b/src/Components/Assets/AssetsList.tsx
@@ -310,19 +310,21 @@ const AssetsList = () => {
options={
<>
{authorizedForImportExport && (
-
+
,
+ icon: (
+
+ ),
onClick: () => setImportAssetModalOpen(true),
},
},
{
- label: "Export Assets",
+ label: "Export Assets (JSON)",
action: () =>
authorizedForImportExport &&
listAssets({
@@ -331,10 +333,28 @@ const AssetsList = () => {
limit: totalCount,
}),
type: "json",
- filePrefix: `assets_${facility?.name}`,
+ filePrefix: `assets_${facility?.name ?? "all"}`,
options: {
icon:
,
disabled: totalCount === 0 || !authorizedForImportExport,
+ id: "export-json-option",
+ },
+ },
+ {
+ label: "Export Assets (CSV)",
+ action: () =>
+ authorizedForImportExport &&
+ listAssets({
+ ...qParams,
+ csv: true,
+ limit: totalCount,
+ }),
+ type: "csv",
+ filePrefix: `assets_${facility?.name ?? "all"}`,
+ options: {
+ icon:
,
+ disabled: totalCount === 0 || !authorizedForImportExport,
+ id: "export-csv-option",
},
},
]}
diff --git a/src/Components/Common/DateInputV2.tsx b/src/Components/Common/DateInputV2.tsx
index ecee0b8a969..bcebd4e0055 100644
--- a/src/Components/Common/DateInputV2.tsx
+++ b/src/Components/Common/DateInputV2.tsx
@@ -284,7 +284,7 @@ const DateInputV2: React.FC
= ({
datePickerHeaderDate.getMonth() - 1
)
}
- className="aspect-square inline-flex cursor-pointer items-center justify-center rounded p-2 transition duration-100 ease-in-out hover:bg-gray-300"
+ className="inline-flex aspect-square cursor-pointer items-center justify-center rounded p-2 transition duration-100 ease-in-out hover:bg-gray-300"
onClick={decrement}
>
@@ -317,7 +317,7 @@ const DateInputV2: React.FC = ({
new Date().getFullYear() === year.getFullYear()) ||
!isDateWithinConstraints(getLastDay())
}
- className="aspect-square inline-flex cursor-pointer items-center justify-center rounded p-2 transition duration-100 ease-in-out hover:bg-gray-300"
+ className="inline-flex aspect-square cursor-pointer items-center justify-center rounded p-2 transition duration-100 ease-in-out hover:bg-gray-300"
onClick={increment}
>
diff --git a/src/Components/Common/UserAutocompleteFormField.tsx b/src/Components/Common/UserAutocompleteFormField.tsx
index 6262db47bc3..ebe6d96bbc5 100644
--- a/src/Components/Common/UserAutocompleteFormField.tsx
+++ b/src/Components/Common/UserAutocompleteFormField.tsx
@@ -8,11 +8,13 @@ import {
} from "../Form/FormFields/Utils";
import { UserModel } from "../Users/models";
import { isUserOnline } from "../../Utils/utils";
+import { UserRole } from "../../Common/constants";
type Props = FormFieldBaseProps & {
placeholder?: string;
facilityId?: string;
- userType?: string;
+ homeFacility?: string;
+ userType?: UserRole;
showActiveStatus?: boolean;
};
@@ -26,6 +28,7 @@ export default function UserAutocompleteFormField(props: Props) {
let search_filter: {
limit: number;
offset: number;
+ home_facility?: string;
user_type?: string;
search_text?: string;
} = { limit: 5, offset: 0 };
@@ -34,6 +37,10 @@ export default function UserAutocompleteFormField(props: Props) {
search_filter = { ...search_filter, user_type: props.userType };
}
+ if (props.homeFacility) {
+ search_filter = { ...search_filter, home_facility: props.homeFacility };
+ }
+
const getStatusIcon = (option: UserModel) => {
if (!props.showActiveStatus) return null;
@@ -69,11 +76,11 @@ export default function UserAutocompleteFormField(props: Props) {
onQuery={(query) =>
fetchOptions(
props.facilityId
- ? getFacilityUsers(props.facilityId)
- : getUserList({
+ ? getFacilityUsers(props.facilityId, {
...search_filter,
search_text: query,
})
+ : getUserList({ ...search_filter, search_text: query })
)
}
isLoading={isLoading}
diff --git a/src/Components/Common/components/ButtonV2.tsx b/src/Components/Common/components/ButtonV2.tsx
index 4c09445217d..2f3d3002451 100644
--- a/src/Components/Common/components/ButtonV2.tsx
+++ b/src/Components/Common/components/ButtonV2.tsx
@@ -161,7 +161,7 @@ export default ButtonV2;
// Common buttons
-type CommonButtonProps = ButtonProps & { label?: string };
+export type CommonButtonProps = ButtonProps & { label?: string };
export const Submit = ({ label = "Submit", ...props }: CommonButtonProps) => {
const { t } = useTranslation();
diff --git a/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res b/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res
index f3f789e9dcd..35d137e0414 100644
--- a/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res
+++ b/src/Components/CriticalCareRecording/NeurologicalMonitoring/CriticalCare__NeurologicalMonitoringEditor.res
@@ -485,7 +485,7 @@ let make = (~updateCB, ~neurologicalMonitoring, ~id, ~consultationId) => {
{str("Glasgow Coma Scale")}
-
{str("Eye Open")}
+
{str("Eye Opening Response")}
{Js.Array.mapi(
(x, i) =>
diff --git a/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res b/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res
index 1e8804c7524..f42ca5c140d 100644
--- a/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res
+++ b/src/Components/CriticalCareRecording/types/CriticalCare__NeurologicalMonitoring.res
@@ -45,25 +45,25 @@ let make = (
~limbResponseLowerExtremityRight,
~limbResponseLowerExtremityLeft,
) => {
- inPronePosition: inPronePosition,
- consciousnessLevel: consciousnessLevel,
- consciousnessLevelDetails: consciousnessLevelDetails,
- leftPupilSize: leftPupilSize,
- leftPupilSizeDetails: leftPupilSizeDetails,
- leftPupilLightReaction: leftPupilLightReaction,
- leftPupilLightReactionDetails: leftPupilLightReactionDetails,
- rightPupilSize: rightPupilSize,
- rightPupilSizeDetails: rightPupilSizeDetails,
- rightPupilLightReaction: rightPupilLightReaction,
- rightPupilLightReactionDetails: rightPupilLightReactionDetails,
- glasgowEyeOpen: glasgowEyeOpen,
- glasgowVerbalResponse: glasgowVerbalResponse,
- glasgowMotorResponse: glasgowMotorResponse,
- glasgowTotalCalculated: glasgowTotalCalculated,
- limbResponseUpperExtremityRight: limbResponseUpperExtremityRight,
- limbResponseUpperExtremityLeft: limbResponseUpperExtremityLeft,
- limbResponseLowerExtremityRight: limbResponseLowerExtremityRight,
- limbResponseLowerExtremityLeft: limbResponseLowerExtremityLeft,
+ inPronePosition,
+ consciousnessLevel,
+ consciousnessLevelDetails,
+ leftPupilSize,
+ leftPupilSizeDetails,
+ leftPupilLightReaction,
+ leftPupilLightReactionDetails,
+ rightPupilSize,
+ rightPupilSizeDetails,
+ rightPupilLightReaction,
+ rightPupilLightReactionDetails,
+ glasgowEyeOpen,
+ glasgowVerbalResponse,
+ glasgowMotorResponse,
+ glasgowTotalCalculated,
+ limbResponseUpperExtremityRight,
+ limbResponseUpperExtremityLeft,
+ limbResponseLowerExtremityRight,
+ limbResponseLowerExtremityLeft,
}
let makeConsciousnessLevel = consciousnessLevel => {
@@ -173,8 +173,8 @@ let limpResponseToString = limpResponse => {
let eyeOpenToString = eyeOpen => {
switch eyeOpen {
- | 1 => "1 - None"
- | 2 => "2 - Pain"
+ | 1 => "1 - No Response"
+ | 2 => "2 - To Pain"
| 3 => "3 - To Speech"
| 4 => "4 - Spontaneous"
| _ => "Unknown"
@@ -183,23 +183,23 @@ let eyeOpenToString = eyeOpen => {
let motorResposneToString = eyeOpen => {
switch eyeOpen {
- | 1 => "1 - None"
- | 2 => "2 - Incomprehensible words/Moans to pain"
+ | 1 => "1 - No Response"
+ | 2 => "2 - Abnormal Extension"
| 3 => "3 - Abnormal Flexion"
- | 4 => "4 - Withdrawing"
- | 5 => "5 - Localizing/Withdrawl to touch"
- | 6 => "6 - Obeying/Normal Activity"
+ | 4 => "4 - Flexion/Withdrawal to pain"
+ | 5 => "5 - Moves to localized pain"
+ | 6 => "6 - Obeys commands/Normal Activity"
| _ => "Unknown"
}
}
let verbalResposneToString = eyeOpen => {
switch eyeOpen {
- | 1 => "1 - None"
+ | 1 => "1 - No Response"
| 2 => "2 - Incomprehensible words/Moans to pain"
| 3 => "3 - Inappropriate words/Cry to pain"
| 4 => "4 - Confused/Irritable"
- | 5 => "5 - Oriented/Coos/Babbies"
+ | 5 => "5 - Oriented to Time, Place and Person"
| _ => "Unknown"
}
}
diff --git a/src/Components/ExternalResult/ExternalResultUpload.tsx b/src/Components/ExternalResult/ExternalResultUpload.tsx
index 4d517f1a442..5f39cb213a4 100644
--- a/src/Components/ExternalResult/ExternalResultUpload.tsx
+++ b/src/Components/ExternalResult/ExternalResultUpload.tsx
@@ -8,6 +8,8 @@ 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";
export default function ExternalResultUpload() {
const { sample_format_external_result_import } = useConfig();
@@ -20,6 +22,7 @@ export default function ExternalResultUpload() {
setCsvData(data);
};
const { t } = useTranslation();
+ const { goBack } = useAppHistory();
const papaparseOptions = {
header: true,
@@ -67,11 +70,11 @@ export default function ExternalResultUpload() {
backUrl="/external_results"
className="mt-4"
/>
-
-
+
+
-
+
diff --git a/src/Components/ExternalResult/ResultList.tsx b/src/Components/ExternalResult/ResultList.tsx
index 18de6f29134..74fbf8430b0 100644
--- a/src/Components/ExternalResult/ResultList.tsx
+++ b/src/Components/ExternalResult/ResultList.tsx
@@ -6,7 +6,7 @@ import { externalResultList } from "../../Redux/actions";
import ListFilter from "./ListFilter";
import FacilitiesSelectDialogue from "./FacilitiesSelectDialogue";
import { FacilityModel } from "../Facility/models";
-import parsePhoneNumberFromString from "libphonenumber-js";
+import { parsePhoneNumber } from "../../Utils/utils";
import SearchInput from "../Form/SearchInput";
import useFilters from "../../Common/hooks/useFilters";
import CareIcon from "../../CAREUI/icons/CareIcon";
@@ -65,7 +65,7 @@ export default function ResultList() {
page: qParams.page || 1,
name: qParams.name || "",
mobile_number: qParams.mobile_number
- ? parsePhoneNumberFromString(qParams.mobile_number)?.format("E.164")
+ ? parsePhoneNumber(qParams.mobile_number) ?? ""
: "",
wards: qParams.wards || undefined,
local_bodies: qParams.local_bodies || undefined,
diff --git a/src/Components/Facility/AddLocationForm.tsx b/src/Components/Facility/AddLocationForm.tsx
index d3c64ec9e04..f0dd7893aca 100644
--- a/src/Components/Facility/AddLocationForm.tsx
+++ b/src/Components/Facility/AddLocationForm.tsx
@@ -158,7 +158,7 @@ export const AddLocationForm = (props: LocationFormProps) => {
/>
-
+
navigate(`/facility/${facilityId}/location`, {
diff --git a/src/Components/Facility/AssetCreate.tsx b/src/Components/Facility/AssetCreate.tsx
index 1e6eead5242..156d738857a 100644
--- a/src/Components/Facility/AssetCreate.tsx
+++ b/src/Components/Facility/AssetCreate.tsx
@@ -30,13 +30,12 @@ import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
import TextFormField from "../Form/FormFields/TextFormField";
import { navigate } from "raviger";
-import { parsePhoneNumberFromString } from "libphonenumber-js";
import { parseQueryParams } from "../../Utils/primitives";
import useAppHistory from "../../Common/hooks/useAppHistory";
import { useDispatch } from "react-redux";
import useVisibility from "../../Utils/useVisibility";
import { validateEmailAddress } from "../../Common/validation";
-import { dateQueryString } from "../../Utils/utils.js";
+import { dateQueryString, parsePhoneNumber } from "../../Utils/utils.js";
import dayjs from "../../Utils/dayjs";
import DateInputV2 from "../Common/DateInputV2.js";
@@ -341,7 +340,7 @@ const AssetCreate = (props: AssetProps) => {
support_email: support_email,
support_phone: support_phone.startsWith("1800")
? support_phone
- : parsePhoneNumberFromString(support_phone)?.format("E.164"),
+ : parsePhoneNumber(support_phone),
qr_code_id: qrCodeId !== "" ? qrCodeId : null,
manufacturer: manufacturer,
warranty_amc_end_of_validity: warranty_amc_end_of_validity
diff --git a/src/Components/Facility/ConsultationCard.tsx b/src/Components/Facility/ConsultationCard.tsx
index 467729f0f73..f6b4484b477 100644
--- a/src/Components/Facility/ConsultationCard.tsx
+++ b/src/Components/Facility/ConsultationCard.tsx
@@ -5,6 +5,7 @@ import ButtonV2 from "../Common/components/ButtonV2";
import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import RelativeDateUserMention from "../Common/RelativeDateUserMention";
import useConfig from "../../Common/hooks/useConfig";
+import Chip from "../../CAREUI/display/Chip";
interface ConsultationProps {
itemData: ConsultationModel;
@@ -70,6 +71,15 @@ export const ConsultationCard = (props: ConsultationProps) => {
{formatDateTime(itemData.admission_date)}
+ {itemData.is_readmission && (
+
+ )}
diff --git a/src/Components/Facility/ConsultationDetails.tsx b/src/Components/Facility/ConsultationDetails.tsx
deleted file mode 100644
index 257d3712544..00000000000
--- a/src/Components/Facility/ConsultationDetails.tsx
+++ /dev/null
@@ -1,1305 +0,0 @@
-import { AssetBedModel, AssetClass, AssetData } from "../Assets/AssetTypes";
-import {
- CONSULTATION_TABS,
- DISCHARGE_REASONS,
- GENDER_TYPES,
- OptionsType,
- SYMPTOM_CHOICES,
-} from "../../Common/constants";
-import {
- BedModel,
- ConsultationModel,
- FacilityModel,
- ICD11DiagnosisModel,
-} from "./models";
-import {
- getConsultation,
- getPatient,
- getPermittedFacility,
- listAssetBeds,
-} from "../../Redux/actions";
-import { statusType, useAbortableEffect } from "../../Common/utils";
-import { lazy, useCallback, useEffect, useState } from "react";
-
-import { ABGPlots } from "./Consultations/ABGPlots";
-import ButtonV2 from "../Common/components/ButtonV2";
-import CareIcon from "../../CAREUI/icons/CareIcon";
-import Chip from "../../CAREUI/display/Chip";
-import { DailyRoundsList } from "./Consultations/DailyRoundsList";
-import { DialysisPlots } from "./Consultations/DialysisPlots";
-import DischargeModal from "./DischargeModal";
-import DischargeSummaryModal from "./DischargeSummaryModal";
-import DoctorVideoSlideover from "./DoctorVideoSlideover";
-import { Feed } from "./Consultations/Feed";
-import { FileUpload } from "../Patient/FileUpload";
-import HL7PatientVitalsMonitor from "../VitalsMonitor/HL7PatientVitalsMonitor";
-import InvestigationTab from "./Investigations/investigationsTab";
-import { make as Link } from "../Common/components/Link.bs";
-import { NeurologicalTable } from "./Consultations/NeurologicalTables";
-import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
-import { NursingPlot } from "./Consultations/NursingPlot";
-import { NutritionPlots } from "./Consultations/NutritionPlots";
-import PatientInfoCard from "../Patient/PatientInfoCard";
-import { PatientModel } from "../Patient/models";
-import PrescriptionsTable from "../Medicine/PrescriptionsTable";
-import { PressureSoreDiagrams } from "./Consultations/PressureSoreDiagrams";
-import { PrimaryParametersPlot } from "./Consultations/PrimaryParametersPlot";
-import ReadMore from "../Common/components/Readmore";
-import VentilatorPatientVitalsMonitor from "../VitalsMonitor/VentilatorPatientVitalsMonitor";
-import { VentilatorPlot } from "./Consultations/VentilatorPlot";
-import { formatDate, formatDateTime, relativeTime } from "../../Utils/utils";
-
-import { navigate } from "raviger";
-import { useDispatch } from "react-redux";
-import { useQueryParams } from "raviger";
-import { useTranslation } from "react-i18next";
-import { triggerGoal } from "../Common/Plausible";
-import useVitalsAspectRatioConfig from "../VitalsMonitor/useVitalsAspectRatioConfig";
-import useAuthUser from "../../Common/hooks/useAuthUser";
-import PrescriptionAdministrationsTable from "../Medicine/PrescriptionAdministrationsTable";
-
-const Loading = lazy(() => import("../Common/Loading"));
-const PageTitle = lazy(() => import("../Common/PageTitle"));
-const symptomChoices = [...SYMPTOM_CHOICES];
-
-export const ConsultationDetails = (props: any) => {
- const { t } = useTranslation();
- const { facilityId, patientId, consultationId } = props;
- const tab = props.tab.toUpperCase();
- const dispatch: any = useDispatch();
- const [isLoading, setIsLoading] = useState(false);
- const [showDoctors, setShowDoctors] = useState(false);
- const [qParams, _] = useQueryParams();
-
- const [consultationData, setConsultationData] = useState
(
- {} as ConsultationModel
- );
- const [patientData, setPatientData] = useState({});
- const [openDischargeSummaryDialog, setOpenDischargeSummaryDialog] =
- useState(false);
- const [openDischargeDialog, setOpenDischargeDialog] = useState(false);
- const [showAutomatedRounds, setShowAutomatedRounds] = useState(true);
-
- const getPatientGender = (patientData: any) =>
- GENDER_TYPES.find((i) => i.id === patientData.gender)?.text;
-
- const getPatientAddress = (patientData: any) =>
- `${patientData.address},\n${patientData.ward_object?.name},\n${patientData.local_body_object?.name},\n${patientData.district_object?.name},\n${patientData.state_object?.name}`;
-
- const getPatientComorbidities = (patientData: any) => {
- if (patientData?.medical_history?.length) {
- const medHis = patientData.medical_history;
- return medHis.map((item: any) => item.disease).join(", ");
- } else {
- return "None";
- }
- };
-
- const [hl7SocketUrl, setHL7SocketUrl] = useState();
- const [ventilatorSocketUrl, setVentilatorSocketUrl] = useState();
- const [monitorBedData, setMonitorBedData] = useState();
- const [ventilatorBedData, setVentilatorBedData] = useState();
- const authUser = useAuthUser();
-
- useEffect(() => {
- if (
- !consultationData.facility ||
- !consultationData.current_bed?.bed_object.id
- )
- return;
-
- const fetchData = async () => {
- const [facilityRes, assetBedRes] = await Promise.all([
- dispatch(getPermittedFacility(consultationData.facility as any)),
- dispatch(
- listAssetBeds({
- facility: consultationData.facility as any,
- bed: consultationData.current_bed?.bed_object.id,
- })
- ),
- ]);
-
- const { middleware_address } = facilityRes.data as FacilityModel;
- const assetBeds = assetBedRes.data.results as AssetBedModel[];
-
- const monitorBedData = assetBeds.find(
- (i) => i.asset_object.asset_class === AssetClass.HL7MONITOR
- );
- setMonitorBedData(monitorBedData);
- const assetDataForMonitor = monitorBedData?.asset_object;
- const hl7Meta = assetDataForMonitor?.meta;
- const hl7Middleware = hl7Meta?.middleware_hostname || middleware_address;
- if (hl7Middleware && hl7Meta?.local_ip_address) {
- setHL7SocketUrl(
- `wss://${hl7Middleware}/observations/${hl7Meta.local_ip_address}`
- );
- }
-
- const consultationBedVentilator =
- consultationData?.current_bed?.assets_objects?.find(
- (i) => i.asset_class === AssetClass.VENTILATOR
- );
- let ventilatorBedData;
- if (consultationBedVentilator) {
- ventilatorBedData = {
- asset_object: consultationBedVentilator,
- bed_object: consultationData?.current_bed?.bed_object,
- } as AssetBedModel;
- } else {
- ventilatorBedData = assetBeds.find(
- (i) => i.asset_object.asset_class === AssetClass.VENTILATOR
- );
- }
- setVentilatorBedData(ventilatorBedData);
- const ventilatorMeta = ventilatorBedData?.asset_object?.meta;
- const ventilatorMiddleware =
- ventilatorMeta?.middleware_hostname || middleware_address;
- if (ventilatorMiddleware && ventilatorMeta?.local_ip_address) {
- setVentilatorSocketUrl(
- `wss://${ventilatorMiddleware}/observations/${ventilatorMeta?.local_ip_address}`
- );
- }
-
- if (
- !(hl7Middleware && hl7Meta?.local_ip_address) &&
- !(ventilatorMiddleware && ventilatorMeta?.local_ip_address)
- ) {
- setHL7SocketUrl(undefined);
- setVentilatorSocketUrl(undefined);
- }
- };
-
- fetchData();
- }, [consultationData]);
-
- const fetchData = useCallback(
- async (status: statusType) => {
- setIsLoading(true);
- const res = await dispatch(getConsultation(consultationId));
- if (!status.aborted) {
- if (res?.data) {
- const data: ConsultationModel = {
- ...res.data,
- symptoms_text: "",
- };
- if (res.data.symptoms?.length) {
- const symptoms = res.data.symptoms
- .filter((symptom: number) => symptom !== 9)
- .map((symptom: number) => {
- const option = symptomChoices.find((i) => i.id === symptom);
- return option ? option.text.toLowerCase() : symptom;
- });
- data.symptoms_text = symptoms.join(", ");
- }
- setConsultationData(data);
- const id = res.data.patient;
- const patientRes = await dispatch(getPatient({ id }));
- if (patientRes?.data) {
- const patientGender = getPatientGender(patientRes.data);
- const patientAddress = getPatientAddress(patientRes.data);
- const patientComorbidities = getPatientComorbidities(
- patientRes.data
- );
- const data = {
- ...patientRes.data,
- gender: patientGender,
- address: patientAddress,
- comorbidities: patientComorbidities,
- is_declared_positive: patientRes.data.is_declared_positive
- ? "Yes"
- : "No",
- is_vaccinated: patientData.is_vaccinated ? "Yes" : "No",
- };
- setPatientData(data);
- }
- } else {
- navigate("/not-found");
- }
- setIsLoading(false);
- }
- },
- [consultationId, dispatch, patientData.is_vaccinated]
- );
-
- useAbortableEffect((status: statusType) => {
- fetchData(status);
- triggerGoal("Patient Consultation Viewed", {
- facilityId: facilityId,
- consultationId: consultationId,
- userID: authUser.id,
- });
- }, []);
-
- const vitals = useVitalsAspectRatioConfig({
- default: undefined,
- md: 8 / 11,
- lg: 15 / 11,
- xl: 13 / 11,
- "2xl": 19 / 11,
- "3xl": 23 / 11,
- });
-
- if (isLoading) {
- return ;
- }
-
- const tabButtonClasses = (selected: boolean) =>
- `capitalize min-w-max-content cursor-pointer border-transparent text-gray-700 hover:text-gray-700 hover:border-gray-300 font-bold whitespace-nowrap ${
- selected === true ? "border-primary-500 text-primary-600 border-b-2" : ""
- }`;
-
- const ShowDiagnosis = ({
- diagnoses = [],
- label = "Diagnosis",
- nshow = 2,
- }: {
- diagnoses: ICD11DiagnosisModel[] | undefined;
- label: string;
- nshow?: number;
- }) => {
- const [showMore, setShowMore] = useState(false);
-
- return diagnoses.length ? (
-
- ) : null;
- };
-
- return (
-
-
setOpenDischargeSummaryDialog(false)}
- />
-
- setOpenDischargeDialog(false)}
- consultationData={consultationData}
- />
-
-
-
-
-
-
-
-
- {consultationData.admitted_to && (
-
-
- Patient
- {consultationData.discharge_date
- ? " Discharged from"
- : " Admitted to"}
-
- {consultationData.admitted_to}
-
-
- {(consultationData.admission_date ??
- consultationData.discharge_date) && (
-
- {relativeTime(
- consultationData.discharge_date
- ? consultationData.discharge_date
- : consultationData.admission_date
- )}
-
- )}
-
- {consultationData.admission_date &&
- formatDateTime(consultationData.admission_date)}
- {consultationData.discharge_date &&
- ` - ${formatDateTime(consultationData.discharge_date)}`}
-
-
- )}
-
-
-
-
- {/*consultationData.other_symptoms && (
-
-
- Other Symptoms:{" "}
-
- {consultationData.other_symptoms}
-
- )*/}
-
-
-
-
-
- {consultationData.verified_by && (
-
-
- Verified By:{" "}
-
- {consultationData.verified_by}
-
-
- )}
-
-
- setOpenDischargeSummaryDialog(true)}>
-
- {t("discharge_summary")}
-
-
- setOpenDischargeDialog(true)}
- disabled={!!consultationData.discharge_date}
- >
-
- {t("discharge_from_care")}
-
-
-
-
-
-
- Created:
- {consultationData.created_date
- ? formatDateTime(consultationData.created_date)
- : "--:--"}{" "}
- |
-
- {consultationData.created_by && (
-
- {` ${consultationData.created_by.first_name} ${consultationData.created_by.last_name} `}
- {`@${consultationData.created_by.username} (${consultationData.created_by.user_type})`}
-
- )}
-
-
-
- Last Modified:
- {consultationData.modified_date
- ? formatDateTime(consultationData.modified_date)
- : "--:--"}{" "}
- |
-
- {consultationData.last_edited_by && (
-
- {` ${consultationData.last_edited_by.first_name} ${consultationData.last_edited_by.last_name} `}
- {`@${consultationData.last_edited_by.username} (${consultationData.last_edited_by.user_type})`}
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
- {tab === "UPDATES" && (
-
- {!consultationData.discharge_date &&
- hl7SocketUrl &&
- ventilatorSocketUrl && (
-
- )}
-
-
-
-
- {!consultationData.discharge_date &&
- ((hl7SocketUrl && !ventilatorSocketUrl) ||
- (!hl7SocketUrl && ventilatorSocketUrl)) && (
-
- {(hl7SocketUrl || ventilatorSocketUrl) && (
-
- {hl7SocketUrl && (
-
-
-
- )}
- {ventilatorSocketUrl && (
-
-
-
- )}
-
- )}
-
- )}
- {consultationData.discharge_date && (
-
-
-
- Discharge Information
-
-
-
- Reason {" - "}
-
- {DISCHARGE_REASONS.find(
- (d) =>
- d.id === consultationData.discharge_reason
- )?.text ?? "--"}
-
-
- {consultationData.discharge_reason === "REF" && (
-
- Referred Facility {" - "}
-
- {consultationData.referred_to_external ||
- consultationData.referred_to_object?.name ||
- "--"}
-
-
- )}
- {consultationData.discharge_reason === "REC" && (
-
-
- Discharge Date {" - "}
-
- {consultationData.discharge_date
- ? formatDate(
- consultationData.discharge_date
- )
- : "--/--/----"}
-
-
-
- Advice {" - "}
-
- {consultationData.discharge_notes ?? "--"}
-
-
-
-
-
-
- )}
- {consultationData.discharge_reason === "EXP" && (
-
-
- Date of Death {" - "}
-
- {consultationData.death_datetime
- ? formatDateTime(
- consultationData.death_datetime
- )
- : "--:--"}
-
-
-
- Cause of death {" - "}
-
- {consultationData.discharge_notes ?? "--"}
-
-
-
- Confirmed By {" - "}
-
- {consultationData.death_confirmed_doctor ??
- "--"}
-
-
-
- )}
- {["REF", "LAMA"].includes(
- consultationData.discharge_reason ?? ""
- ) && (
-
-
- Discharge Date {" - "}
-
- {consultationData.discharge_date
- ? formatDate(
- consultationData.discharge_date
- )
- : "--/--/----"}
-
-
-
- Notes {" - "}
-
- {consultationData.discharge_notes ?? "--"}
-
-
-
- )}
-
-
-
- )}
- {consultationData.symptoms_text && (
-
-
-
- Symptoms
-
-
-
- Last Daily Update
-
- {consultationData.last_daily_round
- ?.additional_symptoms && (
- <>
-
- {consultationData.last_daily_round?.additional_symptoms.map(
- (symptom: any, index: number) => (
- choice.id === symptom
- )?.text ?? "Err. Unknown"
- }
- size="small"
- />
- )
- )}
-
- {consultationData.last_daily_round
- ?.other_symptoms && (
-
-
- Other Symptoms:
-
- {
- consultationData.last_daily_round
- ?.other_symptoms
- }
-
- )}
-
- from{" "}
- {formatDate(
- consultationData.last_daily_round.created_at
- )}
-
- >
- )}
-
-
- Consultation Update
-
-
- {consultationData.symptoms?.map(
- (symptom, index) => (
- choice.id === symptom
- )?.text ?? "Err. Unknown"
- }
- size="small"
- />
- )
- )}
-
- {consultationData.other_symptoms && (
-
-
- Other Symptoms:
-
- {consultationData.other_symptoms}
-
- )}
-
- from{" "}
- {consultationData.symptoms_onset_date
- ? formatDate(consultationData.symptoms_onset_date)
- : "--/--/----"}
-
-
-
-
- )}
-
- {consultationData.history_of_present_illness && (
-
-
-
- History of Present Illness
-
-
-
-
-
-
- )}
-
- {consultationData.examination_details && (
-
-
-
- Examination details and Clinical conditions:{" "}
-
-
-
-
-
-
- )}
- {consultationData.treatment_plan && (
-
-
-
- Treatment Summary
-
-
-
-
-
-
- )}
- {consultationData.consultation_notes && (
-
-
-
- General Instructions
-
-
-
-
-
-
- )}
-
- {(consultationData.operation ??
- consultationData.special_instruction) && (
-
-
-
- Notes
-
-
- {consultationData.operation && (
-
-
Operation
-
-
- )}
-
- {consultationData.special_instruction && (
-
-
Special Instruction
-
-
- )}
-
-
-
- )}
-
- {consultationData.procedure &&
- consultationData.procedure.length > 0 && (
-
-
-
-
-
-
- Procedure
- |
-
- Notes
- |
-
- Repetitive
- |
-
- Time / Frequency
- |
-
-
-
- {consultationData.procedure?.map(
- (procedure, index) => (
-
-
- {procedure.procedure}
- |
-
- {procedure.notes}
- |
-
- {procedure.repetitive ? "Yes" : "No"}
- |
-
- {procedure.repetitive
- ? procedure.frequency
- : formatDateTime(String(procedure.time))}
- |
-
- )
- )}
-
-
-
-
- )}
- {consultationData.intubation_start_date && (
-
-
-
- Date/Size/LL:{" "}
-
-
-
- Intubation Date{" - "}
-
- {formatDateTime(
- consultationData.intubation_start_date
- )}
-
-
-
- Extubation Date{" - "}
-
- {consultationData.intubation_end_date &&
- formatDateTime(
- consultationData.intubation_end_date
- )}
-
-
-
- ETT/TT (mmid){" - "}
-
- {consultationData.ett_tt}
-
-
-
- Cuff Pressure (mmhg){" - "}
-
- {consultationData.cuff_pressure}
-
-
-
-
-
- )}
-
- {consultationData.lines?.length > 0 && (
-
-
-
- Lines and Catheters
-
-
- {consultationData.lines?.map(
- (line: any, idx: number) => (
-
-
{line.type}
-
- Details:
-
- {line.other_type}
-
-
- Insertion Date:{" "}
-
- {formatDateTime(line.start_date)}
-
-
-
- Site/Level of Fixation:
-
- {line.site}
-
-
-
- )
- )}
-
-
-
- )}
-
-
-
-
- Body Details
-
-
-
- Gender {" - "}
-
- {patientData.gender ?? "-"}
-
-
-
- Age {" - "}
-
- {patientData.age ?? "-"}
-
-
-
- Weight {" - "}
-
- {consultationData.weight ?? "-"} Kg
-
-
-
- Height {" - "}
-
- {consultationData.height ?? "-"} cm
-
-
-
- Body Surface Area {" - "}
-
- {Math.sqrt(
- (Number(consultationData.weight) *
- Number(consultationData.height)) /
- 3600
- ).toFixed(2)}{" "}
- m2
-
-
-
- Blood Group {" - "}
-
- {patientData.blood_group ?? "-"}
-
-
-
-
-
-
-
-
-
-
- setShowAutomatedRounds((s) => !s)}
- />
-
-
-
-
-
-
-
- )}
- {tab === "FEED" && (
-
- )}
- {tab === "SUMMARY" && (
-
- )}
- {tab === "MEDICINES" && (
-
- )}
- {tab === "FILES" && (
-
-
-
- )}
-
- {tab === "ABG" && (
-
- )}
- {tab === "NURSING" && (
-
- )}
- {tab === "NEUROLOGICAL_MONITORING" && (
-
- )}
- {tab === "VENTILATOR" && (
-
- )}
- {tab === "NUTRITION" && (
-
- )}
- {tab === "PRESSURE_SORE" && (
-
- )}
- {tab === "DIALYSIS" && (
-
- )}
- {tab === "INVESTIGATIONS" && (
-
-
-
-
-
- navigate(
- `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/investigation/`
- )
- }
- >
-
- {t("log_lab_results")}
-
-
-
-
-
- )}
-
-
-
-
- );
-};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationABGTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationABGTab.tsx
new file mode 100644
index 00000000000..cf0ce7bd6af
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationABGTab.tsx
@@ -0,0 +1,22 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { ABGPlots } from "../Consultations/ABGPlots";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationABGTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationDialysisTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationDialysisTab.tsx
new file mode 100644
index 00000000000..c3515a80953
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationDialysisTab.tsx
@@ -0,0 +1,14 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { DialysisPlots } from "../Consultations/DialysisPlots";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationDialysisTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationFeedTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationFeedTab.tsx
new file mode 100644
index 00000000000..f4fbc08331c
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationFeedTab.tsx
@@ -0,0 +1,22 @@
+import { lazy } from "react";
+import { Feed } from "../Consultations/Feed";
+import { ConsultationTabProps } from "./index";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationFeedTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationFilesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationFilesTab.tsx
new file mode 100644
index 00000000000..754d4bf7b86
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationFilesTab.tsx
@@ -0,0 +1,18 @@
+import { ConsultationTabProps } from "./index";
+import { FileUpload } from "../../Patient/FileUpload";
+
+export const ConsultationFilesTab = (props: ConsultationTabProps) => {
+ return (
+
+
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationInvestigationsTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationInvestigationsTab.tsx
new file mode 100644
index 00000000000..69b11a30ed5
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationInvestigationsTab.tsx
@@ -0,0 +1,39 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { NonReadOnlyUsers } from "../../../Utils/AuthorizeFor";
+import ButtonV2 from "../../Common/components/ButtonV2";
+import { navigate } from "raviger";
+import CareIcon from "../../../CAREUI/icons/CareIcon";
+import InvestigationTab from "../Investigations/investigationsTab";
+import { t } from "i18next";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+export const ConsultationInvestigationsTab = (props: ConsultationTabProps) => {
+ return (
+
+
+
+
+
+ navigate(
+ `/facility/${props.facilityId}/patient/${props.patientId}/consultation/${props.consultationId}/investigation/`
+ )
+ }
+ >
+
+ {t("log_lab_results")}
+
+
+
+
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationMedicinesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationMedicinesTab.tsx
new file mode 100644
index 00000000000..19810102833
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationMedicinesTab.tsx
@@ -0,0 +1,19 @@
+import { ConsultationTabProps } from "./index";
+import PrescriptionAdministrationsTable from "../../Medicine/PrescriptionAdministrationsTable";
+
+export const ConsultationMedicinesTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationNeurologicalMonitoringTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationNeurologicalMonitoringTab.tsx
new file mode 100644
index 00000000000..85f34f0ec63
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationNeurologicalMonitoringTab.tsx
@@ -0,0 +1,24 @@
+import { lazy } from "react";
+import { NeurologicalTable } from "../Consultations/NeurologicalTables";
+import { ConsultationTabProps } from "./index";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationNeurologicalMonitoringTab = (
+ props: ConsultationTabProps
+) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationNeutritionTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationNeutritionTab.tsx
new file mode 100644
index 00000000000..69f130aca0d
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationNeutritionTab.tsx
@@ -0,0 +1,18 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { NutritionPlots } from "../Consultations/NutritionPlots";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationNeutritionTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationNursingTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationNursingTab.tsx
new file mode 100644
index 00000000000..721ee18d13e
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationNursingTab.tsx
@@ -0,0 +1,18 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { NursingPlot } from "../Consultations/NursingPlot";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationNursingTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationPressureSoreTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationPressureSoreTab.tsx
new file mode 100644
index 00000000000..05327ca6870
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationPressureSoreTab.tsx
@@ -0,0 +1,14 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { PressureSoreDiagrams } from "../Consultations/PressureSoreDiagrams";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationPressureSoreTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationSummaryTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationSummaryTab.tsx
new file mode 100644
index 00000000000..69d20dd64c9
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationSummaryTab.tsx
@@ -0,0 +1,22 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { PrimaryParametersPlot } from "../Consultations/PrimaryParametersPlot";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationSummaryTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
new file mode 100644
index 00000000000..705b3d9479a
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
@@ -0,0 +1,690 @@
+import { lazy, useEffect, useState } from "react";
+import { ConsultationTabProps } from "./index";
+import { AssetBedModel, AssetClass, AssetData } from "../../Assets/AssetTypes";
+import { useDispatch } from "react-redux";
+import { getPermittedFacility, listAssetBeds } from "../../../Redux/actions";
+import { BedModel, FacilityModel } from "../models";
+import HL7PatientVitalsMonitor from "../../VitalsMonitor/HL7PatientVitalsMonitor";
+import VentilatorPatientVitalsMonitor from "../../VitalsMonitor/VentilatorPatientVitalsMonitor";
+import useVitalsAspectRatioConfig from "../../VitalsMonitor/useVitalsAspectRatioConfig";
+import { DISCHARGE_REASONS, SYMPTOM_CHOICES } from "../../../Common/constants";
+import PrescriptionsTable from "../../Medicine/PrescriptionsTable";
+import Chip from "../../../CAREUI/display/Chip";
+import { formatDate, formatDateTime } from "../../../Utils/utils";
+import ReadMore from "../../Common/components/Readmore";
+import { DailyRoundsList } from "../Consultations/DailyRoundsList";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationUpdatesTab = (props: ConsultationTabProps) => {
+ const dispatch: any = useDispatch();
+ const [showAutomatedRounds, setShowAutomatedRounds] = useState(true);
+ const [hl7SocketUrl, setHL7SocketUrl] = useState();
+ const [ventilatorSocketUrl, setVentilatorSocketUrl] = useState();
+ const [monitorBedData, setMonitorBedData] = useState();
+ const [ventilatorBedData, setVentilatorBedData] = useState();
+
+ const vitals = useVitalsAspectRatioConfig({
+ default: undefined,
+ md: 8 / 11,
+ lg: 15 / 11,
+ xl: 13 / 11,
+ "2xl": 19 / 11,
+ "3xl": 23 / 11,
+ });
+
+ useEffect(() => {
+ if (
+ !props.consultationData.facility ||
+ !props.consultationData.current_bed?.bed_object.id
+ )
+ return;
+
+ const fetchData = async () => {
+ const [facilityRes, assetBedRes] = await Promise.all([
+ dispatch(getPermittedFacility(props.consultationData.facility as any)),
+ dispatch(
+ listAssetBeds({
+ facility: props.consultationData.facility as any,
+ bed: props.consultationData.current_bed?.bed_object.id,
+ })
+ ),
+ ]);
+
+ const { middleware_address } = facilityRes.data as FacilityModel;
+ const assetBeds = assetBedRes?.data?.results as AssetBedModel[];
+
+ const monitorBedData = assetBeds?.find(
+ (i) => i.asset_object?.asset_class === AssetClass.HL7MONITOR
+ );
+ setMonitorBedData(monitorBedData);
+ const assetDataForMonitor = monitorBedData?.asset_object;
+ const hl7Meta = assetDataForMonitor?.meta;
+ const hl7Middleware = hl7Meta?.middleware_hostname || middleware_address;
+ if (hl7Middleware && hl7Meta?.local_ip_address) {
+ setHL7SocketUrl(
+ `wss://${hl7Middleware}/observations/${hl7Meta.local_ip_address}`
+ );
+ }
+
+ const consultationBedVentilator =
+ props.consultationData?.current_bed?.assets_objects?.find(
+ (i) => i.asset_class === AssetClass.VENTILATOR
+ );
+ let ventilatorBedData;
+ if (consultationBedVentilator) {
+ ventilatorBedData = {
+ asset_object: consultationBedVentilator,
+ bed_object: props.consultationData?.current_bed?.bed_object,
+ } as AssetBedModel;
+ } else {
+ ventilatorBedData = assetBeds?.find(
+ (i) => i.asset_object.asset_class === AssetClass.VENTILATOR
+ );
+ }
+ setVentilatorBedData(ventilatorBedData);
+ const ventilatorMeta = ventilatorBedData?.asset_object?.meta;
+ const ventilatorMiddleware =
+ ventilatorMeta?.middleware_hostname || middleware_address;
+ if (ventilatorMiddleware && ventilatorMeta?.local_ip_address) {
+ setVentilatorSocketUrl(
+ `wss://${ventilatorMiddleware}/observations/${ventilatorMeta?.local_ip_address}`
+ );
+ }
+
+ if (
+ !(hl7Middleware && hl7Meta?.local_ip_address) &&
+ !(ventilatorMiddleware && ventilatorMeta?.local_ip_address)
+ ) {
+ setHL7SocketUrl(undefined);
+ setVentilatorSocketUrl(undefined);
+ }
+ };
+
+ fetchData();
+ }, [props.consultationData]);
+
+ return (
+
+ {!props.consultationData.discharge_date &&
+ hl7SocketUrl &&
+ ventilatorSocketUrl && (
+
+ )}
+
+
+
+
+ {!props.consultationData.discharge_date &&
+ ((hl7SocketUrl && !ventilatorSocketUrl) ||
+ (!hl7SocketUrl && ventilatorSocketUrl)) && (
+
+ {(hl7SocketUrl || ventilatorSocketUrl) && (
+
+ {hl7SocketUrl && (
+
+
+
+ )}
+ {ventilatorSocketUrl && (
+
+
+
+ )}
+
+ )}
+
+ )}
+ {props.consultationData.discharge_date && (
+
+
+
+ Discharge Information
+
+
+
+ Reason {" - "}
+
+ {DISCHARGE_REASONS.find(
+ (d) =>
+ d.id === props.consultationData.discharge_reason
+ )?.text ?? "--"}
+
+
+ {props.consultationData.discharge_reason === "REF" && (
+
+ Referred Facility {" - "}
+
+ {props.consultationData.referred_to_external ||
+ props.consultationData.referred_to_object?.name ||
+ "--"}
+
+
+ )}
+ {props.consultationData.discharge_reason === "REC" && (
+
+
+ Discharge Date {" - "}
+
+ {props.consultationData.discharge_date
+ ? formatDate(
+ props.consultationData.discharge_date
+ )
+ : "--/--/----"}
+
+
+
+ Advice {" - "}
+
+ {props.consultationData.discharge_notes ?? "--"}
+
+
+
+
+
+
+ )}
+ {props.consultationData.discharge_reason === "EXP" && (
+
+
+ Date of Death {" - "}
+
+ {props.consultationData.death_datetime
+ ? formatDateTime(
+ props.consultationData.death_datetime
+ )
+ : "--:--"}
+
+
+
+ Cause of death {" - "}
+
+ {props.consultationData.discharge_notes ?? "--"}
+
+
+
+ Confirmed By {" - "}
+
+ {props.consultationData.death_confirmed_doctor ??
+ "--"}
+
+
+
+ )}
+ {["REF", "LAMA"].includes(
+ props.consultationData.discharge_reason ?? ""
+ ) && (
+
+
+ Discharge Date {" - "}
+
+ {props.consultationData.discharge_date
+ ? formatDate(
+ props.consultationData.discharge_date
+ )
+ : "--/--/----"}
+
+
+
+ Notes {" - "}
+
+ {props.consultationData.discharge_notes ?? "--"}
+
+
+
+ )}
+
+
+
+ )}
+ {props.consultationData.symptoms_text && (
+
+
+
+ Symptoms
+
+
+
+ Last Daily Update
+
+ {props.consultationData.last_daily_round
+ ?.additional_symptoms && (
+ <>
+
+ {props.consultationData.last_daily_round?.additional_symptoms.map(
+ (symptom: any, index: number) => (
+ choice.id === symptom
+ )?.text ?? "Err. Unknown"
+ }
+ size="small"
+ />
+ )
+ )}
+
+ {props.consultationData.last_daily_round
+ ?.other_symptoms && (
+
+
+ Other Symptoms:
+
+ {
+ props.consultationData.last_daily_round
+ ?.other_symptoms
+ }
+
+ )}
+
+ from{" "}
+ {formatDate(
+ props.consultationData.last_daily_round.created_at
+ )}
+
+ >
+ )}
+
+
+ Consultation Update
+
+
+ {props.consultationData.symptoms?.map(
+ (symptom, index) => (
+ choice.id === symptom
+ )?.text ?? "Err. Unknown"
+ }
+ size="small"
+ />
+ )
+ )}
+
+ {props.consultationData.other_symptoms && (
+
+
+ Other Symptoms:
+
+ {props.consultationData.other_symptoms}
+
+ )}
+
+ from{" "}
+ {props.consultationData.symptoms_onset_date
+ ? formatDate(props.consultationData.symptoms_onset_date)
+ : "--/--/----"}
+
+
+
+
+ )}
+
+ {props.consultationData.history_of_present_illness && (
+
+
+
+ History of Present Illness
+
+
+
+
+
+
+ )}
+
+ {props.consultationData.examination_details && (
+
+
+
+ Examination details and Clinical conditions:{" "}
+
+
+
+
+
+
+ )}
+ {props.consultationData.treatment_plan && (
+
+
+
+ Treatment Summary
+
+
+
+
+
+
+ )}
+ {props.consultationData.consultation_notes && (
+
+
+
+ General Instructions
+
+
+
+
+
+
+ )}
+
+ {(props.consultationData.operation ??
+ props.consultationData.special_instruction) && (
+
+
+
+ Notes
+
+
+ {props.consultationData.operation && (
+
+
Operation
+
+
+ )}
+
+ {props.consultationData.special_instruction && (
+
+
Special Instruction
+
+
+ )}
+
+
+
+ )}
+
+ {props.consultationData.procedure &&
+ props.consultationData.procedure.length > 0 && (
+
+
+
+
+
+
+ Procedure
+ |
+
+ Notes
+ |
+
+ Repetitive
+ |
+
+ Time / Frequency
+ |
+
+
+
+ {props.consultationData.procedure?.map(
+ (procedure, index) => (
+
+
+ {procedure.procedure}
+ |
+
+ {procedure.notes}
+ |
+
+ {procedure.repetitive ? "Yes" : "No"}
+ |
+
+ {procedure.repetitive
+ ? procedure.frequency
+ : formatDateTime(String(procedure.time))}
+ |
+
+ )
+ )}
+
+
+
+
+ )}
+ {props.consultationData.intubation_start_date && (
+
+
+
+ Date/Size/LL:{" "}
+
+
+
+ Intubation Date{" - "}
+
+ {formatDateTime(
+ props.consultationData.intubation_start_date
+ )}
+
+
+
+ Extubation Date{" - "}
+
+ {props.consultationData.intubation_end_date &&
+ formatDateTime(
+ props.consultationData.intubation_end_date
+ )}
+
+
+
+ ETT/TT (mmid){" - "}
+
+ {props.consultationData.ett_tt}
+
+
+
+ Cuff Pressure (mmhg){" - "}
+
+ {props.consultationData.cuff_pressure}
+
+
+
+
+
+ )}
+
+ {props.consultationData.lines?.length > 0 && (
+
+
+
+ Lines and Catheters
+
+
+ {props.consultationData.lines?.map(
+ (line: any, idx: number) => (
+
+
{line.type}
+
+ Details:
+
+ {line.other_type}
+
+
+ Insertion Date:{" "}
+
+ {formatDateTime(line.start_date)}
+
+
+
+ Site/Level of Fixation:
+
+ {line.site}
+
+
+
+ )
+ )}
+
+
+
+ )}
+
+
+
+
+ Body Details
+
+
+
+ Gender {" - "}
+
+ {props.patientData.gender ?? "-"}
+
+
+
+ Age {" - "}
+
+ {props.patientData.age ?? "-"}
+
+
+
+ Weight {" - "}
+
+ {props.consultationData.weight ?? "-"} Kg
+
+
+
+ Height {" - "}
+
+ {props.consultationData.height ?? "-"} cm
+
+
+
+ Body Surface Area {" - "}
+
+ {Math.sqrt(
+ (Number(props.consultationData.weight) *
+ Number(props.consultationData.height)) /
+ 3600
+ ).toFixed(2)}{" "}
+ m2
+
+
+
+ Blood Group {" - "}
+
+ {props.patientData.blood_group ?? "-"}
+
+
+
+
+
+
+
+
+
+
+ setShowAutomatedRounds((s) => !s)}
+ />
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationVentilatorTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationVentilatorTab.tsx
new file mode 100644
index 00000000000..d14b54cc096
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/ConsultationVentilatorTab.tsx
@@ -0,0 +1,22 @@
+import { lazy } from "react";
+import { ConsultationTabProps } from "./index";
+import { VentilatorPlot } from "../Consultations/VentilatorPlot";
+
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+
+export const ConsultationVentilatorTab = (props: ConsultationTabProps) => {
+ return (
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx
new file mode 100644
index 00000000000..490c704f295
--- /dev/null
+++ b/src/Components/Facility/ConsultationDetails/index.tsx
@@ -0,0 +1,501 @@
+import {
+ CONSULTATION_TABS,
+ GENDER_TYPES,
+ OptionsType,
+ SYMPTOM_CHOICES,
+} from "../../../Common/constants";
+import { ConsultationModel, ICD11DiagnosisModel } from "../models";
+import { getConsultation, getPatient } from "../../../Redux/actions";
+import { statusType, useAbortableEffect } from "../../../Common/utils";
+import { lazy, useCallback, useState } from "react";
+
+import ButtonV2 from "../../Common/components/ButtonV2";
+import CareIcon from "../../../CAREUI/icons/CareIcon";
+import DischargeModal from "../DischargeModal";
+import DischargeSummaryModal from "../DischargeSummaryModal";
+import DoctorVideoSlideover from "../DoctorVideoSlideover";
+import { make as Link } from "../../Common/components/Link.bs";
+import PatientInfoCard from "../../Patient/PatientInfoCard";
+import { PatientModel } from "../../Patient/models";
+import { formatDateTime, relativeTime } from "../../../Utils/utils";
+
+import { navigate } from "raviger";
+import { useDispatch } from "react-redux";
+import { useQueryParams } from "raviger";
+import { useTranslation } from "react-i18next";
+import { triggerGoal } from "../../Common/Plausible";
+import useAuthUser from "../../../Common/hooks/useAuthUser";
+import { ConsultationUpdatesTab } from "./ConsultationUpdatesTab";
+import { ConsultationABGTab } from "./ConsultationABGTab";
+import { ConsultationNursingTab } from "./ConsultationNursingTab";
+import { ConsultationFeedTab } from "./ConsultationFeedTab";
+import { ConsultationSummaryTab } from "./ConsultationSummaryTab";
+import { ConsultationFilesTab } from "./ConsultationFilesTab";
+import { ConsultationMedicinesTab } from "./ConsultationMedicinesTab";
+import { ConsultationInvestigationsTab } from "./ConsultationInvestigationsTab";
+import { ConsultationVentilatorTab } from "./ConsultationVentilatorTab";
+import { ConsultationPressureSoreTab } from "./ConsultationPressureSoreTab";
+import { ConsultationDialysisTab } from "./ConsultationDialysisTab";
+import { ConsultationNeurologicalMonitoringTab } from "./ConsultationNeurologicalMonitoringTab";
+
+const Loading = lazy(() => import("../../Common/Loading"));
+const PageTitle = lazy(() => import("../../Common/PageTitle"));
+const symptomChoices = [...SYMPTOM_CHOICES];
+
+export interface ConsultationTabProps {
+ consultationId: string;
+ facilityId: string;
+ patientId: string;
+ consultationData: ConsultationModel;
+ patientData: PatientModel;
+}
+
+export const ConsultationDetails = (props: any) => {
+ const { t } = useTranslation();
+ const { facilityId, patientId, consultationId } = props;
+ const tab = props.tab.toUpperCase();
+ const dispatch: any = useDispatch();
+ const [isLoading, setIsLoading] = useState(false);
+ const [showDoctors, setShowDoctors] = useState(false);
+ const [qParams, _] = useQueryParams();
+
+ const [consultationData, setConsultationData] = useState(
+ {} as ConsultationModel
+ );
+ const [patientData, setPatientData] = useState({});
+ const [openDischargeSummaryDialog, setOpenDischargeSummaryDialog] =
+ useState(false);
+ const [openDischargeDialog, setOpenDischargeDialog] = useState(false);
+
+ const getPatientGender = (patientData: any) =>
+ GENDER_TYPES.find((i) => i.id === patientData.gender)?.text;
+
+ const getPatientAddress = (patientData: any) =>
+ `${patientData.address},\n${patientData.ward_object?.name},\n${patientData.local_body_object?.name},\n${patientData.district_object?.name},\n${patientData.state_object?.name}`;
+
+ const getPatientComorbidities = (patientData: any) => {
+ if (patientData?.medical_history?.length) {
+ const medHis = patientData.medical_history;
+ return medHis.map((item: any) => item.disease).join(", ");
+ } else {
+ return "None";
+ }
+ };
+
+ const authUser = useAuthUser();
+
+ const fetchData = useCallback(
+ async (status: statusType) => {
+ setIsLoading(true);
+ const res = await dispatch(getConsultation(consultationId));
+ if (!status.aborted) {
+ if (res?.data) {
+ const data: ConsultationModel = {
+ ...res.data,
+ symptoms_text: "",
+ };
+ if (res.data.symptoms?.length) {
+ const symptoms = res.data.symptoms
+ .filter((symptom: number) => symptom !== 9)
+ .map((symptom: number) => {
+ const option = symptomChoices.find((i) => i.id === symptom);
+ return option ? option.text.toLowerCase() : symptom;
+ });
+ data.symptoms_text = symptoms.join(", ");
+ }
+ setConsultationData(data);
+ const id = res.data.patient;
+ const patientRes = await dispatch(getPatient({ id }));
+ if (patientRes?.data) {
+ const patientGender = getPatientGender(patientRes.data);
+ const patientAddress = getPatientAddress(patientRes.data);
+ const patientComorbidities = getPatientComorbidities(
+ patientRes.data
+ );
+ const data = {
+ ...patientRes.data,
+ gender: patientGender,
+ address: patientAddress,
+ comorbidities: patientComorbidities,
+ is_declared_positive: patientRes.data.is_declared_positive
+ ? "Yes"
+ : "No",
+ is_vaccinated: patientData.is_vaccinated ? "Yes" : "No",
+ };
+ setPatientData(data);
+ }
+ } else {
+ navigate("/not-found");
+ }
+ setIsLoading(false);
+ }
+ },
+ [consultationId, dispatch, patientData.is_vaccinated]
+ );
+
+ useAbortableEffect((status: statusType) => {
+ fetchData(status);
+ triggerGoal("Patient Consultation Viewed", {
+ facilityId: facilityId,
+ consultationId: consultationId,
+ userId: authUser.id,
+ });
+ }, []);
+
+ const TABS = {
+ UPDATES: ConsultationUpdatesTab,
+ FEED: ConsultationFeedTab,
+ SUMMARY: ConsultationSummaryTab,
+ MEDICINES: ConsultationMedicinesTab,
+ FILES: ConsultationFilesTab,
+ INVESTIGATIONS: ConsultationInvestigationsTab,
+ ABG: ConsultationABGTab,
+ NURSING: ConsultationNursingTab,
+ NEUROLOGICAL_MONITORING: ConsultationNeurologicalMonitoringTab,
+ VENTILATOR: ConsultationVentilatorTab,
+ NUTRITION: ConsultationNursingTab,
+ PRESSURE_SORE: ConsultationPressureSoreTab,
+ DIALYSIS: ConsultationDialysisTab,
+ };
+
+ const consultationTabProps: ConsultationTabProps = {
+ consultationId,
+ facilityId,
+ patientId,
+ consultationData,
+ patientData,
+ };
+
+ const SelectedTab = TABS[tab];
+
+ if (isLoading) {
+ return ;
+ }
+
+ const tabButtonClasses = (selected: boolean) =>
+ `capitalize min-w-max-content cursor-pointer border-transparent text-gray-700 hover:text-gray-700 hover:border-gray-300 font-bold whitespace-nowrap ${
+ selected === true ? "border-primary-500 text-primary-600 border-b-2" : ""
+ }`;
+
+ const ShowDiagnosis = ({
+ diagnoses = [],
+ label = "Diagnosis",
+ nshow = 2,
+ }: {
+ diagnoses: ICD11DiagnosisModel[] | undefined;
+ label: string;
+ nshow?: number;
+ }) => {
+ const [showMore, setShowMore] = useState(false);
+
+ return diagnoses.length ? (
+
+ ) : null;
+ };
+
+ return (
+
+
setOpenDischargeSummaryDialog(false)}
+ />
+
+ setOpenDischargeDialog(false)}
+ consultationData={consultationData}
+ />
+
+
+
+
+
+
+
+
+ {consultationData.admitted_to && (
+
+
+ Patient
+ {consultationData.discharge_date
+ ? " Discharged from"
+ : " Admitted to"}
+
+ {consultationData.admitted_to}
+
+
+ {(consultationData.admission_date ??
+ consultationData.discharge_date) && (
+
+ {relativeTime(
+ consultationData.discharge_date
+ ? consultationData.discharge_date
+ : consultationData.admission_date
+ )}
+
+ )}
+
+ {consultationData.admission_date &&
+ formatDateTime(consultationData.admission_date)}
+ {consultationData.discharge_date &&
+ ` - ${formatDateTime(consultationData.discharge_date)}`}
+
+
+ )}
+
+
+
+
+ {/*consultationData.other_symptoms && (
+
+
+ Other Symptoms:{" "}
+
+ {consultationData.other_symptoms}
+
+ )*/}
+
+ {consultationData.icd11_principal_diagnosis && (
+
+ d.id === consultationData.icd11_principal_diagnosis
+ )!,
+ ]}
+ />
+ )}
+
+
+
+
+
+ {(consultationData.verified_by_object ||
+ consultationData.deprecated_verified_by) && (
+
+
+ Treating Physician:{" "}
+
+ {consultationData.verified_by_object
+ ? `${consultationData.verified_by_object.first_name} ${consultationData.verified_by_object.last_name}`
+ : consultationData.deprecated_verified_by}
+
+
+ )}
+
+
+ setOpenDischargeSummaryDialog(true)}>
+
+ {t("discharge_summary")}
+
+
+ setOpenDischargeDialog(true)}
+ disabled={!!consultationData.discharge_date}
+ >
+
+ {t("discharge_from_care")}
+
+
+
+
+
+
+ Created:
+ {consultationData.created_date
+ ? formatDateTime(consultationData.created_date)
+ : "--:--"}{" "}
+ |
+
+ {consultationData.created_by && (
+
+ {` ${consultationData.created_by.first_name} ${consultationData.created_by.last_name} `}
+ {`@${consultationData.created_by.username} (${consultationData.created_by.user_type})`}
+
+ )}
+
+
+
+ Last Modified:
+ {consultationData.modified_date
+ ? formatDateTime(consultationData.modified_date)
+ : "--:--"}{" "}
+ |
+
+ {consultationData.last_edited_by && (
+
+ {` ${consultationData.last_edited_by.first_name} ${consultationData.last_edited_by.last_name} `}
+ {`@${consultationData.last_edited_by.username} (${consultationData.last_edited_by.user_type})`}
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx
index ed7fd7b57b6..ca2301b5964 100644
--- a/src/Components/Facility/ConsultationForm.tsx
+++ b/src/Components/Facility/ConsultationForm.tsx
@@ -40,7 +40,10 @@ import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField";
import DateFormField from "../Form/FormFields/DateFormField";
import { DiagnosisSelectFormField } from "../Common/DiagnosisSelectFormField";
import { FacilitySelect } from "../Common/FacilitySelect";
-import { FieldChangeEventHandler } from "../Form/FormFields/Utils";
+import {
+ FieldChangeEvent,
+ FieldChangeEventHandler,
+} from "../Form/FormFields/Utils";
import { FormAction } from "../Form/Utils";
import PatientCategorySelect from "../Patient/PatientCategorySelect";
import { SelectFormField } from "../Form/FormFields/SelectFormField";
@@ -57,6 +60,7 @@ import useConfig from "../../Common/hooks/useConfig";
import { useDispatch } from "react-redux";
import useVisibility from "../../Utils/useVisibility";
import dayjs from "../../Utils/dayjs";
+import AutocompleteFormField from "../Form/FormFields/Autocomplete.js";
const Loading = lazy(() => import("../Common/Loading"));
const PageTitle = lazy(() => import("../Common/PageTitle"));
@@ -80,7 +84,9 @@ type FormDetails = {
referred_to_external?: string;
icd11_diagnoses_object: ICD11DiagnosisModel[];
icd11_provisional_diagnoses_object: ICD11DiagnosisModel[];
+ icd11_principal_diagnosis?: ICD11DiagnosisModel["id"];
verified_by: string;
+ verified_by_object: UserModel | null;
is_kasp: BooleanStrings;
kasp_enabled_date: null;
examination_details: string;
@@ -124,7 +130,9 @@ const initForm: FormDetails = {
referred_to_external: "",
icd11_diagnoses_object: [],
icd11_provisional_diagnoses_object: [],
+ icd11_principal_diagnosis: undefined,
verified_by: "",
+ verified_by_object: null,
is_kasp: "false",
kasp_enabled_date: null,
examination_details: "",
@@ -198,7 +206,8 @@ const consultationFormReducer = (state = initialState, action: FormAction) => {
type ConsultationFormSection =
| "Consultation Details"
| "Diagnosis"
- | "Treatment Plan";
+ | "Treatment Plan"
+ | "Bed Status";
export const ConsultationForm = (props: any) => {
const { goBack } = useAppHistory();
@@ -223,6 +232,7 @@ export const ConsultationForm = (props: any) => {
const [consultationDetailsVisible, consultationDetailsRef] = useVisibility();
const [diagnosisVisible, diagnosisRef] = useVisibility(-300);
const [treatmentPlanVisible, treatmentPlanRef] = useVisibility(-300);
+ const [bedStatusVisible, bedStatusRef] = useVisibility(-300);
const [disabledFields, setDisabledFields] = useState([]);
const sections = {
@@ -241,6 +251,11 @@ export const ConsultationForm = (props: any) => {
visible: treatmentPlanVisible,
ref: treatmentPlanRef,
},
+ "Bed Status": {
+ iconClass: "care-l-bed",
+ visible: bedStatusVisible,
+ ref: bedStatusRef,
+ },
};
useEffect(() => {
@@ -248,9 +263,15 @@ export const ConsultationForm = (props: any) => {
if (consultationDetailsVisible) return "Consultation Details";
if (diagnosisVisible) return "Diagnosis";
if (treatmentPlanVisible) return "Treatment Plan";
+ if (bedStatusVisible) return "Bed Status";
return prev;
});
- }, [consultationDetailsVisible, diagnosisVisible, treatmentPlanVisible]);
+ }, [
+ consultationDetailsVisible,
+ diagnosisVisible,
+ treatmentPlanVisible,
+ bedStatusVisible,
+ ]);
useEffect(() => {
async function fetchPatientName() {
@@ -313,12 +334,13 @@ export const ConsultationForm = (props: any) => {
?.id ?? "Comfort"
: "Comfort",
patient_no: res.data.patient_no ?? "",
- verified_by: res.data.verified_by ? res.data.verified_by : "",
OPconsultation: res.data.consultation_notes,
is_telemedicine: `${res.data.is_telemedicine}`,
is_kasp: `${res.data.is_kasp}`,
assigned_to: res.data.assigned_to || "",
assigned_to_object: res.data.assigned_to_object,
+ verified_by: res.data.verified_by || "",
+ verified_by_object: res.data.verified_by_object,
ett_tt: res.data.ett_tt ? Number(res.data.ett_tt) : 3,
special_instruction: res.data.special_instruction || "",
weight: res.data.weight ? res.data.weight : "",
@@ -516,8 +538,8 @@ export const ConsultationForm = (props: any) => {
}
case "verified_by": {
- if (!state.form[field].replace(/\s/g, "").length) {
- errors[field] = "Please fill verified by";
+ if (state.form.suggestion !== "DD" && !state.form[field]) {
+ errors[field] = "Please fill treating physician";
invalidForm = true;
break;
}
@@ -538,6 +560,44 @@ export const ConsultationForm = (props: any) => {
return;
}
+ case "icd11_principal_diagnosis": {
+ if (!state.form[field]) {
+ errors[field] = "Please select Principal Diagnosis";
+ invalidForm = true;
+ break;
+ }
+
+ if (
+ state.form[field] &&
+ state.form["icd11_diagnoses_object"].length &&
+ !state.form["icd11_provisional_diagnoses_object"] &&
+ !state.form["icd11_diagnoses_object"]
+ .map((d) => d.id)
+ .includes(state.form[field]!)
+ ) {
+ errors[field] =
+ "Please select Principal Diagnosis from Final Diagnosis";
+ invalidForm = true;
+ break;
+ }
+
+ if (
+ state.form[field] &&
+ state.form["icd11_provisional_diagnoses_object"].length &&
+ !state.form["icd11_diagnoses_object"] &&
+ !state.form["icd11_provisional_diagnoses_object"]
+ .map((d) => d.id)
+ .includes(state.form[field]!)
+ ) {
+ errors[field] =
+ "Please select Principal Diagnosis from Provisional Diagnosis";
+ invalidForm = true;
+ break;
+ }
+
+ return;
+ }
+
default:
return;
}
@@ -558,6 +618,7 @@ export const ConsultationForm = (props: any) => {
};
const declareThePatientDead = async (
+ id: string,
cause_of_death: string,
death_datetime: string,
death_confirmed_doctor: string
@@ -569,6 +630,7 @@ export const ConsultationForm = (props: any) => {
discharge_notes: cause_of_death,
death_datetime: death_datetime,
death_confirmed_doctor: death_confirmed_doctor,
+ discharge_date: dayjs().toISOString(),
},
{ id }
)
@@ -617,6 +679,7 @@ export const ConsultationForm = (props: any) => {
state.form.icd11_provisional_diagnoses_object.map(
(o: ICD11DiagnosisModel) => o.id
),
+ icd11_principal_diagnosis: state.form.icd11_principal_diagnosis,
verified_by: state.form.verified_by,
investigation: state.form.InvestigationAdvice,
procedure: state.form.procedures,
@@ -653,6 +716,7 @@ export const ConsultationForm = (props: any) => {
if (data.suggestion === "DD") {
await declareThePatientDead(
+ res.data.id,
state.form.cause_of_death,
state.form.death_datetime,
state.form.death_confirmed_doctor
@@ -692,7 +756,6 @@ export const ConsultationForm = (props: any) => {
symptoms_onset_date: new Date(),
category: "Critical",
suggestion: "DD",
- verified_by: "Brought Dead",
},
});
} else if (event.name === "suggestion" && event.value === "DD") {
@@ -705,6 +768,18 @@ export const ConsultationForm = (props: any) => {
verified_by: "Declared Dead",
},
});
+ } else if (
+ event.name === "icd11_diagnoses_object" ||
+ event.name === "icd11_provisional_diagnoses_object"
+ ) {
+ dispatch({
+ type: "set_form",
+ form: {
+ ...state.form,
+ [event.name]: event.value,
+ icd11_principal_diagnosis: undefined,
+ },
+ });
} else {
dispatch({
type: "set_form",
@@ -713,14 +788,14 @@ export const ConsultationForm = (props: any) => {
}
};
- const handleDoctorSelect = (doctor: UserModel | null) => {
- if (doctor?.id) {
+ const handleDoctorSelect = (event: FieldChangeEvent) => {
+ if (event.value?.id) {
dispatch({
type: "set_form",
form: {
...state.form,
- assigned_to: doctor.id.toString(),
- assigned_to_object: doctor,
+ [event.name]: event.value.id.toString(),
+ [`${event.name}_object`]: event.value,
},
});
} else {
@@ -728,8 +803,8 @@ export const ConsultationForm = (props: any) => {
type: "set_form",
form: {
...state.form,
- assigned_to: "",
- assigned_to_object: null,
+ [event.name]: "",
+ [`${event.name}_object`]: null,
},
});
}
@@ -817,6 +892,9 @@ export const ConsultationForm = (props: any) => {
if (state.form.consultation_status === 1) {
return null;
}
+ if (!isUpdate && sectionTitle === "Bed Status") {
+ return null;
+ }
const isCurrent = currentSection === sectionTitle;
const section = sections[sectionTitle as ConsultationFormSection];
return (
@@ -1136,6 +1214,22 @@ export const ConsultationForm = (props: any) => {
label="Final Diagnosis"
/>
+
+
+
option.label}
+ optionValue={(option) => option.id}
+ required
+ />
+
@@ -1225,11 +1319,17 @@ export const ConsultationForm = (props: any) => {
className="col-span-6"
ref={fieldRef["verified_by"]}
>
-
@@ -1274,11 +1374,10 @@ export const ConsultationForm = (props: any) => {
value={
state.form.assigned_to_object ?? undefined
}
- onChange={(option) =>
- handleDoctorSelect(option.value)
- }
+ onChange={handleDoctorSelect}
userType={"Doctor"}
name={"assigned_to"}
+ label="Assigned to"
/>
)}
@@ -1306,7 +1405,7 @@ export const ConsultationForm = (props: any) => {
{isUpdate && (
<>
-
Update Bed
+ {sectionTitle("Bed Status")}
= ({ consultationId, facilityId }) => {
const [precision, setPrecision] = useState(1);
const [cameraState, setCameraState] = useState(null);
const [isFullscreen, setFullscreen] = useFullscreen();
+ const [videoStartTime, setVideoStartTime] = useState(null);
const authUser = useAuthUser();
useEffect(() => {
@@ -98,7 +99,7 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
async (status: statusType) => {
setIsLoading(true);
const res = await dispatch(getConsultation(consultationId));
- if (!status.aborted && res.data) {
+ if (!status.aborted && res?.data) {
const consultation = res.data as ConsultationModel;
const consultationBedId = consultation.current_bed?.bed_object?.id;
if (consultationBedId) {
@@ -197,6 +198,16 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
dispatch,
});
+ const calculateVideoLiveDelay = () => {
+ const video = liveFeedPlayerRef.current as HTMLVideoElement;
+ if (!video || !videoStartTime) return 0;
+
+ const timeDifference =
+ (new Date().getTime() - videoStartTime.getTime()) / 1000;
+
+ return timeDifference - video.currentTime;
+ };
+
const getBedPresets = async (asset: any) => {
if (asset.id && bed) {
const bedAssets = await dispatch(listAssetBeds({ asset: asset.id, bed }));
@@ -240,7 +251,7 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
}, []);
useEffect(() => {
- if (streamStatus === StreamStatus.Playing) {
+ if (!currentPreset && streamStatus === StreamStatus.Playing) {
setLoading(CAMERA_STATES.MOVING.GENERIC);
const preset =
bedPresets?.find(
@@ -296,12 +307,19 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
},
reset: () => {
setStreamStatus(StreamStatus.Loading);
+ setVideoStartTime(null);
startStream({
onSuccess: () => setStreamStatus(StreamStatus.Playing),
onError: () => setStreamStatus(StreamStatus.Offline),
});
},
fullScreen: () => {
+ if (isIOS) {
+ const element = document.querySelector("video");
+ if (!element) return;
+ setFullscreen(true, element as HTMLElement);
+ return;
+ }
if (!liveFeedPlayerRef.current) return;
setFullscreen(
!isFullscreen,
@@ -431,10 +449,16 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
playsinline={true}
playing={true}
muted={true}
+ onPlay={() => {
+ setVideoStartTime(() => new Date());
+ }}
width="100%"
height="100%"
onBuffer={() => {
- setStreamStatus(StreamStatus.Loading);
+ const delay = calculateVideoLiveDelay();
+ if (delay > 5) {
+ setStreamStatus(StreamStatus.Loading);
+ }
}}
onError={(e: any, _: any, hlsInstance: any) => {
if (e === "hlsError") {
@@ -453,6 +477,15 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
muted
playsInline
className="max-h-full max-w-full"
+ onPlay={() => {
+ setVideoStartTime(() => new Date());
+ }}
+ onWaiting={() => {
+ const delay = calculateVideoLiveDelay();
+ if (delay > 5) {
+ setStreamStatus(StreamStatus.Loading);
+ }
+ }}
ref={liveFeedPlayerRef as any}
/>
)}
@@ -524,6 +557,13 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
clickAction={() => cameraPTZ[4].callback()}
/>
+ {streamStatus === StreamStatus.Playing &&
+ calculateVideoLiveDelay() > 3 && (
+
+
+ Slow Network Detected
+
+ )}
{[
false,
diff --git a/src/Components/Facility/Consultations/NeurologicalTables.tsx b/src/Components/Facility/Consultations/NeurologicalTables.tsx
index 79a0675a708..89e9d598604 100644
--- a/src/Components/Facility/Consultations/NeurologicalTables.tsx
+++ b/src/Components/Facility/Consultations/NeurologicalTables.tsx
@@ -411,7 +411,9 @@ export const NeurologicalTable = (props: any) => {
Scale Description
-
Eye Open
+
+ Eye Opening Response
+
{EYE_OPEN_SCALE.map((x: any) => (
0) {
setLatestClaim(res.data.results[0]);
if (isCreateClaimLoading)
Notification.Success({ msg: "Fetched Claim Approval Results" });
diff --git a/src/Components/Facility/FacilityCard.tsx b/src/Components/Facility/FacilityCard.tsx
index e66fc4f3cc2..43e515cec93 100644
--- a/src/Components/Facility/FacilityCard.tsx
+++ b/src/Components/Facility/FacilityCard.tsx
@@ -9,7 +9,7 @@ import ButtonV2, { Cancel, Submit } from "../Common/components/ButtonV2";
import * as Notification from "../../Utils/Notifications.js";
import Chip from "../../CAREUI/display/Chip";
import CareIcon from "../../CAREUI/icons/CareIcon";
-import { parsePhoneNumber } from "libphonenumber-js";
+import { formatPhoneNumber, parsePhoneNumber } from "../../Utils/utils";
import DialogModal from "../Common/Dialog";
import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
import useConfig from "../../Common/hooks/useConfig";
@@ -147,10 +147,9 @@ export const FacilityCard = (props: { facility: any; userType: any }) => {
href={`tel:${facility.phone_number}`}
className="text-sm font-semibold tracking-wider"
>
- {parsePhoneNumber(
- facility.phone_number as string,
- "IN"
- ).formatInternational() || "-"}
+ {formatPhoneNumber(
+ parsePhoneNumber(facility.phone_number as string) ?? "-"
+ )}
diff --git a/src/Components/Facility/FacilityCreate.tsx b/src/Components/Facility/FacilityCreate.tsx
index d1243daaf1d..e742caefb82 100644
--- a/src/Components/Facility/FacilityCreate.tsx
+++ b/src/Components/Facility/FacilityCreate.tsx
@@ -26,7 +26,11 @@ import {
listDoctor,
updateFacility,
} from "../../Redux/actions";
-import { getPincodeDetails, includesIgnoreCase } from "../../Utils/utils";
+import {
+ getPincodeDetails,
+ includesIgnoreCase,
+ parsePhoneNumber,
+} from "../../Utils/utils";
import {
phonePreg,
validateLatitude,
@@ -51,11 +55,11 @@ import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
import TextFormField from "../Form/FormFields/TextFormField";
import { navigate } from "raviger";
-import { parsePhoneNumberFromString } from "libphonenumber-js";
import useAppHistory from "../../Common/hooks/useAppHistory";
import useConfig from "../../Common/hooks/useConfig";
import { useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
+import { PhoneNumberValidator } from "../Form/FieldValidators.js";
const Loading = lazy(() => import("../Common/Loading"));
@@ -434,11 +438,11 @@ export const FacilityCreate = (props: FacilityProps) => {
return;
case "phone_number":
// eslint-disable-next-line no-case-declarations
- const phoneNumber = parsePhoneNumberFromString(state.form[field]);
+ const phoneNumber = state.form[field];
if (
- !state.form[field] ||
- !phoneNumber?.isPossible() ||
- !phonePreg(String(phoneNumber?.number))
+ !phoneNumber ||
+ !PhoneNumberValidator()(phoneNumber) === undefined ||
+ !phonePreg(phoneNumber)
) {
errors[field] = t("invalid_phone_number");
invalidForm = true;
@@ -488,9 +492,7 @@ export const FacilityCreate = (props: FacilityProps) => {
kasp_empanelled: JSON.parse(state.form.kasp_empanelled),
latitude: state.form.latitude || null,
longitude: state.form.longitude || null,
- phone_number: parsePhoneNumberFromString(
- state.form.phone_number
- )?.format("E.164"),
+ phone_number: parsePhoneNumber(state.form.phone_number),
oxygen_capacity: state.form.oxygen_capacity
? state.form.oxygen_capacity
: 0,
diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx
index ec157d61884..15317b1b56c 100644
--- a/src/Components/Facility/FacilityHome.tsx
+++ b/src/Components/Facility/FacilityHome.tsx
@@ -565,6 +565,7 @@ export const FacilityHome = (props: any) => {
Location Management
navigate(`/facility/${facilityId}/resource/new`)
}
@@ -574,6 +575,7 @@ export const FacilityHome = (props: any) => {
Resource Request
navigate(`/facility/${facilityId}/assets/new`)}
authorizeFor={NonReadOnlyUsers}
icon={}
@@ -581,18 +583,21 @@ export const FacilityHome = (props: any) => {
Create Asset
navigate(`/assets?facility=${facilityId}`)}
icon={}
>
View Assets
navigate(`/facility/${facilityId}/users`)}
icon={}
>
View Users
setOpenDeleteDialog(true)}
className="flex items-center gap-3"
diff --git a/src/Components/Facility/LocationManagement.tsx b/src/Components/Facility/LocationManagement.tsx
index 01e0c246ecb..38dcfc1f389 100644
--- a/src/Components/Facility/LocationManagement.tsx
+++ b/src/Components/Facility/LocationManagement.tsx
@@ -1,176 +1,99 @@
-import { useCallback, useState, ReactElement, lazy } from "react";
-
-import { useDispatch } from "react-redux";
-import { statusType, useAbortableEffect } from "../../Common/utils";
-import { listFacilityAssetLocation, getAnyFacility } from "../../Redux/actions";
-import Pagination from "../Common/Pagination";
-import { LocationModel } from "./models";
+import { lazy } from "react";
import ButtonV2 from "../Common/components/ButtonV2";
import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import CareIcon from "../../CAREUI/icons/CareIcon";
import Page from "../Common/components/Page";
-const Loading = lazy(() => import("../Common/Loading"));
+import routes from "../../Redux/api";
+import PaginatedList from "../../CAREUI/misc/PaginatedList";
+import { LocationModel } from "./models";
-interface LocationManagementProps {
- facilityId: string;
-}
+const Loading = lazy(() => import("../Common/Loading"));
-interface LocationRowProps {
- id: string;
+interface Props {
facilityId: string;
- name: string;
- description: string;
}
-const LocationRow = (props: LocationRowProps) => {
- const { id, facilityId, name, description } = props;
-
+export default function LocationManagement({ facilityId }: Props) {
return (
-
-
-
-
{name}
-
{description}
-
-
-
-
-
- Edit
-
-
(
+
+
+ Add New Location
+
+ }
>
-
- Manage Beds
-
-
-
- );
-};
-
-export const LocationManagement = (props: LocationManagementProps) => {
- const { facilityId } = props;
- const dispatchAction: any = useDispatch();
- const [isLoading, setIsLoading] = useState(false);
- let location: ReactElement | null = null;
- let locationsList: ReactElement[] | ReactElement = [];
- const [locations, setLocations] = useState([]);
- const [offset, setOffset] = useState(0);
- const [currentPage, setCurrentPage] = useState(1);
- const [totalCount, setTotalCount] = useState(0);
- const [facilityName, setFacilityName] = useState("");
- const limit = 14;
-
- const fetchData = useCallback(
- async (status: statusType) => {
- setIsLoading(true);
- const facility = await dispatchAction(getAnyFacility(facilityId));
-
- setFacilityName(facility?.data?.name || "");
-
- const res = await dispatchAction(
- listFacilityAssetLocation(
- { limit, offset },
- { facility_external_id: facilityId }
- )
- );
- if (!status.aborted) {
- if (res?.data) {
- setLocations(res.data.results);
- setTotalCount(res.data.count);
- }
- setIsLoading(false);
- }
- },
- [dispatchAction, offset, facilityId]
- );
-
- useAbortableEffect(
- (status: statusType) => {
- fetchData(status);
- },
- [fetchData]
- );
+
+
+
+ Add New Location
+
+
+
+ No locations available
+
- const handlePagination = (page: number, limit: number) => {
- const offset = (page - 1) * limit;
- setCurrentPage(page);
- setOffset(offset);
- };
+
+
+
- if (locations?.length) {
- locationsList = locations.map((locationItem: LocationModel) => (
-
- ));
- } else if (locations && locations.length === 0) {
- locationsList = (
-
- No locations available
-
- );
- }
+ className="my-8 flex grow flex-col gap-3 lg:mx-8">
+ {(item) => }
+
- if (locations) {
- location = (
- <>
-
- {locationsList}
-
- {totalCount > limit && (
-
-
+
- )}
- >
- );
- }
-
- if (isLoading || !locations) {
- return
;
- }
+
+ )}
+
+ );
+}
- return (
-
-
-
-
-
- Add New Location
-
-
- {location}
+const Location = ({ name, description, id }: LocationModel) => (
+
+
+
+
+
+
+ Edit
+
+
+
+ Manage Beds
+
+
+
+);
diff --git a/src/Components/Facility/TriageForm.tsx b/src/Components/Facility/TriageForm.tsx
index a627fda1bbe..3c8e6b1497b 100644
--- a/src/Components/Facility/TriageForm.tsx
+++ b/src/Components/Facility/TriageForm.tsx
@@ -283,20 +283,20 @@ export const TriageForm = (props: triageFormProps) => {
handleSubmit();
}}
>
-
-
-
-
+
goBack()} />
diff --git a/src/Components/Facility/UpdateFacilityMiddleware.tsx b/src/Components/Facility/UpdateFacilityMiddleware.tsx
index 4fd5a4f24b0..211d8cf458a 100644
--- a/src/Components/Facility/UpdateFacilityMiddleware.tsx
+++ b/src/Components/Facility/UpdateFacilityMiddleware.tsx
@@ -11,7 +11,6 @@ import { navigate } from "raviger";
import { Cancel, Submit } from "../Common/components/ButtonV2";
import TextFormField from "../Form/FormFields/TextFormField";
import Page from "../Common/components/Page";
-import useConfig from "../../Common/hooks/useConfig";
import { ConfigureHealthFacility } from "../ABDM/ConfigureHealthFacility";
const Loading = lazy(() => import("../Common/Loading"));
@@ -52,7 +51,6 @@ export const UpdateFacilityMiddleware = (props: any) => {
const { facilityId } = props;
const dispatchAction: any = useDispatch();
const [isLoading, setIsLoading] = useState(false);
- const config = useConfig();
const fetchData = useCallback(
async (status: statusType) => {
@@ -169,11 +167,8 @@ export const UpdateFacilityMiddleware = (props: any) => {
- {config.enable_abdm ? (
-
- ) : (
- <>>
- )}
+
+
);
};
diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx
index 5c24c80687a..cc34140e7a9 100644
--- a/src/Components/Facility/models.tsx
+++ b/src/Components/Facility/models.tsx
@@ -2,6 +2,7 @@ import { AssignedToObjectModel } from "../Patient/models";
import { ProcedureType } from "../Common/prescription-builder/ProcedureBuilder";
import { NormalPrescription, PRNPrescription } from "../Medicine/models";
import { AssetData } from "../Assets/AssetTypes";
+import { UserBareMinimum } from "../Users/models";
export interface LocalBodyModel {
name: string;
@@ -112,7 +113,10 @@ export interface ConsultationModel {
diagnosis?: string;
icd11_diagnoses_object?: ICD11DiagnosisModel[];
icd11_provisional_diagnoses_object?: ICD11DiagnosisModel[];
+ icd11_principal_diagnosis?: ICD11DiagnosisModel["id"];
+ deprecated_verified_by?: string;
verified_by?: string;
+ verified_by_object?: UserBareMinimum;
suggestion_text?: string;
symptoms?: Array
;
symptoms_text?: string;
@@ -138,6 +142,7 @@ export interface ConsultationModel {
cause_of_death?: string;
death_datetime?: string;
death_confirmed_doctor?: string;
+ is_readmission?: boolean;
}
export interface PatientStatsModel {
id?: number;
diff --git a/src/Components/Form/FormFields/Autocomplete.tsx b/src/Components/Form/FormFields/Autocomplete.tsx
index dcf3ab5e8b6..bbc60643faf 100644
--- a/src/Components/Form/FormFields/Autocomplete.tsx
+++ b/src/Components/Form/FormFields/Autocomplete.tsx
@@ -157,6 +157,7 @@ export const Autocomplete = (props: AutocompleteProps) => {
placeholder={props.placeholder ?? "Select"}
displayValue={(value: any) => value?.label || ""}
onChange={(event) => setQuery(event.target.value.toLowerCase())}
+ onBlur={() => value && setQuery("")}
autoComplete="off"
/>
diff --git a/src/Components/Form/FormFields/CheckBoxFormField.tsx b/src/Components/Form/FormFields/CheckBoxFormField.tsx
index 90c4513f4b7..f3382d522de 100644
--- a/src/Components/Form/FormFields/CheckBoxFormField.tsx
+++ b/src/Components/Form/FormFields/CheckBoxFormField.tsx
@@ -14,6 +14,7 @@ export default function CheckBoxFormField(props: FormFieldBaseProps) {
name={field.name}
checked={field.value}
onChange={(e) => field.handleChange(e.target.checked)}
+ disabled={field.disabled}
/>
= phoneCodesJson;
interface Props extends FormFieldBaseProps {
@@ -39,21 +34,6 @@ export default function PhoneNumberFormField(props: Props) {
[props.types]
);
- const asYouType = useMemo(() => {
- const asYouType = new AsYouType();
-
- asYouType.reset();
-
- if (field.value) {
- asYouType.input(field.value);
- } else {
- asYouType.input("+91");
- field.handleChange(asYouType.getNumberValue());
- }
-
- return asYouType;
- }, []);
-
const validate = useMemo(
() => (value: string | undefined, event: "blur" | "change") => {
if (!value || props.disableValidation) {
@@ -73,9 +53,9 @@ export default function PhoneNumberFormField(props: Props) {
const setValue = (value: string) => {
value = value.replaceAll(/[^0-9+]/g, "");
-
- asYouType.reset();
- asYouType.input(value);
+ if (value.length > 12 && value.startsWith("+910")) {
+ value = "+91" + value.slice(4);
+ }
const error = validate(value, "change");
field.handleChange(value);
@@ -83,6 +63,8 @@ export default function PhoneNumberFormField(props: Props) {
setError(error);
};
+ useEffect(() => setValue(field.value || "+91"), []);
+
return (
setValue(e.target.value)}
disabled={field.disabled}
onBlur={() => setError(validate(field.value, "blur"))}
@@ -122,7 +104,7 @@ export default function PhoneNumberFormField(props: Props) {
autoComplete="country"
className="cui-input-base h-full border-0 bg-transparent pl-2 pr-8 text-end font-medium tracking-wider text-gray-700 focus:ring-2 focus:ring-inset"
value={
- asYouType.getCountry() ??
+ getCountryCode(field.value) ??
(field.value?.startsWith("1800") ? "1800" : "Other")
}
onChange={(e) => {
@@ -176,15 +158,15 @@ const conditionPhoneCode = (code: string) => {
return code.startsWith("+") ? code : "+" + code;
};
-const formatPhoneNumber = (value: string) => {
+const formatPhoneNumber = (value: string, types: PhoneNumberType[]) => {
if (value === undefined || value === null) {
return "+91 ";
}
- if (!isValidPhoneNumber(value)) {
+ if (PhoneNumberValidator(types)(value) !== undefined || value.length < 13) {
return value;
}
const phoneNumber = parsePhoneNumber(value);
- return phoneNumber.formatInternational();
+ return phoneNumber ? formatPhoneNumberUtil(phoneNumber) : value;
};
diff --git a/src/Components/Medicine/AdministerMedicine.tsx b/src/Components/Medicine/AdministerMedicine.tsx
index 0159bc4b7a8..5141d8f26bd 100644
--- a/src/Components/Medicine/AdministerMedicine.tsx
+++ b/src/Components/Medicine/AdministerMedicine.tsx
@@ -9,6 +9,9 @@ import PrescriptionDetailCard from "./PrescriptionDetailCard";
import CareIcon from "../../CAREUI/icons/CareIcon";
import { formatDateTime } from "../../Utils/utils";
import { useTranslation } from "react-i18next";
+import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField";
+import TextFormField from "../Form/FormFields/TextFormField";
+import dayjs from "../../Utils/dayjs";
interface Props {
prescription: Prescription;
@@ -21,6 +24,10 @@ export default function AdministerMedicine({ prescription, ...props }: Props) {
const dispatch = useDispatch();
const [isLoading, setIsLoading] = useState(false);
const [notes, setNotes] = useState("");
+ const [isCustomTime, setIsCustomTime] = useState(false);
+ const [customTime, setCustomTime] = useState(
+ dayjs().format("YYYY-MM-DDTHH:mm")
+ );
return (
props.onClose(false)}
- // variant="primary"
onConfirm={async () => {
setIsLoading(true);
- const res = await dispatch(props.actions.administer({ notes }));
+ const res = await dispatch(
+ props.actions.administer({
+ notes,
+ administered_date: isCustomTime ? customTime : undefined,
+ })
+ );
if (res.status === 201) {
Success({ msg: t("medicines_administered") });
}
@@ -61,15 +72,43 @@ export default function AdministerMedicine({ prescription, ...props }: Props) {
readonly
actions={props.actions}
/>
- setNotes(value)}
- errorClassName="hidden"
- disabled={isLoading}
- />
+
+
+
setNotes(value)}
+ errorClassName="hidden"
+ disabled={isLoading}
+ />
+
+ {
+ setIsCustomTime(value);
+ if (!value) {
+ setCustomTime(dayjs().format("YYYY-MM-DDTHH:mm"));
+ }
+ }}
+ errorClassName="hidden"
+ />
+ setCustomTime(value)}
+ disabled={!isCustomTime}
+ min={dayjs(prescription.created_date).format("YYYY-MM-DDTHH:mm")}
+ max={dayjs().format("YYYY-MM-DDTHH:mm")}
+ />
+
+
);
diff --git a/src/Components/Medicine/MedibaseAutocompleteFormField.tsx b/src/Components/Medicine/MedibaseAutocompleteFormField.tsx
index 473bb3a2598..2b5612f6f32 100644
--- a/src/Components/Medicine/MedibaseAutocompleteFormField.tsx
+++ b/src/Components/Medicine/MedibaseAutocompleteFormField.tsx
@@ -1,3 +1,5 @@
+import { useEffect, useState } from "react";
+import Switch from "../../CAREUI/interactive/Switch";
import { useAsyncOptions } from "../../Common/hooks/useAsyncOptions";
import { listMedibaseMedicines } from "../../Redux/actions";
import { Autocomplete } from "../Form/FormFields/Autocomplete";
@@ -15,15 +17,39 @@ export default function MedibaseAutocompleteFormField(
const { isLoading, options, fetchOptions } =
useAsyncOptions("id");
+ const [query, setQuery] = useState("");
+ const [type, setType] = useState();
+
+ useEffect(() => {
+ fetchOptions(listMedibaseMedicines(query, type));
+ }, [query, type]);
+
return (
-
+ {
+ setType(type === "all" ? undefined : type);
+ }}
+ />
+ ),
+ }}
+ >
option.name.toUpperCase()}
optionDescription={(option) => }
optionValue={(option) => option}
@@ -34,7 +60,7 @@ export default function MedibaseAutocompleteFormField(
)
}
- onQuery={(query) => fetchOptions(listMedibaseMedicines(query))}
+ onQuery={setQuery}
isLoading={isLoading}
/>
diff --git a/src/Components/Medicine/MedicineAdministration.tsx b/src/Components/Medicine/MedicineAdministration.tsx
index 16926b32f7b..5d8347ba5a5 100644
--- a/src/Components/Medicine/MedicineAdministration.tsx
+++ b/src/Components/Medicine/MedicineAdministration.tsx
@@ -10,6 +10,8 @@ import { useDispatch } from "react-redux";
import { Error, Success } from "../../Utils/Notifications";
import { formatDateTime } from "../../Utils/utils";
import { useTranslation } from "react-i18next";
+import dayjs from "../../Utils/dayjs";
+import TextFormField from "../Form/FormFields/TextFormField";
interface Props {
prescriptions: Prescription[];
@@ -24,6 +26,8 @@ export default function MedicineAdministration(props: Props) {
const [notes, setNotes] = useState(
[]
);
+ const [isCustomTime, setIsCustomTime] = useState([]);
+ const [customTime, setCustomTime] = useState([]);
const prescriptions = useMemo(
() =>
@@ -36,13 +40,21 @@ export default function MedicineAdministration(props: Props) {
useEffect(() => {
setShouldAdminister(Array(prescriptions.length).fill(false));
setNotes(Array(prescriptions.length).fill(""));
+ setIsCustomTime(Array(prescriptions.length).fill(false));
+ setCustomTime(
+ Array(prescriptions.length).fill(dayjs().format("YYYY-MM-DDTHH:mm"))
+ );
}, [props.prescriptions]);
const handleSubmit = () => {
const records: MedicineAdministrationRecord[] = [];
prescriptions.forEach((prescription, i) => {
if (shouldAdminister[i]) {
- records.push({ prescription, notes: notes[i] });
+ records.push({
+ prescription,
+ notes: notes[i],
+ administered_date: isCustomTime[i] ? customTime[i] : undefined,
+ });
}
});
@@ -73,7 +85,7 @@ export default function MedicineAdministration(props: Props) {
actions={props.action(obj?.id ?? "")}
selected={shouldAdminister[index]}
>
-
+
-
- setNotes((notes) => {
- const newNotes = [...notes];
- newNotes[index] = event.value;
- return newNotes;
- })
- }
- errorClassName="hidden"
- />
+
+
+ setNotes((notes) => {
+ const newNotes = [...notes];
+ newNotes[index] = event.value;
+ return newNotes;
+ })
+ }
+ errorClassName="hidden"
+ />
+
+ {
+ setIsCustomTime((arr) => {
+ const newArr = [...arr];
+ newArr[index] = value;
+ return newArr;
+ });
+ if (!value) {
+ setCustomTime((arr) => {
+ const newArr = [...arr];
+ newArr[index] = dayjs().format("YYYY-MM-DDTHH:mm");
+ return newArr;
+ });
+ }
+ }}
+ errorClassName="hidden"
+ />
+ {
+ setCustomTime((arr) => {
+ const newArr = [...arr];
+ newArr[index] = value;
+ return newArr;
+ });
+ }}
+ disabled={!shouldAdminister[index] || !isCustomTime[index]}
+ min={dayjs(obj.created_date).format("YYYY-MM-DDTHH:mm")}
+ max={dayjs().format("YYYY-MM-DDTHH:mm")}
+ />
+
+
))}
diff --git a/src/Components/Medicine/PrescriptionAdministrationsTable.tsx b/src/Components/Medicine/PrescriptionAdministrationsTable.tsx
index c60d531baa3..81282126d7c 100644
--- a/src/Components/Medicine/PrescriptionAdministrationsTable.tsx
+++ b/src/Components/Medicine/PrescriptionAdministrationsTable.tsx
@@ -85,7 +85,7 @@ export default function PrescriptionAdministrationsTable({
{state?.prescriptions && (
diff --git a/src/Components/Medicine/models.ts b/src/Components/Medicine/models.ts
index cb48e9cc174..62aea46b6d2 100644
--- a/src/Components/Medicine/models.ts
+++ b/src/Components/Medicine/models.ts
@@ -53,8 +53,8 @@ export type MedicineAdministrationRecord = {
readonly id?: string;
readonly prescription?: Prescription;
notes: string;
+ administered_date?: string;
readonly administered_by?: PerformedByModel;
- readonly administered_date?: string;
readonly created_date?: string;
readonly modified_date?: string;
};
diff --git a/src/Components/Patient/FileUpload.tsx b/src/Components/Patient/FileUpload.tsx
index 3fb0fde6229..fe0881e6994 100644
--- a/src/Components/Patient/FileUpload.tsx
+++ b/src/Components/Patient/FileUpload.tsx
@@ -481,15 +481,20 @@ export const FileUpload = (props: FileUploadProps) => {
};
const responseData = await dispatch(retrieveUpload(data, id));
const file_extension = getExtension(responseData.data.read_signed_url);
- setFileState({
- ...file_state,
- open: true,
- name: responseData.data.name,
- extension: file_extension,
- isImage: ExtImage.includes(file_extension),
- });
- downloadFileUrl(responseData.data.read_signed_url);
- setFileUrl(responseData.data.read_signed_url);
+ if (file_extension === "pdf") {
+ window.open(responseData.data.read_signed_url, "_blank");
+ setFileState({ ...file_state, open: false });
+ } else {
+ setFileState({
+ ...file_state,
+ open: true,
+ name: responseData.data.name,
+ extension: file_extension,
+ isImage: ExtImage.includes(file_extension),
+ });
+ downloadFileUrl(responseData.data.read_signed_url);
+ setFileUrl(responseData.data.read_signed_url);
+ }
};
const validateEditFileName = (name: any) => {
@@ -1457,7 +1462,7 @@ export const FileUpload = (props: FileUploadProps) => {
)}
-
+
{
if (phone_number === "+91" || phone_number === "") {
setPhoneNumberError("");
- updateQuery({ phone_number: "" });
+ qParams.phone_number && updateQuery({ phone_number: null });
return;
}
@@ -138,7 +138,8 @@ export const PatientManager = () => {
if (emergency_phone_number === "+91" || emergency_phone_number === "") {
setEmergencyPhoneNumberError("");
- updateQuery({ emergency_phone_number: "" });
+ qParams.emergency_phone_number &&
+ updateQuery({ emergency_phone_number: null });
return;
}
@@ -160,12 +161,10 @@ export const PatientManager = () => {
(qParams.is_active || "True"),
disease_status: qParams.disease_status || undefined,
phone_number: qParams.phone_number
- ? parsePhoneNumberFromString(qParams.phone_number)?.format("E.164")
+ ? parsePhoneNumber(qParams.phone_number)
: undefined,
emergency_phone_number: qParams.emergency_phone_number
- ? parsePhoneNumberFromString(qParams.emergency_phone_number)?.format(
- "E.164"
- )
+ ? parsePhoneNumber(qParams.emergency_phone_number)
: undefined,
local_body: qParams.lsgBody || undefined,
facility: qParams.facility,
@@ -602,6 +601,15 @@ export const PatientManager = () => {
text="Review Missed"
/>
)}
+ {patient.last_consultation?.is_readmission && (
+
+ )}
{patient.disease_status === "POSITIVE" && (
{
fetchpatient(status);
triggerGoal("Patient Profile Viewed", {
facilityId: facilityId,
- userID: authUser.id,
+ userId: authUser.id,
});
},
[dispatch, fetchpatient]
@@ -374,6 +374,13 @@ export const PatientHome = (props: any) => {
);
};
+ const isPatientEligibleForNewConsultation = (patientData: PatientModel) => {
+ return !patientData.last_consultation ||
+ patientData.last_consultation?.discharge_date
+ ? true
+ : false;
+ };
+
return (
{
Present Health
-
+
{patientData.present_health}
@@ -1060,7 +1070,10 @@ export const PatientHome = (props: any) => {
Ongoing Medications
-
+
{patientData.ongoing_medication}
@@ -1070,7 +1083,10 @@ export const PatientHome = (props: any) => {
Allergies
-
+
{patientData.allergies}
@@ -1096,23 +1112,31 @@ export const PatientHome = (props: any) => {
- patientData.is_active &&
- (!patientData?.last_consultation ||
- patientData?.last_consultation?.discharge_date) &&
+ isPatientEligibleForNewConsultation(patientData) &&
navigate(
`/facility/${patientData?.facility}/patient/${id}/consultation`
)
}
>
-
-
+
+
diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx
index a15b9f436b5..a01d9b70fb8 100644
--- a/src/Components/Patient/PatientInfoCard.tsx
+++ b/src/Components/Patient/PatientInfoCard.tsx
@@ -148,7 +148,7 @@ export default function PatientInfoCard(props: {
)}
-
+
)}
+ {consultation?.is_readmission && (
+ <>
+
•
+
+
+ Readmitted
+
+ >
+ )}
diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx
index d52ce840090..41f36bffd35 100644
--- a/src/Components/Patient/PatientRegister.tsx
+++ b/src/Components/Patient/PatientRegister.tsx
@@ -25,6 +25,7 @@ import {
dateQueryString,
getPincodeDetails,
includesIgnoreCase,
+ parsePhoneNumber,
} from "../../Utils/utils";
import { navigate, useQueryParams } from "raviger";
import { statusType, useAbortableEffect } from "../../Common/utils";
@@ -40,7 +41,11 @@ import DateFormField from "../Form/FormFields/DateFormField";
import DialogModal from "../Common/Dialog";
import { DupPatientModel } from "../Facility/models";
import DuplicatePatientDialog from "../Facility/DuplicatePatientDialog";
-import { FieldError, RequiredFieldValidator } from "../Form/FieldValidators";
+import {
+ FieldError,
+ PhoneNumberValidator,
+ RequiredFieldValidator,
+} from "../Form/FieldValidators";
import { FieldErrorText, FieldLabel } from "../Form/FormFields/FormField";
import Form from "../Form/Form";
import { HCXPolicyModel } from "../HCX/models";
@@ -58,7 +63,6 @@ import TransferPatientDialog from "../Facility/TransferPatientDialog";
import countryList from "../../Common/static/countries.json";
import { debounce } from "lodash";
-import { parsePhoneNumberFromString } from "libphonenumber-js";
import useAppHistory from "../../Common/hooks/useAppHistory";
import useConfig from "../../Common/hooks/useConfig";
import { useDispatch } from "react-redux";
@@ -98,7 +102,7 @@ const initForm: any = {
age: "",
gender: "",
phone_number: "+91",
- emergency_phone_number: null,
+ emergency_phone_number: "+91",
blood_group: "",
disease_status: diseaseStatus[2],
is_declared_positive: "false",
@@ -596,14 +600,22 @@ export const PatientRegister = (props: PatientRegisterProps) => {
}
return;
case "phone_number":
- phoneNumber = parsePhoneNumberFromString(form[field]);
- if (!form[field] || !phoneNumber?.isPossible()) {
+ phoneNumber = parsePhoneNumber(form[field]);
+ if (
+ !form[field] ||
+ !phoneNumber ||
+ !PhoneNumberValidator()(phoneNumber) === undefined
+ ) {
errors[field] = "Please enter valid phone number";
}
return;
case "emergency_phone_number":
- emergency_phone_number = parsePhoneNumberFromString(form[field]);
- if (!form[field] || !emergency_phone_number?.isPossible()) {
+ emergency_phone_number = parsePhoneNumber(form[field]);
+ if (
+ !form[field] ||
+ !emergency_phone_number ||
+ !PhoneNumberValidator()(emergency_phone_number) === undefined
+ ) {
errors[field] = "Please enter valid phone number";
}
return;
@@ -729,12 +741,8 @@ export const PatientRegister = (props: PatientRegisterProps) => {
});
const data = {
abha_number: state.form.abha_number,
- phone_number: parsePhoneNumberFromString(formData.phone_number)?.format(
- "E.164"
- ),
- emergency_phone_number: parsePhoneNumberFromString(
- formData.emergency_phone_number
- )?.format("E.164"),
+ phone_number: parsePhoneNumber(formData.phone_number),
+ emergency_phone_number: parsePhoneNumber(formData.emergency_phone_number),
date_of_birth: dateQueryString(formData.date_of_birth),
disease_status: formData.disease_status,
date_of_test: formData.date_of_test ? formData.date_of_test : undefined,
@@ -912,12 +920,12 @@ export const PatientRegister = (props: PatientRegisterProps) => {
if (mobile) {
field("phone_number").onChange({
name: "phone_number",
- value: parsePhoneNumberFromString(mobile, "IN")?.format("E.164"),
+ value: parsePhoneNumber(mobile),
});
field("emergency_phone_number").onChange({
name: "emergency_phone_number",
- value: parsePhoneNumberFromString(mobile, "IN")?.format("E.164"),
+ value: parsePhoneNumber(mobile),
});
}
@@ -958,9 +966,12 @@ export const PatientRegister = (props: PatientRegisterProps) => {
const duplicateCheck = useCallback(
debounce(async (phoneNo: string) => {
- if (phoneNo && parsePhoneNumberFromString(phoneNo)?.isPossible()) {
+ if (
+ phoneNo &&
+ PhoneNumberValidator()(parsePhoneNumber(phoneNo) ?? "") === undefined
+ ) {
const query = {
- phone_number: parsePhoneNumberFromString(phoneNo)?.format("E.164"),
+ phone_number: parsePhoneNumber(phoneNo),
};
const res = await dispatchAction(searchPatient(query));
if (res?.data?.results) {
diff --git a/src/Components/Patient/ShiftCreate.tsx b/src/Components/Patient/ShiftCreate.tsx
index 7283fb3d5d7..e8e89ebc59c 100644
--- a/src/Components/Patient/ShiftCreate.tsx
+++ b/src/Components/Patient/ShiftCreate.tsx
@@ -18,7 +18,7 @@ import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField";
import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
import TextFormField from "../Form/FormFields/TextFormField";
import { navigate } from "raviger";
-import { parsePhoneNumberFromString } from "libphonenumber-js";
+import { parsePhoneNumber } from "../../Utils/utils.js";
import { phonePreg } from "../../Common/validation";
import useAppHistory from "../../Common/hooks/useAppHistory";
import useConfig from "../../Common/hooks/useConfig";
@@ -28,6 +28,7 @@ import Page from "../Common/components/Page.js";
import Card from "../../CAREUI/display/Card.js";
import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField.js";
import { SelectFormField } from "../Form/FormFields/SelectFormField.js";
+import { PhoneNumberValidator } from "../Form/FieldValidators.js";
const Loading = lazy(() => import("../Common/Loading"));
@@ -56,13 +57,13 @@ export const ShiftCreate = (props: patientShiftProps) => {
vehicle_preference: "",
comments: "",
refering_facility_contact_name: "",
- refering_facility_contact_number: "+91",
+ refering_facility_contact_number: "",
assigned_facility_type: null,
preferred_vehicle_choice: null,
breathlessness_level: null,
patient_category: "",
ambulance_driver_name: "",
- ambulance_phone_number: undefined,
+ ambulance_phone_number: "",
ambulance_number: "",
};
@@ -162,10 +163,10 @@ export const ShiftCreate = (props: patientShiftProps) => {
errors[field] = requiredFields[field].errorText;
isInvalidForm = true;
} else if (
- !parsePhoneNumberFromString(state.form[field])?.isPossible() ||
- !phonePreg(
- String(parsePhoneNumberFromString(state.form[field])?.number)
- )
+ !PhoneNumberValidator()(
+ parsePhoneNumber(state.form[field]) ?? ""
+ ) === undefined ||
+ !phonePreg(String(parsePhoneNumber(state.form[field])))
) {
errors[field] = requiredFields[field].invalidText;
isInvalidForm = true;
@@ -222,15 +223,15 @@ export const ShiftCreate = (props: patientShiftProps) => {
preferred_vehicle_choice: state.form.preferred_vehicle_choice,
refering_facility_contact_name:
state.form.refering_facility_contact_name,
- refering_facility_contact_number: parsePhoneNumberFromString(
+ refering_facility_contact_number: parsePhoneNumber(
state.form.refering_facility_contact_number
- )?.format("E.164"),
+ ),
breathlessness_level: state.form.breathlessness_level,
patient_category: patientCategory,
ambulance_driver_name: state.form.ambulance_driver_name,
- ambulance_phone_number: parsePhoneNumberFromString(
+ ambulance_phone_number: parsePhoneNumber(
state.form.ambulance_phone_number
- )?.format("E.164"),
+ ),
ambulance_number: state.form.ambulance_number,
};
diff --git a/src/Components/Resource/ListView.tsx b/src/Components/Resource/ListView.tsx
index ab02d31bedd..b368c9bf3ea 100644
--- a/src/Components/Resource/ListView.tsx
+++ b/src/Components/Resource/ListView.tsx
@@ -174,6 +174,7 @@ export default function ListView() {