From cbdcf36088f683806487699259c444f05f82025f Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Mon, 9 Sep 2024 19:03:52 +0530 Subject: [PATCH 1/4] Enable features from backend feature flags --- .example.env | 3 - care.config.ts | 12 --- src/App.tsx | 11 ++- src/Components/Facility/DischargeModal.tsx | 5 +- .../HCX/InsuranceDetailsBuilder.tsx | 5 +- src/Components/Patient/DailyRounds.tsx | 1 + src/Components/Patient/PatientInfoCard.tsx | 8 +- src/Components/Patient/PatientRegister.tsx | 9 +- src/Components/Scribe/Scribe.tsx | 13 ++- src/Integrations/index.tsx | 4 +- src/Redux/api.tsx | 6 ++ src/Routers/AppRouter.tsx | 4 +- src/Utils/featureFlags.tsx | 86 +++++++++++++++++++ 13 files changed, 132 insertions(+), 35 deletions(-) create mode 100644 src/Utils/featureFlags.tsx diff --git a/.example.env b/.example.env index dd4a8865878..87082129e92 100644 --- a/.example.env +++ b/.example.env @@ -67,9 +67,6 @@ REACT_STILL_WATCHING_IDLE_TIMEOUT= 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) diff --git a/care.config.ts b/care.config.ts index 4341a03dd48..4ad8fd84654 100644 --- a/care.config.ts +++ b/care.config.ts @@ -95,18 +95,6 @@ const careConfig = { "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/src/App.tsx b/src/App.tsx index 2e7f185f80b..6c6d5255b4d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,11 @@ import { Suspense } from "react"; import Routers from "./Routers"; import ThemedFavicon from "./CAREUI/misc/ThemedFavicon"; -import Intergrations from "./Integrations"; +import Integrations from "./Integrations"; import Loading from "./Components/Common/Loading"; import HistoryAPIProvider from "./Providers/HistoryAPIProvider"; import AuthUserProvider from "./Providers/AuthUserProvider"; +import { FeatureFlagsProvider } from "./Utils/featureFlags"; const App = () => { return ( @@ -12,12 +13,14 @@ const App = () => { }> - + + + {/* Integrations */} - - + + ); diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index ac86ff02c55..3ca7308c57c 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -27,7 +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"; +import { useFeatureFlags } from "../../Utils/featureFlags"; interface PreDischargeFormInterface { new_discharge_reason: number | null; @@ -80,6 +80,7 @@ const DischargeModal = ({ const [isSendingDischargeApi, setIsSendingDischargeApi] = useState(false); const [facility, setFacility] = useState(referred_to); const [errors, setErrors] = useState({}); + const featureFlags = useFeatureFlags(); useEffect(() => { setPreDischargeForm((prev) => ({ @@ -384,7 +385,7 @@ const DischargeModal = ({ )} - {careConfig.hcx.enabled && ( + {featureFlags.hcx.enabled && ( // TODO: if policy and approved pre-auth exists

Claim Insurance

diff --git a/src/Components/HCX/InsuranceDetailsBuilder.tsx b/src/Components/HCX/InsuranceDetailsBuilder.tsx index 2c51d3b90d3..fce34826452 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 careConfig from "@careConfig"; +import { useFeatureFlags } from "../../Utils/featureFlags"; type Props = FormFieldBaseProps & { gridView?: boolean }; @@ -97,6 +97,7 @@ const InsuranceDetailEditCard = ({ policy.insurer_id && policy.insurer_name ? { code: policy.insurer_id, name: policy.insurer_name } : undefined; + const featureFlags = useFeatureFlags(); return (
@@ -132,7 +133,7 @@ const InsuranceDetailEditCard = ({ value={policy.policy_id} onChange={handleUpdate} /> - {careConfig.hcx.enabled ? ( + {featureFlags.hcx.enabled ? ( { >
{ setDiagnosisSuggestions([]); diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index f301db6333e..cd37c1f643a 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -42,7 +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"; +import { useFeatureFlags } from "../../Utils/featureFlags.js"; const formatSkills = (arr: SkillModel[]) => { const skills = arr.map((skill) => skill.skill_object.name); @@ -133,6 +133,8 @@ export default function PatientInfoCard(props: { prefetch: !!consultation?.treating_physician_object?.username, }); + const featureFlags = useFeatureFlags(); + return ( <>
- {careConfig.abdm.enabled && + {featureFlags.abdm.enabled && (patient.abha_number ? ( <> diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx index c25a6365e70..9e1053342f7 100644 --- a/src/Components/Patient/PatientRegister.tsx +++ b/src/Components/Patient/PatientRegister.tsx @@ -73,6 +73,7 @@ import _ from "lodash"; import { ILocalBodies } from "../ExternalResult/models.js"; import { useTranslation } from "react-i18next"; import careConfig from "@careConfig"; +import { useFeatureFlags } from "../../Utils/featureFlags.js"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -499,11 +500,13 @@ export const PatientRegister = (props: PatientRegisterProps) => { prefetch: !!facilityId, }); + const featureFlags = useFeatureFlags(); + const validateForm = (form: any) => { const errors: Partial> = {}; const insuranceDetailsError = insuranceDetails - .map((policy) => HCXPolicyValidator(policy, careConfig.hcx.enabled)) + .map((policy) => HCXPolicyValidator(policy, featureFlags.hcx.enabled)) .find((error) => !!error); setInsuranceDetailsError(insuranceDetailsError); @@ -794,7 +797,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { body: policy, }); - if (careConfig.hcx.enabled && policyData?.id) { + if (featureFlags.hcx.enabled && policyData?.id) { await request(routes.hcxCheckEligibility, { body: { policy: policyData?.id }, onResponse: ({ res }) => { @@ -1183,7 +1186,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { Import From External Results
- {careConfig.abdm.enabled && ( + {featureFlags.abdm.enabled && (

ABHA Details diff --git a/src/Components/Scribe/Scribe.tsx b/src/Components/Scribe/Scribe.tsx index d952ff7b1b2..76b5a6b4556 100644 --- a/src/Components/Scribe/Scribe.tsx +++ b/src/Components/Scribe/Scribe.tsx @@ -7,8 +7,8 @@ import * as Notify from "../../Utils/Notifications"; import request from "../../Utils/request/request"; import { UserModel } from "../Users/models"; import useSegmentedRecording from "../../Utils/useSegmentedRecorder"; -import careConfig from "@careConfig"; import uploadFile from "../../Utils/request/uploadFile"; +import { useFeatureFlags } from "../../Utils/featureFlags"; interface FieldOption { id: string | number; @@ -52,6 +52,7 @@ export type ScribeModel = { }; interface ScribeProps { + facilityId: string; form: ScribeForm; existingData?: { [key: string]: any }; onFormUpdate: (fields: any) => void; @@ -62,7 +63,11 @@ const SCRIBE_FILE_TYPES = { SCRIBE: 1, }; -export const Scribe: React.FC = ({ form, onFormUpdate }) => { +export const Scribe: React.FC = ({ + form, + onFormUpdate, + facilityId, +}) => { const [open, setOpen] = useState(false); const [_progress, setProgress] = useState(0); const [stage, setStage] = useState("start"); @@ -80,6 +85,8 @@ export const Scribe: React.FC = ({ form, onFormUpdate }) => { const stageRef = useRef(stage); const [fields, setFields] = useState([]); + const featureFlags = useFeatureFlags(facilityId); + useEffect(() => { const loadFields = async () => { const fields = await form.fields(); @@ -544,7 +551,7 @@ export const Scribe: React.FC = ({ form, onFormUpdate }) => { } } - if (!careConfig.scribe.enabled) return null; + if (!featureFlags.scribe.enabled) return null; return ( diff --git a/src/Integrations/index.tsx b/src/Integrations/index.tsx index aeb0399a452..9b2b1e156fd 100644 --- a/src/Integrations/index.tsx +++ b/src/Integrations/index.tsx @@ -1,6 +1,6 @@ import Sentry from "./Sentry"; import Plausible from "./Plausible"; -const Intergrations = { Sentry, Plausible }; +const Integrations = { Sentry, Plausible }; -export default Intergrations; +export default Integrations; diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index e72f7766bbe..cb8fad0b97e 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -111,6 +111,7 @@ import { HCXPolicyModel } from "../Components/HCX/models"; import { IComment, IResource } from "../Components/Resource/models"; import { IShift } from "../Components/Shifting/models"; import { ScribeModel } from "../Components/Scribe/Scribe"; +import { FeatureFlagsResponse } from "../Utils/featureFlags"; /** * A fake function that returns an empty object casted to type T @@ -131,6 +132,11 @@ export interface LoginCredentials { } const routes = { + getFeatureFlags: { + path: "/api/flags/", + method: "GET", + TRes: Type(), + }, createScribe: { path: "/api/care_scribe/scribe/", method: "POST", diff --git a/src/Routers/AppRouter.tsx b/src/Routers/AppRouter.tsx index 60e0f9411d5..2a0ab140a44 100644 --- a/src/Routers/AppRouter.tsx +++ b/src/Routers/AppRouter.tsx @@ -28,6 +28,7 @@ import ExternalResultRoutes from "./routes/ExternalResultRoutes"; import { DetailRoute } from "./types"; import useAuthUser from "../Common/hooks/useAuthUser"; import careConfig from "@careConfig"; +import { useFeatureFlags } from "../Utils/featureFlags"; const Routes = { "/": () => , @@ -59,10 +60,11 @@ const Routes = { export default function AppRouter() { const authUser = useAuthUser(); + const featureFlags = useFeatureFlags(); let routes = Routes; - if (careConfig.hcx.enabled) { + if (featureFlags.hcx.enabled) { routes = { ...routes, ...HCXRoutes }; } diff --git a/src/Utils/featureFlags.tsx b/src/Utils/featureFlags.tsx new file mode 100644 index 00000000000..0e9cf785897 --- /dev/null +++ b/src/Utils/featureFlags.tsx @@ -0,0 +1,86 @@ +import { createContext, useContext, useState, useEffect } from "react"; +import useQuery from "./request/useQuery"; +import routes from "../Redux/api"; + +export interface FeatureFlags { + hcx: { + enabled: boolean; + }; + + abdm: { + enabled: boolean; + }; + + scribe: { + enabled: boolean; + }; +} + +export interface FeatureFlagsResponse { + user_flags: FeatureFlags; + facility_flags: { + facility: string; + features: FeatureFlags; + }[]; +} + +const defaultFlags: FeatureFlags = { + hcx: { + enabled: false, + }, + + abdm: { + enabled: false, + }, + + scribe: { + enabled: false, + }, +}; + +const FeatureFlagsContext = createContext({ + user_flags: defaultFlags, + facility_flags: [], +}); + +export const FeatureFlagsProvider = (props: { children: React.ReactNode }) => { + const [featureFlags, setFeatureFlags] = useState({ + user_flags: defaultFlags, + facility_flags: [], + }); + + const query = useQuery(routes.getFeatureFlags, { + silent: true, + }); + + useEffect(() => { + if (query.data) { + setFeatureFlags(query.data); + } + }, [query.data]); + + return ( + + {props.children} + + ); +}; + +export const useFeatureFlags = (facilityId?: string) => { + const context = useContext(FeatureFlagsContext); + if (context === undefined) { + throw new Error( + "useFeatureFlags must be used within a FeatureFlagsProvider", + ); + } + let facilityFlags; + if (facilityId) { + facilityFlags = context?.facility_flags.find( + (f) => f.facility === facilityId, + )?.features; + } + return { + ...context.user_flags, + ...facilityFlags, + }; +}; From 84f366ee91dc03d40669e55584804b0071ee4ec3 Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Fri, 20 Sep 2024 13:44:43 +0530 Subject: [PATCH 2/4] merge fix --- src/Components/Patient/DailyRounds.tsx | 311 ++++++++++++++++++------- 1 file changed, 232 insertions(+), 79 deletions(-) diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx index acfe6871e3a..0c6e01be6f2 100644 --- a/src/Components/Patient/DailyRounds.tsx +++ b/src/Components/Patient/DailyRounds.tsx @@ -3,11 +3,19 @@ import { navigate } from "raviger"; import dayjs from "dayjs"; import { lazy, useCallback, useEffect, useState } from "react"; import { + APPETITE_CHOICES, + BLADDER_DRAINAGE_CHOICES, + BLADDER_ISSUE_CHOICES, + BOWEL_ISSUE_CHOICES, CONSCIOUSNESS_LEVEL, + NUTRITION_ROUTE_CHOICES, + ORAL_ISSUE_CHOICES, PATIENT_CATEGORIES, REVIEW_AT_CHOICES, RHYTHM_CHOICES, + SLEEP_CHOICES, TELEMEDICINE_ACTIONS, + URINATION_FREQUENCY_CHOICES, } from "../../Common/constants"; import useAppHistory from "../../Common/hooks/useAppHistory"; import { DraftSection, useAutoSaveReducer } from "../../Utils/AutoSave"; @@ -30,7 +38,7 @@ import request from "../../Utils/request/request"; import routes from "../../Redux/api"; import { Scribe } from "../Scribe/Scribe"; import { SCRIBE_FORMS } from "../Scribe/formDetails"; -import { DailyRoundsModel } from "./models"; +import { DailyRoundsModel, DailyRoundTypes } from "./models"; import InvestigationBuilder from "../Common/prescription-builder/InvestigationBuilder"; import { FieldErrorText } from "../Form/FormFields/FormField"; import { error } from "@pnotify/core"; @@ -48,6 +56,7 @@ import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField"; import SymptomsApi from "../Symptoms/api"; import { scrollTo } from "../../Utils/utils"; import { ICD11DiagnosisModel } from "../Facility/models"; +import NursingCare from "../LogUpdate/Sections/NursingCare"; const Loading = lazy(() => import("../Common/Loading")); @@ -281,6 +290,16 @@ export const DailyRounds = (props: any) => { } return; } + + case "oral_issue": { + if (state.form.nutrition_route !== "ORAL" && state.form[field]) { + errors[field] = t("oral_issue_for_non_oral_nutrition_route_error"); + invalidForm = true; + break; + } + return; + } + default: return; } @@ -329,7 +348,7 @@ export const DailyRounds = (props: any) => { review_interval: Number(prevReviewInterval), }; - if (!["VENTILATOR"].includes(state.form.rounds_type)) { + if (state.form.rounds_type !== "VENTILATOR") { data = { ...data, bp: state.form.bp ?? {}, @@ -340,6 +359,17 @@ export const DailyRounds = (props: any) => { rhythm_detail: state.form.rhythm_detail, ventilator_spo2: state.form.ventilator_spo2 ?? null, consciousness_level: state.form.consciousness_level || undefined, + bowel_issue: state.form.bowel_issue ?? undefined, + bladder_drainage: state.form.bladder_drainage ?? undefined, + bladder_issue: state.form.bladder_issue ?? undefined, + is_experiencing_dysuria: state.form.is_experiencing_dysuria, + urination_frequency: state.form.urination_frequency ?? undefined, + sleep: state.form.sleep ?? undefined, + nutrition_route: state.form.nutrition_route ?? undefined, + oral_issue: state.form.oral_issue ?? undefined, + appetite: state.form.appetite ?? undefined, + blood_sugar_level: state.form.blood_sugar_level, + nursing: state.form.nursing, }; } @@ -354,9 +384,15 @@ export const DailyRounds = (props: any) => { if (obj) { dispatch({ type: "set_form", form: initForm }); Notification.Success({ - msg: `${t(obj.rounds_type as string)} log updated successfully`, + msg: t("LOG_UPDATE_UPDATED_NOTIFICATION", { + roundType: t(`ROUNDS_TYPE__${state.form.rounds_type}`), + }), }); - if (["NORMAL", "TELEMEDICINE"].includes(state.form.rounds_type)) { + if ( + ["NORMAL", "TELEMEDICINE", "COMMUNITY_NURSES_LOG"].includes( + state.form.rounds_type, + ) + ) { navigate( `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`, ); @@ -375,10 +411,16 @@ export const DailyRounds = (props: any) => { if (obj) { dispatch({ type: "set_form", form: initForm }); Notification.Success({ - msg: `${t(state.form.rounds_type)} log created successfully`, + msg: t("LOG_UPDATE_CREATED_NOTIFICATION", { + roundType: t(`ROUNDS_TYPE__${state.form.rounds_type}`), + }), }); - if (["NORMAL", "TELEMEDICINE"].includes(state.form.rounds_type)) { + if ( + ["NORMAL", "TELEMEDICINE", "COMMUNITY_NURSES_LOG"].includes( + state.form.rounds_type, + ) + ) { navigate( `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`, ); @@ -408,6 +450,7 @@ export const DailyRounds = (props: any) => { const field = (name: string) => { return { id: name, + label: t(`LOG_UPDATE_FIELD_LABEL__${name}`), name, value: state.form[name], error: state.errors[name], @@ -415,6 +458,18 @@ export const DailyRounds = (props: any) => { }; }; + const selectField = ( + name: keyof DailyRoundsModel, + options: readonly T[], + ) => { + return { + ...field(name), + options, + optionLabel: (option: T) => t(`${name.toUpperCase()}__${option}`), + optionValue: (option: T) => option, + }; + }; + const getExpectedReviewTime = () => { const nextReviewTime = Number( state.form.review_interval || prevReviewInterval, @@ -428,30 +483,30 @@ export const DailyRounds = (props: any) => { return ; } - const roundTypes: { id: string; text: string }[] = []; + const roundTypes: (typeof DailyRoundTypes)[number][] = []; if ( ["Doctor", "Staff", "DistrictAdmin", "StateAdmin"].includes( authUser.user_type, ) ) { - roundTypes.push({ id: "DOCTORS_LOG", text: t("DOCTORS_LOG") }); + roundTypes.push("DOCTORS_LOG"); } - - roundTypes.push( - { id: "NORMAL", text: t("NORMAL") }, - { id: "VENTILATOR", text: t("VENTILATOR") }, - ); - + roundTypes.push("NORMAL", "COMMUNITY_NURSES_LOG", "VENTILATOR"); if (consultationSuggestion === "DC") { - roundTypes.push({ id: "TELEMEDICINE", text: t("TELEMEDICINE") }); + roundTypes.push("TELEMEDICINE"); } + const submitButtonDisabled = (() => { if (buttonText !== "Save") { return false; } - if (["VENTILATOR", "DOCTORS_LOG"].includes(state.form.rounds_type)) { + if ( + ["VENTILATOR", "DOCTORS_LOG", "COMMUNITY_NURSES_LOG"].includes( + state.form.rounds_type, + ) + ) { return false; } @@ -540,7 +595,7 @@ export const DailyRounds = (props: any) => { "additional_symptoms", ].includes(f), ) && - roundTypes.some((t) => t.id === "DOCTORS_LOG") + roundTypes.some((t) => t === "DOCTORS_LOG") ) { rounds_type = "DOCTORS_LOG"; } @@ -578,20 +633,15 @@ export const DailyRounds = (props: any) => {

option.text} - optionValue={(option) => option.id} />
@@ -611,63 +661,67 @@ export const DailyRounds = (props: any) => { />
- - + + - {state.form.rounds_type !== "DOCTORS_LOG" && ( + {state.form.rounds_type === "COMMUNITY_NURSES_LOG" && ( <> +
+

{t("routine")}

+ option.desc} - optionValue={(option) => option.text} - value={prevAction} - onChange={(event) => { - handleFormFieldChange(event); - setPreviousAction(event.value); - }} - /> - - option.text} - optionValue={(option) => option.id} - value={prevReviewInterval} - onChange={(event) => { - handleFormFieldChange(event); - setPreviousReviewInterval(Number(event.value)); - }} + {...selectField("bowel_issue", BOWEL_ISSUE_CHOICES)} /> +
+
{t("bladder")}
+ + + t(c ? "yes" : "no")} + /> + +
+
+
{t("nutrition")}
+ + + +
)} - {["NORMAL", "TELEMEDICINE", "DOCTORS_LOG"].includes( - state.form.rounds_type, - ) && ( + {[ + "NORMAL", + "TELEMEDICINE", + "DOCTORS_LOG", + "COMMUNITY_NURSES_LOG", + ].includes(state.form.rounds_type) && ( <> -

Vitals

+
+

{t("vitals")}

- + { }, ]} /> + + )} - + + + )} + + {["NORMAL", "TELEMEDICINE", "DOCTORS_LOG"].includes( + state.form.rounds_type, + ) && ( + <> + { { option.desc} optionValue={(option) => option.id} @@ -760,18 +843,19 @@ export const DailyRounds = (props: any) => { a.value), + )} options={CONSCIOUSNESS_LEVEL.map((level) => ({ label: t(`CONSCIOUSNESS_LEVEL__${level.value}`), value: level.value, }))} - optionDisplay={(option) => option.label} + optionLabel={(option) => option.label} optionValue={(option) => option.value} unselectLabel="Unknown" layout="vertical" @@ -779,6 +863,45 @@ export const DailyRounds = (props: any) => { )} + {state.form.rounds_type === "COMMUNITY_NURSES_LOG" && ( +
+
+
+

+ {t("prescription_medications")} +

+ + setShowDiscontinuedPrescriptions(value) + } + errorClassName="hidden" + /> +
+ +
+ )} + + {state.form.rounds_type === "COMMUNITY_NURSES_LOG" && ( +
+
+
+

{t("nursing_care")}

+
+ + handleFormFieldChange({ name: "nursing", value: log.nursing }) + } + /> +
+ )} + {state.form.rounds_type === "DOCTORS_LOG" && ( <>
@@ -861,6 +984,36 @@ export const DailyRounds = (props: any) => {
)} + + {state.form.rounds_type !== "DOCTORS_LOG" && ( + <> +
+ option.desc} + optionValue={(option) => option.text} + value={prevAction} + onChange={(event) => { + handleFormFieldChange(event); + setPreviousAction(event.value); + }} + /> + + option.text} + optionValue={(option) => option.id} + value={prevReviewInterval} + onChange={(event) => { + handleFormFieldChange(event); + setPreviousReviewInterval(Number(event.value)); + }} + /> + + )}
From 089d5f8c55ab8c532eca5d7aecb76275efa5e93a Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Sat, 21 Sep 2024 01:03:47 +0530 Subject: [PATCH 3/4] revert other changes --- .example.env | 2 ++ care.config.ts | 8 ++++++++ src/Components/Facility/DischargeModal.tsx | 5 ++--- src/Components/HCX/InsuranceDetailsBuilder.tsx | 5 ++--- src/Components/Patient/PatientInfoCard.tsx | 8 +++----- src/Components/Patient/PatientRegister.tsx | 11 +++-------- src/Routers/AppRouter.tsx | 4 +--- src/Utils/featureFlags.tsx | 2 +- 8 files changed, 22 insertions(+), 23 deletions(-) diff --git a/.example.env b/.example.env index 87082129e92..127db15e710 100644 --- a/.example.env +++ b/.example.env @@ -67,6 +67,8 @@ REACT_STILL_WATCHING_IDLE_TIMEOUT= REACT_STILL_WATCHING_PROMPT_DURATION= # Feature flags +REACT_ENABLE_HCX=true +REACT_ENABLE_ABDM=true REACT_WARTIME_SHIFTING=true # JWT token refresh interval (in milliseconds) (default: 5 minutes) diff --git a/care.config.ts b/care.config.ts index 4ad8fd84654..e3effeca1b0 100644 --- a/care.config.ts +++ b/care.config.ts @@ -95,6 +95,14 @@ const careConfig = { "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", + }, } as const; export default careConfig; diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index d05d36a30a3..ac86ff02c55 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -27,7 +27,7 @@ import { FieldError } from "../Form/FieldValidators"; import { useTranslation } from "react-i18next"; import useConfirmedAction from "../../Common/hooks/useConfirmedAction"; import ConfirmDialog from "../Common/ConfirmDialog"; -import { useFeatureFlags } from "../../Utils/featureFlags"; +import careConfig from "@careConfig"; interface PreDischargeFormInterface { new_discharge_reason: number | null; @@ -80,7 +80,6 @@ const DischargeModal = ({ const [isSendingDischargeApi, setIsSendingDischargeApi] = useState(false); const [facility, setFacility] = useState(referred_to); const [errors, setErrors] = useState({}); - const featureFlags = useFeatureFlags(); useEffect(() => { setPreDischargeForm((prev) => ({ @@ -385,7 +384,7 @@ const DischargeModal = ({ )}
- {featureFlags.includes("HCX_ENABLED") && ( + {careConfig.hcx.enabled && ( // TODO: if policy and approved pre-auth exists

Claim Insurance

diff --git a/src/Components/HCX/InsuranceDetailsBuilder.tsx b/src/Components/HCX/InsuranceDetailsBuilder.tsx index b7ba094b86c..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 { useFeatureFlags } from "../../Utils/featureFlags"; +import careConfig from "@careConfig"; type Props = FormFieldBaseProps & { gridView?: boolean }; @@ -97,7 +97,6 @@ const InsuranceDetailEditCard = ({ policy.insurer_id && policy.insurer_name ? { code: policy.insurer_id, name: policy.insurer_name } : undefined; - const featureFlags = useFeatureFlags(); return (
@@ -133,7 +132,7 @@ const InsuranceDetailEditCard = ({ value={policy.policy_id} onChange={handleUpdate} /> - {featureFlags.includes("HCX_ENABLED") ? ( + {careConfig.hcx.enabled ? ( { const skills = arr.map((skill) => skill.skill_object.name); @@ -135,8 +135,6 @@ export default function PatientInfoCard(props: { prefetch: !!consultation?.treating_physician_object?.username, }); - const featureFlags = useFeatureFlags(); - return ( <>
- {featureFlags.includes("ABDM_ENABLED") && + {careConfig.abdm.enabled && (props.abhaNumber ? ( <> diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx index b706d75ee1d..033d0187649 100644 --- a/src/Components/Patient/PatientRegister.tsx +++ b/src/Components/Patient/PatientRegister.tsx @@ -75,7 +75,6 @@ import _ from "lodash"; import { ILocalBodies } from "../ExternalResult/models.js"; import { useTranslation } from "react-i18next"; import careConfig from "@careConfig"; -import { useFeatureFlags } from "../../Utils/featureFlags.js"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -514,15 +513,11 @@ export const PatientRegister = (props: PatientRegisterProps) => { prefetch: !!facilityId, }); - const featureFlags = useFeatureFlags(); - const validateForm = (form: any) => { const errors: Partial> = {}; const insuranceDetailsError = insuranceDetails - .map((policy) => - HCXPolicyValidator(policy, featureFlags.includes("HCX_ENABLED")), - ) + .map((policy) => HCXPolicyValidator(policy, careConfig.hcx.enabled)) .find((error) => !!error); setInsuranceDetailsError(insuranceDetailsError); @@ -832,7 +827,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { body: policy, }); - if (featureFlags.includes("HCX_ENABLED") && policyData?.id) { + if (careConfig.hcx.enabled && policyData?.id) { await request(routes.hcxCheckEligibility, { body: { policy: policyData?.id }, onResponse: ({ res }) => { @@ -1221,7 +1216,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { Import From External Results
- {featureFlags.includes("ABDM_ENABLED") && ( + {careConfig.abdm.enabled && (

ABHA Details diff --git a/src/Routers/AppRouter.tsx b/src/Routers/AppRouter.tsx index 930fde191aa..60e0f9411d5 100644 --- a/src/Routers/AppRouter.tsx +++ b/src/Routers/AppRouter.tsx @@ -28,7 +28,6 @@ import ExternalResultRoutes from "./routes/ExternalResultRoutes"; import { DetailRoute } from "./types"; import useAuthUser from "../Common/hooks/useAuthUser"; import careConfig from "@careConfig"; -import { useFeatureFlags } from "../Utils/featureFlags"; const Routes = { "/": () => , @@ -60,11 +59,10 @@ const Routes = { export default function AppRouter() { const authUser = useAuthUser(); - const featureFlags = useFeatureFlags(); let routes = Routes; - if (featureFlags.includes("HCX_ENABLED")) { + if (careConfig.hcx.enabled) { routes = { ...routes, ...HCXRoutes }; } diff --git a/src/Utils/featureFlags.tsx b/src/Utils/featureFlags.tsx index 7a1f4b79d1a..f5fe4ca0bd6 100644 --- a/src/Utils/featureFlags.tsx +++ b/src/Utils/featureFlags.tsx @@ -4,7 +4,7 @@ import routes from "../Redux/api"; import useAuthUser from "../Common/hooks/useAuthUser"; import { FacilityModel } from "../Components/Facility/models"; -export type FeatureFlag = "HCX_ENABLED" | "ABDM_ENABLED" | "SCRIBE_ENABLED"; +export type FeatureFlag = "SCRIBE_ENABLED"; // "HCX_ENABLED" | "ABDM_ENABLED" | export interface FeatureFlagsResponse { user_flags: FeatureFlag[]; From b0583300a4d827fa630c56cd9bde2e0d7725529a Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Sat, 21 Sep 2024 01:16:11 +0530 Subject: [PATCH 4/4] minor fix --- src/Utils/featureFlags.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utils/featureFlags.tsx b/src/Utils/featureFlags.tsx index f5fe4ca0bd6..739d49e821a 100644 --- a/src/Utils/featureFlags.tsx +++ b/src/Utils/featureFlags.tsx @@ -57,11 +57,11 @@ export const useFeatureFlags = (facility?: FacilityModel | string) => { ); } - const facilityQuery = useQuery(routes.getAnyFacility, { + const facilityQuery = useQuery(routes.getPermittedFacility, { pathParams: { id: typeof facility === "string" ? facility : "", }, - prefetch: typeof facility === "string", + prefetch: false, silent: true, onResponse: (res) => { setFacilityObject(res.data);