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..79332e6b9af --- /dev/null +++ b/.example.env @@ -0,0 +1,73 @@ +# 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 + +# 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..87604b50030 --- /dev/null +++ b/care.config.ts @@ -0,0 +1,103 @@ +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", + + 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..7a4c86157da 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, + }, }); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 8c1b60f3d88..776e3409511 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -2,6 +2,8 @@ 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}`); cy.visit("/"); @@ -14,7 +16,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 +45,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 +71,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/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/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 5fa8748b399..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" }, 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/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/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/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 1d498ea3d14..f9faffaba0f 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/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/HCX/InsuranceDetailsBuilder.tsx b/src/Components/HCX/InsuranceDetailsBuilder.tsx index 1e401410ff0..2c51d3b90d3 100644 --- a/src/Components/HCX/InsuranceDetailsBuilder.tsx +++ b/src/Components/HCX/InsuranceDetailsBuilder.tsx @@ -12,7 +12,7 @@ import { useDispatch } from "react-redux"; import { HCXActions } from "../../Redux/actions"; import { classNames } from "../../Utils/utils"; import InsurerAutocomplete from "./InsurerAutocomplete"; -import useConfig from "../../Common/hooks/useConfig"; +import careConfig from "@careConfig"; type Props = FormFieldBaseProps & { 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 ? (

{encounter?.facility_name}

- care logo + care logo
diff --git a/src/Components/Patient/PatientFilter.tsx b/src/Components/Patient/PatientFilter.tsx index b69436171d8..31c54c5b9c4 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({ @@ -702,14 +701,18 @@ export default function PatientFilter(props: any) { className="w-full rounded-md" >
- {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"); @@ -545,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/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 (