diff --git a/.env b/.env index 0496daa2587..8b3b02b3d97 100644 --- a/.env +++ b/.env @@ -1,12 +1,14 @@ # Whitelabelling envs REACT_APP_TITLE=CARE -REACT_APP_META_DESCRIPTION=Revolutionizing EMR with AI: Open Healthcare Network develops free, open-source tools to enhance efficiency in global healthcare delivery. Our EMR system is recognized as a Digital Public Good by the United Nations. +REACT_APP_META_DESCRIPTION="Revolutionizing EMR with AI: Open Healthcare Network develops free, open-source tools to enhance efficiency in global healthcare delivery. Our EMR system is recognized as a Digital Public Good by the United Nations." REACT_APP_COVER_IMAGE=https://cdn.ohc.network/care_logo.svg REACT_APP_COVER_IMAGE_ALT=https://cdn.ohc.network/care_logo.svg REACT_PUBLIC_URL=https://care.ohc.network +# Care API URL without the /api prefix +REACT_CARE_API_URL=https://careapi.ohc.network + # Dev envs ESLINT_NO_DEV_ERRORS=true - CARE_CDN_URL="https://egov-s3-facility-10bedicu.s3.amazonaws.com https://egov-s3-patient-data-10bedicu.s3.amazonaws.com http://localhost:4566" diff --git a/.envrc b/.envrc index fc7d890f90a..c729eb59836 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,2 @@ +dotenv test -f .env.local && dotenv .env.local \ No newline at end of file diff --git a/.example.env b/.example.env new file mode 100644 index 00000000000..dd4a8865878 --- /dev/null +++ b/.example.env @@ -0,0 +1,79 @@ +# Backend URL +REACT_CARE_API_URL=https://careapi.ohc.network + +# Dashboard URL +REACT_DASHBOARD_URL= + +# GitHub URL (default: https://github.com/ohcnetwork) +REACT_GITHUB_URL= + +# OHCN URL (default: https://ohc.network?ref=care) +REACT_OHCN_URL= + +# Plausible site domain (default: care.ohc.network) +REACT_PLAUSIBLE_SITE_DOMAIN= + +# Plausible server URL (default: https://plausible.10bedicu.in) +REACT_PLAUSIBLE_SERVER_URL= + + +# Main logo (JSON string with light and dark properties) +REACT_HEADER_LOGO= + +# Main logo (JSON string with light and dark properties) +# Example: REACT_MAIN_LOGO="{\"light\": \"https://cdn.ohc.network/light-logo.svg\", \"dark\": \"https://cdn.ohc.network/dark-logo.svg\"}" +REACT_MAIN_LOGO= + +# State logo (JSON string with light and dark properties) +REACT_STATE_LOGO= + +# Custom logo (JSON string with light and dark properties) +REACT_CUSTOM_LOGO= + +# Custom alternative logo (JSON string with light and dark properties) +REACT_CUSTOM_LOGO_ALT= + +# Custom description +REACT_CUSTOM_DESCRIPTION= + +# Google Maps API key +REACT_GMAPS_API_KEY= + +# Government data API key +REACT_GOV_DATA_API_KEY= + +# reCAPTCHA site key +REACT_RECAPTCHA_SITE_KEY= + +# Sentry DSN +REACT_SENTRY_DSN= + +# Sentry environment (default: staging) +REACT_SENTRY_ENVIRONMENT= + +# KASP settings +REACT_KASP_ENABLED=true +REACT_KASP_STRING=KASP +REACT_KASP_FULL_STRING=Karunya Arogya Suraksha Padhathi + +# Sample format file paths +REACT_SAMPLE_FORMAT_ASSET_IMPORT=/asset-import-template.xlsx +REACT_SAMPLE_FORMAT_EXTERNAL_RESULT_IMPORT=/External-Results-Template.csv + +# Camera feed, still watching idle timeout (in seconds; default: 180) +REACT_STILL_WATCHING_IDLE_TIMEOUT= + +# Camera feed, still watching prompt duration (in seconds; default: 30) +REACT_STILL_WATCHING_PROMPT_DURATION= + +# Feature flags +REACT_ENABLE_HCX=true +REACT_ENABLE_ABDM=true +REACT_ENABLE_SCRIBE=true +REACT_WARTIME_SHIFTING=true + +# JWT token refresh interval (in milliseconds) (default: 5 minutes) +REACT_JWT_TOKEN_REFRESH_INTERVAL= + +# Minimum encounter date (default: 2020-01-01) +REACT_MIN_ENCOUNTER_DATE= diff --git a/.github/workflows/cypress.yaml b/.github/workflows/cypress.yaml index f5039548e76..14a15d30ee8 100644 --- a/.github/workflows/cypress.yaml +++ b/.github/workflows/cypress.yaml @@ -18,6 +18,8 @@ jobs: fail-fast: false matrix: containers: [1, 2, 3, 4, 5, 6, 7, 8] + env: + REACT_CARE_API_URL: http://localhost:9000 steps: - name: Checkout 📥 uses: actions/checkout@v3 @@ -42,6 +44,7 @@ jobs: run: | cd care echo DISABLE_RATELIMIT=True >> docker/.prebuilt.env + echo "CORS_ALLOWED_ORIGINS=\"[\\\"http://localhost:4000\\\"]\"" >> docker/.prebuilt.env make docker_config_file=docker-compose.pre-built.yaml up make docker_config_file=docker-compose.pre-built.yaml load-dummy-data cd .. @@ -66,7 +69,7 @@ jobs: - name: Install dependencies 📦 run: npm install - - name: Build & Compile rescript files ⚙️ + - name: Build ⚙️ run: npm run build - name: Install Specific Chrome Version @@ -89,7 +92,6 @@ jobs: parallel: true group: "UI-Chrome" 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 @@ -111,7 +113,6 @@ jobs: group: "UI-Chrome" env: CYPRESS_SPLIT_TESTS: "true" - CARE_API: http://localhost:9000 CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NODE_OPTIONS: --max_old_space_size=4096 diff --git a/README.md b/README.md index 740a0857ed0..fd5328150f2 100644 --- a/README.md +++ b/README.md @@ -81,11 +81,11 @@ To ensure the quality of our pull requests, we use a variety of tools: To run cypress tests locally, you'll need to setup the backend to run locally and load dummy data required for cypress to the database. See [docs](https://github.com/ohcnetwork/care#self-hosting). -Once backend is running locally, you'll have to ensure your local front-end is connected to local backend, by setting the `CARE_API` env. +Once backend is running locally, you'll have to ensure your local front-end is connected to local backend, by setting the `REACT_CARE_API_URL` env. ```env #.env -CARE_API=http://127.0.0.1:9000 +REACT_CARE_API_URL=http://127.0.0.1:9000 ``` Once done, start the development server by running diff --git a/care.config.ts b/care.config.ts new file mode 100644 index 00000000000..4341a03dd48 --- /dev/null +++ b/care.config.ts @@ -0,0 +1,112 @@ +const env = import.meta.env; + +interface ILogo { + light: string; + dark: string; +} + +const logo = (value?: string, fallback?: ILogo) => { + if (!value) { + return fallback; + } + + try { + return JSON.parse(value) as ILogo; + } catch { + // TODO: define vite plugin to validate care.config.ts during build step + return fallback; + } +}; +const careConfig = { + apiUrl: env.REACT_CARE_API_URL, + + urls: { + dashboard: env.REACT_DASHBOARD_URL, + github: env.REACT_GITHUB_URL || "https://github.com/ohcnetwork", + ohcn: env.REACT_OHCN_URL || "https://ohc.network?ref=care", + }, + + headerLogo: logo(env.REACT_HEADER_LOGO, { + light: "https://cdn.ohc.network/header_logo.png", + dark: "https://cdn.ohc.network/header_logo.png", + }), + mainLogo: logo(env.REACT_MAIN_LOGO, { + light: "https://cdn.ohc.network/light-logo.svg", + dark: "https://cdn.ohc.network/black-logo.svg", + }), + stateLogo: logo(env.REACT_STATE_LOGO), + customLogo: logo(env.REACT_CUSTOM_LOGO), + customLogoAlt: logo(env.REACT_CUSTOM_LOGO_ALT), + customDescription: env.REACT_CUSTOM_DESCRIPTION, + + gmapsApiKey: + env.REACT_GMAPS_API_KEY || "AIzaSyDsBAc3y7deI5ZO3NtK5GuzKwtUzQNJNUk", + + govDataApiKey: + env.REACT_GOV_DATA_API_KEY || + "579b464db66ec23bdd000001cdd3946e44ce4aad7209ff7b23ac571b", + reCaptchaSiteKey: + env.REACT_RECAPTCHA_SITE_KEY || "6LdvxuQUAAAAADDWVflgBqyHGfq-xmvNJaToM0pN", + + kasp: { + enabled: env.REACT_KASP_ENABLED === "true", + string: env.REACT_KASP_STRING || "KASP", + fullString: + env.REACT_KASP_FULL_STRING || "Karunya Arogya Suraksha Padhathi", + }, + + sampleFormats: { + assetImport: + env.REACT_SAMPLE_FORMAT_ASSET_IMPORT || "/asset-import-template.xlsx", + externalResultImport: + env.REACT_SAMPLE_FORMAT_EXTERNAL_RESULT_IMPORT || + "/External-Results-Template.csv", + }, + + wartimeShifting: env.REACT_WARTIME_SHIFTING === "true", + + stillWatching: { + idleTimeout: env.REACT_STILL_WATCHING_IDLE_TIMEOUT + ? parseInt(env.REACT_STILL_WATCHING_IDLE_TIMEOUT) + : 3 * 60, + promptDuration: env.REACT_STILL_WATCHING_PROMPT_DURATION + ? parseInt(env.REACT_STILL_WATCHING_PROMPT_DURATION) + : 30, + }, + + auth: { + tokenRefreshInterval: env.REACT_JWT_TOKEN_REFRESH_INTERVAL + ? parseInt(env.REACT_JWT_TOKEN_REFRESH_INTERVAL) + : 5 * 60e3, + }, + + minEncounterDate: new Date(env.REACT_MIN_ENCOUNTER_DATE || "2020-01-01"), + + // Plugins related configs... + + plausible: { + server: env.REACT_PLAUSIBLE_SERVER_URL || "https://plausible.10bedicu.in", + domain: env.REACT_PLAUSIBLE_SITE_DOMAIN || "care.ohc.network", + }, + + sentry: { + dsn: + env.REACT_SENTRY_DSN || + "https://8801155bd0b848a09de9ebf6f387ebc8@sentry.io/5183632", + environment: env.REACT_SENTRY_ENVIRONMENT || "staging", + }, + + hcx: { + enabled: env.REACT_ENABLE_HCX === "true", + }, + + abdm: { + enabled: (env.REACT_ENABLE_ABDM ?? "true") === "true", + }, + + scribe: { + enabled: env.REACT_ENABLE_SCRIBE === "true", + }, +} as const; + +export default careConfig; diff --git a/cypress.config.ts b/cypress.config.ts index 5a6f5183274..f7302869051 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -32,4 +32,7 @@ export default defineConfig({ requestTimeout: 15000, excludeSpecPattern: "**/*roles.cy.ts", }, + env: { + API_URL: process.env.REACT_CARE_API_URL ?? "http://localhost:9000", + }, }); diff --git a/cypress/e2e/assets_spec/asset_homepage.cy.ts b/cypress/e2e/assets_spec/asset_homepage.cy.ts index 5710df08e83..0f6bfe4da2c 100644 --- a/cypress/e2e/assets_spec/asset_homepage.cy.ts +++ b/cypress/e2e/assets_spec/asset_homepage.cy.ts @@ -1,6 +1,3 @@ -/// - -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"; @@ -65,7 +62,7 @@ describe("Asset Tab", () => { "Dummy Facility 40", "ACTIVE", "ONVIF Camera", - "Camera Loc" + "Camera Loc", ); assetFilters.clickadvancefilter(); assetFilters.clickslideoverbackbutton(); // to verify the back button doesn't clear applied filters diff --git a/cypress/e2e/assets_spec/assets_creation.cy.ts b/cypress/e2e/assets_spec/assets_creation.cy.ts index 8602ab8eb5b..1bcd984a7a3 100644 --- a/cypress/e2e/assets_spec/assets_creation.cy.ts +++ b/cypress/e2e/assets_spec/assets_creation.cy.ts @@ -1,5 +1,3 @@ -/// -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"; diff --git a/cypress/e2e/assets_spec/assets_manage.cy.ts b/cypress/e2e/assets_spec/assets_manage.cy.ts index 3a47ebec8df..983a82be07b 100644 --- a/cypress/e2e/assets_spec/assets_manage.cy.ts +++ b/cypress/e2e/assets_spec/assets_manage.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import { AssetPage } from "../../pageobject/Asset/AssetCreation"; import LoginPage from "../../pageobject/Login/LoginPage"; import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; diff --git a/cypress/e2e/auth_spec/auth.cy.ts b/cypress/e2e/auth_spec/auth.cy.ts index d03ea34e671..61708bc029a 100644 --- a/cypress/e2e/auth_spec/auth.cy.ts +++ b/cypress/e2e/auth_spec/auth.cy.ts @@ -1,7 +1,3 @@ -/// - -import { cy, describe, beforeEach, it } from "local-cypress"; - describe("Authorisation/Authentication", () => { beforeEach(() => { cy.awaitUrl("/", true); diff --git a/cypress/e2e/auth_spec/forget_password.cy.ts b/cypress/e2e/auth_spec/forget_password.cy.ts index 86b1d761821..c1b1db7ecad 100644 --- a/cypress/e2e/auth_spec/forget_password.cy.ts +++ b/cypress/e2e/auth_spec/forget_password.cy.ts @@ -1,5 +1,3 @@ -import { cy, describe, beforeEach, it } from "local-cypress"; - describe("Forgot Password", () => { beforeEach(() => { cy.awaitUrl("/", true); diff --git a/cypress/e2e/auth_spec/redirect.cy.ts b/cypress/e2e/auth_spec/redirect.cy.ts index 671a896a94f..3822a67b194 100644 --- a/cypress/e2e/auth_spec/redirect.cy.ts +++ b/cypress/e2e/auth_spec/redirect.cy.ts @@ -1,4 +1,3 @@ -import { cy, describe, it, beforeEach, Cypress } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; describe("redirect", () => { diff --git a/cypress/e2e/auth_spec/roles.cy.ts b/cypress/e2e/auth_spec/roles.cy.ts index dcf13fb2b30..07fe3c3d1fb 100644 --- a/cypress/e2e/auth_spec/roles.cy.ts +++ b/cypress/e2e/auth_spec/roles.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, cy, describe, it } from "local-cypress"; import * as users from "../../fixtures/users.json"; describe("authentication", () => { diff --git a/cypress/e2e/external_results_spec/external_result.cy.ts b/cypress/e2e/external_results_spec/external_result.cy.ts index 2091a5f93be..d0d78e5f5f6 100644 --- a/cypress/e2e/external_results_spec/external_result.cy.ts +++ b/cypress/e2e/external_results_spec/external_result.cy.ts @@ -1,13 +1,3 @@ -import { - cy, - describe, - it, - before, - beforeEach, - afterEach, - expect, -} from "local-cypress"; - describe("Edit Profile Testing", () => { before(() => { cy.loginByApi("devdistrictadmin", "Coronasafe@123"); @@ -52,7 +42,7 @@ describe("Edit Profile Testing", () => { }); it("export", () => { - cy.intercept("**", (req: Cypress.Request) => { + cy.intercept("**", (req) => { const url = new URL(req.url); const params = new URLSearchParams(url.search); if ( diff --git a/cypress/e2e/external_results_spec/filter.cy.ts b/cypress/e2e/external_results_spec/filter.cy.ts index 5a0a8eccab9..45c050cad8c 100644 --- a/cypress/e2e/external_results_spec/filter.cy.ts +++ b/cypress/e2e/external_results_spec/filter.cy.ts @@ -1,5 +1,3 @@ -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; - describe("External Results Filters", () => { before(() => { cy.loginByApi("devdistrictadmin", "Coronasafe@123"); diff --git a/cypress/e2e/facility_spec/facility_creation.cy.ts b/cypress/e2e/facility_spec/facility_creation.cy.ts index a092d23390e..57735a9dcde 100644 --- a/cypress/e2e/facility_spec/facility_creation.cy.ts +++ b/cypress/e2e/facility_spec/facility_creation.cy.ts @@ -1,13 +1,3 @@ -// FacilityCreation -import { - cy, - describe, - before, - beforeEach, - it, - afterEach, - expect, -} from "local-cypress"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; @@ -37,7 +27,7 @@ describe("Facility Creation", () => { const totalOccupancy = "10"; const doctorCapacity = "5"; const totalDoctor = "10"; - const facilityName = "cypress facility"; + const facilityName = "Cypress Facility"; const facilityName2 = "Dummy Facility 40"; const facilityAddress = "cypress address"; const facilityUpdateAddress = "cypress updated address"; diff --git a/cypress/e2e/facility_spec/facility_homepage.cy.ts b/cypress/e2e/facility_spec/facility_homepage.cy.ts index 1832fa973b7..11b3ec6f37f 100644 --- a/cypress/e2e/facility_spec/facility_homepage.cy.ts +++ b/cypress/e2e/facility_spec/facility_homepage.cy.ts @@ -1,5 +1,5 @@ // FacilityCreation -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; + import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; diff --git a/cypress/e2e/facility_spec/facility_manage.cy.ts b/cypress/e2e/facility_spec/facility_manage.cy.ts index d317b222078..868a26de022 100644 --- a/cypress/e2e/facility_spec/facility_manage.cy.ts +++ b/cypress/e2e/facility_spec/facility_manage.cy.ts @@ -1,4 +1,3 @@ -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityManage from "../../pageobject/Facility/FacilityManage"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; diff --git a/cypress/e2e/facility_spec/inventory.cy.ts b/cypress/e2e/facility_spec/inventory.cy.ts index b365fb3b02d..78e7af88cea 100644 --- a/cypress/e2e/facility_spec/inventory.cy.ts +++ b/cypress/e2e/facility_spec/inventory.cy.ts @@ -1,4 +1,3 @@ -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; diff --git a/cypress/e2e/facility_spec/locations.cy.ts b/cypress/e2e/facility_spec/locations.cy.ts index bad772ac410..113a5e3eaab 100644 --- a/cypress/e2e/facility_spec/locations.cy.ts +++ b/cypress/e2e/facility_spec/locations.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import { AssetPage } from "../../pageobject/Asset/AssetCreation"; import { UserCreationPage } from "../../pageobject/Users/UserCreation"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; @@ -92,7 +91,7 @@ describe("Location Management Section", () => { facilityLocation.selectBedType(bedType); assetPage.clickassetupdatebutton(); facilityLocation.verifyNotification( - "Name - Bed with same name already exists in location" + "Name - Bed with same name already exists in location", ); facilityHome.verifyAndCloseNotifyModal(); // edit the created bed @@ -185,7 +184,7 @@ describe("Location Management Section", () => { facilityLocation.deleteLocation("Test Location"); assetPage.clickassetupdatebutton(); facilityLocation.verifyNotification( - "Location Test Location deleted successfully" + "Location Test Location deleted successfully", ); facilityLocation.closeNotification(); }); @@ -204,7 +203,7 @@ describe("Location Management Section", () => { facilityLocation.deleteLocation("Test Location with Beds"); assetPage.clickassetupdatebutton(); facilityLocation.verifyNotification( - "Cannot delete a Location with associated Beds" + "Cannot delete a Location with associated Beds", ); facilityLocation.closeNotification(); @@ -219,7 +218,7 @@ describe("Location Management Section", () => { facilityLocation.deleteLocation("Test Location with Beds"); assetPage.clickassetupdatebutton(); facilityLocation.verifyNotification( - "Location Test Location with Beds deleted successfully" + "Location Test Location with Beds deleted successfully", ); facilityLocation.closeNotification(); }); @@ -249,14 +248,14 @@ describe("Location Management Section", () => { "Vendor's Name", serialNumber, "25122021", - "Test note for asset creation!" + "Test note for asset creation!", ); assetPage.clickassetupdatebutton(); facilityLocation.loadLocationManagementPage("Dummy Shifting Center"); facilityLocation.deleteLocation("Test Location with linked Assets"); assetPage.clickassetupdatebutton(); facilityLocation.verifyNotification( - "Cannot delete a Location with associated Assets" + "Cannot delete a Location with associated Assets", ); facilityLocation.closeNotification(); @@ -271,7 +270,7 @@ describe("Location Management Section", () => { facilityLocation.deleteLocation("Test Location with linked Assets"); assetPage.clickassetupdatebutton(); facilityLocation.verifyNotification( - "Location Test Location with linked Assets deleted successfully" + "Location Test Location with linked Assets deleted successfully", ); facilityLocation.closeNotification(); }); diff --git a/cypress/e2e/patient_spec/patient_consultation.cy.ts b/cypress/e2e/patient_spec/patient_consultation.cy.ts index cf84b0db0d8..a27d560e1a0 100644 --- a/cypress/e2e/patient_spec/patient_consultation.cy.ts +++ b/cypress/e2e/patient_spec/patient_consultation.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; diff --git a/cypress/e2e/patient_spec/patient_discharge.cy.ts b/cypress/e2e/patient_spec/patient_discharge.cy.ts index 242c936730d..be9b06303cb 100644 --- a/cypress/e2e/patient_spec/patient_discharge.cy.ts +++ b/cypress/e2e/patient_spec/patient_discharge.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import PatientDischarge from "../../pageobject/Patient/PatientDischarge"; diff --git a/cypress/e2e/patient_spec/patient_fileupload.cy.ts b/cypress/e2e/patient_spec/patient_fileupload.cy.ts index 3d5bb37ce58..9d6852d16e7 100644 --- a/cypress/e2e/patient_spec/patient_fileupload.cy.ts +++ b/cypress/e2e/patient_spec/patient_fileupload.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import { PatientFileUpload } from "../../pageobject/Patient/PatientFileupload"; diff --git a/cypress/e2e/patient_spec/patient_logupdate.cy.ts b/cypress/e2e/patient_spec/patient_logupdate.cy.ts index 26894bd0815..13e69e33211 100644 --- a/cypress/e2e/patient_spec/patient_logupdate.cy.ts +++ b/cypress/e2e/patient_spec/patient_logupdate.cy.ts @@ -1,14 +1,17 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import PatientLogupdate from "../../pageobject/Patient/PatientLogupdate"; +import PatientInvestigation from "../../pageobject/Patient/PatientInvestigation"; +import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; describe("Patient Log Update in Normal, Critical and TeleIcu", () => { const loginPage = new LoginPage(); const patientConsultationPage = new PatientConsultationPage(); const patientPage = new PatientPage(); const patientLogupdate = new PatientLogupdate(); + const patientInvestigation = new PatientInvestigation(); + const patientPrescription = new PatientPrescription(); const domicilaryPatient = "Dummy Patient 11"; const patientCategory = "Moderate"; const additionalSymptoms = "Fever"; @@ -36,7 +39,72 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.awaitUrl("/patients"); }); - it("Create a new log teleicu update for a domicilary care patient and verify the copy previous value function", () => { + it("Create a new Progress log update for a admitted patient and edit it", () => { + patientPage.visitPatient("Dummy Patient 12"); + patientLogupdate.clickLogupdate(); + cy.verifyNotification("Please assign a bed to the patient"); + patientLogupdate.selectBed("Dummy Bed 4"); + cy.closeNotification(); + patientLogupdate.clickLogupdate(); + // Only will be using random non-unique progress note fields + patientLogupdate.selectPatientCategory(patientCategory); + patientLogupdate.selectRoundType("Progress Note"); + patientLogupdate.selectSymptomsDate("01012024"); + patientLogupdate.typeAndMultiSelectSymptoms("fe", ["Fever"]); + patientLogupdate.typeTemperature(patientTemperature); + // add diagnosis + patientConsultationPage.selectPatientDiagnosis( + "1A06", + "add-icd11-diagnosis-as-differential", + ); + // add a investigation for the patient + patientInvestigation.clickAddInvestigation(); + patientInvestigation.selectInvestigation("Vitals (GROUP)"); + patientInvestigation.clickInvestigationCheckbox(); + patientInvestigation.selectInvestigationFrequency("6"); + // add a medicine for the patient + patientPrescription.clickAddPrescription(); + patientPrescription.interceptMedibase(); + patientPrescription.selectMedicinebox(); + patientPrescription.selectMedicine("DOLO"); + patientPrescription.enterDosage("4"); + patientPrescription.selectDosageFrequency("Twice daily"); + cy.submitButton("Submit"); + cy.verifyNotification("Medicine prescribed"); + cy.closeNotification(); + // Submit the doctors log update + cy.submitButton("Save and Continue"); + cy.verifyNotification("Progress Note log created successfully"); + cy.closeNotification(); + // modify the relevant critical care log update + cy.contains("button", "Neurological Monitoring").click(); + cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); + cy.get("#left_pupil_light_reaction-option-FIXED").click(); + cy.submitButton("Update Details"); + cy.verifyNotification( + "Neurological Monitoring details succesfully updated.", + ); + cy.closeNotification(); + // Final Submission of the form + cy.submitButton("Complete"); + cy.verifyNotification("Progress Note Log Update filed successfully"); + cy.closeNotification(); + // Verify the data reflection + cy.contains("button", "Daily Rounds").click(); + patientLogupdate.clickLogupdateCard("#dailyround-entry", patientCategory); + cy.verifyContentPresence("#consultation-preview", [ + patientCategory, + patientTemperature, + ]); + // verify the edit functionality + patientLogupdate.clickUpdateDetail(); + patientLogupdate.typeSystolic(patientModifiedSystolic); + patientLogupdate.typeDiastolic(patientModifiedDiastolic); + cy.submitButton("Continue"); + cy.verifyNotification("Progress Note log updated successfully"); + }); + + it("Create a new TeleIcu log update for a domicilary care patient", () => { patientPage.visitPatient("Dummy Patient 11"); patientConsultationPage.clickEditConsultationButton(); patientConsultationPage.selectPatientSuggestion("Domiciliary Care"); @@ -63,7 +131,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.verifyNotification("Telemedicine log created successfully"); }); - it("Create a new log normal update for a domicilary care patient and edit it", () => { + it("Create a new Normal Log update for a domicilary care patient and edit it", () => { patientPage.visitPatient(domicilaryPatient); patientConsultationPage.clickEditConsultationButton(); patientConsultationPage.selectPatientSuggestion("Domiciliary Care"); @@ -118,7 +186,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { ]); }); - it("Create a new log normal update for a admission patient and verify its reflection in cards", () => { + it("Create a new Normal update for a admission patient and verify its reflection in cards", () => { patientPage.visitPatient("Dummy Patient 13"); patientLogupdate.clickLogupdate(); cy.verifyNotification("Please assign a bed to the patient"); @@ -148,7 +216,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.verifyContentPresence("#encounter-symptoms", [additionalSymptoms]); }); - it("Create a normal log update to verify MEWS Score Functionality", () => { + it("Create a Normal Log update to verify MEWS Score Functionality", () => { patientPage.visitPatient(domicilaryPatient); patientConsultationPage.clickEditConsultationButton(); patientConsultationPage.selectPatientSuggestion("Domiciliary Care"); diff --git a/cypress/e2e/patient_spec/patient_manage.cy.ts b/cypress/e2e/patient_spec/patient_manage.cy.ts index 313877ac565..22d77aa2fda 100644 --- a/cypress/e2e/patient_spec/patient_manage.cy.ts +++ b/cypress/e2e/patient_spec/patient_manage.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; diff --git a/cypress/e2e/patient_spec/patient_prescription.cy.ts b/cypress/e2e/patient_spec/patient_prescription.cy.ts index 4a27ce14cb2..a150bfa6e31 100644 --- a/cypress/e2e/patient_spec/patient_prescription.cy.ts +++ b/cypress/e2e/patient_spec/patient_prescription.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; diff --git a/cypress/e2e/patient_spec/patient_registration.cy.ts b/cypress/e2e/patient_spec/patient_registration.cy.ts index f94dbbe46cd..2e7ce853fc5 100644 --- a/cypress/e2e/patient_spec/patient_registration.cy.ts +++ b/cypress/e2e/patient_spec/patient_registration.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; diff --git a/cypress/e2e/resource_spec/filter.cy.ts b/cypress/e2e/resource_spec/filter.cy.ts index d9f5f50c16f..aafc03680ee 100644 --- a/cypress/e2e/resource_spec/filter.cy.ts +++ b/cypress/e2e/resource_spec/filter.cy.ts @@ -1,5 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; - describe("Resource filter", () => { before(() => { cy.loginByApi("devdistrictadmin", "Coronasafe@123"); diff --git a/cypress/e2e/resource_spec/resources.cy.ts b/cypress/e2e/resource_spec/resources.cy.ts index f0c2b8698f9..2b4e75e1883 100644 --- a/cypress/e2e/resource_spec/resources.cy.ts +++ b/cypress/e2e/resource_spec/resources.cy.ts @@ -1,4 +1,3 @@ -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"; diff --git a/cypress/e2e/sample_test_spec/filter.cy.ts b/cypress/e2e/sample_test_spec/filter.cy.ts index df934c641bb..ad2e57b7433 100644 --- a/cypress/e2e/sample_test_spec/filter.cy.ts +++ b/cypress/e2e/sample_test_spec/filter.cy.ts @@ -1,5 +1,3 @@ -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; - describe("Sample Filter", () => { before(() => { cy.loginByApi("devdistrictadmin", "Coronasafe@123"); diff --git a/cypress/e2e/sample_test_spec/sample_test.cy.ts b/cypress/e2e/sample_test_spec/sample_test.cy.ts index 1a134fffdac..1af1cfc5cb4 100644 --- a/cypress/e2e/sample_test_spec/sample_test.cy.ts +++ b/cypress/e2e/sample_test_spec/sample_test.cy.ts @@ -1,5 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; - describe("Sample List", () => { before(() => { cy.loginByApi("devdistrictadmin", "Coronasafe@123"); diff --git a/cypress/e2e/shifting_spec/filter.cy.ts b/cypress/e2e/shifting_spec/filter.cy.ts index 82fad9d99e4..bb536a1865c 100644 --- a/cypress/e2e/shifting_spec/filter.cy.ts +++ b/cypress/e2e/shifting_spec/filter.cy.ts @@ -1,4 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import ShiftingPage from "../../pageobject/Shift/ShiftFilters"; describe("Shifting section filter", () => { diff --git a/cypress/e2e/shifting_spec/shifting.cy.ts b/cypress/e2e/shifting_spec/shifting.cy.ts index f33278cbec4..a0a637f97f1 100644 --- a/cypress/e2e/shifting_spec/shifting.cy.ts +++ b/cypress/e2e/shifting_spec/shifting.cy.ts @@ -1,5 +1,3 @@ -import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; - describe("Shifting Page", () => { before(() => { cy.loginByApi("devdistrictadmin", "Coronasafe@123"); diff --git a/cypress/e2e/users_spec/user_creation.cy.ts b/cypress/e2e/users_spec/user_creation.cy.ts index 91efb3aee31..cc3a8250971 100644 --- a/cypress/e2e/users_spec/user_creation.cy.ts +++ b/cypress/e2e/users_spec/user_creation.cy.ts @@ -1,4 +1,3 @@ -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; diff --git a/cypress/e2e/users_spec/user_homepage.cy.ts b/cypress/e2e/users_spec/user_homepage.cy.ts index 3ac07dd9d9c..b1ecd567d86 100644 --- a/cypress/e2e/users_spec/user_homepage.cy.ts +++ b/cypress/e2e/users_spec/user_homepage.cy.ts @@ -1,6 +1,3 @@ -/// - -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { UserPage } from "../../pageobject/Users/UserSearch"; diff --git a/cypress/e2e/users_spec/user_manage.cy.ts b/cypress/e2e/users_spec/user_manage.cy.ts index 0ff66fba27a..9c339f4b8e3 100644 --- a/cypress/e2e/users_spec/user_manage.cy.ts +++ b/cypress/e2e/users_spec/user_manage.cy.ts @@ -1,4 +1,3 @@ -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { UserPage } from "../../pageobject/Users/UserSearch"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; diff --git a/cypress/e2e/users_spec/user_profile.cy.ts b/cypress/e2e/users_spec/user_profile.cy.ts index 3cbc2e91404..2672cccad7e 100644 --- a/cypress/e2e/users_spec/user_profile.cy.ts +++ b/cypress/e2e/users_spec/user_profile.cy.ts @@ -1,4 +1,3 @@ -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import UserProfilePage from "../../pageobject/Users/UserProfilePage"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; diff --git a/cypress/pageobject/Asset/AssetCreation.ts b/cypress/pageobject/Asset/AssetCreation.ts index 331a4588c6f..2de13561a0b 100644 --- a/cypress/pageobject/Asset/AssetCreation.ts +++ b/cypress/pageobject/Asset/AssetCreation.ts @@ -1,5 +1,4 @@ // assetPage.ts -import { cy, expect } from "local-cypress"; export class AssetPage { createAsset() { diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index 328719f5e90..a1676e625dd 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -1,5 +1,4 @@ // FacilityPage.ts -import { cy } from "local-cypress"; class FacilityPage { visitCreateFacilityPage() { diff --git a/cypress/pageobject/Facility/FacilityHome.ts b/cypress/pageobject/Facility/FacilityHome.ts index fa163757584..b10368717a6 100644 --- a/cypress/pageobject/Facility/FacilityHome.ts +++ b/cypress/pageobject/Facility/FacilityHome.ts @@ -1,5 +1,3 @@ -// cypress/support/pageObjects/FacilityHome.ts - class FacilityHome { // Selectors exportButton = "#export-button"; diff --git a/cypress/pageobject/Login/LoginPage.ts b/cypress/pageobject/Login/LoginPage.ts index 94e52c33613..c75a024ae03 100644 --- a/cypress/pageobject/Login/LoginPage.ts +++ b/cypress/pageobject/Login/LoginPage.ts @@ -1,5 +1,4 @@ // LoginPage.ts -import { cy } from "local-cypress"; class LoginPage { loginAsDisctrictAdmin(): void { diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index dc5d9e2b2bb..e4a9810141e 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -52,7 +52,7 @@ export class PatientConsultationPage { cy.searchAndSelectOption("#icd11-search", icdCode); cy.get("#diagnosis-list") .contains("Add as") - .focus() + .scrollIntoView() .click() .then(() => { cy.get(`#${statusId}`).click(); diff --git a/cypress/pageobject/Patient/PatientFileupload.ts b/cypress/pageobject/Patient/PatientFileupload.ts index 8d5fecace4f..3f353cb8807 100644 --- a/cypress/pageobject/Patient/PatientFileupload.ts +++ b/cypress/pageobject/Patient/PatientFileupload.ts @@ -1,5 +1,3 @@ -import { cy } from "local-cypress"; - export class PatientFileUpload { clickFileUploadIcon() { cy.get("#patient-details").click(); diff --git a/cypress/pageobject/Patient/PatientPrescription.ts b/cypress/pageobject/Patient/PatientPrescription.ts index 108fedbd676..403d361e55c 100644 --- a/cypress/pageobject/Patient/PatientPrescription.ts +++ b/cypress/pageobject/Patient/PatientPrescription.ts @@ -1,4 +1,3 @@ -import { cy } from "local-cypress"; export class PatientPrescription { clickAddPrescription() { cy.get("#add-prescription").scrollIntoView(); diff --git a/cypress/pageobject/Users/UserProfilePage.ts b/cypress/pageobject/Users/UserProfilePage.ts index 77b624606cc..c3de5035dc7 100644 --- a/cypress/pageobject/Users/UserProfilePage.ts +++ b/cypress/pageobject/Users/UserProfilePage.ts @@ -1,5 +1,3 @@ -import { cy } from "local-cypress"; - export default class UserProfilePage { assertVideoConnectLink(link: string) { cy.get("#videoconnectlink-profile-details").should("contain.text", link); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 8c1b60f3d88..c6437505349 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -1,6 +1,6 @@ import "cypress-localstorage-commands"; -import { Cypress, cy } from "local-cypress"; +const apiUrl = Cypress.env("API_URL"); Cypress.Commands.add("login", (username: string, password: string) => { cy.log(`Logging in the user: ${username}:${password}`); @@ -14,7 +14,7 @@ Cypress.Commands.add("login", (username: string, password: string) => { Cypress.Commands.add("refreshApiLogin", (username, password) => { cy.request({ method: "POST", - url: "/api/v1/auth/login/", + url: `${apiUrl}/api/v1/auth/login/`, body: { username, password, @@ -43,7 +43,7 @@ Cypress.Commands.add("loginByApi", (username, password) => { if (tkn && token.access && token.username === username) { cy.request({ method: "POST", - url: "/api/v1/auth/token/verify/", + url: `${apiUrl}/api/v1/auth/token/verify/`, body: { token: token.access, }, @@ -69,7 +69,7 @@ Cypress.Commands.add("loginByApi", (username, password) => { Cypress.Commands.add( "awaitUrl", (url: string, disableLoginVerification = false) => { - cy.intercept(/currentuser/).as("currentuser"); + cy.intercept(/getcurrentuser/).as("currentuser"); cy.visit(url); disableLoginVerification ? cy.wait("@currentuser") diff --git a/cypress/support/index.ts b/cypress/support/index.ts index c9af6a02c96..9ddfd0c819a 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -1,4 +1,3 @@ -/// import "./commands"; declare global { diff --git a/index.html b/index.html index 8fea63f2bad..6d2c83a0a99 100644 --- a/index.html +++ b/index.html @@ -11,7 +11,7 @@ - + diff --git a/netlify.toml b/netlify.toml index a79fe05eefe..c1d30732a53 100644 --- a/netlify.toml +++ b/netlify.toml @@ -7,12 +7,6 @@ NODE_VERSION = "20.12.0" NPM_FLAGS = "--legacy-peer-deps" NODE_OPTIONS = "--max_old_space_size=4096" -[[redirects]] -from = "/api/*" -to = "https://careapi.ohc.network/api/:splat" -status = 200 -force = true - [[redirects]] from = "/*" to = "/index.html" diff --git a/package-lock.json b/package-lock.json index b3eeb9e919f..b9b0c4d0583 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,7 +67,7 @@ "@typescript-eslint/eslint-plugin": "^7.18.0", "@vitejs/plugin-react-swc": "^3.6.0", "autoprefixer": "^10.4.19", - "cypress": "^13.13.1", + "cypress": "^13.14.1", "cypress-localstorage-commands": "^2.2.5", "cypress-split": "^1.23.2", "eslint-config-prettier": "^9.1.0", @@ -6590,13 +6590,13 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cypress": { - "version": "13.13.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.1.tgz", - "integrity": "sha512-8F9UjL5MDUdgC/S5hr8CGLHbS5gGht5UOV184qc2pFny43fnkoaKxlzH/U6//zmGu/xRTaKimNfjknLT8+UDFg==", + "version": "13.14.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.1.tgz", + "integrity": "sha512-Wo+byPmjps66hACEH5udhXINEiN3qS3jWNGRzJOjrRJF3D0+YrcP2LVB1T7oYaVQM/S+eanqEvBWYc8cf7Vcbg==", "dev": true, "hasInstallScript": true, "dependencies": { - "@cypress/request": "^3.0.0", + "@cypress/request": "^3.0.1", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", diff --git a/package.json b/package.json index d57aee0fda4..0b3d1547ee0 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "@typescript-eslint/eslint-plugin": "^7.18.0", "@vitejs/plugin-react-swc": "^3.6.0", "autoprefixer": "^10.4.19", - "cypress": "^13.13.1", + "cypress": "^13.14.1", "cypress-localstorage-commands": "^2.2.5", "cypress-split": "^1.23.2", "eslint-config-prettier": "^9.1.0", diff --git a/src/App.tsx b/src/App.tsx index f89dfd11e74..2e7f185f80b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,28 +1,23 @@ import { Suspense } from "react"; import Routers from "./Routers"; -import { - AppConfigProvider, - AuthUserProvider, - HistoryAPIProvider, -} from "./Providers"; import ThemedFavicon from "./CAREUI/misc/ThemedFavicon"; import Intergrations from "./Integrations"; import Loading from "./Components/Common/Loading"; +import HistoryAPIProvider from "./Providers/HistoryAPIProvider"; +import AuthUserProvider from "./Providers/AuthUserProvider"; const App = () => { return ( }> - - }> - - + }> + + - {/* Integrations */} - - - + {/* Integrations */} + + ); diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index 6e5a9e33e4e..681fe874475 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -1,4 +1,3 @@ -import { IConfig } from "./hooks/useConfig"; import { PatientCategory } from "../Components/Facility/models"; import { SortOption } from "../Components/Common/SortDropdown"; import { dateQueryString } from "../Utils/utils"; @@ -9,6 +8,7 @@ import { ConsentHIType, ConsentPurpose, } from "../Components/ABDM/types/consent"; +import careConfig from "@careConfig"; export const RESULTS_PER_PAGE_LIMIT = 14; export const PAGINATION_LIMIT = 36; @@ -217,33 +217,30 @@ export const DISCHARGED_PATIENT_SORT_OPTIONS: SortOption[] = [ { isAscending: false, value: "-name" }, ]; -export const getBedTypes = ({ - kasp_enabled, - kasp_string, -}: Pick) => { - const kaspBedTypes = kasp_enabled - ? [ - { id: 40, text: kasp_string + " Ordinary Beds" }, - { id: 60, text: kasp_string + " Oxygen beds" }, - { id: 50, text: kasp_string + " ICU (ICU without ventilator)" }, - { id: 70, text: kasp_string + " ICU (ICU with ventilator)" }, - ] - : []; - - return [ - { id: 1, text: "Ordinary Beds" }, - { id: 150, text: "Oxygen beds" }, - { id: 10, text: "ICU (ICU without ventilator)" }, - { id: 20, text: "Ventilator (ICU with ventilator)" }, - { id: 30, text: "Covid Ordinary Beds" }, - { id: 120, text: "Covid Oxygen beds" }, - { id: 110, text: "Covid ICU (ICU without ventilator)" }, - { id: 100, text: "Covid Ventilators (ICU with ventilator)" }, - ...kaspBedTypes, - { id: 2, text: "Hostel" }, - { id: 3, text: "Single Room with Attached Bathroom" }, - ]; -}; +const { kasp } = careConfig; + +const KASP_BED_TYPES = kasp.enabled + ? [ + { id: 40, text: kasp.string + " Ordinary Beds" }, + { id: 60, text: kasp.string + " Oxygen beds" }, + { id: 50, text: kasp.string + " ICU (ICU without ventilator)" }, + { id: 70, text: kasp.string + " ICU (ICU with ventilator)" }, + ] + : []; + +export const BED_TYPES: OptionsType[] = [ + { id: 1, text: "Ordinary Beds" }, + { id: 150, text: "Oxygen beds" }, + { id: 10, text: "ICU (ICU without ventilator)" }, + { id: 20, text: "Ventilator (ICU with ventilator)" }, + { id: 30, text: "Covid Ordinary Beds" }, + { id: 120, text: "Covid Oxygen beds" }, + { id: 110, text: "Covid ICU (ICU without ventilator)" }, + { id: 100, text: "Covid Ventilators (ICU with ventilator)" }, + ...KASP_BED_TYPES, + { id: 2, text: "Hostel" }, + { id: 3, text: "Single Room with Attached Bathroom" }, +]; export const DOCTOR_SPECIALIZATION: Array = [ { id: 1, text: "General Medicine" }, @@ -731,6 +728,12 @@ export const RESOURCE_FILTER_ORDER: Array = [ { id: 4, text: "-modified_date", desc: "DESC Modified Date" }, ]; +export const HEARTBEAT_RHYTHM_CHOICES = [ + "REGULAR", + "IRREGULAR", + "UNKNOWN", +] as const; + export const NURSING_CARE_PROCEDURES = [ "personal_hygiene", "positioning", @@ -792,12 +795,12 @@ export const RHYTHM_CHOICES = [ { id: 10, text: "IRREGULAR", desc: "Irregular" }, ] as const; -export const LOCATION_BED_TYPES: Array = [ +export const LOCATION_BED_TYPES = [ { id: "ISOLATION", name: "Isolation" }, { id: "ICU", name: "ICU" }, { id: "BED_WITH_OXYGEN_SUPPORT", name: "Bed with oxygen support" }, { id: "REGULAR", name: "Regular" }, -]; +] as const; export const ASSET_META_TYPE = [ { id: "CAMERA", text: "Camera(ONVIF)" }, diff --git a/src/Common/hooks/useConfig.ts b/src/Common/hooks/useConfig.ts deleted file mode 100644 index 38e2336d583..00000000000 --- a/src/Common/hooks/useConfig.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { createContext, useContext } from "react"; - -export const AppConfigContext = createContext(null); - -interface ILogo { - light: string; - dark: string; -} - -export interface IConfig { - dashboard_url?: string; - github_url: string; - ohcn_url: string; - site_url: string; - analytics_server_url: string; - - /** - * The main logo of the app displayed on login and sidebar header. - */ - main_logo: ILogo; - /** - * If present, the image will be displayed on the login page before the main logo. - */ - state_logo?: ILogo; - /** - * if present, this replaces the state logo on the login page only. - */ - custom_logo?: ILogo; - /** - * if present, this replaces the main logo on the login page only. - */ - custom_logo_alt?: ILogo; - - custom_description?: string; - - /** - * The API key for the Google Maps API used for location picker. - */ - gmaps_api_key: string; - /** - * The API key for the data.gov.in API used for pincode auto-complete. - */ - gov_data_api_key: string; - recaptcha_site_key: string; - /** - * SENTRY_DSN - */ - sentry_dsn: string; - /** - * SENTRY_ENVIRONMENT - */ - sentry_environment: string; - - /** - * The header banner is displayed on the top of - * the shift print form if the facility is kasp. - */ - header_logo: ILogo; - kasp_enabled: boolean; - kasp_string: string; - kasp_full_string: string; - /** - * URL of the sample format for asset import. - */ - sample_format_asset_import: string; - /** - * URL of the sample format for external result import. - */ - sample_format_external_result_import: string; - /** - * Env to enable HCX features - */ - enable_hcx: boolean; - /** - * Env to enable ABDM features - */ - enable_abdm: boolean; - /** - * Env to enable scribe features - */ - enable_scribe: boolean; - /** - * Env to toggle peacetime and wartime shifting - */ - wartime_shifting: boolean; - jwt_token_refresh_interval?: number; - - /* - * Minimum date for a possible consultation encounter. - */ - min_encounter_date: string; -} - -const useConfig = () => { - const config = useContext(AppConfigContext); - - if (!config) { - throw new Error("useConfig must be used within an AppConfigProvider"); - } - - return config; -}; - -export default useConfig; diff --git a/src/Common/hooks/useFilters.tsx b/src/Common/hooks/useFilters.tsx index c0919be9acc..a4b924edcdb 100644 --- a/src/Common/hooks/useFilters.tsx +++ b/src/Common/hooks/useFilters.tsx @@ -3,9 +3,9 @@ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import GenericFilterBadge from "../../CAREUI/display/FilterBadge"; import PaginationComponent from "../../Components/Common/Pagination"; -import useConfig from "./useConfig"; import { classNames, humanizeStrings } from "../../Utils/utils"; import FiltersCache from "../../Utils/FiltersCache"; +import careConfig from "@careConfig"; export type FilterState = Record; @@ -27,7 +27,6 @@ export default function useFilters({ cacheBlacklist?: string[]; }) { const { t } = useTranslation(); - const { kasp_string } = useConfig(); const hasPagination = limit > 0; const [showFilters, setShowFilters] = useState(false); const [qParams, _setQueryParams] = useQueryParams(); @@ -155,8 +154,9 @@ export default function useFilters({ return { name, value, paramKey }; }, kasp(nameSuffix = "", paramKey = "is_kasp") { - const name = nameSuffix ? kasp_string + " " + nameSuffix : kasp_string; - const [trueLabel, falseLabel] = [kasp_string, "Non " + kasp_string]; + const { kasp } = careConfig; + const name = nameSuffix ? kasp.string + " " + nameSuffix : kasp.string; + const [trueLabel, falseLabel] = [kasp.string, "Non " + kasp.string]; return badgeUtils.boolean(name, paramKey, { trueLabel, falseLabel }); }, }; diff --git a/src/Components/Assets/AssetImportModal.tsx b/src/Components/Assets/AssetImportModal.tsx index d553e30b79e..6ff51e293af 100644 --- a/src/Components/Assets/AssetImportModal.tsx +++ b/src/Components/Assets/AssetImportModal.tsx @@ -5,12 +5,14 @@ import { AssetData } from "./AssetTypes"; import * as Notification from "../../Utils/Notifications.js"; import { Cancel } from "../Common/components/ButtonV2"; import { Link } from "raviger"; -import { LocalStorageKeys, AssetImportSchema } from "../../Common/constants"; -import useConfig from "../../Common/hooks/useConfig"; +import { AssetImportSchema } from "../../Common/constants"; import DialogModal from "../Common/Dialog"; import useQuery from "../../Utils/request/useQuery"; import routes from "../../Redux/api"; import { SelectFormField } from "../Form/FormFields/SelectFormField"; +import careConfig from "@careConfig"; +import request from "../../Utils/request/request"; + const ExcelFileDragAndDrop = lazy( () => import("../Common/ExcelFIleDragAndDrop"), ); @@ -29,7 +31,6 @@ const AssetImportModal = ({ open, onClose, facility, onUpdate }: Props) => { const [errors, setErrors] = useState({ location: "", }); - const { sample_format_asset_import } = useConfig(); const closeModal = () => { onClose && onClose(); @@ -85,17 +86,8 @@ const AssetImportModal = ({ open, onClose, facility, onUpdate }: Props) => { asset_data["warranty_amc_end_of_validity"] = asset.warranty_amc_end_of_validity; - const response = await fetch("/api/v1/asset/", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: - "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken), - }, - body: JSON.stringify(asset_data), - }); - const data = await response.json(); - if (response.status !== 201) { + const { res } = await request(routes.createAsset, { body: asset_data }); + if (!res?.ok) { Notification.Error({ msg: "Error importing asset: " + asset.name + " " + JSON.stringify(data), @@ -176,7 +168,7 @@ const AssetImportModal = ({ open, onClose, facility, onUpdate }: Props) => { handleSubmit={handleUpload} loading={isImporting} schema={AssetImportSchema} - sampleLink={sample_format_asset_import} + sampleLink={careConfig.sampleFormats.assetImport} setIsValid={setIsValid} /> diff --git a/src/Components/Auth/Login.tsx b/src/Components/Auth/Login.tsx index d0d055413cb..17ecf061ef2 100644 --- a/src/Components/Auth/Login.tsx +++ b/src/Components/Auth/Login.tsx @@ -7,26 +7,25 @@ import * as Notification from "../../Utils/Notifications.js"; import LegendInput from "../../CAREUI/interactive/LegendInput"; import LanguageSelectorLogin from "../Common/LanguageSelectorLogin"; import CareIcon from "../../CAREUI/icons/CareIcon"; -import useConfig from "../../Common/hooks/useConfig"; import CircularProgress from "../Common/components/CircularProgress"; import ReactMarkdown from "react-markdown"; import rehypeRaw from "rehype-raw"; import { useAuthContext } from "../../Common/hooks/useAuthUser"; import FiltersCache from "../../Utils/FiltersCache"; import { classNames } from "../../Utils/utils"; +import careConfig from "@careConfig"; export const Login = (props: { forgot?: boolean }) => { const { signIn } = useAuthContext(); const { - main_logo, - recaptcha_site_key, - github_url, - ohcn_url, - state_logo, - custom_logo, - custom_logo_alt, - custom_description, - } = useConfig(); + mainLogo, + reCaptchaSiteKey, + urls, + stateLogo, + customLogo, + customLogoAlt, + customDescription, + } = careConfig; const initForm: any = { username: "", password: "", @@ -162,10 +161,10 @@ export const Login = (props: { forgot?: boolean }) => {
- {(custom_logo || state_logo) && ( + {(customLogo || stateLogo) && ( <> state logo @@ -173,13 +172,13 @@ export const Login = (props: { forgot?: boolean }) => { )} Open Healthcare Network logo @@ -189,13 +188,13 @@ export const Login = (props: { forgot?: boolean }) => {

{t("care")}

- {custom_description ? ( + {customDescription ? (
- {custom_description || t("goal")} + {customDescription || t("goal")}
) : ( @@ -220,7 +219,7 @@ export const Login = (props: { forgot?: boolean }) => { />
{
{
- {(custom_logo || state_logo) && ( + {(customLogo || stateLogo) && ( <> state logo @@ -265,7 +264,7 @@ export const Login = (props: { forgot?: boolean }) => { )} care logo @@ -310,7 +309,7 @@ export const Login = (props: { forgot?: boolean }) => { {isCaptchaEnabled && (
{errors.captcha} diff --git a/src/Components/CameraFeed/AssetBedSelect.tsx b/src/Components/CameraFeed/AssetBedSelect.tsx index b97675c7b31..18bef259b2b 100644 --- a/src/Components/CameraFeed/AssetBedSelect.tsx +++ b/src/Components/CameraFeed/AssetBedSelect.tsx @@ -1,14 +1,15 @@ -import { AssetBedModel } from "../Assets/AssetTypes"; import { Listbox, ListboxButton, ListboxOption, ListboxOptions, } from "@headlessui/react"; + +import { AssetBedModel } from "../Assets/AssetTypes"; +import ButtonV2 from "../Common/components/ButtonV2"; import CareIcon from "../../CAREUI/icons/CareIcon"; import { classNames } from "../../Utils/utils"; import { dropdownOptionClassNames } from "../Form/MultiSelectMenuV2"; -import ButtonV2 from "../Common/components/ButtonV2"; interface Props { disabled?: boolean; @@ -108,6 +109,7 @@ export const CameraPresetDropdown = ( diff --git a/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx b/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx index d2e7fd89494..3cca4c00ec4 100644 --- a/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx +++ b/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx @@ -8,6 +8,7 @@ import Fullscreen from "../../../CAREUI/misc/Fullscreen"; import useBreakpoints from "../../../Common/hooks/useBreakpoints"; import { useQueryParams } from "raviger"; import LiveMonitoringFilters from "./LiveMonitoringFilters"; +import StillWatching from "../StillWatching"; export default function CentralLiveMonitoring(props: { facilityId: string }) { const [isFullscreen, setFullscreen] = useState(false); @@ -59,19 +60,21 @@ export default function CentralLiveMonitoring(props: { facilityId: string }) { No Camera present in this location or facility.
) : ( - setFullscreen(false)} - > -
- {data.results.map((asset) => ( -
- -
- ))} -
-
+ + setFullscreen(false)} + > +
+ {data.results.map((asset) => ( +
+ +
+ ))} +
+
+
)} ); diff --git a/src/Components/CameraFeed/StillWatching.tsx b/src/Components/CameraFeed/StillWatching.tsx new file mode 100644 index 00000000000..0b5a8056b43 --- /dev/null +++ b/src/Components/CameraFeed/StillWatching.tsx @@ -0,0 +1,82 @@ +import { useEffect, useState } from "react"; +import ConfirmDialog from "../Common/ConfirmDialog"; +import ButtonV2 from "../Common/components/ButtonV2"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import { useTranslation } from "react-i18next"; +import { useTimer } from "../../Utils/useTimer"; +import careConfig from "@careConfig"; + +type State = "watching" | "prompted" | "timed-out"; + +const useStillWatching = () => { + const { idleTimeout, promptDuration } = careConfig.stillWatching; + const [state, setState] = useState("watching"); + const [sequence, setSequence] = useState(1); + + const timer = useTimer(true); + + const remainingTime = Math.ceil( + (idleTimeout + promptDuration) * Math.min(sequence, 3) - timer.seconds, + ); + + useEffect(() => { + if (remainingTime < 0) { + setState("timed-out"); + timer.stop(); + return; + } + if (remainingTime < promptDuration) { + setState("prompted"); + return; + } + }, [promptDuration, remainingTime]); + + return { + state, + remainingTime, + reset: (hardReset?: boolean) => { + if (hardReset) { + setSequence((seq) => seq + 1); + } + timer.reset(); + setState("watching"); + timer.start(); + }, + }; +}; + +export default function StillWatching(props: { children: React.ReactNode }) { + const { t } = useTranslation(); + const { state, remainingTime, reset } = useStillWatching(); + + return ( +
reset()}> + + + {t("continue_watching")} ({remainingTime}s.) + + } + onConfirm={() => reset(true)} + onClose={() => reset(true)} + /> + {state === "timed-out" ? ( +
+ + {t("stream_stopped_due_to_inativity")} + + reset(true)}> + + {t("resume")} + +
+ ) : ( + props.children + )} +
+ ); +} diff --git a/src/Components/Common/GLocationPicker.tsx b/src/Components/Common/GLocationPicker.tsx index 5119d219e73..0b03d2775ce 100644 --- a/src/Components/Common/GLocationPicker.tsx +++ b/src/Components/Common/GLocationPicker.tsx @@ -4,8 +4,8 @@ import { deepEqual } from "../../Common/utils"; import { isLatLngLiteral } from "@googlemaps/typescript-guards"; import Spinner from "./Spinner"; import CareIcon from "../../CAREUI/icons/CareIcon"; -import useConfig from "../../Common/hooks/useConfig"; import { PopoverButton } from "@headlessui/react"; +import careConfig from "@careConfig"; interface GLocationPickerProps { lat: number; @@ -24,7 +24,6 @@ const GLocationPicker = ({ handleOnClose, handleOnSelectCurrentLocation, }: GLocationPickerProps) => { - const { gmaps_api_key } = useConfig(); const [location, setLocation] = React.useState( null, ); @@ -87,7 +86,7 @@ const GLocationPicker = ({
diff --git a/src/Components/Common/Sidebar/Sidebar.tsx b/src/Components/Common/Sidebar/Sidebar.tsx index f454c9c6ab9..52e5e0680fa 100644 --- a/src/Components/Common/Sidebar/Sidebar.tsx +++ b/src/Components/Common/Sidebar/Sidebar.tsx @@ -4,11 +4,11 @@ import SidebarUserCard from "./SidebarUserCard"; import NotificationItem from "../../Notifications/NotificationsList"; import useActiveLink from "../../../Common/hooks/useActiveLink"; import CareIcon, { IconName } from "../../../CAREUI/icons/CareIcon"; -import useConfig from "../../../Common/hooks/useConfig"; import SlideOver from "../../../CAREUI/interactive/SlideOver"; import { classNames } from "../../../Utils/utils"; import { Link } from "raviger"; import useAuthUser from "../../../Common/hooks/useAuthUser"; +import careConfig from "@careConfig"; export const SIDEBAR_SHRINK_PREFERENCE_KEY = "sidebarShrinkPreference"; @@ -62,10 +62,8 @@ const StatelessSidebar = ({ { text: "Notice Board", to: "/notice_board", icon: "l-meeting-board" }, ]; - const { main_logo } = useConfig(); const activeLink = useActiveLink(); const Item = shrinked ? ShrinkedSidebarItem : SidebarItem; - const { dashboard_url } = useConfig(); const indicatorRef = useRef(null); const activeLinkRef = useRef(null); @@ -75,7 +73,7 @@ const StatelessSidebar = ({ useEffect(() => { if (!indicatorRef.current) return; const index = NavItems.findIndex((item) => item.to === activeLink); - const navItemCount = NavItems.length + (dashboard_url ? 2 : 1); // +2 for notification and dashboard + const navItemCount = NavItems.length + (careConfig.urls.dashboard ? 2 : 1); // +2 for notification and dashboard if (index !== -1) { // Haha math go brrrrrrrrr @@ -118,7 +116,7 @@ const StatelessSidebar = ({ className={`${ shrinked ? "mx-auto" : "ml-5" } mb-2 h-5 self-start transition md:mb-5 md:h-8`} - src={shrinked ? LOGO_COLLAPSE : main_logo.light} + src={shrinked ? LOGO_COLLAPSE : careConfig.mainLogo?.light} />
{/* flexible spacing */} @@ -151,10 +149,10 @@ const StatelessSidebar = ({ handleOverflow={handleOverflow} onClickCB={() => onItemClick && onItemClick(false)} /> - {dashboard_url && ( + {careConfig.urls.dashboard && ( } external handleOverflow={handleOverflow} diff --git a/src/Components/Common/components/Menu.tsx b/src/Components/Common/components/Menu.tsx index 166b55737ea..14dabfe9781 100644 --- a/src/Components/Common/components/Menu.tsx +++ b/src/Components/Common/components/Menu.tsx @@ -1,9 +1,9 @@ import { Anyone, AuthorizedElementProps } from "../../../Utils/AuthorizeFor"; - import { ButtonSize, ButtonVariant } from "./ButtonV2"; -import CareIcon from "../../../CAREUI/icons/CareIcon"; -import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; import { DetailedHTMLProps, HTMLAttributes, ReactNode } from "react"; +import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; + +import CareIcon from "../../../CAREUI/icons/CareIcon"; import { classNames } from "../../../Utils/utils"; import { useIsAuthorized } from "../../../Common/hooks/useIsAuthorized"; @@ -51,6 +51,7 @@ export default function DropdownMenu({ <>{props.children} diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx index 39f35a4fcf4..6bc309f5716 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -17,6 +17,8 @@ interface AddICD11DiagnosisProps { onAdd: (object: CreateDiagnosis) => Promise; disallowed: ICD11DiagnosisModel[]; disabled?: boolean; + prefill?: ICD11DiagnosisModel; + onSelect?: (selected: ICD11DiagnosisModel) => unknown; } export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { @@ -26,6 +28,7 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { const hasError = !!props.disallowed.find((d) => d?.id === selected?.id); const { res, data, loading, refetch } = useQuery(routes.listICD11Diagnosis, { + prefetch: false, silent: true, }); @@ -35,6 +38,8 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { } }, [res?.status]); + useEffect(() => props.prefill && setSelected(props.prefill), [props.prefill]); + const handleAdd = async (status: CreateDiagnosis["verification_status"]) => { if (!selected) return; @@ -63,7 +68,10 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { disabled={props.disabled || adding} placeholder={t("search_icd11_placeholder")} value={selected} - onChange={(e) => setSelected(e.value)} + onChange={(e) => { + setSelected(e.value); + props.onSelect?.(e.value); + }} options={mergeQueryOptions( selected ? [selected] : [], data ?? [], diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx index b6495143f5d..043654929a8 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx @@ -11,6 +11,7 @@ import request from "../../../Utils/request/request"; import DiagnosesRoutes from "../routes"; import * as Notification from "../../../Utils/Notifications"; import PrincipalDiagnosisSelect from "./PrincipalDiagnosisSelect"; +import CareIcon from "../../../CAREUI/icons/CareIcon"; interface CreateDiagnosesProps { className?: string; @@ -78,11 +79,14 @@ export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { interface EditDiagnosesProps { className?: string; value: ConsultationDiagnosis[]; + suggestions?: ICD11DiagnosisModel[]; + onUpdate?: (diagnoses: ConsultationDiagnosis[]) => void; } export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { const consultation = useSlug("consultation"); const [diagnoses, setDiagnoses] = useState(props.value); + const [prefill, setPrefill] = useState(); useEffect(() => { setDiagnoses(props.value); @@ -129,16 +133,34 @@ export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { if (res?.ok && data) { setDiagnoses([...diagnoses, data]); + setPrefill(undefined); + props.onUpdate?.(diagnoses); return true; } if (error) { Notification.Error({ msg: error }); } - return false; }} + prefill={prefill} + onSelect={() => setPrefill(undefined)} /> + {!!props.suggestions?.length && ( +
+ {props.suggestions?.map((suggestion, i) => ( + + ))} +
+ )}
diff --git a/src/Components/ExternalResult/ExternalResultImportModal.tsx b/src/Components/ExternalResult/ExternalResultImportModal.tsx index 06ba575b3f2..79df1cfdc09 100644 --- a/src/Components/ExternalResult/ExternalResultImportModal.tsx +++ b/src/Components/ExternalResult/ExternalResultImportModal.tsx @@ -1,13 +1,13 @@ import _ from "lodash-es"; import { navigate } from "raviger"; import { useEffect, useState, lazy } from "react"; -import useConfig from "../../Common/hooks/useConfig"; import * as Notification from "../../Utils/Notifications.js"; import request from "../../Utils/request/request"; import routes from "../../Redux/api"; import { ExternalResultImportSchema } from "../../Common/constants"; import DialogModal from "../Common/Dialog"; import { IExternalResult } from "./models"; +import careConfig from "@careConfig"; const ExcelFileDragAndDrop = lazy( () => import("../Common/ExcelFIleDragAndDrop"), ); @@ -18,7 +18,6 @@ interface Props { } export default function ExternalResultImportModal({ open, onClose }: Props) { - const { sample_format_external_result_import } = useConfig(); const [loading, setLoading] = useState(false); const fetchUser = async () => { @@ -105,7 +104,7 @@ export default function ExternalResultImportModal({ open, onClose }: Props) { onClose={onClose} handleSubmit={handleSubmit} loading={loading} - sampleLink={sample_format_external_result_import} + sampleLink={careConfig.sampleFormats.externalResultImport} schema={ExternalResultImportSchema} /> diff --git a/src/Components/Facility/BedCapacity.tsx b/src/Components/Facility/BedCapacity.tsx index c0f239203d5..a4437823d5d 100644 --- a/src/Components/Facility/BedCapacity.tsx +++ b/src/Components/Facility/BedCapacity.tsx @@ -1,15 +1,14 @@ import { useEffect, useReducer, useState } from "react"; import * as Notification from "../../Utils/Notifications.js"; -import { CapacityModal, OptionsType } from "./models"; +import { CapacityModal } from "./models"; import TextFormField from "../Form/FormFields/TextFormField"; import { Cancel, Submit } from "../Common/components/ButtonV2"; import { SelectFormField } from "../Form/FormFields/SelectFormField"; import { FieldChangeEvent } from "../Form/FormFields/Utils"; -import useConfig from "../../Common/hooks/useConfig"; -import { getBedTypes } from "../../Common/constants"; import routes from "../../Redux/api"; import request from "../../Utils/request/request"; import { useTranslation } from "react-i18next"; +import { BED_TYPES } from "../../Common/constants.js"; interface BedCapacityProps extends CapacityModal { facilityId: string; @@ -51,11 +50,10 @@ const bedCountReducer = (state = initialState, action: any) => { export const BedCapacity = (props: BedCapacityProps) => { const { t } = useTranslation(); - const config = useConfig(); const { facilityId, handleClose, handleUpdate, className, id } = props; const [state, dispatch] = useReducer(bedCountReducer, initialState); + const [bedTypes, setBedTypes] = useState(BED_TYPES); const [isLastOptionType, setIsLastOptionType] = useState(false); - const [bedTypes, setBedTypes] = useState(getBedTypes(config)); const [isLoading, setIsLoading] = useState(false); const headerText = !id ? "Add Bed Capacity" : "Edit Bed Capacity"; @@ -73,11 +71,11 @@ export const BedCapacity = (props: BedCapacityProps) => { if (capacityQuery?.data) { const existingData = capacityQuery.data?.results; // if all options are diabled - if (existingData.length === getBedTypes(config).length) { + if (existingData.length === BED_TYPES.length) { return; } // disable existing bed types - const updatedBedTypes = getBedTypes(config).map((type: OptionsType) => { + const updatedBedTypes = BED_TYPES.map((type) => { const isExisting = existingData.find( (i: CapacityModal) => i.room_type === type.id, ); @@ -113,8 +111,7 @@ export const BedCapacity = (props: BedCapacityProps) => { useEffect(() => { const lastBedType = - bedTypes.filter((i: OptionsType) => i.disabled).length === - getBedTypes(config).length - 1; + bedTypes.filter((i) => i.disabled).length === BED_TYPES.length - 1; setIsLastOptionType(lastBedType); }, [bedTypes]); @@ -179,7 +176,7 @@ export const BedCapacity = (props: BedCapacityProps) => { ); setIsLoading(false); if (data) { - const updatedBedTypes = bedTypes.map((type: OptionsType) => { + const updatedBedTypes = bedTypes.map((type) => { return { ...type, disabled: data.room_type !== type.id ? type.disabled : true, diff --git a/src/Components/Facility/ConsultationCard.tsx b/src/Components/Facility/ConsultationCard.tsx index 12f4bf0a1e3..23b9cb86567 100644 --- a/src/Components/Facility/ConsultationCard.tsx +++ b/src/Components/Facility/ConsultationCard.tsx @@ -4,12 +4,12 @@ import { formatDateTime } from "../../Utils/utils"; 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"; import * as Notification from "../../Utils/Notifications.js"; import { useState } from "react"; import DialogModal from "../Common/Dialog.js"; import Beds from "./Consultations/Beds"; +import careConfig from "@careConfig"; interface ConsultationProps { itemData: ConsultationModel; @@ -19,7 +19,6 @@ interface ConsultationProps { export const ConsultationCard = (props: ConsultationProps) => { const { itemData, isLastConsultation, refetch } = props; - const { kasp_string } = useConfig(); const [open, setOpen] = useState(false); const bedDialogTitle = itemData.discharge_date ? "Bed History" @@ -51,7 +50,7 @@ export const ConsultationCard = (props: ConsultationProps) => {
{itemData.is_kasp && (
- {kasp_string} + {careConfig.kasp.string}
)} @@ -85,7 +84,7 @@ export const ConsultationCard = (props: ConsultationProps) => {
- {kasp_string} Enabled date{" "} + {careConfig.kasp.string} Enabled date{" "}
{itemData.kasp_enabled_date diff --git a/src/Components/Facility/ConsultationDetails/ConsultationFeedTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationFeedTab.tsx index 08d2b314b82..2e999d1956e 100644 --- a/src/Components/Facility/ConsultationDetails/ConsultationFeedTab.tsx +++ b/src/Components/Facility/ConsultationDetails/ConsultationFeedTab.tsx @@ -21,6 +21,7 @@ import useBreakpoints from "../../../Common/hooks/useBreakpoints"; import { Warn } from "../../../Utils/Notifications"; import { useTranslation } from "react-i18next"; import { GetStatusResponse } from "../../CameraFeed/routes"; +import StillWatching from "../../CameraFeed/StillWatching"; export const ConsultationFeedTab = (props: ConsultationTabProps) => { const { t } = useTranslation(); @@ -148,7 +149,7 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { const cannotSaveToPreset = !hasMoved || !preset?.id; return ( - <> + {
- + ); }; diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 2a7bf3f3b67..2cfe9c8f4df 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -38,7 +38,6 @@ import { UserBareMinimum } from "../Users/models"; import { navigate } from "raviger"; import useAppHistory from "../../Common/hooks/useAppHistory"; -import useConfig from "../../Common/hooks/useConfig"; import useVisibility from "../../Utils/useVisibility"; import dayjs from "../../Utils/dayjs"; import RouteToFacilitySelect, { @@ -65,6 +64,7 @@ import { EncounterSymptomsBuilder, CreateSymptomsBuilder, } from "../Symptoms/SymptomsBuilder.js"; +import careConfig from "@careConfig"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -229,7 +229,6 @@ type Props = { export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { const { goBack } = useAppHistory(); - const { kasp_enabled, kasp_string } = useConfig(); const submitController = useRef(); const [state, dispatch] = useAutoSaveReducer( consultationFormReducer, @@ -255,8 +254,6 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { const [disabledFields, setDisabledFields] = useState([]); - const { min_encounter_date } = useConfig(); - const sections = { "Consultation Details": { iconClass: "l-medkit", @@ -474,11 +471,12 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { invalidForm = true; } if ( - min_encounter_date && - dayjs(state.form.encounter_date).isBefore(dayjs(min_encounter_date)) + dayjs(state.form.encounter_date).isBefore( + careConfig.minEncounterDate, + ) ) { errors[field] = - `Admission date cannot be before ${min_encounter_date}`; + `Admission date cannot be before ${careConfig.minEncounterDate}`; invalidForm = true; } return; @@ -552,7 +550,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { case "is_kasp": if (!state.form[field]) { errors[field] = - `Please select an option, ${kasp_string} is mandatory`; + `Please select an option, ${careConfig.kasp.string} is mandatory`; invalidForm = true; } return; @@ -1226,11 +1224,9 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { "YYYY-MM-DDTHH:mm", )} max={dayjs().format("YYYY-MM-DDTHH:mm")} - min={ - min_encounter_date - ? dayjs(min_encounter_date).format("YYYY-MM-DDTHH:mm") - : undefined - } + min={dayjs(careConfig.minEncounterDate).format( + "YYYY-MM-DDTHH:mm", + )} /> {dayjs().diff(state.form.encounter_date, "day") > 30 && (
@@ -1402,12 +1398,12 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { />
- {kasp_enabled && ( + {careConfig.kasp.enabled && ( )} diff --git a/src/Components/Facility/CoverImageEditModal.tsx b/src/Components/Facility/CoverImageEditModal.tsx index d521d55c7ce..bade873c5fa 100644 --- a/src/Components/Facility/CoverImageEditModal.tsx +++ b/src/Components/Facility/CoverImageEditModal.tsx @@ -20,6 +20,8 @@ import DialogModal from "../Common/Dialog"; import request from "../../Utils/request/request"; import routes from "../../Redux/api"; import uploadFile from "../../Utils/request/uploadFile"; +import careConfig from "@careConfig"; + interface Props { open: boolean; onClose: (() => void) | undefined; @@ -116,7 +118,7 @@ const CoverImageEditModal = ({ const formData = new FormData(); formData.append("cover_image", selectedFile); - const url = `/api/v1/facility/${facility.id}/cover_image/`; + const url = `${careConfig.apiUrl}/api/v1/facility/${facility.id}/cover_image/`; setIsProcessing(true); uploadFile( diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index fe99b4ddd53..ac86ff02c55 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -16,7 +16,6 @@ import { SelectFormField } from "../Form/FormFields/SelectFormField"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; import TextFormField from "../Form/FormFields/TextFormField"; import { dischargePatient } from "../../Redux/actions"; -import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import { useMessageListener } from "../../Common/hooks/useMessageListener"; import PrescriptionBuilder from "../Medicine/PrescriptionBuilder"; @@ -28,6 +27,7 @@ import { FieldError } from "../Form/FieldValidators"; import { useTranslation } from "react-i18next"; import useConfirmedAction from "../../Common/hooks/useConfirmedAction"; import ConfirmDialog from "../Common/ConfirmDialog"; +import careConfig from "@careConfig"; interface PreDischargeFormInterface { new_discharge_reason: number | null; @@ -61,7 +61,6 @@ const DischargeModal = ({ death_datetime = dayjs().format("YYYY-MM-DDTHH:mm"), }: IProps) => { const { t } = useTranslation(); - const { enable_hcx } = useConfig(); const dispatch: any = useDispatch(); const [preDischargeForm, setPreDischargeForm] = @@ -385,7 +384,7 @@ const DischargeModal = ({ )}
- {enable_hcx && ( + {careConfig.hcx.enabled && ( // TODO: if policy and approved pre-auth exists

Claim Insurance

diff --git a/src/Components/Facility/DischargedPatientsList.tsx b/src/Components/Facility/DischargedPatientsList.tsx index ca375fa505b..5a7d706ee87 100644 --- a/src/Components/Facility/DischargedPatientsList.tsx +++ b/src/Components/Facility/DischargedPatientsList.tsx @@ -402,10 +402,6 @@ const DischargedPatientsList = ({ badge("Declared Status", "is_declared_positive"), ...dateRange("Result", "date_of_result"), ...dateRange("Declared positive", "date_declared_positive"), - ...dateRange( - "Symptoms onset", - "last_consultation_symptoms_onset_date", - ), ...dateRange("Last vaccinated", "last_vaccinated_date"), { name: "Telemedicine", diff --git a/src/Components/Facility/FacilityBedCapacity.tsx b/src/Components/Facility/FacilityBedCapacity.tsx index e2a24b3fab3..77481fa8716 100644 --- a/src/Components/Facility/FacilityBedCapacity.tsx +++ b/src/Components/Facility/FacilityBedCapacity.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import { getBedTypes } from "../../Common/constants"; import routes from "../../Redux/api"; import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; import useQuery from "../../Utils/request/useQuery"; @@ -7,12 +6,11 @@ import DialogModal from "../Common/Dialog"; import ButtonV2 from "../Common/components/ButtonV2"; import { BedCapacity } from "./BedCapacity"; import BedTypeCard from "./BedTypeCard"; -import useConfig from "../../Common/hooks/useConfig"; import CareIcon from "../../CAREUI/icons/CareIcon"; +import { BED_TYPES } from "../../Common/constants"; export const FacilityBedCapacity = (props: any) => { const [bedCapacityModalOpen, setBedCapacityModalOpen] = useState(false); - const config = useConfig(); const capacityQuery = useQuery(routes.getCapacity, { pathParams: { facilityId: props.facilityId }, @@ -45,7 +43,7 @@ export const FacilityBedCapacity = (props: any) => { return; }} /> - {getBedTypes(config).map((x) => { + {BED_TYPES.map((x) => { const res = capacityQuery.data?.results.find((data) => { return data.room_type === x.id; }); diff --git a/src/Components/Facility/FacilityCard.tsx b/src/Components/Facility/FacilityCard.tsx index 858386b72e6..c7fbf728dc9 100644 --- a/src/Components/Facility/FacilityCard.tsx +++ b/src/Components/Facility/FacilityCard.tsx @@ -9,14 +9,13 @@ import CareIcon from "../../CAREUI/icons/CareIcon"; import { formatPhoneNumber, parsePhoneNumber } from "../../Utils/utils"; import DialogModal from "../Common/Dialog"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; -import useConfig from "../../Common/hooks/useConfig"; import { classNames } from "../../Utils/utils"; import request from "../../Utils/request/request"; import routes from "../../Redux/api"; +import careConfig from "@careConfig"; export const FacilityCard = (props: { facility: any; userType: any }) => { const { facility, userType } = props; - const { kasp_string } = useConfig(); const { t } = useTranslation(); const [notifyModalFor, setNotifyModalFor] = useState(undefined); @@ -92,7 +91,7 @@ export const FacilityCard = (props: { facility: any; userType: any }) => {
{facility.kasp_empanelled && (
- {kasp_string} + {careConfig.kasp.string}
)}
import("../Common/Loading")); @@ -143,7 +143,6 @@ const facilityCreateReducer = (state = initialState, action: FormAction) => { export const FacilityCreate = (props: FacilityProps) => { const { t } = useTranslation(); - const { gov_data_api_key, kasp_string, kasp_enabled } = useConfig(); const { facilityId } = props; const [state, dispatch] = useAutoSaveReducer( @@ -327,7 +326,10 @@ export const FacilityCreate = (props: FacilityProps) => { if (!validatePincode(e.value)) return; - const pincodeDetails = await getPincodeDetails(e.value, gov_data_api_key); + const pincodeDetails = await getPincodeDetails( + e.value, + careConfig.govDataApiKey, + ); if (!pincodeDetails) return; const matchedState = (stateData ? stateData.results : []).find((state) => { @@ -561,7 +563,7 @@ export const FacilityCreate = (props: FacilityProps) => { return; }} /> - {getBedTypes({ kasp_string, kasp_enabled }).map((x) => { + {BED_TYPES.map((x) => { const res = capacityData.find((data) => { return data.room_type === x.id; }); @@ -922,10 +924,10 @@ export const FacilityCreate = (props: FacilityProps) => { />
- {kasp_enabled && ( + {careConfig.kasp.enabled && ( (o ? "Yes" : "No")} optionValue={(o) => String(o)} diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx index 50edef824c8..a0dcf06026f 100644 --- a/src/Components/Facility/FacilityHome.tsx +++ b/src/Components/Facility/FacilityHome.tsx @@ -88,7 +88,7 @@ export const FacilityHome = ({ facilityId }: Props) => { onResponse: ({ res }) => { if (res?.ok) { Notification.Success({ - msg: "Facility deleted successfully", + msg: t("deleted_successfully", { name: facilityData?.name }), }); } navigate("/facility"); @@ -150,11 +150,10 @@ export const FacilityHome = ({ facilityId }: Props) => { backUrl="/facility" > - Are you sure you want to delete{" "} - {facilityData?.name} + {t("are_you_sure_want_to_delete", { name: facilityData?.name })} } action="Delete" @@ -247,7 +246,7 @@ export const FacilityHome = ({ facilityId }: Props) => {

- Address + {t("address")}

{facilityData?.address} @@ -257,7 +256,7 @@ export const FacilityHome = ({ facilityId }: Props) => {

- Local Body + {t("local_body")}

{facilityData?.local_body_object?.name} @@ -266,7 +265,7 @@ export const FacilityHome = ({ facilityId }: Props) => {

- Ward + {t("ward")}

{facilityData?.ward_object?.number + @@ -276,7 +275,7 @@ export const FacilityHome = ({ facilityId }: Props) => {

- District + {t("district")}

{facilityData?.district_object?.name} @@ -286,7 +285,7 @@ export const FacilityHome = ({ facilityId }: Props) => {

- Phone Number + {t("phone_number")}

{ {facilityData?.features?.some((feature) => FACILITY_FEATURE_TYPES.some((f) => f.id === feature), ) && ( -

Available features

+

+ {t("available_features")} +

)}
{ authorizeFor={NonReadOnlyUsers} icon={} > - Update Facility + {t("update_facility")} { authorizeFor={NonReadOnlyUsers} icon={} > - Configure Facility + {t("configure_facility")} navigate(`/facility/${facilityId}/inventory`)} icon={} > - Inventory Management + {t("inventory_management")} { } > - Location Management + {t("location_management")} { authorizeFor={NonReadOnlyUsers} icon={} > - Resource Request + {t("resource_request")} { authorizeFor={NonReadOnlyUsers} icon={} > - Create Asset + {t("create_asset")} navigate(`/assets?facility=${facilityId}`)} icon={} > - View Assets + {t("view_asset")} navigate(`/facility/${facilityId}/users`)} icon={} > - View Users + {t("view_users")} navigate(`/facility/${facilityId}/abdm`)} icon={} > - View ABDM Records + {t("view_abdm_records")} {hasPermissionToDeleteFacility ? ( { className="flex items-center gap-3" icon={} > - Delete Facility + {t("delete_facility")} ) : ( <> @@ -437,7 +438,7 @@ export const FacilityHome = ({ facilityId }: Props) => { onClick={() => navigate(`/facility/${facilityId}/cns`)} > - Central Nursing Station + {t("central_nursing_station")} {CameraFeedPermittedUserTypes.includes(authUser.user_type) && ( @@ -451,7 +452,7 @@ export const FacilityHome = ({ facilityId }: Props) => { authorizeFor={NonReadOnlyUsers} > - Add Details of a Patient + {t("add_details_of_patient")} { onClick={() => navigate(`/patients?facility=${facilityId}`)} > - View Patients + {t("view_patients")}
@@ -472,7 +473,7 @@ export const FacilityHome = ({ facilityId }: Props) => {
-

Oxygen Information

+

{t("oxygen_information")}

{ const facilityId = useSlug("facility"); const [location, setLocation] = useState(); + const { t } = useTranslation(); + return ( @@ -528,7 +531,7 @@ const LiveMonitoringButton = () => { id="facility-detailspage-livemonitoring" > - Live Monitoring + {t("live_monitoring")} @@ -545,7 +548,7 @@ const LiveMonitoringButton = () => {
- Choose a location + {t("choose_location")}
{ className="w-full" href={`/facility/${facilityId}/live-monitoring?location=${location}`} > - Open Live Monitoring + {t("open_live_monitoring")}
diff --git a/src/Components/Facility/FacilityUsers.tsx b/src/Components/Facility/FacilityUsers.tsx index 61231ed7d21..2572731f720 100644 --- a/src/Components/Facility/FacilityUsers.tsx +++ b/src/Components/Facility/FacilityUsers.tsx @@ -27,7 +27,6 @@ export default function FacilityUsers(props: any) { const [currentPage, setCurrentPage] = useState(1); const [expandFacilityList, setExpandFacilityList] = useState(false); const [selectedUser, setSelectedUser] = useState(null); - // eslint-disable-next-line @typescript-eslint/no-unused-vars const [offset, setOffset] = useState(0); const [linkFacility, setLinkFacility] = useState<{ @@ -103,7 +102,7 @@ export default function FacilityUsers(props: any) { onResponse: ({ res }) => { if (res?.status === 204) { Notification.Success({ - msg: "User deleted successfully", + msg: t("user_deleted_successfuly"), }); } }, @@ -152,7 +151,7 @@ export default function FacilityUsers(props: any) {
)}
- Last Online:{" "} + {t("last_online")}{" "} {user.last_login ? relativeTime(user.last_login) - : "Never"} + : t("never")}
@@ -189,7 +188,7 @@ export default function FacilityUsers(props: any) {
- Phone: + {t("phone_number")}
-

Linked Facilities

+

{t("linked_facilities")}

)} @@ -250,7 +249,7 @@ export default function FacilityUsers(props: any) { manageUsers = (
-
No Users Found
+
{t("no_users_found")}
); @@ -258,9 +257,8 @@ export default function FacilityUsers(props: any) { return ( {linkFacility.show && ( @@ -271,10 +269,10 @@ export default function FacilityUsers(props: any) { /> )} -
+
{facilityUserData && ( -
+
{manageUsers}
{userData.show && ( diff --git a/src/Components/Facility/LocationManagement.tsx b/src/Components/Facility/LocationManagement.tsx index abf4a056695..83bf335aff2 100644 --- a/src/Components/Facility/LocationManagement.tsx +++ b/src/Components/Facility/LocationManagement.tsx @@ -87,7 +87,7 @@ export default function LocationManagement({ facilityId }: Props) { id="add-new-location" href={`/facility/${facilityId}/location/add`} authorizeFor={NonReadOnlyUsers} - className="mr-8 hidden lg:block" + className="mr-4 hidden lg:block" > Add New Location diff --git a/src/Components/Facility/TreatmentSummary.tsx b/src/Components/Facility/TreatmentSummary.tsx index e75eec5b80a..e719e859a4b 100644 --- a/src/Components/Facility/TreatmentSummary.tsx +++ b/src/Components/Facility/TreatmentSummary.tsx @@ -4,16 +4,34 @@ import { formatDateTime, formatPatientAge, } from "../../Utils/utils"; -import useSlug from "../../Common/hooks/useSlug"; import useAppHistory from "../../Common/hooks/useAppHistory"; import routes from "../../Redux/api"; import useQuery from "../../Utils/request/useQuery"; import CareIcon from "../../CAREUI/icons/CareIcon"; +import { ConsultationModel } from "./models"; +import { useMemo } from "react"; +import { + ActiveConditionVerificationStatuses, + ConsultationDiagnosis, +} from "../Diagnosis/types"; +import PageHeadTitle from "../Common/PageHeadTitle"; +import { useTranslation } from "react-i18next"; +import { PatientModel } from "../Patient/models"; +import MedicineRoutes from "../Medicine/routes"; + +export interface ITreatmentSummaryProps { + consultationId: string; + patientId: string; + facilityId: string; +} -const TreatmentSummary = (props: any) => { - const { consultationId, patientId } = props; +export default function TreatmentSummary({ + consultationId, + patientId, + facilityId, +}: ITreatmentSummaryProps) { + const { t } = useTranslation(); const date = new Date(); - const facilityId = useSlug("facility"); const { goBack } = useAppHistory(); const url = `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`; @@ -22,11 +40,6 @@ const TreatmentSummary = (props: any) => { prefetch: patientId !== undefined, }); - const { data: investigations } = useQuery(routes.getInvestigation, { - pathParams: { consultation_external_id: consultationId }, - prefetch: consultationId !== undefined, - }); - const { data: consultationData } = useQuery(routes.getConsultation, { pathParams: { id: consultationId }, prefetch: consultationId !== undefined, @@ -34,16 +47,19 @@ const TreatmentSummary = (props: any) => { return (
+
@@ -52,290 +68,463 @@ const TreatmentSummary = (props: any) => { {consultationData?.facility_name ?? ""} -

INTERIM TREATMENT SUMMARY

+

+ {t("treatment_summary__heading")} +

{formatDate(date)}
-
-
-
- Name : {patientData?.name ?? ""} -
-
- Address : {patientData?.address ?? ""} -
-
- -
-
-
- Age :{" "} - {patientData ? formatPatientAge(patientData, true) : ""} -
-
- OP : {consultationData?.patient_no ?? ""} -
-
+
+ -
- {consultationData?.suggestion === "DC" ? ( - Date of domiciliary care commenced : - ) : ( - Date of admission : - )} - - {consultationData?.encounter_date - ? formatDateTime(consultationData.encounter_date) - : " --/--/----"} - -
-
+ -
-
- Gender : - {GENDER_TYPES.find((i) => i.id === patientData?.gender)?.text} -
+ -
- Contact person : - - {" "} - {patientData?.emergency_phone_number - ? patientData.emergency_phone_number - : " -"} - -
-
- -
- Comorbidities : -
- - - - - - - - - {patientData?.medical_history && - patientData.medical_history.length > 0 ? ( - patientData.medical_history.map( - (obj: any, index: number) => { - return ( - - - - - ); - }, - ) - ) : ( - - - - - )} - -
DiseaseDetails
- {obj["disease"]} - - {obj["details"] ? obj["details"] : "---"} -
- --- - - --- -
-
-
- -
- Diagnosis : -
-
- History of present illness : - {consultationData?.history_of_present_illness - ? consultationData.history_of_present_illness - : " ---"} -
- -
- Examination details and clinical conditions : - {consultationData?.examination_details - ? consultationData.examination_details - : " ---"} -
- -
- Physical Examination info : - {consultationData?.last_daily_round?.physical_examination_info - ? consultationData.last_daily_round - ?.physical_examination_info - : " ---"} -
-
-
- -
- General Instructions : - {patientData?.last_consultation?.consultation_notes ? ( -
- {patientData.last_consultation.consultation_notes} -
- ) : ( - " ---" - )} -
- -
- Relevant investigations : - -
- - - - - - - - - - - - - - {investigations && investigations.results.length > 0 ? ( - investigations.results.map( - (value: any, index: number) => { - return ( - - - - - - - - - ); - }, - ) - ) : ( - - - - - - - - - )} - -
- Date - - Name - - Result - - Ideal value - - values range - - unit -
- {formatDate( - value["session_object"][ - "session_created_date" - ], - )} - - {value["investigation_object"]["name"]} - - {value["notes"] || value["value"]} - - {value["investigation_object"]["ideal_value"] || - "-"} - - {value["investigation_object"]["min_value"]} -{" "} - {value["investigation_object"]["max_value"]} - - {value["investigation_object"]["unit"] || "-"} -
- --- - - --- - - --- - - --- - - --- - - --- -
-
-
- -
- Treatment : - {consultationData?.treatment_plan ? ( -

{consultationData.treatment_plan}

- ) : ( -

---

- )} - Treatment summary/Treament Plan : - -
- - - - - - - - - - - {consultationData?.last_daily_round ? ( - - - - - - ) : ( - - - - - - )} - -
DateSpo2 - Temperature -
- {formatDateTime( - consultationData.last_daily_round.modified_date, - )} - - {consultationData.last_daily_round.ventilator_spo2 || - "-"} - - {consultationData.last_daily_round.temperature || "-"} -
- --- - - --- - - --- -
-
-
+ + + + + + +
); -}; +} + +interface IBasicDetailsSection { + patientData?: PatientModel; + consultationData?: ConsultationModel; +} + +function BasicDetailsSection({ + patientData, + consultationData, +}: IBasicDetailsSection) { + const { t } = useTranslation(); + + return ( + <> +
+
+ {t("patient_registration__name")} : {patientData?.name ?? ""} +
+
+ {t("patient_registration__address")} :{" "} + {patientData?.address ?? ""} +
+
+ +
+
+
+ {t("patient_registration__age")} :{" "} + {patientData ? formatPatientAge(patientData, true) : ""} +
+
+ + {consultationData?.suggestion === "A" + ? t("patient_consultation__ip") + : t("patient_consultation__op")}{" "} + : + {" "} + {consultationData?.patient_no ?? ""} +
+
+ +
+ {consultationData?.suggestion === "DC" ? ( + {t("patient_consultation__dc_admission")} : + ) : ( + {t("patient_consultation__admission")} : + )}{" "} + + {consultationData?.encounter_date + ? formatDateTime(consultationData.encounter_date) + : t("empty_date_time")} + +
+
+ +
+
+ {t("patient_registration__gender")} :{" "} + {GENDER_TYPES.find((i) => i.id === patientData?.gender)?.text} +
+ +
+ {t("patient_registration__contact")} :{" "} + {patientData?.emergency_phone_number ?? ""} +
+
+ + ); +} + +interface IComorbiditiesSection { + patientData?: PatientModel; +} + +function ComorbiditiesSection({ patientData }: IComorbiditiesSection) { + const { t } = useTranslation(); + + return patientData?.medical_history?.filter( + (comorbidities) => comorbidities.disease !== "NO", + ).length ? ( +
+ {t("patient_registration__comorbidities")} +
+ + + + + + + + + {patientData.medical_history.map((obj, index) => { + return ( + + + + + ); + })} + +
+ {t("patient_registration__comorbidities__disease")} + + {t("patient_registration__comorbidities__details")} +
+ {obj["disease"]} + + {obj["details"] || "---"} +
+
+
+ ) : null; +} + +interface IDiagnosisSection { + consultationData?: ConsultationModel; +} + +type DiagnosisType = + | (typeof ActiveConditionVerificationStatuses)[number] + | "principal"; + +function DiagnosisSection({ consultationData }: IDiagnosisSection) { + const { t } = useTranslation(); + + const diagnoses = useMemo(() => { + return consultationData?.diagnoses?.reduce( + (acc, curr) => { + if (curr.is_principal) { + acc.principal.push(curr); + } else if ( + ActiveConditionVerificationStatuses.includes( + curr.verification_status as (typeof ActiveConditionVerificationStatuses)[number], + ) + ) { + acc[curr.verification_status as keyof typeof acc].push(curr); + } + + return acc; + }, + { + principal: [], + confirmed: [], + provisional: [], + unconfirmed: [], + differential: [], + } as Record, + ); + }, [consultationData?.diagnoses]); + + if (!diagnoses) { + return null; + } + + return ( +
+ {t("diagnosis")} +
+ {( + [ + "principal", + "confirmed", + "provisional", + "unconfirmed", + "differential", + ] as DiagnosisType[] + ).map( + (type) => + !!diagnoses[type].length && ( +
+ + {t(`diagnosis__${type}`)} {t("diagnosis")} + +
    + {diagnoses[type].map((d) => ( +
  1. + {d.diagnosis_object.label} + {d.is_principal && ( + + {t(`diagnosis__${d.verification_status}`)} + + )} +
  2. + ))} +
+
+ ), + )} +
+
+ ); +} + +interface IInvestigationsSection { + consultationId: string; +} + +function InvestigationsSection({ consultationId }: IInvestigationsSection) { + const { t } = useTranslation(); + + const { data: investigations } = useQuery(routes.getInvestigation, { + pathParams: { consultation_external_id: consultationId }, + prefetch: consultationId !== undefined, + }); + + return investigations?.results.length ? ( +
+ {t("suggested_investigations")} + +
+ + + + + + + + + + + + + + {investigations?.results.map((value, index) => ( + + + + + + + + + ))} + +
+ {t("investigations__date")} + + {t("investigations__name")} + + {t("investigations__result")} + + {t("investigations__ideal_value")} + + {t("investigations__range")} + + {t("investigations__unit")} +
+ {formatDate(value["session_object"]["session_created_date"])} + + {value["investigation_object"]["name"]} + + {value["notes"] || value["value"]} + + {value["investigation_object"]["ideal_value"] || "-"} + + {value["investigation_object"]["min_value"]} -{" "} + {value["investigation_object"]["max_value"]} + + {value["investigation_object"]["unit"] || "-"} +
+
+
+ ) : null; +} + +interface ITreatmentSection { + consultationData?: ConsultationModel; +} + +function TreatmentSection({ consultationData }: ITreatmentSection) { + const { t } = useTranslation(); + + const isTreatmentSummaryAvailable = useMemo(() => { + return ( + consultationData?.last_daily_round && + (consultationData.last_daily_round.ventilator_spo2 || + consultationData.last_daily_round.temperature) + ); + }, [consultationData]); -export default TreatmentSummary; + return consultationData?.treatment_plan || isTreatmentSummaryAvailable ? ( +
+ {consultationData?.treatment_plan && ( + <> + {t("patient_consultation__treatment__plan")} +

{consultationData.treatment_plan}

+ + )} + + {isTreatmentSummaryAvailable && ( + <> + + {t("patient_consultation__treatment__summary")} + +
+ + + + + + + + + + + + + + + + +
+ {t("patient_consultation__treatment__summary__date")} + + {t("patient_consultation__treatment__summary__spo2")} + + {t("patient_consultation__treatment__summary__temperature")} +
+ {formatDateTime( + consultationData?.last_daily_round?.modified_date, + )} + + {consultationData?.last_daily_round?.ventilator_spo2 || "-"} + + {consultationData?.last_daily_round?.temperature || "-"} +
+
+ + )} +
+ ) : null; +} + +interface IPrescriptionsSection { + consultationId: string; +} + +function PrescriptionsSection({ consultationId }: IPrescriptionsSection) { + const { t } = useTranslation(); + + const { data: prescriptions } = useQuery(MedicineRoutes.listPrescriptions, { + pathParams: { consultation: consultationId }, + query: { discontinued: false }, + }); + + return prescriptions?.results.length ? ( +
+ {t("active_prescriptions")} + +
+ + + + + + + + + + + + {prescriptions?.results.map((prescription, index) => ( + + + + + + + ))} + +
+ {t("prescriptions__medicine")} + + {t("prescriptions__route")} + + {t("prescriptions__dosage_frequency")} + + {t("prescriptions__start_date")} +
+ {prescription.medicine_object?.name ?? "-"} + + {prescription.route ?? "-"} + + {prescription.dosage_type !== "TITRATED" ? ( +

{prescription.base_dosage}

+ ) : ( +

+ {prescription.base_dosage} - {prescription.target_dosage} +

+ )} + +

+ {prescription.dosage_type !== "PRN" + ? t("PRESCRIPTION_FREQUENCY_" + prescription.frequency) + : prescription.indicator} +

+
+ {formatDate(prescription.created_date)} +
+
+
+ ) : null; +} + +interface IInstructionsSection { + consultationData?: ConsultationModel; +} + +function InstructionsSection({ consultationData }: IInstructionsSection) { + const { t } = useTranslation(); + + return ( + <> + {consultationData?.consultation_notes && ( +
+ {t("patient_consultation__consultation_notes")} + +
{consultationData.consultation_notes}
+
+ )} + + {consultationData?.special_instruction && ( +
+ {t("patient_consultation__special_instruction")} + +
{consultationData.special_instruction}
+
+ )} + + ); +} diff --git a/src/Components/Form/AutoCompleteAsync.tsx b/src/Components/Form/AutoCompleteAsync.tsx index 9b4c1f876e4..1cd07a93df1 100644 --- a/src/Components/Form/AutoCompleteAsync.tsx +++ b/src/Components/Form/AutoCompleteAsync.tsx @@ -1,4 +1,3 @@ -import { useEffect, useState, useMemo } from "react"; import { Combobox, ComboboxButton, @@ -6,15 +5,17 @@ import { ComboboxOption, ComboboxOptions, } from "@headlessui/react"; -import { debounce } from "lodash-es"; -import { DropdownTransition } from "../Common/components/HelperComponents"; -import CareIcon from "../../CAREUI/icons/CareIcon"; import { MultiSelectOptionChip, dropdownOptionClassNames, } from "./MultiSelectMenuV2"; -import { useTranslation } from "react-i18next"; +import { useEffect, useMemo, useState } from "react"; + +import CareIcon from "../../CAREUI/icons/CareIcon"; +import { DropdownTransition } from "../Common/components/HelperComponents"; import { classNames } from "../../Utils/utils"; +import { debounce } from "lodash-es"; +import { useTranslation } from "react-i18next"; interface Props { id?: string; @@ -153,6 +154,7 @@ const AutoCompleteAsync = (props: Props) => {
diff --git a/src/Components/Form/FormFields/Autocomplete.tsx b/src/Components/Form/FormFields/Autocomplete.tsx index 7802a296201..2addbfa9b33 100644 --- a/src/Components/Form/FormFields/Autocomplete.tsx +++ b/src/Components/Form/FormFields/Autocomplete.tsx @@ -1,4 +1,3 @@ -import { useEffect, useState } from "react"; import { Combobox, ComboboxButton, @@ -6,12 +5,14 @@ import { ComboboxOption, ComboboxOptions, } from "@headlessui/react"; -import { DropdownTransition } from "../../Common/components/HelperComponents"; -import CareIcon from "../../../CAREUI/icons/CareIcon"; -import { dropdownOptionClassNames } from "../MultiSelectMenuV2"; import { FormFieldBaseProps, useFormFieldPropsResolver } from "./Utils"; +import { useEffect, useState } from "react"; + +import CareIcon from "../../../CAREUI/icons/CareIcon"; +import { DropdownTransition } from "../../Common/components/HelperComponents"; import FormField from "./FormField"; import { classNames } from "../../../Utils/utils"; +import { dropdownOptionClassNames } from "../MultiSelectMenuV2"; import { useTranslation } from "react-i18next"; type OptionCallback = (option: T) => R; @@ -209,6 +210,7 @@ export const Autocomplete = (props: AutocompleteProps) => { diff --git a/src/Components/Form/FormFields/AutocompleteMultiselect.tsx b/src/Components/Form/FormFields/AutocompleteMultiselect.tsx index 7fea2d4c6e7..4e9386afeba 100644 --- a/src/Components/Form/FormFields/AutocompleteMultiselect.tsx +++ b/src/Components/Form/FormFields/AutocompleteMultiselect.tsx @@ -1,10 +1,3 @@ -import { FormFieldBaseProps, useFormFieldPropsResolver } from "./Utils"; -import { - MultiSelectOptionChip, - dropdownOptionClassNames, -} from "../MultiSelectMenuV2"; -import { ReactNode, useEffect, useRef, useState } from "react"; -import CareIcon from "../../../CAREUI/icons/CareIcon"; import { Combobox, ComboboxButton, @@ -12,6 +5,14 @@ import { ComboboxOption, ComboboxOptions, } from "@headlessui/react"; +import { FormFieldBaseProps, useFormFieldPropsResolver } from "./Utils"; +import { + MultiSelectOptionChip, + dropdownOptionClassNames, +} from "../MultiSelectMenuV2"; +import { ReactNode, useEffect, useRef, useState } from "react"; + +import CareIcon from "../../../CAREUI/icons/CareIcon"; import { DropdownTransition } from "../../Common/components/HelperComponents"; import FormField from "./FormField"; import { classNames } from "../../../Utils/utils"; @@ -26,6 +27,7 @@ type AutocompleteMultiSelectFormFieldProps = FormFieldBaseProps & { optionDisabled?: OptionCallback; onQuery?: (query: string) => void; dropdownIcon?: React.ReactNode | undefined; + minQueryLength?: number; isLoading?: boolean; selectAll?: boolean; }; @@ -64,6 +66,7 @@ type AutocompleteMutliSelectProps = { isLoading?: boolean; selectAll?: boolean; error?: string; + minQueryLength?: number; }; /** @@ -80,7 +83,9 @@ export const AutocompleteMutliSelect = ( const [query, setQuery] = useState(""); // Ensure lower case const comboButtonRef = useRef(null); useEffect(() => { - props.onQuery && props.onQuery(query); + query.length >= (props.minQueryLength || 1) && + props.onQuery && + props.onQuery(query); }, [query]); const handleSingleSelect = (o: any) => { if (o.option?.isSingleSelect === true && comboButtonRef.current) { @@ -172,10 +177,15 @@ export const AutocompleteMutliSelect = ( - {props.isLoading ? ( + {props.minQueryLength && query.length < props.minQueryLength ? ( +
+ {`Please enter at least ${props.minQueryLength} characters to search`} +
+ ) : props.isLoading ? ( ) : filteredOptions.length ? ( <> diff --git a/src/Components/Form/MultiSelectMenuV2.tsx b/src/Components/Form/MultiSelectMenuV2.tsx index e728260e142..d3a46cdb1f9 100644 --- a/src/Components/Form/MultiSelectMenuV2.tsx +++ b/src/Components/Form/MultiSelectMenuV2.tsx @@ -1,4 +1,3 @@ -import CareIcon from "../../CAREUI/icons/CareIcon"; import { Label, Listbox, @@ -6,9 +5,11 @@ import { ListboxOption, ListboxOptions, } from "@headlessui/react"; -import { classNames } from "../../Utils/utils"; import { ReactNode, useRef } from "react"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import { classNames } from "../../Utils/utils"; + type OptionCallback = (option: T) => R; type Props = { @@ -135,6 +136,7 @@ const MultiSelectMenuV2 = (props: Props) => {
diff --git a/src/Components/Form/SelectMenuV2.tsx b/src/Components/Form/SelectMenuV2.tsx index 379eb7b7315..cea890b7330 100644 --- a/src/Components/Form/SelectMenuV2.tsx +++ b/src/Components/Form/SelectMenuV2.tsx @@ -5,10 +5,11 @@ import { ListboxOption, ListboxOptions, } from "@headlessui/react"; + import CareIcon from "../../CAREUI/icons/CareIcon"; -import { dropdownOptionClassNames } from "./MultiSelectMenuV2"; -import { classNames } from "../../Utils/utils"; import { ReactNode } from "react"; +import { classNames } from "../../Utils/utils"; +import { dropdownOptionClassNames } from "./MultiSelectMenuV2"; type OptionCallback = (option: T) => R; @@ -131,7 +132,11 @@ const SelectMenuV2 = (props: SelectMenuProps) => { props.position === "above" ? "bottom-0 mb-12" : "top-0 mt-12", )} > - + {options.map((option, index) => ( & { gridView?: boolean }; @@ -93,7 +93,6 @@ const InsuranceDetailEditCard = ({ handleRemove: () => void; gridView?: boolean; }) => { - const { enable_hcx } = useConfig(); const seletedInsurer = policy.insurer_id && policy.insurer_name ? { code: policy.insurer_id, name: policy.insurer_name } @@ -133,7 +132,7 @@ const InsuranceDetailEditCard = ({ value={policy.policy_id} onChange={handleUpdate} /> - {enable_hcx ? ( + {careConfig.hcx.enabled ? ( + +

Pain Scale

diff --git a/src/Components/LogUpdate/Sections/Vitals.tsx b/src/Components/LogUpdate/Sections/Vitals.tsx index 796575e4145..1fa4b3f3aac 100644 --- a/src/Components/LogUpdate/Sections/Vitals.tsx +++ b/src/Components/LogUpdate/Sections/Vitals.tsx @@ -1,3 +1,4 @@ +import { useTranslation } from "react-i18next"; import { celsiusToFahrenheit, fahrenheitToCelsius, @@ -10,11 +11,12 @@ import RadioFormField from "../../Form/FormFields/RadioFormField"; import RangeFormField from "../../Form/FormFields/RangeFormField"; import TextAreaFormField from "../../Form/FormFields/TextAreaFormField"; import { FieldChangeEvent } from "../../Form/FormFields/Utils"; -import { DailyRoundsModel } from "../../Patient/models"; import PainChart from "../components/PainChart"; import { LogUpdateSectionMeta, LogUpdateSectionProps } from "../utils"; +import { HEARTBEAT_RHYTHM_CHOICES } from "../../../Common/constants"; const Vitals = ({ log, onChange }: LogUpdateSectionProps) => { + const { t } = useTranslation(); const handleBloodPressureChange = (event: FieldChangeEvent) => { const bp = { ...(log.bp ?? {}), @@ -27,11 +29,14 @@ const Vitals = ({ log, onChange }: LogUpdateSectionProps) => { return (
-

Blood Pressure

- MAP: {(log.bp?.mean && properRoundOf(log.bp.mean)) || "--"} +

{t("blood_pressure")}

+ + {t("map_acronym")}:{" "} + {(log.bp?.mean && properRoundOf(log.bp.mean)) || "--"} +
{ valueDescriptions={rangeValueDescription({ low: 99, high: 139 })} /> { />
- SpO2 - - } + label={t("spo2")} name="ventilator_spo2" //TODO: ensure whether this should be ventilator_spo2 itself or spo2 onChange={(c) => onChange({ ventilator_spo2: c.value })} value={log.ventilator_spo2} @@ -69,7 +70,7 @@ const Vitals = ({ log, onChange }: LogUpdateSectionProps) => { valueDescriptions={rangeValueDescription({ low: 89 })} /> onChange({ temperature: c.value })} value={log.temperature} @@ -87,7 +88,7 @@ const Vitals = ({ log, onChange }: LogUpdateSectionProps) => { ]} /> onChange({ resp: c.value })} value={log.resp} @@ -99,9 +100,9 @@ const Vitals = ({ log, onChange }: LogUpdateSectionProps) => { />
-

Pain

+

{t("pain")}

- Mark region and intensity of pain + {t("pain_chart_description")}
{ />
onChange({ pulse: c.value })} value={log.pulse} @@ -122,36 +123,30 @@ const Vitals = ({ log, onChange }: LogUpdateSectionProps) => { { till: 40, className: "text-red-500", - text: "Bradycardia", + text: t("bradycardia"), }, { till: 100, className: "text-green-500", - text: "Normal", + text: t("normal"), }, { className: "text-red-500", - text: "Tachycardia", + text: t("tachycardia"), }, ]} /> c.label} - optionValue={(c) => c.value || ""} + options={HEARTBEAT_RHYTHM_CHOICES} + optionDisplay={(c) => t(`HEARTBEAT_RHYTHM__${c}`)} + optionValue={(c) => c} value={log.rhythm} - onChange={(c) => - onChange({ rhythm: c.value as DailyRoundsModel["rhythm"] }) - } + onChange={(c) => onChange({ rhythm: c.value ?? undefined })} /> onChange({ rhythm_detail: c.value })} diff --git a/src/Components/Medicine/PrintPreview.tsx b/src/Components/Medicine/PrintPreview.tsx index 05763e00f79..a5b78b5a3ec 100644 --- a/src/Components/Medicine/PrintPreview.tsx +++ b/src/Components/Medicine/PrintPreview.tsx @@ -12,11 +12,10 @@ import { } from "../../Utils/utils"; import MedicineRoutes from "./routes"; import { Prescription } from "./models"; -import useConfig from "../../Common/hooks/useConfig"; import { ReactNode } from "react"; +import careConfig from "@careConfig"; export default function PrescriptionsPrintPreview() { - const { main_logo } = useConfig(); const { t } = useTranslation(); const [patientId, consultationId] = useSlugs("patient", "consultation"); @@ -49,7 +48,11 @@ export default function PrescriptionsPrintPreview() { >

{encounter?.facility_name}

- care logo + care logo
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx index 8c09db3f8c2..0f0c7396f5e 100644 --- a/src/Components/Patient/DailyRounds.tsx +++ b/src/Components/Patient/DailyRounds.tsx @@ -46,9 +46,8 @@ import { FieldLabel } from "../Form/FormFields/FormField"; import useAuthUser from "../../Common/hooks/useAuthUser"; import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField"; import SymptomsApi from "../Symptoms/api"; -import DiagnosesRoutes from "../Diagnosis/routes"; -import MedicineRoutes from "../Medicine/routes"; import { scrollTo } from "../../Utils/utils"; +import { ICD11DiagnosisModel } from "../Facility/models"; const Loading = lazy(() => import("../Common/Loading")); @@ -58,7 +57,9 @@ export const DailyRounds = (props: any) => { const { goBack } = useAppHistory(); const { facilityId, patientId, consultationId, id } = props; const [symptomsSeed, setSymptomsSeed] = useState(1); - const [prescriptionSeed, setPrescriptionSeed] = useState(1); + const [diagnosisSuggestions, setDiagnosisSuggestions] = useState< + ICD11DiagnosisModel[] + >([]); const initForm: any = { physical_examination_info: "", @@ -489,6 +490,7 @@ export const DailyRounds = (props: any) => { { + setDiagnosisSuggestions([]); // Symptoms let rounds_type = fields.rounds_type || state.form.rounds_type; if (fields.additional_symptoms) { @@ -522,74 +524,10 @@ export const DailyRounds = (props: any) => { continue; } - const availableDiagnosis = icdData?.[0]?.id; + const availableDiagnosis = icdData?.slice(0, 5); - if (!availableDiagnosis) { - error({ - text: "Could not find the requested diagnosis. Please enter manually.", - }); - continue; - } - - const { res, data } = await request( - DiagnosesRoutes.createConsultationDiagnosis, - { - pathParams: { consultation: consultationId }, - body: { - ...diagnosis, - diagnosis: availableDiagnosis, - }, - }, - ); - - if (res?.ok && data) - setDiagnoses((diagnoses) => [...(diagnoses || []), data]); - } - } - - // Prescriptions - if (fields.prescriptions || fields.prn_prescriptions) { - const combined_prescriptions = [ - ...(fields.prescriptions || []), - ...(fields.prn_prescriptions || []), - ]; - for (const prescription of combined_prescriptions) { - // fetch medicine - const { res: medicineRes, data: medicineData } = await request( - routes.listMedibaseMedicines, - { - query: { query: prescription.medicine }, - }, - ); - - if (!medicineRes?.ok) { - error({ - text: "Failed to fetch medicine", - }); - continue; - } - - const availableMedicine = medicineData?.[0]?.id; - - if (!availableMedicine) { - error({ - text: "Could not find the requested medicine. Please enter manually.", - }); - continue; - } - - const { res } = await request( - MedicineRoutes.createPrescription, - { - pathParams: { consultation: consultationId }, - body: { - ...prescription, - medicine: availableMedicine, - }, - }, - ); - - if (res?.ok) setPrescriptionSeed((s) => s + 1); + if (availableDiagnosis?.length) + setDiagnosisSuggestions(availableDiagnosis); } } @@ -598,8 +536,7 @@ export const DailyRounds = (props: any) => { [ "investigations", "icd11_diagnosis", - "prescriptions", - "prn_prescriptions", + "additional_symptoms", ].includes(f), ) && roundTypes.some((t) => t.id === "DOCTORS_LOG") @@ -844,20 +781,23 @@ export const DailyRounds = (props: any) => { {state.form.rounds_type === "DOCTORS_LOG" && ( <>
-
+

{t("diagnosis")}

- {/* */} {diagnoses ? ( - + setDiagnosisSuggestions([])} + /> ) : (
Fetching existing diagnosis of patient...
)}
-
+

{t("investigations")}

@@ -891,7 +831,6 @@ export const DailyRounds = (props: any) => { discontinued={ showDiscontinuedPrescriptions ? undefined : false } - key={prescriptionSeed} actions={["discontinue"]} />
@@ -916,7 +855,6 @@ export const DailyRounds = (props: any) => { showDiscontinuedPrescriptions ? undefined : false } actions={["discontinue"]} - key={prescriptionSeed} />
diff --git a/src/Components/Patient/DiagnosesFilter.tsx b/src/Components/Patient/DiagnosesFilter.tsx index c4c4872fdda..1217e821389 100644 --- a/src/Components/Patient/DiagnosesFilter.tsx +++ b/src/Components/Patient/DiagnosesFilter.tsx @@ -37,6 +37,7 @@ export default function DiagnosesFilter(props: Props) { const [diagnoses, setDiagnoses] = useState([]); const { res, data, loading, refetch } = useQuery(routes.listICD11Diagnosis, { silent: true, + prefetch: false, }); useEffect(() => { @@ -72,6 +73,7 @@ export default function DiagnosesFilter(props: Props) { name="icd11_search" className="w-full" placeholder={t("search_icd11_placeholder")} + minQueryLength={2} value={diagnoses} onChange={(e) => { setDiagnoses(e.value); diff --git a/src/Components/Patient/ManagePatients.tsx b/src/Components/Patient/ManagePatients.tsx index ab570dd57b6..944a5163c96 100644 --- a/src/Components/Patient/ManagePatients.tsx +++ b/src/Components/Patient/ManagePatients.tsx @@ -206,10 +206,6 @@ export const PatientManager = () => { covin_id: qParams.covin_id || undefined, is_kasp: qParams.is_kasp || undefined, is_declared_positive: qParams.is_declared_positive || undefined, - last_consultation_symptoms_onset_date_before: - qParams.last_consultation_symptoms_onset_date_before || undefined, - last_consultation_symptoms_onset_date_after: - qParams.last_consultation_symptoms_onset_date_after || undefined, last_vaccinated_date_before: qParams.last_vaccinated_date_before || undefined, last_vaccinated_date_after: qParams.last_vaccinated_date_after || undefined, @@ -262,10 +258,6 @@ export const PatientManager = () => { params.last_consultation_discharge_date_before, params.last_consultation_discharge_date_after, ], - [ - params.last_consultation_symptoms_onset_date_before, - params.last_consultation_symptoms_onset_date_after, - ], ]; const durations = date_range_fields.map((field: string[]) => { @@ -854,7 +846,7 @@ export const PatientManager = () => { { text: t("discharged"), value: 1 }, ]} onTabChange={(tab) => { - if (tab === "LIVE") { + if (tab === 0) { updateQuery({ is_active: "True" }); } else { const id = qParams.facility || onlyAccessibleFacility?.id; @@ -1125,10 +1117,6 @@ export const PatientManager = () => { ), badge("Declared Status", "is_declared_positive"), ...dateRange("Declared positive", "date_declared_positive"), - ...dateRange( - "Symptoms onset", - "last_consultation_symptoms_onset_date", - ), ...dateRange("Last vaccinated", "last_vaccinated_date"), { name: "Telemedicine", diff --git a/src/Components/Patient/PatientFilter.tsx b/src/Components/Patient/PatientFilter.tsx index b69436171d8..773a3f333b7 100644 --- a/src/Components/Patient/PatientFilter.tsx +++ b/src/Components/Patient/PatientFilter.tsx @@ -10,7 +10,6 @@ import { PATIENT_FILTER_CATEGORIES, RATION_CARD_CATEGORY, } from "../../Common/constants"; -import useConfig from "../../Common/hooks/useConfig"; import useMergeState from "../../Common/hooks/useMergeState"; import { dateQueryString } from "../../Utils/utils"; import { DateRange } from "../Common/DateRangeInputV2"; @@ -35,6 +34,7 @@ import request from "../../Utils/request/request"; import useAuthUser from "../../Common/hooks/useAuthUser"; import { SelectFormField } from "../Form/FormFields/SelectFormField"; import { useTranslation } from "react-i18next"; +import careConfig from "@careConfig"; const getDate = (value: any) => value && dayjs(value).isValid() && dayjs(value).toDate(); @@ -42,7 +42,6 @@ const getDate = (value: any) => export default function PatientFilter(props: any) { const { t } = useTranslation(); const authUser = useAuthUser(); - const { kasp_enabled, kasp_string } = useConfig(); const { filter, onChange, closeFilter, removeFilters } = props; const [filterState, setFilterState] = useMergeState({ @@ -88,10 +87,6 @@ export default function PatientFilter(props: any) { covin_id: filter.covin_id || null, is_kasp: filter.is_kasp || null, is_declared_positive: filter.is_declared_positive || null, - last_consultation_symptoms_onset_date_before: - filter.last_consultation_symptoms_onset_date_before || null, - last_consultation_symptoms_onset_date_after: - filter.last_consultation_symptoms_onset_date_after || null, last_vaccinated_date_before: filter.last_vaccinated_date_before || null, last_vaccinated_date_after: filter.last_vaccinated_date_after || null, last_consultation_is_telemedicine: @@ -192,8 +187,6 @@ export default function PatientFilter(props: any) { covin_id, is_kasp, is_declared_positive, - last_consultation_symptoms_onset_date_before, - last_consultation_symptoms_onset_date_after, last_vaccinated_date_before, last_vaccinated_date_after, last_consultation_is_telemedicine, @@ -251,12 +244,6 @@ export default function PatientFilter(props: any) { covin_id: covin_id || "", is_kasp: is_kasp || "", is_declared_positive: is_declared_positive || "", - last_consultation_symptoms_onset_date_before: dateQueryString( - last_consultation_symptoms_onset_date_before, - ), - last_consultation_symptoms_onset_date_after: dateQueryString( - last_consultation_symptoms_onset_date_after, - ), last_vaccinated_date_before: dateQueryString(last_vaccinated_date_before), last_vaccinated_date_after: dateQueryString(last_vaccinated_date_after), last_consultation_is_telemedicine: @@ -591,21 +578,6 @@ export default function PatientFilter(props: any) { onChange={handleDateRangeChange} errorClassName="hidden" /> -
- {kasp_enabled && ( + {careConfig.kasp.enabled && (
- {kasp_string} + + {careConfig.kasp.string} + - o ? `Show ${kasp_string}` : `Show Non ${kasp_string}` + o + ? `Show ${careConfig.kasp.string}` + : `Show Non ${careConfig.kasp.string}` } value={filterState.is_kasp} onChange={(v) => setFilterState({ ...filterState, is_kasp: v })} diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index 005c93521d6..f301db6333e 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -12,7 +12,6 @@ import { Switch, MenuItem, Field, Label } from "@headlessui/react"; import { Link, navigate } from "raviger"; import { useState } from "react"; import CareIcon from "../../CAREUI/icons/CareIcon.js"; -import useConfig from "../../Common/hooks/useConfig.js"; import dayjs from "../../Utils/dayjs.js"; import { classNames, @@ -43,6 +42,7 @@ import useQuery from "../../Utils/request/useQuery.js"; import FetchRecordsModal from "../ABDM/FetchRecordsModal.js"; import { SkillModel } from "../Users/models.js"; import { AuthorizedForConsultationRelatedActions } from "../../CAREUI/misc/AuthorizedChild.js"; +import careConfig from "@careConfig"; const formatSkills = (arr: SkillModel[]) => { const skills = arr.map((skill) => skill.skill_object.name); @@ -73,8 +73,6 @@ export default function PatientInfoCard(props: { const [openDischargeSummaryDialog, setOpenDischargeSummaryDialog] = useState(false); const [openDischargeDialog, setOpenDischargeDialog] = useState(false); - - const { enable_hcx, enable_abdm } = useConfig(); const [showLinkCareContext, setShowLinkCareContext] = useState(false); const patient = props.patient; @@ -665,7 +663,7 @@ export default function PatientInfoCard(props: { ], ] .concat( - enable_hcx + careConfig.hcx.enabled ? [ [ `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/claims`, @@ -735,7 +733,7 @@ export default function PatientInfoCard(props: {
- {enable_abdm && + {careConfig.abdm.enabled && (patient.abha_number ? ( <> diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx index 3b38c3d54af..c25a6365e70 100644 --- a/src/Components/Patient/PatientRegister.tsx +++ b/src/Components/Patient/PatientRegister.tsx @@ -61,7 +61,6 @@ import countryList from "../../Common/static/countries.json"; import { debounce } from "lodash-es"; import useAppHistory from "../../Common/hooks/useAppHistory"; -import useConfig from "../../Common/hooks/useConfig"; import { validatePincode } from "../../Common/validation"; import { FormContextValue } from "../Form/FormContext.js"; import useAuthUser from "../../Common/hooks/useAuthUser.js"; @@ -73,6 +72,7 @@ import SelectMenuV2 from "../Form/SelectMenuV2.js"; import _ from "lodash"; import { ILocalBodies } from "../ExternalResult/models.js"; import { useTranslation } from "react-i18next"; +import careConfig from "@careConfig"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -181,7 +181,6 @@ export const PatientRegister = (props: PatientRegisterProps) => { const authUser = useAuthUser(); const { t } = useTranslation(); const { goBack } = useAppHistory(); - const { gov_data_api_key, enable_hcx, enable_abdm } = useConfig(); const { facilityId, id } = props; const [state, dispatch] = useReducer(patientFormReducer, initialState); const [showAlertMessage, setAlertMessage] = useState({ @@ -504,7 +503,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { const errors: Partial> = {}; const insuranceDetailsError = insuranceDetails - .map((policy) => HCXPolicyValidator(policy, enable_hcx)) + .map((policy) => HCXPolicyValidator(policy, careConfig.hcx.enabled)) .find((error) => !!error); setInsuranceDetailsError(insuranceDetailsError); @@ -644,7 +643,10 @@ export const PatientRegister = (props: PatientRegisterProps) => { const handlePincodeChange = async (e: any, setField: any) => { if (!validatePincode(e.value)) return; - const pincodeDetails = await getPincodeDetails(e.value, gov_data_api_key); + const pincodeDetails = await getPincodeDetails( + e.value, + careConfig.govDataApiKey, + ); if (!pincodeDetails) return; const matchedState = stateData?.results?.find((state) => { @@ -792,7 +794,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { body: policy, }); - if (enable_hcx && policyData?.id) { + if (careConfig.hcx.enabled && policyData?.id) { await request(routes.hcxCheckEligibility, { body: { policy: policyData?.id }, onResponse: ({ res }) => { @@ -1181,7 +1183,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { Import From External Results
- {enable_abdm && ( + {careConfig.abdm.enabled && (

ABHA Details diff --git a/src/Components/Patient/ShiftCreate.tsx b/src/Components/Patient/ShiftCreate.tsx index 7307727d372..c3b01ad189d 100644 --- a/src/Components/Patient/ShiftCreate.tsx +++ b/src/Components/Patient/ShiftCreate.tsx @@ -20,7 +20,6 @@ import { navigate } from "raviger"; import { parsePhoneNumber } from "../../Utils/utils.js"; import { phonePreg } from "../../Common/validation"; import useAppHistory from "../../Common/hooks/useAppHistory"; -import useConfig from "../../Common/hooks/useConfig"; import { useTranslation } from "react-i18next"; import Page from "../Common/components/Page.js"; import Card from "../../CAREUI/display/Card.js"; @@ -30,6 +29,7 @@ import { PhoneNumberValidator } from "../Form/FieldValidators.js"; import useQuery from "../../Utils/request/useQuery.js"; import routes from "../../Redux/api.js"; import request from "../../Utils/request/request.js"; +import careConfig from "@careConfig"; const Loading = lazy(() => import("../Common/Loading")); @@ -44,7 +44,6 @@ export const ShiftCreate = (props: patientShiftProps) => { const [isLoading, setIsLoading] = useState(false); const [patientCategory, setPatientCategory] = useState(); const { t } = useTranslation(); - const { wartime_shifting } = useConfig(); const initForm: any = { shifting_approving_facility: null, @@ -79,7 +78,7 @@ export const ShiftCreate = (props: patientShiftProps) => { }, }; - if (wartime_shifting) { + if (careConfig.wartimeShifting) { requiredFields = { ...requiredFields, shifting_approving_facility: { @@ -200,7 +199,7 @@ export const ShiftCreate = (props: patientShiftProps) => { setIsLoading(true); const data = { - status: wartime_shifting ? "PENDING" : "APPROVED", + status: careConfig.wartimeShifting ? "PENDING" : "APPROVED", origin_facility: props.facilityId, shifting_approving_facility: state.form.shifting_approving_facility?.id, assigned_facility: state.form?.assigned_facility?.id, @@ -282,7 +281,7 @@ export const ShiftCreate = (props: patientShiftProps) => { types={["mobile", "landline"]} /> - {wartime_shifting && ( + {careConfig.wartimeShifting && (
Name of shifting approving facility @@ -336,7 +335,7 @@ export const ShiftCreate = (props: patientShiftProps) => { label="Patient Category" /> - {wartime_shifting && ( + {careConfig.wartimeShifting && ( <> = ({ form, onFormUpdate }) => { - const { enable_scribe } = useConfig(); const [open, setOpen] = useState(false); const [_progress, setProgress] = useState(0); const [stage, setStage] = useState("start"); @@ -120,21 +119,20 @@ export const Scribe: React.FC = ({ form, onFormUpdate }) => { return; } const newFile = new File([f], `${internal_name}`, { type: f.type }); - const config = { - headers: { - "Content-type": newFile?.type?.split(";")?.[0], - "Content-disposition": "inline", - }, + const headers = { + "Content-type": newFile?.type?.split(";")?.[0], + "Content-disposition": "inline", }; - axios - .put(url, newFile, config) - .then(() => { - resolve(); - }) - .catch((error) => { - reject(error); - }); + uploadFile( + url, + newFile, + "PUT", + headers, + (xhr: XMLHttpRequest) => (xhr.status === 200 ? resolve() : reject()), + null, + reject, + ); }); }; @@ -546,7 +544,7 @@ export const Scribe: React.FC = ({ form, onFormUpdate }) => { } } - if (!enable_scribe) return null; + if (!careConfig.scribe.enabled) return null; return ( diff --git a/src/Components/Scribe/formDetails.ts b/src/Components/Scribe/formDetails.ts index 736ab971744..6300ac7e3c2 100644 --- a/src/Components/Scribe/formDetails.ts +++ b/src/Components/Scribe/formDetails.ts @@ -270,7 +270,7 @@ const DAILY_ROUND_FORM_SCRIBE_DATA: Field[] = [ }); return true; }, - }, + } /* { friendlyName: "Prescriptions", id: "prescriptions", @@ -330,7 +330,7 @@ const DAILY_ROUND_FORM_SCRIBE_DATA: Field[] = [ return true; }, }, - /*{ + { friendlyName: "Round Type", id: "rounds_type", type: "string", @@ -355,7 +355,7 @@ const DAILY_ROUND_FORM_SCRIBE_DATA: Field[] = [ "A string to store the date and time at which the round was taken or measured. 'The round was taken yesterday/today' would amount to yesterday/today's date.", validator: (value) => typeof value === "string", }, -*/ +*/, ]; export const SCRIBE_FORMS: { [key: string]: ScribeForm } = { diff --git a/src/Components/Shifting/BoardView.tsx b/src/Components/Shifting/BoardView.tsx index a974e0da79f..f4fb45093aa 100644 --- a/src/Components/Shifting/BoardView.tsx +++ b/src/Components/Shifting/BoardView.tsx @@ -12,7 +12,6 @@ import { downloadShiftRequests } from "../../Redux/actions"; import { formatFilter } from "./Commons"; import { navigate } from "raviger"; -import useConfig from "../../Common/hooks/useConfig"; import useFilters from "../../Common/hooks/useFilters"; import { lazy, useLayoutEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -21,6 +20,7 @@ import ButtonV2 from "../Common/components/ButtonV2"; import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover"; import CareIcon from "../../CAREUI/icons/CareIcon"; import Tabs from "../Common/components/Tabs"; +import careConfig from "@careConfig"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -31,13 +31,12 @@ export default function BoardView() { limit: -1, cacheBlacklist: ["patient_name"], }); - const { wartime_shifting } = useConfig(); - const shiftStatusOptions = wartime_shifting + const shiftStatusOptions = careConfig.wartimeShifting ? SHIFTING_CHOICES_WARTIME : SHIFTING_CHOICES_PEACETIME; - const COMPLETED = wartime_shifting + const COMPLETED = careConfig.wartimeShifting ? [ "COMPLETED", "REJECTED", diff --git a/src/Components/Shifting/ListFilter.tsx b/src/Components/Shifting/ListFilter.tsx index 12bb17db09c..17692ac8f35 100644 --- a/src/Components/Shifting/ListFilter.tsx +++ b/src/Components/Shifting/ListFilter.tsx @@ -17,7 +17,6 @@ import DateRangeFormField from "../Form/FormFields/DateRangeFormField"; import FiltersSlideover from "../../CAREUI/interactive/FiltersSlideover"; import { SelectFormField } from "../Form/FormFields/SelectFormField"; import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; -import useConfig from "../../Common/hooks/useConfig"; import useMergeState from "../../Common/hooks/useMergeState"; import { useTranslation } from "react-i18next"; @@ -26,18 +25,20 @@ import { dateQueryString, parsePhoneNumber } from "../../Utils/utils"; import dayjs from "dayjs"; import useQuery from "../../Utils/request/useQuery"; import routes from "../../Redux/api"; +import careConfig from "@careConfig"; const getDate = (value: any) => value && dayjs(value).isValid() && dayjs(value).toDate(); export default function ListFilter(props: any) { - const { kasp_enabled, kasp_string, wartime_shifting } = useConfig(); const { filter, onChange, closeFilter, removeFilters } = props; const { t } = useTranslation(); const shiftStatusOptions = ( - wartime_shifting ? SHIFTING_CHOICES_WARTIME : SHIFTING_CHOICES_PEACETIME + careConfig.wartimeShifting + ? SHIFTING_CHOICES_WARTIME + : SHIFTING_CHOICES_PEACETIME ).map((option) => option.text); const [filterState, setFilterState] = useMergeState({ @@ -227,7 +228,7 @@ export default function ListFilter(props: any) {

- {wartime_shifting && ( + {careConfig.wartimeShifting && (
{t("shifting_approving_facility")}
@@ -308,12 +309,12 @@ export default function ListFilter(props: any) { errorClassName="hidden" /> - {kasp_enabled && ( + {careConfig.kasp.enabled && ( option} diff --git a/src/Components/Shifting/ListView.tsx b/src/Components/Shifting/ListView.tsx index cfffcef7377..b05795f934d 100644 --- a/src/Components/Shifting/ListView.tsx +++ b/src/Components/Shifting/ListView.tsx @@ -11,11 +11,7 @@ import SearchInput from "../Form/SearchInput"; import { formatDateTime, formatPatientAge } from "../../Utils/utils"; import { formatFilter } from "./Commons"; import { navigate } from "raviger"; - -import useConfig from "../../Common/hooks/useConfig"; - import useFilters from "../../Common/hooks/useFilters"; - import { useTranslation } from "react-i18next"; import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover"; import CareIcon from "../../CAREUI/icons/CareIcon"; @@ -24,11 +20,11 @@ import useAuthUser from "../../Common/hooks/useAuthUser"; import request from "../../Utils/request/request"; import routes from "../../Redux/api"; import useQuery from "../../Utils/request/useQuery"; +import careConfig from "@careConfig"; const Loading = lazy(() => import("../Common/Loading")); export default function ListView() { - const { wartime_shifting } = useConfig(); const { qParams, updateQuery, @@ -127,7 +123,7 @@ export default function ListView() {
- {wartime_shifting && ( + {careConfig.wartimeShifting && (
import("../Common/Loading")); export default function ShiftDetails(props: { id: string }) { - const { header_logo, kasp_full_string, wartime_shifting, kasp_enabled } = - useConfig(); - const [isPrintMode, setIsPrintMode] = useState(false); const [isCopied, setIsCopied] = useState(false); const [openDeleteShiftDialog, setOpenDeleteShiftDialog] = useState(false); const { t } = useTranslation(); - const shiftStatusOptions = wartime_shifting + const shiftStatusOptions = careConfig.wartimeShifting ? SHIFTING_CHOICES_WARTIME : SHIFTING_CHOICES_PEACETIME; @@ -113,7 +110,7 @@ export default function ShiftDetails(props: { id: string }) { t("reason") + ":" + data?.reason; - if (wartime_shifting) { + if (careConfig.wartimeShifting) { formattedText += t("facility_preference") + ": " + data?.assigned_facility_type + "\n"; } @@ -304,7 +301,9 @@ export default function ShiftDetails(props: { id: string }) { return (
-
{data.is_kasp && logo}
+
+ {data.is_kasp && logo} +
@@ -571,7 +570,7 @@ export default function ShiftDetails(props: { id: string }) { {data?.origin_facility_object?.name || "--"}
- {wartime_shifting && ( + {careConfig.wartimeShifting && (
{t("shifting_approving_facility")}:{" "} @@ -635,10 +634,10 @@ export default function ShiftDetails(props: { id: string }) { data?.patient_object.last_consultation?.category}
- {kasp_enabled && ( + {careConfig.kasp.enabled && (
- {kasp_full_string}:{" "} + {careConfig.kasp.fullString}:{" "} {" "} @@ -646,11 +645,11 @@ export default function ShiftDetails(props: { id: string }) {
)} - {wartime_shifting && ( + {careConfig.wartimeShifting && ( <>
- {kasp_full_string}:{" "} + {careConfig.kasp.fullString}:{" "} {" "} @@ -813,7 +812,7 @@ export default function ShiftDetails(props: { id: string }) { {showFacilityCard(data?.assigned_facility_object)}
)} - {wartime_shifting && ( + {careConfig.wartimeShifting && (

{t("details_of_shifting_approving_facility")} diff --git a/src/Components/Shifting/ShiftDetailsUpdate.tsx b/src/Components/Shifting/ShiftDetailsUpdate.tsx index 37adecaedcd..8e6fb582906 100644 --- a/src/Components/Shifting/ShiftDetailsUpdate.tsx +++ b/src/Components/Shifting/ShiftDetailsUpdate.tsx @@ -11,7 +11,6 @@ import { USER_TYPES, } from "../../Common/constants"; import { Cancel, Submit } from "../Common/components/ButtonV2"; - import { navigate, useQueryParams } from "raviger"; import { lazy, useReducer, useState } from "react"; import { ConsultationModel } from "../Facility/models.js"; @@ -26,8 +25,6 @@ import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; import TextFormField from "../Form/FormFields/TextFormField"; import { parsePhoneNumber } from "../../Utils/utils.js"; import useAppHistory from "../../Common/hooks/useAppHistory"; -import useConfig from "../../Common/hooks/useConfig"; - import { useTranslation } from "react-i18next"; import CircularProgress from "../Common/components/CircularProgress.js"; import Card from "../../CAREUI/display/Card"; @@ -41,6 +38,7 @@ import { IShift } from "./models.js"; import request from "../../Utils/request/request.js"; import { PatientModel } from "../Patient/models.js"; import useAuthUser from "../../Common/hooks/useAuthUser.js"; +import careConfig from "@careConfig"; const Loading = lazy(() => import("../Common/Loading")); @@ -51,9 +49,6 @@ interface patientShiftProps { export const ShiftDetailsUpdate = (props: patientShiftProps) => { const { goBack } = useAppHistory(); const { user_type, home_facility } = useAuthUser(); - - const { kasp_full_string, kasp_enabled, wartime_shifting } = useConfig(); - const [qParams, _] = useQueryParams(); const [isLoading, setIsLoading] = useState(true); @@ -137,7 +132,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { }, }; - if (wartime_shifting) { + if (careConfig.wartimeShifting) { requiredFields = { ...requiredFields, shifting_approving_facility_object: { @@ -336,7 +331,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { label={t("status")} required options={ - wartime_shifting + careConfig.wartimeShifting ? SHIFTING_CHOICES_WARTIME : SHIFTING_CHOICES_PEACETIME } @@ -355,7 +350,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { className="w-full bg-white md:col-span-1 md:leading-5" /> - {wartime_shifting && + {careConfig.wartimeShifting && (assignedUserLoading ? ( ) : ( @@ -369,7 +364,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { /> ))} - {wartime_shifting && ( + {careConfig.wartimeShifting && (
{t("name_of_shifting_approving_facility")} @@ -429,11 +424,11 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { optionValue={(option) => option.value} /> - {kasp_enabled && ( + {careConfig.kasp.enabled && ( { error={state.errors.patient_category} /> - {wartime_shifting && ( + {careConfig.wartimeShifting && ( <> { - const { wartime_shifting } = useConfig(); const [modalFor, setModalFor] = useState({ externalId: undefined, loading: false, @@ -110,7 +108,7 @@ const ShiftCard = ({ shift, filter }: any) => {

- {wartime_shifting && ( + {careConfig.wartimeShifting && (
{ plausible("pageview"); }); @@ -17,11 +15,11 @@ export default function Plausible() { return (