From 9a7661ba45b38af1ece95b93e9b171b1d2d8eba9 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Sun, 29 Oct 2023 22:12:34 +0530 Subject: [PATCH 01/22] useSlug: support for fallbacks for graceful handling --- src/Common/hooks/useSlug.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Common/hooks/useSlug.ts b/src/Common/hooks/useSlug.ts index 69d8f591c84..8885a074678 100644 --- a/src/Common/hooks/useSlug.ts +++ b/src/Common/hooks/useSlug.ts @@ -8,9 +8,9 @@ import { usePath } from "raviger"; * // Current path: /consultation/94b9a * const consultation = useSlug("consultation"); // consultation = "94b9a" */ -export default function useSlug(prefix: string) { +export default function useSlug(prefix: string, fallback?: string) { const path = usePath() ?? ""; - return findSlug(path.split("/"), prefix); + return findSlug(path.split("/"), prefix, fallback); } /** @@ -28,7 +28,7 @@ export const useSlugs = (...prefix: string[]) => { return prefix.map((p) => findSlug(path.split("/"), p)); }; -const findSlug = (segments: string[], prefix: string) => { +const findSlug = (segments: string[], prefix: string, fallback?: string) => { const index = segments.findIndex((segment) => segment === prefix); if (index === -1) { throw new Error( @@ -36,8 +36,8 @@ const findSlug = (segments: string[], prefix: string) => { ); } - const slug = segments[index + 1]; - if (!slug) { + const slug = segments[index + 1] ?? fallback; + if (slug === undefined) { throw new Error(`Slug not found in path "${segments.join("/")}"`); } From d8aa83b6936890d4dd4e973a2e8e52df9e4541f6 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 14:44:25 +0530 Subject: [PATCH 02/22] Miscellaneous changes / cleanup --- src/Components/Diagnosis/types.ts | 47 +++++++ .../Facility/ConsultationDetails/index.tsx | 117 ++++++++---------- src/Components/Facility/TreatmentSummary.tsx | 7 -- src/Components/Facility/models.tsx | 17 +-- src/Components/Shifting/ShiftDetails.tsx | 9 +- src/Redux/actions.tsx | 4 +- 6 files changed, 109 insertions(+), 92 deletions(-) create mode 100644 src/Components/Diagnosis/types.ts diff --git a/src/Components/Diagnosis/types.ts b/src/Components/Diagnosis/types.ts new file mode 100644 index 00000000000..0b843aee866 --- /dev/null +++ b/src/Components/Diagnosis/types.ts @@ -0,0 +1,47 @@ +import { PerformedByModel } from "../HCX/misc"; + +export type ICD11DiagnosisModel = { + id: string; + label: string; +}; + +export const ActiveConditionVerificationStatuses = [ + "unconfirmed", + "provisional", + "differential", + "confirmed", +] as const; + +export const InactiveConditionVerificationStatuses = [ + "refuted", + "entered-in-error", +] as const; + +export const ConditionVerificationStatuses = [ + ...ActiveConditionVerificationStatuses, + ...InactiveConditionVerificationStatuses, +] as const; + +export type ConditionVerificationStatus = + (typeof ConditionVerificationStatuses)[number]; + +export interface ConsultationDiagnosis { + id: string; + diagnosis_object: ICD11DiagnosisModel; + verification_status: ConditionVerificationStatus; + is_principal: boolean; + is_migrated: boolean; + created_by: PerformedByModel; + created_date: string; + modified_date: string; +} + +export interface CreateDiagnosis { + diagnosis: ICD11DiagnosisModel["id"]; + diagnosis_object?: ICD11DiagnosisModel; + verification_status: (typeof ActiveConditionVerificationStatuses)[number]; +} + +export interface ConsultationCreateDignosis extends CreateDiagnosis { + is_principal: boolean; +} diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index cedb1a843d3..1d06bb5535e 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -4,7 +4,7 @@ import { OptionsType, SYMPTOM_CHOICES, } from "../../../Common/constants"; -import { ConsultationModel, ICD11DiagnosisModel } from "../models"; +import { ConsultationModel } from "../models"; import { getConsultation, getPatient, @@ -12,7 +12,6 @@ import { } from "../../../Redux/actions"; import { statusType, useAbortableEffect } from "../../../Common/utils"; import { lazy, useCallback, useState } from "react"; -import ToolTip from "../../Common/utils/Tooltip"; import ButtonV2 from "../../Common/components/ButtonV2"; import CareIcon from "../../../CAREUI/icons/CareIcon"; import DischargeModal from "../DischargeModal"; @@ -205,56 +204,56 @@ export const ConsultationDetails = (props: any) => { selected === true ? "border-primary-500 text-primary-600 border-b-2" : "" }`; - const ShowDiagnosis = ({ - diagnoses = [], - label = "Diagnosis", - nshow = 2, - }: { - diagnoses: ICD11DiagnosisModel[] | undefined; - label: string; - nshow?: number; - }) => { - const [showMore, setShowMore] = useState(false); - - return diagnoses.length ? ( -
-

{label}

- {diagnoses.slice(0, !showMore ? nshow : undefined).map((diagnosis) => - diagnosis.id === consultationData.icd11_principal_diagnosis ? ( -
-

{diagnosis.label}

-
- - - -
-
- ) : ( -

{diagnosis.label}

- ) - )} - {diagnoses.length > nshow && ( - <> - {!showMore ? ( - setShowMore(true)} - className="cursor-pointer text-sm text-blue-600 hover:text-blue-300" - > - show more - - ) : ( - setShowMore(false)} - className="cursor-pointer text-sm text-blue-600 hover:text-blue-300" - > - show less - - )} - - )} -
- ) : null; - }; + // const ShowDiagnosis = ({ + // diagnoses = [], + // label = "Diagnosis", + // nshow = 2, + // }: { + // diagnoses: ICD11DiagnosisModel[] | undefined; + // label: string; + // nshow?: number; + // }) => { + // const [showMore, setShowMore] = useState(false); + + // return diagnoses.length ? ( + //
+ //

{label}

+ // {diagnoses.slice(0, !showMore ? nshow : undefined).map((diagnosis) => + // diagnosis.id === consultationData.icd11_principal_diagnosis ? ( + //
+ //

{diagnosis.label}

+ //
+ // + // + // + //
+ //
+ // ) : ( + //

{diagnosis.label}

+ // ) + // )} + // {diagnoses.length > nshow && ( + // <> + // {!showMore ? ( + // setShowMore(true)} + // className="cursor-pointer text-sm text-blue-600 hover:text-blue-300" + // > + // show more + // + // ) : ( + // setShowMore(false)} + // className="cursor-pointer text-sm text-blue-600 hover:text-blue-300" + // > + // show less + // + // )} + // + // )} + //
+ // ) : null; + // }; return (
@@ -415,22 +414,12 @@ export const ConsultationDetails = (props: any) => {
)*/} - - - + /> */} {(consultationData.verified_by_object || consultationData.deprecated_verified_by) && ( diff --git a/src/Components/Facility/TreatmentSummary.tsx b/src/Components/Facility/TreatmentSummary.tsx index 3fbd80ac8b2..674c161428d 100644 --- a/src/Components/Facility/TreatmentSummary.tsx +++ b/src/Components/Facility/TreatmentSummary.tsx @@ -236,13 +236,6 @@ const TreatmentSummary = (props: any) => { : " ---"} -
- Diagnosis : - {consultationData.diagnosis - ? consultationData.diagnosis - : " ---"} -
-
Physical Examination info : {dailyRounds.physical_examination_info diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index f5ddde19d2d..94e31820556 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -3,6 +3,10 @@ import { ProcedureType } from "../Common/prescription-builder/ProcedureBuilder"; import { NormalPrescription, PRNPrescription } from "../Medicine/models"; import { AssetData } from "../Assets/AssetTypes"; import { UserBareMinimum } from "../Users/models"; +import { + ConsultationCreateDignosis, + ConsultationDiagnosis, +} from "../Diagnosis/types"; export interface LocalBodyModel { name: string; @@ -113,10 +117,8 @@ export interface ConsultationModel { consultation_status?: number; is_kasp?: boolean; kasp_enabled_date?: string; - diagnosis?: string; - icd11_diagnoses_object?: ICD11DiagnosisModel[]; - icd11_provisional_diagnoses_object?: ICD11DiagnosisModel[]; - icd11_principal_diagnosis?: ICD11DiagnosisModel["id"]; + readonly diagnoses?: ConsultationDiagnosis[]; + create_diagnoses?: ConsultationCreateDignosis[]; // Used for bulk creating diagnoses upon consultation creation deprecated_verified_by?: string; verified_by?: string; verified_by_object?: UserBareMinimum; @@ -222,10 +224,3 @@ export interface CurrentBed { end_date: string; meta: Record; } - -// Voluntarily made as `type` for it to achieve type-safety when used with -// `useAsyncOptions` -export type ICD11DiagnosisModel = { - id: string; - label: string; -}; diff --git a/src/Components/Shifting/ShiftDetails.tsx b/src/Components/Shifting/ShiftDetails.tsx index 7bffe429960..d34551c76e7 100644 --- a/src/Components/Shifting/ShiftDetails.tsx +++ b/src/Components/Shifting/ShiftDetails.tsx @@ -454,20 +454,13 @@ export default function ShiftDetails(props: { id: string }) {
-
+ {/*
{t("diagnosis")}:{" "} {consultation.diagnosis || "-"}
-
- - {/*
-
- Comorbidities (if any): - {consultation.diagnosis || '-'} -
*/}
diff --git a/src/Redux/actions.tsx b/src/Redux/actions.tsx index 1d2d6f4f7b6..9a48a02ff87 100644 --- a/src/Redux/actions.tsx +++ b/src/Redux/actions.tsx @@ -791,8 +791,8 @@ export const editInvestigation = ( }; // ICD11 -export const listICD11Diagnosis = (params: object, key: string) => { - return fireRequest("listICD11Diagnosis", [], params, null, key); +export const listICD11Diagnosis = (params: object) => { + return fireRequest("listICD11Diagnosis", [], params, null); }; // Medibase export const listMedibaseMedicines = ( From aec3be2910e4fa9dd1bec9ef418227c82966c3d1 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 15:00:31 +0530 Subject: [PATCH 03/22] Add API routes --- src/Components/Diagnosis/routes.ts | 41 ++++++++++++++++++++++++++++++ src/Redux/api.tsx | 3 ++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/Components/Diagnosis/routes.ts diff --git a/src/Components/Diagnosis/routes.ts b/src/Components/Diagnosis/routes.ts new file mode 100644 index 00000000000..0bd43b38b2d --- /dev/null +++ b/src/Components/Diagnosis/routes.ts @@ -0,0 +1,41 @@ +import { Type } from "../../Redux/api"; +import { PaginatedResponse } from "../../Utils/request/types"; +import { ConsultationDiagnosis, CreateDiagnosis } from "./types"; + +const DiagnosesRoutes = { + // ICD-11 + searchICD11Diagnoses: { + path: "/api/v1/icd/", + }, + + // Consultation Diagnoses + listConsultationDiagnoses: { + path: "/api/v1/consultation/{consultation}/diagnoses/", + TRes: Type>(), + }, + + createConsultationDiagnosis: { + path: "/api/v1/consultation/{consultation}/diagnoses/", + TBody: Type(), + }, + + getConsultationDiagnosis: { + path: "/api/v1/consultation/{consultation}/diagnoses/{id}/", + TRes: Type(), + }, + + updateConsultationDiagnosis: { + path: "/api/v1/consultation/{consultation}/diagnoses/{id}/", + method: "PATCH", + TBody: Type>(), + TRes: Type(), + }, + + toggleIsPrincipalConsultationDiagnosis: { + path: "/api/v1/consultation/{consultation}/diagnoses/{id}/toggle_is_principal/", + method: "POST", + TRes: Type>(), + }, +}; + +export default DiagnosesRoutes; diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index 104fa0c0c75..e34b090d6a5 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -28,6 +28,7 @@ import { AssetUpdate, } from "../Components/Assets/AssetTypes"; import { + ConsultationModel, FacilityModel, LocationModel, WardModel, @@ -49,7 +50,7 @@ import { PaginatedResponse } from "../Utils/request/types"; * A fake function that returns an empty object casted to type T * @returns Empty object as type T */ -function Type(): T { +export function Type(): T { return {} as T; } From 6abdcd6c47509e352324684bde055cea5b10bf95 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 15:03:59 +0530 Subject: [PATCH 04/22] remove old diagnoses from Consultation Form --- .../Common/DiagnosisSelectFormField.tsx | 45 ----- src/Components/Facility/ConsultationForm.tsx | 180 ++++++++---------- src/Components/Facility/models.tsx | 8 +- 3 files changed, 82 insertions(+), 151 deletions(-) delete mode 100644 src/Components/Common/DiagnosisSelectFormField.tsx diff --git a/src/Components/Common/DiagnosisSelectFormField.tsx b/src/Components/Common/DiagnosisSelectFormField.tsx deleted file mode 100644 index 4086664d4ba..00000000000 --- a/src/Components/Common/DiagnosisSelectFormField.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useAsyncOptions } from "../../Common/hooks/useAsyncOptions"; -import { listICD11Diagnosis } from "../../Redux/actions"; -import { ICD11DiagnosisModel } from "../Facility/models"; -import { AutocompleteMutliSelect } from "../Form/FormFields/AutocompleteMultiselect"; -import FormField from "../Form/FormFields/FormField"; -import { - FormFieldBaseProps, - useFormFieldPropsResolver, -} from "../Form/FormFields/Utils"; - -type Props = - // | ({ multiple?: false | undefined } & FormFieldBaseProps) // uncomment when single select form field is required and implemented. - { multiple: true } & FormFieldBaseProps; - -export function DiagnosisSelectFormField(props: Props) { - const field = useFormFieldPropsResolver(props); - const { fetchOptions, isLoading, options } = - useAsyncOptions("id"); - - if (!props.multiple) { - return ( -
- Component not implemented -
- ); - } - - return ( - - option.label} - optionValue={(option) => option} - onQuery={(query) => - fetchOptions(listICD11Diagnosis({ query }, field.id || "")) - } - isLoading={isLoading} - /> - - ); -} diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 01a5f02b7b1..4d67d6c499f 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -1,6 +1,6 @@ import * as Notification from "../../Utils/Notifications.js"; -import { BedModel, FacilityModel, ICD11DiagnosisModel } from "./models"; +import { BedModel, FacilityModel } from "./models"; import { CONSULTATION_STATUS, CONSULTATION_SUGGESTION, @@ -38,7 +38,6 @@ import Beds from "./Consultations/Beds"; import CareIcon from "../../CAREUI/icons/CareIcon"; import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField"; import DateFormField from "../Form/FormFields/DateFormField"; -import { DiagnosisSelectFormField } from "../Common/DiagnosisSelectFormField"; import { FacilitySelect } from "../Common/FacilitySelect"; import { FieldChangeEvent, @@ -60,7 +59,10 @@ import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import useVisibility from "../../Utils/useVisibility"; import dayjs from "../../Utils/dayjs"; -import AutocompleteFormField from "../Form/FormFields/Autocomplete.js"; +import { + ConsultationCreateDignosis, + ConsultationDiagnosis, +} from "../Diagnosis/types.js"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -82,9 +84,8 @@ type FormDetails = { discharge_date: null; referred_to?: string; referred_to_external?: string; - icd11_diagnoses_object: ICD11DiagnosisModel[]; - icd11_provisional_diagnoses_object: ICD11DiagnosisModel[]; - icd11_principal_diagnosis?: ICD11DiagnosisModel["id"]; + create_diagnoses: ConsultationCreateDignosis[]; + readonly diagnoses: ConsultationDiagnosis[]; verified_by: string; verified_by_object: UserModel | null; is_kasp: BooleanStrings; @@ -128,9 +129,8 @@ const initForm: FormDetails = { discharge_date: null, referred_to: "", referred_to_external: "", - icd11_diagnoses_object: [], - icd11_provisional_diagnoses_object: [], - icd11_principal_diagnosis: undefined, + create_diagnoses: [], + diagnoses: [], verified_by: "", verified_by_object: null, is_kasp: "false", @@ -328,14 +328,14 @@ export const ConsultationForm = (props: any) => { event.name === "icd11_diagnoses_object" || event.name === "icd11_provisional_diagnoses_object" ) { - dispatch({ - type: "set_form", - form: { - ...state.form, - [event.name]: event.value, - icd11_principal_diagnosis: undefined, - }, - }); + // dispatch({ + // type: "set_form", + // form: { + // ...state.form, + // [event.name]: event.value, + // icd11_principal_diagnosis: undefined, + // }, + // }); } else { dispatch({ type: "set_form", @@ -588,57 +588,57 @@ export const ConsultationForm = (props: any) => { return; } - case "icd11_provisional_diagnoses_object": { - if ( - state.form[field].length === 0 && - state.form["icd11_diagnoses_object"].length === 0 - ) { - for (const err_field of [field, "icd11_diagnoses_object"]) - errors[err_field] = - "Please select either Provisional Diagnosis or Final Diagnosis"; - invalidForm = true; - break; - } - return; - } - - case "icd11_principal_diagnosis": { - if (!state.form[field]) { - errors[field] = "Please select Principal Diagnosis"; - invalidForm = true; - break; - } - - if ( - state.form[field] && - state.form["icd11_diagnoses_object"].length && - !state.form["icd11_provisional_diagnoses_object"] && - !state.form["icd11_diagnoses_object"] - .map((d) => d.id) - .includes(state.form[field]!) - ) { - errors[field] = - "Please select Principal Diagnosis from Final Diagnosis"; - invalidForm = true; - break; - } - - if ( - state.form[field] && - state.form["icd11_provisional_diagnoses_object"].length && - !state.form["icd11_diagnoses_object"] && - !state.form["icd11_provisional_diagnoses_object"] - .map((d) => d.id) - .includes(state.form[field]!) - ) { - errors[field] = - "Please select Principal Diagnosis from Provisional Diagnosis"; - invalidForm = true; - break; - } - - return; - } + // case "icd11_provisional_diagnoses_object": { + // if ( + // state.form[field].length === 0 && + // state.form["icd11_diagnoses_object"].length === 0 + // ) { + // for (const err_field of [field, "icd11_diagnoses_object"]) + // errors[err_field] = + // "Please select either Provisional Diagnosis or Final Diagnosis"; + // invalidForm = true; + // break; + // } + // return; + // } + + // case "icd11_principal_diagnosis": { + // if (!state.form[field]) { + // errors[field] = "Please select Principal Diagnosis"; + // invalidForm = true; + // break; + // } + + // if ( + // state.form[field] && + // state.form["icd11_diagnoses_object"].length && + // !state.form["icd11_provisional_diagnoses_object"] && + // !state.form["icd11_diagnoses_object"] + // .map((d) => d.id) + // .includes(state.form[field]!) + // ) { + // errors[field] = + // "Please select Principal Diagnosis from Final Diagnosis"; + // invalidForm = true; + // break; + // } + + // if ( + // state.form[field] && + // state.form["icd11_provisional_diagnoses_object"].length && + // !state.form["icd11_diagnoses_object"] && + // !state.form["icd11_provisional_diagnoses_object"] + // .map((d) => d.id) + // .includes(state.form[field]!) + // ) { + // errors[field] = + // "Please select Principal Diagnosis from Provisional Diagnosis"; + // invalidForm = true; + // break; + // } + + // return; + // } default: return; @@ -714,14 +714,14 @@ export const ConsultationForm = (props: any) => { treatment_plan: state.form.treatment_plan, discharge_date: state.form.discharge_date, patient_no: state.form.patient_no, - icd11_diagnoses: state.form.icd11_diagnoses_object.map( - (o: ICD11DiagnosisModel) => o.id - ), - icd11_provisional_diagnoses: - state.form.icd11_provisional_diagnoses_object.map( - (o: ICD11DiagnosisModel) => o.id - ), - icd11_principal_diagnosis: state.form.icd11_principal_diagnosis, + // icd11_diagnoses: state.form.icd11_diagnoses_object.map( + // (o: ICD11DiagnosisModel) => o.id + // ), + // icd11_provisional_diagnoses: + // state.form.icd11_provisional_diagnoses_object.map( + // (o: ICD11DiagnosisModel) => o.id + // ), + // icd11_principal_diagnosis: state.form.icd11_principal_diagnosis, verified_by: state.form.verified_by, investigation: state.form.InvestigationAdvice, procedure: state.form.procedures, @@ -1198,37 +1198,13 @@ export const ConsultationForm = (props: any) => {

-
+ {/*
-
- -
- -
- -
- option.label} - optionValue={(option) => option.id} - required - /> -
+
*/}
diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index 94e31820556..d2173f2f9fa 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -56,10 +56,10 @@ export interface FacilityModel { ward_object?: WardModel; modified_date?: string; created_date?: string; - state: number; - district: number; - local_body: number; - ward: number; + state?: number; + district?: number; + local_body?: number; + ward?: number; } export interface CapacityModal { From edca688e6c4276c0b1f29d7e9796dbd7b19150be Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 15:08:04 +0530 Subject: [PATCH 05/22] Add component: `AddICD11Diagnosis` --- .../AddICD11Diagnosis.tsx | 87 +++++++++++++++++++ src/Locale/en/Diagnosis.json | 4 + src/Locale/en/index.js | 2 + 3 files changed, 93 insertions(+) create mode 100644 src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx create mode 100644 src/Locale/en/Diagnosis.json diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx new file mode 100644 index 00000000000..6610911eb21 --- /dev/null +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -0,0 +1,87 @@ +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import AutocompleteFormField from "../../Form/FormFields/Autocomplete"; +import { + ActiveConditionVerificationStatuses, + CreateDiagnosis, + ICD11DiagnosisModel, +} from "../types"; +import { FieldError } from "../../Form/FieldValidators"; +import { useAsyncOptions } from "../../../Common/hooks/useAsyncOptions"; +import { listICD11Diagnosis } from "../../../Redux/actions"; +import CareIcon from "../../../CAREUI/icons/CareIcon"; +import DropdownMenu, { DropdownItem } from "../../Common/components/Menu"; +import ConditionVerificationStatusMenu from "../ConditionVerificationStatusMenu"; + +interface AddICD11DiagnosisProps { + className?: string; + onAdd: (object: CreateDiagnosis) => Promise; + disallowed: ICD11DiagnosisModel[]; + disabled?: boolean; +} + +export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { + const { t } = useTranslation(); + const [selected, setSelected] = useState(); + const [adding, setAdding] = useState(false); + const hasError = !!props.disallowed.find((d) => d.id === selected?.id); + + const { fetchOptions, isLoading, options } = + useAsyncOptions("id"); + + const handleAdd = async (status: CreateDiagnosis["verification_status"]) => { + if (!selected) return; + + setAdding(true); + const added = await props.onAdd({ + diagnosis: selected.id, + verification_status: status, + }); + setAdding(false); + + if (added) { + setSelected(undefined); + } + }; + + return ( +
+
+ setSelected(e.value)} + options={options(selected ? [selected] : undefined)} + optionLabel={(option) => option.label} + optionValue={(option) => option} + onQuery={(query) => fetchOptions(listICD11Diagnosis({ query }))} + isLoading={isLoading} + error={hasError ? t("diagnosis_already_added") : undefined} + /> + handleAdd(status)} + /> + } + > + {ActiveConditionVerificationStatuses.map((status) => ( + handleAdd(status)} + icon={} + > + Add as {t(status)} + + ))} + +
+
+ ); +} diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json new file mode 100644 index 00000000000..ab636fe5e00 --- /dev/null +++ b/src/Locale/en/Diagnosis.json @@ -0,0 +1,4 @@ +{ + "diagnosis_already_added": "This diagnosis was already added", + "add_diagnosis": "Add diagnosis" +} \ No newline at end of file diff --git a/src/Locale/en/index.js b/src/Locale/en/index.js index 950b441ba84..781ce97b009 100644 --- a/src/Locale/en/index.js +++ b/src/Locale/en/index.js @@ -14,6 +14,7 @@ import Resource from "./Resource.json"; import SortOptions from "./SortOptions.json"; import Bed from "./Bed.json"; import Medicine from "./Medicine.json"; +import Diagnosis from "./Diagnosis.json"; export default { ...Auth, @@ -27,6 +28,7 @@ export default { ...Facility, ...Hub, ...Medicine, + ...Diagnosis, ...Notifications, ...Resource, ...Shifting, From 9b8f805de11159414c9bbe7b365e1f38e637143d Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 15:09:36 +0530 Subject: [PATCH 06/22] Add component: `ConditionVerificationStatusMenu` --- .../ConditionVerificationStatusMenu.tsx | 68 +++++++++++++++++++ src/Locale/en/Common.json | 4 +- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx diff --git a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx new file mode 100644 index 00000000000..ce601e150fd --- /dev/null +++ b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx @@ -0,0 +1,68 @@ +import { useTranslation } from "react-i18next"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import DropdownMenu, { DropdownItem } from "../Common/components/Menu"; +import { ConditionVerificationStatus } from "./types"; + +interface Props { + className?: string; + disabled?: boolean; + value?: T; + placeholder?: string; + options: readonly T[]; + onSelect: (option: T) => void; + onRemove?: () => void; +} + +export default function ConditionVerificationStatusMenu< + T extends ConditionVerificationStatus +>({ placeholder = "Add diagnosis", ...props }: Props) { + const { t } = useTranslation(); + + return ( + } + disabled={props.disabled} + > + <> + {props.options.map((status) => ( + props.onSelect(status)} + icon={ + + } + disabled={props.value === status} + > + + {t(status)} + + + ))} + + {props.value && props.onRemove && ( + props.onRemove?.()} + icon={} + > + {t("remove")} + + )} + + + ); +} + +const StatusStyle = { + unconfirmed: { variant: "warning", icon: "l-question" }, + provisional: { variant: "warning", icon: "l-question" }, + differential: { variant: "warning", icon: "l-question" }, + confirmed: { variant: "primary", icon: "l-check" }, + refuted: { variant: "danger", icon: "l-times" }, + "entered-in-error": { variant: "danger", icon: "l-ban" }, +} as const; diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index 5f71583abd7..2f64d286f72 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -112,6 +112,7 @@ "select": "Select", "lsg": "Lsg", "delete": "Delete", + "remove": "Remove", "max_size_for_image_uploaded_should_be": "Max size for image uploaded should be", "allowed_formats_are": "Allowed formats are", "recommended_aspect_ratio_for": "Recommended aspect ratio for", @@ -153,5 +154,4 @@ "no_data_found": "No data found", "edit": "Edit", "clear_selection": "Clear selection" -} - +} \ No newline at end of file From 85fba654319f49ffb4480a285c76efa8ee667894 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 15:38:42 +0530 Subject: [PATCH 07/22] uncomplicate things --- src/Components/Diagnosis/routes.ts | 8 +------- src/Components/Diagnosis/types.ts | 3 --- src/Components/Facility/ConsultationForm.tsx | 7 ++----- src/Components/Facility/models.tsx | 7 ++----- 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/Components/Diagnosis/routes.ts b/src/Components/Diagnosis/routes.ts index 0bd43b38b2d..9f1a972b6fa 100644 --- a/src/Components/Diagnosis/routes.ts +++ b/src/Components/Diagnosis/routes.ts @@ -27,15 +27,9 @@ const DiagnosesRoutes = { updateConsultationDiagnosis: { path: "/api/v1/consultation/{consultation}/diagnoses/{id}/", method: "PATCH", - TBody: Type>(), + TBody: Type>(), TRes: Type(), }, - - toggleIsPrincipalConsultationDiagnosis: { - path: "/api/v1/consultation/{consultation}/diagnoses/{id}/toggle_is_principal/", - method: "POST", - TRes: Type>(), - }, }; export default DiagnosesRoutes; diff --git a/src/Components/Diagnosis/types.ts b/src/Components/Diagnosis/types.ts index 0b843aee866..a9645c134b0 100644 --- a/src/Components/Diagnosis/types.ts +++ b/src/Components/Diagnosis/types.ts @@ -40,8 +40,5 @@ export interface CreateDiagnosis { diagnosis: ICD11DiagnosisModel["id"]; diagnosis_object?: ICD11DiagnosisModel; verification_status: (typeof ActiveConditionVerificationStatuses)[number]; -} - -export interface ConsultationCreateDignosis extends CreateDiagnosis { is_principal: boolean; } diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 4d67d6c499f..f58f6f26b6b 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -59,10 +59,7 @@ import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import useVisibility from "../../Utils/useVisibility"; import dayjs from "../../Utils/dayjs"; -import { - ConsultationCreateDignosis, - ConsultationDiagnosis, -} from "../Diagnosis/types.js"; +import { ConsultationDiagnosis, CreateDiagnosis } from "../Diagnosis/types.js"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -84,7 +81,7 @@ type FormDetails = { discharge_date: null; referred_to?: string; referred_to_external?: string; - create_diagnoses: ConsultationCreateDignosis[]; + create_diagnoses: CreateDiagnosis[]; readonly diagnoses: ConsultationDiagnosis[]; verified_by: string; verified_by_object: UserModel | null; diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index d2173f2f9fa..bd0f4eafeda 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -3,10 +3,7 @@ import { ProcedureType } from "../Common/prescription-builder/ProcedureBuilder"; import { NormalPrescription, PRNPrescription } from "../Medicine/models"; import { AssetData } from "../Assets/AssetTypes"; import { UserBareMinimum } from "../Users/models"; -import { - ConsultationCreateDignosis, - ConsultationDiagnosis, -} from "../Diagnosis/types"; +import { ConsultationDiagnosis, CreateDiagnosis } from "../Diagnosis/types"; export interface LocalBodyModel { name: string; @@ -118,7 +115,7 @@ export interface ConsultationModel { is_kasp?: boolean; kasp_enabled_date?: string; readonly diagnoses?: ConsultationDiagnosis[]; - create_diagnoses?: ConsultationCreateDignosis[]; // Used for bulk creating diagnoses upon consultation creation + create_diagnoses?: CreateDiagnosis[]; // Used for bulk creating diagnoses upon consultation creation deprecated_verified_by?: string; verified_by?: string; verified_by_object?: UserBareMinimum; From cb79d42ef24d513f70a115e5efceb8a0b4d149eb Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 18:10:24 +0530 Subject: [PATCH 08/22] Add component `ConsultationDiangosisEntry` --- .../AddICD11Diagnosis.tsx | 2 + .../ConsultationDiagnosisEntry.tsx | 133 ++++++++++++++++++ src/Components/Diagnosis/routes.ts | 2 +- src/Locale/en/Diagnosis.json | 4 +- 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx index 6610911eb21..02ef4ebc70f 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -34,8 +34,10 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { setAdding(true); const added = await props.onAdd({ + diagnosis_object: selected, diagnosis: selected.id, verification_status: status, + is_principal: false, }); setAdding(false); diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx new file mode 100644 index 00000000000..67628544d87 --- /dev/null +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx @@ -0,0 +1,133 @@ +import { useTranslation } from "react-i18next"; +import CareIcon from "../../../CAREUI/icons/CareIcon"; +import ButtonV2 from "../../Common/components/ButtonV2"; +import ConditionVerificationStatusMenu from "../ConditionVerificationStatusMenu"; +import { + ActiveConditionVerificationStatuses, + ConditionVerificationStatuses, + ConsultationDiagnosis, + CreateDiagnosis, +} from "../types"; +import DiagnosesRoutes from "../routes"; +import { useState } from "react"; +import request from "../../../Utils/request/request"; +import * as Notification from "../../../Utils/Notifications"; + +interface RemoveAction { + type: "remove"; +} + +interface EditAction { + type: "edit"; + value: CreateDiagnosis | ConsultationDiagnosis; +} + +type Action = RemoveAction | EditAction; + +interface BaseProps { + className?: string; +} + +interface ConsultationCreateProps extends BaseProps { + consultationId?: undefined; + value: CreateDiagnosis; + onChange: (action: Action) => void; +} + +interface ConsultationEditProps extends BaseProps { + consultationId: string; + value: ConsultationDiagnosis; +} + +type Props = ConsultationCreateProps | ConsultationEditProps; + +export default function ConsultationCreateDignosisEntry(props: Props) { + const { t } = useTranslation(); + const [data, setData] = useState(); + const [disabled, setDisabled] = useState(false); + + const handleUpdate = async (value: ConsultationDiagnosis) => { + setDisabled(true); + const { res, data, error } = await request( + DiagnosesRoutes.updateConsultationDiagnosis, + { + pathParams: { + consultation: props.consultationId as string, + id: value.id, + }, + } + ); + setDisabled(false); + + if (error) { + Notification.Error({ msg: error }); + } + + if (res?.ok && data) { + setData(data); + } + }; + + const object = data ?? props.value; + +
+
+
{object.diagnosis_object?.label}
+ + { + const value = { ...object, is_principal: !object.is_principal }; + + if (props.consultationId === undefined) { + props.onChange({ type: "edit", value }); + return; + } + + handleUpdate(value as ConsultationDiagnosis); + }} + > + + + + {object.is_principal + ? t("mark_as_principal") + : t("unmark_as_principal")} + + + + { + const value = { ...object, verification_status }; + + if (props.consultationId === undefined) { + props.onChange({ type: "edit", value: value as CreateDiagnosis }); + return; + } + + handleUpdate(value as ConsultationDiagnosis); + }} + onRemove={ + props.consultationId === undefined + ? () => props.onChange({ type: "remove" }) + : undefined + } + /> +
+
; +} diff --git a/src/Components/Diagnosis/routes.ts b/src/Components/Diagnosis/routes.ts index 9f1a972b6fa..a39e3a64edf 100644 --- a/src/Components/Diagnosis/routes.ts +++ b/src/Components/Diagnosis/routes.ts @@ -30,6 +30,6 @@ const DiagnosesRoutes = { TBody: Type>(), TRes: Type(), }, -}; +} as const; export default DiagnosesRoutes; diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json index ab636fe5e00..22ca75db5ee 100644 --- a/src/Locale/en/Diagnosis.json +++ b/src/Locale/en/Diagnosis.json @@ -1,4 +1,6 @@ { "diagnosis_already_added": "This diagnosis was already added", - "add_diagnosis": "Add diagnosis" + "add_diagnosis": "Add diagnosis", + "mark_as_principal": "Mark as principal", + "unmark_as_principal": "Unmark as principal" } \ No newline at end of file From a836586dfdb6113a06ed2ed8c355c66aef2c3b0a Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 18:51:51 +0530 Subject: [PATCH 09/22] Basic implementation --- .../AddICD11Diagnosis.tsx | 3 +- .../ConsultationDiagnosisBuilder.tsx | 119 ++++++++++++++++++ .../ConsultationDiagnosisEntry.tsx | 118 ++++++++--------- src/Components/Diagnosis/routes.ts | 1 + src/Components/Facility/ConsultationForm.tsx | 45 ++++--- 5 files changed, 202 insertions(+), 84 deletions(-) create mode 100644 src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx index 02ef4ebc70f..92236cdb782 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -6,7 +6,6 @@ import { CreateDiagnosis, ICD11DiagnosisModel, } from "../types"; -import { FieldError } from "../../Form/FieldValidators"; import { useAsyncOptions } from "../../../Common/hooks/useAsyncOptions"; import { listICD11Diagnosis } from "../../../Redux/actions"; import CareIcon from "../../../CAREUI/icons/CareIcon"; @@ -15,7 +14,7 @@ import ConditionVerificationStatusMenu from "../ConditionVerificationStatusMenu" interface AddICD11DiagnosisProps { className?: string; - onAdd: (object: CreateDiagnosis) => Promise; + onAdd: (object: CreateDiagnosis) => Promise; disallowed: ICD11DiagnosisModel[]; disabled?: boolean; } diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx new file mode 100644 index 00000000000..a59eefa4955 --- /dev/null +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx @@ -0,0 +1,119 @@ +import { useState } from "react"; +import useSlug from "../../../Common/hooks/useSlug"; +import { + ConsultationDiagnosis, + CreateDiagnosis, + ICD11DiagnosisModel, +} from "../types"; +import AddICD11Diagnosis from "./AddICD11Diagnosis"; +import ConsultationDiagnosisEntry from "./ConsultationDiagnosisEntry"; +import request from "../../../Utils/request/request"; +import DiagnosesRoutes from "../routes"; +import * as Notification from "../../../Utils/Notifications"; + +interface CreateDiagnosesProps { + className?: string; + value: CreateDiagnosis[]; + onChange: (diagnoses: CreateDiagnosis[]) => void; +} + +export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { + return ( +
+
+ {props.value.map((diagnosis, index) => ( + { + if (action.type === "remove") { + const diagnoses = [...props.value]; + diagnoses.splice(index, 1); + props.onChange(diagnoses); + } + + if (action.type === "edit") { + const diagnoses = action.value.is_principal + ? props.value.map((d) => { + d.is_principal = false; + return d; + }) + : [...props.value]; + diagnoses[index] = action.value as CreateDiagnosis; + props.onChange(diagnoses); + } + }} + /> + ))} + + {props.value.length === 0 && ( +
No diagnoses added
+ )} + + obj.diagnosis_object as ICD11DiagnosisModel + )} + onAdd={async (diagnosis) => { + props.onChange([...props.value, diagnosis]); + return true; + }} + /> +
+
+ ); +}; + +interface EditDiagnosesProps { + className?: string; + value: ConsultationDiagnosis[]; +} + +export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { + const consultation = useSlug("consultation"); + const [diagnoses, setDiagnoses] = useState(props.value); + + return ( +
+
+ {diagnoses.map((diagnosis, index) => ( + + ))} + + {diagnoses.length === 0 && ( +
No diagnoses added
+ )} + + obj.diagnosis_object as ICD11DiagnosisModel + )} + onAdd={async (diagnosis) => { + const { res, data, error } = await request( + DiagnosesRoutes.createConsultationDiagnosis, + { + pathParams: { consultation }, + body: diagnosis, + } + ); + + if (res?.ok && data) { + setDiagnoses([...diagnoses, data]); + return true; + } + + if (error) { + Notification.Error({ msg: error }); + } + + return false; + }} + /> +
+
+ ); +}; diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx index 67628544d87..78024f20f62 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx @@ -41,7 +41,7 @@ interface ConsultationEditProps extends BaseProps { type Props = ConsultationCreateProps | ConsultationEditProps; -export default function ConsultationCreateDignosisEntry(props: Props) { +export default function ConsultationDiagnosisEntry(props: Props) { const { t } = useTranslation(); const [data, setData] = useState(); const [disabled, setDisabled] = useState(false); @@ -70,64 +70,66 @@ export default function ConsultationCreateDignosisEntry(props: Props) { const object = data ?? props.value; -
-
-
{object.diagnosis_object?.label}
- - { - const value = { ...object, is_principal: !object.is_principal }; - - if (props.consultationId === undefined) { - props.onChange({ type: "edit", value }); - return; + return ( +
+
+
{object.diagnosis_object?.label}
+ + { + const value = { ...object, is_principal: !object.is_principal }; + + if (props.consultationId === undefined) { + props.onChange({ type: "edit", value }); + return; + } + + handleUpdate(value as ConsultationDiagnosis); + }} + > + + + + {object.is_principal + ? t("mark_as_principal") + : t("unmark_as_principal")} + + + + - - - - {object.is_principal - ? t("mark_as_principal") - : t("unmark_as_principal")} - - - - { - const value = { ...object, verification_status }; - - if (props.consultationId === undefined) { - props.onChange({ type: "edit", value: value as CreateDiagnosis }); - return; + onSelect={(verification_status) => { + const value = { ...object, verification_status }; + + if (props.consultationId === undefined) { + props.onChange({ type: "edit", value: value as CreateDiagnosis }); + return; + } + + handleUpdate(value as ConsultationDiagnosis); + }} + onRemove={ + props.consultationId === undefined + ? () => props.onChange({ type: "remove" }) + : undefined } - - handleUpdate(value as ConsultationDiagnosis); - }} - onRemove={ - props.consultationId === undefined - ? () => props.onChange({ type: "remove" }) - : undefined - } - /> + /> +
-
; + ); } diff --git a/src/Components/Diagnosis/routes.ts b/src/Components/Diagnosis/routes.ts index a39e3a64edf..f2ab4a808c3 100644 --- a/src/Components/Diagnosis/routes.ts +++ b/src/Components/Diagnosis/routes.ts @@ -17,6 +17,7 @@ const DiagnosesRoutes = { createConsultationDiagnosis: { path: "/api/v1/consultation/{consultation}/diagnoses/", TBody: Type(), + TRes: Type(), }, getConsultationDiagnosis: { diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index f58f6f26b6b..89bd0581552 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -60,6 +60,10 @@ import { useDispatch } from "react-redux"; import useVisibility from "../../Utils/useVisibility"; import dayjs from "../../Utils/dayjs"; import { ConsultationDiagnosis, CreateDiagnosis } from "../Diagnosis/types.js"; +import { + CreateDiagnosesBuilder, + EditDiagnosesBuilder, +} from "../Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.js"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -82,7 +86,7 @@ type FormDetails = { referred_to?: string; referred_to_external?: string; create_diagnoses: CreateDiagnosis[]; - readonly diagnoses: ConsultationDiagnosis[]; + diagnoses: ConsultationDiagnosis[]; verified_by: string; verified_by_object: UserModel | null; is_kasp: BooleanStrings; @@ -321,18 +325,6 @@ export const ConsultationForm = (props: any) => { verified_by: "Declared Dead", }, }); - } else if ( - event.name === "icd11_diagnoses_object" || - event.name === "icd11_provisional_diagnoses_object" - ) { - // dispatch({ - // type: "set_form", - // form: { - // ...state.form, - // [event.name]: event.value, - // icd11_principal_diagnosis: undefined, - // }, - // }); } else { dispatch({ type: "set_form", @@ -1188,20 +1180,25 @@ export const ConsultationForm = (props: any) => {
{sectionTitle("Diagnosis", true)}

- - Either Provisional or Final Diagnosis is mandatory - - | Diagnoses as per ICD-11 recommended by WHO + Diagnoses as per ICD-11 recommended by WHO

- {/*
- -
*/} +
+ {isUpdate ? ( + + ) : ( + { + handleFormFieldChange({ + name: "create_diagnoses", + value: diagnoses, + }); + }} + /> + )} +
From 8c5abe288da888c7060827453afdb9e2172a7504 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 22:01:50 +0530 Subject: [PATCH 10/22] i have no idea what these are, but lots of bugs gone --- src/Components/Common/components/Menu.tsx | 2 +- .../ConditionVerificationStatusMenu.tsx | 16 +++-- .../AddICD11Diagnosis.tsx | 66 ++++++++----------- .../ConsultationDiagnosisEntry.tsx | 36 ++++++---- src/Components/Diagnosis/routes.ts | 3 +- src/Locale/en/Diagnosis.json | 11 +++- 6 files changed, 73 insertions(+), 61 deletions(-) diff --git a/src/Components/Common/components/Menu.tsx b/src/Components/Common/components/Menu.tsx index 49ee02b393e..b9de8db9dd6 100644 --- a/src/Components/Common/components/Menu.tsx +++ b/src/Components/Common/components/Menu.tsx @@ -30,7 +30,7 @@ export default function DropdownMenu({ disabled={props.disabled} className={`button-size-default button-${variant}-default button-shape-square flex w-full cursor-pointer items-center justify-center gap-2 font-medium outline-offset-1 transition-all duration-200 ease-in-out disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-500 lg:justify-between ${props.className}`} > -
+
{props.icon} {props.title || "Dropdown"}
diff --git a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx index ce601e150fd..42bdff7f1a3 100644 --- a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx +++ b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx @@ -4,26 +4,34 @@ import DropdownMenu, { DropdownItem } from "../Common/components/Menu"; import { ConditionVerificationStatus } from "./types"; interface Props { - className?: string; disabled?: boolean; value?: T; placeholder?: string; options: readonly T[]; onSelect: (option: T) => void; onRemove?: () => void; + className?: string; } export default function ConditionVerificationStatusMenu< T extends ConditionVerificationStatus ->({ placeholder = "Add diagnosis", ...props }: Props) { +>(props: Props) { const { t } = useTranslation(); return ( } + title={props.value ? t(props.value) : props.placeholder ?? t("add")} + icon={ + props.value ? ( + + ) : ( + + ) + } disabled={props.disabled} + variant={props.value ? StatusStyle[props.value].variant : "primary"} > <> {props.options.map((status) => ( diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx index 92236cdb782..6866a5f8724 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -8,9 +8,8 @@ import { } from "../types"; import { useAsyncOptions } from "../../../Common/hooks/useAsyncOptions"; import { listICD11Diagnosis } from "../../../Redux/actions"; -import CareIcon from "../../../CAREUI/icons/CareIcon"; -import DropdownMenu, { DropdownItem } from "../../Common/components/Menu"; import ConditionVerificationStatusMenu from "../ConditionVerificationStatusMenu"; +import { classNames } from "../../../Utils/utils"; interface AddICD11DiagnosisProps { className?: string; @@ -46,43 +45,32 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { }; return ( -
-
- setSelected(e.value)} - options={options(selected ? [selected] : undefined)} - optionLabel={(option) => option.label} - optionValue={(option) => option} - onQuery={(query) => fetchOptions(listICD11Diagnosis({ query }))} - isLoading={isLoading} - error={hasError ? t("diagnosis_already_added") : undefined} - /> - handleAdd(status)} - /> - } - > - {ActiveConditionVerificationStatuses.map((status) => ( - handleAdd(status)} - icon={} - > - Add as {t(status)} - - ))} - -
+
+ setSelected(e.value)} + options={options(selected ? [selected] : undefined)} + optionLabel={(option) => option.label} + optionValue={(option) => option} + onQuery={(query) => fetchOptions(listICD11Diagnosis({ query }))} + isLoading={isLoading} + error={hasError ? t("diagnosis_already_added") : undefined} + /> + handleAdd(status)} + />
); } diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx index 78024f20f62..aae3f0432e0 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx @@ -11,7 +11,7 @@ import { import DiagnosesRoutes from "../routes"; import { useState } from "react"; import request from "../../../Utils/request/request"; -import * as Notification from "../../../Utils/Notifications"; +import { classNames } from "../../../Utils/utils"; interface RemoveAction { type: "remove"; @@ -48,21 +48,18 @@ export default function ConsultationDiagnosisEntry(props: Props) { const handleUpdate = async (value: ConsultationDiagnosis) => { setDisabled(true); - const { res, data, error } = await request( + const { res, data } = await request( DiagnosesRoutes.updateConsultationDiagnosis, { pathParams: { consultation: props.consultationId as string, id: value.id, }, + body: value, } ); setDisabled(false); - if (error) { - Notification.Error({ msg: error }); - } - if (res?.ok && data) { setData(data); } @@ -71,12 +68,21 @@ export default function ConsultationDiagnosisEntry(props: Props) { const object = data ?? props.value; return ( -
-
-
{object.diagnosis_object?.label}
+
+
+ {object.diagnosis_object?.label} - + {object.is_principal - ? t("mark_as_principal") - : t("unmark_as_principal")} + ? t("principal_diagnosis") + : t("mark_as_principal")} +
+
(), TRes: Type(), }, @@ -28,7 +29,7 @@ const DiagnosesRoutes = { updateConsultationDiagnosis: { path: "/api/v1/consultation/{consultation}/diagnoses/{id}/", method: "PATCH", - TBody: Type>(), + TBody: Type>(), TRes: Type(), }, } as const; diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json index 22ca75db5ee..70f86a1fee0 100644 --- a/src/Locale/en/Diagnosis.json +++ b/src/Locale/en/Diagnosis.json @@ -1,6 +1,13 @@ { "diagnosis_already_added": "This diagnosis was already added", - "add_diagnosis": "Add diagnosis", + "principal_diagnosis": "Principal diagnosis", "mark_as_principal": "Mark as principal", - "unmark_as_principal": "Unmark as principal" + "unmark_as_principal": "Unmark as principal", + "unconfirmed": "Unconfirmed", + "provisional": "Provisional", + "differential": "Differential", + "confirmed": "Confirmed", + "refuted": "Refuted", + "entered-in-error": "Entered in error", + "search_icd11_placeholder": "Search for ICD-11 Diagnoses" } \ No newline at end of file From 019a272ce3135402659e97ee8fac48cfed20b061 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 23:36:31 +0530 Subject: [PATCH 11/22] goodnight for today --- src/Components/Common/components/Menu.tsx | 11 +- .../Common/components/SelectMenu.tsx | 125 --------------- .../ConditionVerificationStatusMenu.tsx | 73 ++++++--- .../AddICD11Diagnosis.tsx | 2 + .../ConsultationDiagnosisBuilder.tsx | 150 ++++++++++-------- .../ConsultationDiagnosisEntry.tsx | 138 +++++++++------- src/Components/Form/SelectMenuV2.tsx | 2 +- src/Locale/en/Common.json | 1 + 8 files changed, 224 insertions(+), 278 deletions(-) delete mode 100644 src/Components/Common/components/SelectMenu.tsx diff --git a/src/Components/Common/components/Menu.tsx b/src/Components/Common/components/Menu.tsx index b9de8db9dd6..7914864d1aa 100644 --- a/src/Components/Common/components/Menu.tsx +++ b/src/Components/Common/components/Menu.tsx @@ -1,6 +1,6 @@ import { Anyone, AuthorizedElementProps } from "../../../Utils/AuthorizeFor"; -import { ButtonVariant } from "./ButtonV2"; +import { ButtonSize, ButtonVariant } from "./ButtonV2"; import CareIcon from "../../../CAREUI/icons/CareIcon"; import { DropdownTransition } from "./HelperComponents"; import { Menu } from "@headlessui/react"; @@ -12,6 +12,7 @@ interface DropdownMenuProps { id?: string; title: string; variant?: ButtonVariant; + size?: ButtonSize; icon?: JSX.Element | undefined; children: JSX.Element | JSX.Element[]; disabled?: boolean | undefined; @@ -21,6 +22,7 @@ interface DropdownMenuProps { export default function DropdownMenu({ variant = "primary", + size = "default", ...props }: DropdownMenuProps) { return ( @@ -28,13 +30,16 @@ export default function DropdownMenu({
{props.icon} {props.title || "Dropdown"}
- +
= { - options: { - title: string; - description?: string; - value: T; - }[]; - onSelect: (value: T) => void; - selected?: T; - label?: string; - position?: string; - parentRelative?: boolean; -}; - -/** Deprecated. Use SelectMenuV2. */ -export default function SelectMenu(props: Props) { - const options = props.options.map((option) => { - return { - ...option, - current: option.value === props.selected, - }; - }); - - const selected = options.find((option) => option.current) || options[0]; - - return ( - { - props.onSelect(selection.value); - }} - > - {({ open }) => ( - <> - {props.label} -
- -
-
- {selected.value && ( - - )} -

{selected.title}

-
-
- -
-
-
- - - - {options.map((option) => ( - - `relative cursor-default select-none p-4 text-sm transition-all duration-100 ease-in-out ${ - active ? "bg-primary-500 text-white" : "text-gray-900" - }` - } - value={option} - > - {({ selected, active }) => ( -
-
-

- {option.title} -

- {selected ? ( - - - - ) : null} -
- {option.description && ( -

- {option.description} -

- )} -
- )} -
- ))} -
-
-
- - )} -
- ); -} diff --git a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx index 42bdff7f1a3..eb60609bbaa 100644 --- a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx +++ b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx @@ -1,7 +1,12 @@ import { useTranslation } from "react-i18next"; import CareIcon from "../../CAREUI/icons/CareIcon"; import DropdownMenu, { DropdownItem } from "../Common/components/Menu"; -import { ConditionVerificationStatus } from "./types"; +import { + ConditionVerificationStatus, + InactiveConditionVerificationStatuses, +} from "./types"; +import { classNames } from "../../Utils/utils"; +import { ButtonSize } from "../Common/components/ButtonV2"; interface Props { disabled?: boolean; @@ -11,6 +16,7 @@ interface Props { onSelect: (option: T) => void; onRemove?: () => void; className?: string; + size?: ButtonSize; } export default function ConditionVerificationStatusMenu< @@ -20,16 +26,14 @@ export default function ConditionVerificationStatusMenu< return ( - ) : ( - - ) - } + title={props.value ? t(props.value) : props.placeholder ?? t("add_as")} disabled={props.disabled} variant={props.value ? StatusStyle[props.value].variant : "primary"} > @@ -40,12 +44,17 @@ export default function ConditionVerificationStatusMenu< id={`add-icd11-diagnosis-as-${status}`} variant={StatusStyle[status].variant} onClick={() => props.onSelect(status)} - icon={ - - } + // icon={ + // + // } disabled={props.value === status} > + {InactiveConditionVerificationStatuses.includes( + status as (typeof InactiveConditionVerificationStatuses)[number] + ) + ? "Remove as " + : ""} {t(status)} @@ -66,11 +75,35 @@ export default function ConditionVerificationStatusMenu< ); } -const StatusStyle = { - unconfirmed: { variant: "warning", icon: "l-question" }, - provisional: { variant: "warning", icon: "l-question" }, - differential: { variant: "warning", icon: "l-question" }, - confirmed: { variant: "primary", icon: "l-check" }, - refuted: { variant: "danger", icon: "l-times" }, - "entered-in-error": { variant: "danger", icon: "l-ban" }, +export const StatusStyle = { + unconfirmed: { + variant: "warning", + // icon: "l-question", + colors: "text-yellow-500 border-yellow-500", + }, + provisional: { + variant: "warning", + // icon: "l-question", + colors: "text-secondary-800 border-secondary-800", + }, + differential: { + variant: "warning", + // icon: "l-question", + colors: "text-secondary-800 border-secondary-800", + }, + confirmed: { + variant: "primary", + // icon: "l-check", + colors: "text-primary-500 border-primary-500", + }, + refuted: { + variant: "danger", + icon: "l-times", + colors: "text-danger-500 border-danger-500", + }, + "entered-in-error": { + variant: "danger", + // icon: "l-ban", + colors: "text-danger-500 border-danger-500", + }, } as const; diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx index 6866a5f8724..e165518f213 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -67,9 +67,11 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { error={hasError ? t("diagnosis_already_added") : undefined} /> handleAdd(status)} + size="default" />
); diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx index a59eefa4955..801265cdb54 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx @@ -20,45 +20,47 @@ interface CreateDiagnosesProps { export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { return (
-
- {props.value.map((diagnosis, index) => ( - { - if (action.type === "remove") { - const diagnoses = [...props.value]; - diagnoses.splice(index, 1); - props.onChange(diagnoses); - } +
+
+ {props.value.map((diagnosis, index) => ( + { + if (action.type === "remove") { + const diagnoses = [...props.value]; + diagnoses.splice(index, 1); + props.onChange(diagnoses); + } - if (action.type === "edit") { - const diagnoses = action.value.is_principal - ? props.value.map((d) => { - d.is_principal = false; - return d; - }) - : [...props.value]; - diagnoses[index] = action.value as CreateDiagnosis; - props.onChange(diagnoses); - } - }} - /> - ))} + if (action.type === "edit") { + const diagnoses = action.value.is_principal + ? props.value.map((d) => { + d.is_principal = false; + return d; + }) + : [...props.value]; + diagnoses[index] = action.value as CreateDiagnosis; + props.onChange(diagnoses); + } + }} + /> + ))} +
- {props.value.length === 0 && ( -
No diagnoses added
- )} + {props.value.length === 0 && } - obj.diagnosis_object as ICD11DiagnosisModel - )} - onAdd={async (diagnosis) => { - props.onChange([...props.value, diagnosis]); - return true; - }} - /> +
+ obj.diagnosis_object as ICD11DiagnosisModel + )} + onAdd={async (diagnosis) => { + props.onChange([...props.value, diagnosis]); + return true; + }} + /> +
); @@ -75,45 +77,55 @@ export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { return (
-
- {diagnoses.map((diagnosis, index) => ( - - ))} +
+
+ {diagnoses.map((diagnosis, index) => ( + + ))} +
- {diagnoses.length === 0 && ( -
No diagnoses added
- )} + {diagnoses.length === 0 && } - obj.diagnosis_object as ICD11DiagnosisModel - )} - onAdd={async (diagnosis) => { - const { res, data, error } = await request( - DiagnosesRoutes.createConsultationDiagnosis, - { - pathParams: { consultation }, - body: diagnosis, - } - ); +
+ obj.diagnosis_object as ICD11DiagnosisModel + )} + onAdd={async (diagnosis) => { + const { res, data, error } = await request( + DiagnosesRoutes.createConsultationDiagnosis, + { + pathParams: { consultation }, + body: diagnosis, + } + ); - if (res?.ok && data) { - setDiagnoses([...diagnoses, data]); - return true; - } + if (res?.ok && data) { + setDiagnoses([...diagnoses, data]); + return true; + } - if (error) { - Notification.Error({ msg: error }); - } + if (error) { + Notification.Error({ msg: error }); + } - return false; - }} - /> + return false; + }} + /> +
); }; + +const NoDiagnosisAdded = () => { + return ( +
+ Atleast one diagnosis must be added +
+ ); +}; diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx index aae3f0432e0..9980502140e 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx @@ -67,6 +67,10 @@ export default function ConsultationDiagnosisEntry(props: Props) { const object = data ?? props.value; + const isActive = ActiveConditionVerificationStatuses.includes( + object.verification_status as (typeof ActiveConditionVerificationStatuses)[number] + ); + return (
- {object.diagnosis_object?.label} - - { - const value = { ...object, is_principal: !object.is_principal }; - - if (props.consultationId === undefined) { - props.onChange({ type: "edit", value }); - return; - } - - handleUpdate(value as ConsultationDiagnosis); - }} + - - - - {object.is_principal - ? t("principal_diagnosis") - : t("mark_as_principal")} - - -
- -
- { - const value = { ...object, verification_status }; - - if (props.consultationId === undefined) { - props.onChange({ type: "edit", value: value as CreateDiagnosis }); - return; - } - - handleUpdate(value as ConsultationDiagnosis); - }} - onRemove={ - props.consultationId === undefined - ? () => props.onChange({ type: "remove" }) - : undefined - } - /> + {object.diagnosis_object?.label} + + +
+ {isActive && ( + { + const value = { ...object, is_principal: !object.is_principal }; + + if (props.consultationId === undefined) { + props.onChange({ type: "edit", value }); + return; + } + + handleUpdate(value as ConsultationDiagnosis); + }} + tooltip={object.is_principal ? t("unmark_as_principal") : ""} + tooltipClassName="tooltip-bottom -translate-x-1/2 translate-y-1 text-xs" + > + {object.is_principal && ( + + )} + + {object.is_principal + ? t("principal_diagnosis") + : t("mark_as_principal")} + + + )} +
+ { + const value = { ...object, verification_status }; + + if (props.consultationId === undefined) { + props.onChange({ + type: "edit", + value: value as CreateDiagnosis, + }); + return; + } + + handleUpdate(value as ConsultationDiagnosis); + }} + onRemove={ + props.consultationId === undefined + ? () => props.onChange({ type: "remove" }) + : undefined + } + /> +
+
); diff --git a/src/Components/Form/SelectMenuV2.tsx b/src/Components/Form/SelectMenuV2.tsx index f26ce03f0c6..464a754cebe 100644 --- a/src/Components/Form/SelectMenuV2.tsx +++ b/src/Components/Form/SelectMenuV2.tsx @@ -9,7 +9,7 @@ type OptionCallback = (option: T) => R; type SelectMenuProps = { id?: string; - options: T[]; + options: readonly T[]; disabled?: boolean | undefined; value: V | undefined; placeholder?: ReactNode; diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index 2f64d286f72..c470406749c 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -132,6 +132,7 @@ "select_skills": "Select and add some skills", "contact_your_admin_to_add_skills": "Contact your admin to add skills", "add": "Add", + "add_as": "Add as", "sort_by": "Sort By", "none": "None", "RESPIRATORY_SUPPORT_UNKNOWN": "None", From 03db9cfb1794269ba348e20bde1381efeb5fd2d9 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 30 Oct 2023 23:40:52 +0530 Subject: [PATCH 12/22] responsiveness --- .../ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx | 5 +---- .../ConsultationDiagnosisEntry.tsx | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx index e165518f213..4cf55a82b13 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -46,10 +46,7 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { return (
@@ -92,7 +92,7 @@ export default function ConsultationDiagnosisEntry(props: Props) { {object.diagnosis_object?.label} -
+
{isActive && ( Date: Mon, 30 Oct 2023 23:48:13 +0530 Subject: [PATCH 13/22] pre-sort by verification status --- src/Components/Facility/ConsultationForm.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 89bd0581552..ef4ed20a1b2 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -59,7 +59,11 @@ import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import useVisibility from "../../Utils/useVisibility"; import dayjs from "../../Utils/dayjs"; -import { ConsultationDiagnosis, CreateDiagnosis } from "../Diagnosis/types.js"; +import { + ConditionVerificationStatuses, + ConsultationDiagnosis, + CreateDiagnosis, +} from "../Diagnosis/types.js"; import { CreateDiagnosesBuilder, EditDiagnosesBuilder, @@ -382,6 +386,11 @@ export const ConsultationForm = (props: any) => { death_datetime: res.data?.death_datetime || "", death_confirmed_doctor: res.data?.death_confirmed_doctor || "", InvestigationAdvice: res.data.investigation, + diagnoses: res.data.diagnoses.sort( + (a: ConsultationDiagnosis, b: ConsultationDiagnosis) => + ConditionVerificationStatuses.indexOf(a.verification_status) - + ConditionVerificationStatuses.indexOf(b.verification_status) + ), }; dispatch({ type: "set_form", form: { ...state.form, ...formData } }); setBed(formData.bed); @@ -1179,7 +1188,7 @@ export const ConsultationForm = (props: any) => {
{sectionTitle("Diagnosis", true)} -

+

Diagnoses as per ICD-11 recommended by WHO

From a7ebd12dce6a460900da08d454e7479b6137e7df Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 31 Oct 2023 10:42:16 +0530 Subject: [PATCH 14/22] Adds help text --- src/Components/Common/components/Menu.tsx | 7 +++- .../ConditionVerificationStatusMenu.tsx | 34 +++++++++++++------ src/Locale/en/Diagnosis.json | 6 ++++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/Components/Common/components/Menu.tsx b/src/Components/Common/components/Menu.tsx index 7914864d1aa..3292031eebb 100644 --- a/src/Components/Common/components/Menu.tsx +++ b/src/Components/Common/components/Menu.tsx @@ -32,7 +32,12 @@ export default function DropdownMenu({ disabled={props.disabled} className={`button-size-${size} button-${variant}-default button-shape-square flex w-full cursor-pointer items-center justify-center gap-2 font-medium outline-offset-1 transition-all duration-200 ease-in-out disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-500 lg:justify-between ${props.className}`} > -
+
{props.icon} {props.title || "Dropdown"}
diff --git a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx index eb60609bbaa..7f90ce750c0 100644 --- a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx +++ b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx @@ -44,19 +44,31 @@ export default function ConditionVerificationStatusMenu< id={`add-icd11-diagnosis-as-${status}`} variant={StatusStyle[status].variant} onClick={() => props.onSelect(status)} - // icon={ - // - // } + icon={ + + } + className="group" disabled={props.value === status} > - - {InactiveConditionVerificationStatuses.includes( - status as (typeof InactiveConditionVerificationStatuses)[number] - ) - ? "Remove as " - : ""} - {t(status)} - +
+ + {InactiveConditionVerificationStatuses.includes( + status as (typeof InactiveConditionVerificationStatuses)[number] + ) + ? "Remove as " + : ""} + {t(status)} + + + {t(`help_${status}`)} + +
))} diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json index 70f86a1fee0..790180cef12 100644 --- a/src/Locale/en/Diagnosis.json +++ b/src/Locale/en/Diagnosis.json @@ -9,5 +9,11 @@ "confirmed": "Confirmed", "refuted": "Refuted", "entered-in-error": "Entered in error", + "help_unconfirmed": "There is not sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.", + "help_provisional": "This is a tentative diagnosis - still a candidate that is under consideration.", + "help_differential": "One of a set of potential (and typically mutually exclusive) diagnoses asserted to further guide the diagnostic process and preliminary treatment.", + "help_confirmed": "There is sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.", + "help_refuted": "This condition has been ruled out by subsequent diagnostic and clinical evidence.", + "help_entered-in-error": "The statement was entered in error and is not valid.", "search_icd11_placeholder": "Search for ICD-11 Diagnoses" } \ No newline at end of file From d8556b85180182aba54135a800b3aa956316693d Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 31 Oct 2023 11:00:47 +0530 Subject: [PATCH 15/22] responsiveness --- .../Diagnosis/ConditionVerificationStatusMenu.tsx | 6 +++--- .../ConsultationDiagnosisEntry.tsx | 15 +++++++++++---- src/Locale/en/Diagnosis.json | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx index 7f90ce750c0..73b2a2c7c92 100644 --- a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx +++ b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx @@ -48,7 +48,7 @@ export default function ConditionVerificationStatusMenu< @@ -56,7 +56,7 @@ export default function ConditionVerificationStatusMenu< className="group" disabled={props.value === status} > -
+
{InactiveConditionVerificationStatuses.includes( status as (typeof InactiveConditionVerificationStatuses)[number] @@ -65,7 +65,7 @@ export default function ConditionVerificationStatusMenu< : ""} {t(status)} - + {t(`help_${status}`)}
diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx index c571d36226c..73bb675ac3c 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx @@ -92,7 +92,7 @@ export default function ConsultationDiagnosisEntry(props: Props) { {object.diagnosis_object?.label} -
+
{isActive && ( )} - {object.is_principal - ? t("principal_diagnosis") - : t("mark_as_principal")} + {object.is_principal ? ( + <> + + {t("principal_diagnosis")} + + {t("principal")} + + ) : ( + t("mark_as_principal") + )} )} diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json index 790180cef12..b96f719c69a 100644 --- a/src/Locale/en/Diagnosis.json +++ b/src/Locale/en/Diagnosis.json @@ -1,5 +1,6 @@ { "diagnosis_already_added": "This diagnosis was already added", + "principal": "Principal", "principal_diagnosis": "Principal diagnosis", "mark_as_principal": "Mark as principal", "unmark_as_principal": "Unmark as principal", From 368a7cc6d2f716ac647dca734207ad2e487c51db Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 31 Oct 2023 11:26:58 +0530 Subject: [PATCH 16/22] fix overflow --- src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx index 73b2a2c7c92..9f80d47f232 100644 --- a/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx +++ b/src/Components/Diagnosis/ConditionVerificationStatusMenu.tsx @@ -56,7 +56,7 @@ export default function ConditionVerificationStatusMenu< className="group" disabled={props.value === status} > -
+
{InactiveConditionVerificationStatuses.includes( status as (typeof InactiveConditionVerificationStatuses)[number] From be7fe425b7df3153d23da63e310ba9e15d82753e Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 31 Oct 2023 12:37:20 +0530 Subject: [PATCH 17/22] show diagnoses in consultation dashboard --- .../Diagnosis/LegacyDiagnosesList.tsx | 86 +++++++++++++++++++ .../Facility/ConsultationDetails/index.tsx | 10 +-- src/Locale/en/Common.json | 3 +- src/Locale/en/Diagnosis.json | 5 +- 4 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 src/Components/Diagnosis/LegacyDiagnosesList.tsx diff --git a/src/Components/Diagnosis/LegacyDiagnosesList.tsx b/src/Components/Diagnosis/LegacyDiagnosesList.tsx new file mode 100644 index 00000000000..2a2ed7b9c3a --- /dev/null +++ b/src/Components/Diagnosis/LegacyDiagnosesList.tsx @@ -0,0 +1,86 @@ +import { useState } from "react"; +import { + ActiveConditionVerificationStatuses, + ConditionVerificationStatus, + ConsultationDiagnosis, +} from "./types"; +import { useTranslation } from "react-i18next"; +import CareIcon from "../../CAREUI/icons/CareIcon"; + +interface Props { + diagnoses: ConsultationDiagnosis[]; +} + +type GroupedDiagnoses = Record< + ConditionVerificationStatus, + ConsultationDiagnosis[] +>; + +function groupDiagnoses(diagnoses: ConsultationDiagnosis[]) { + const groupedDiagnoses = {} as GroupedDiagnoses; + + for (const status of ActiveConditionVerificationStatuses) { + groupedDiagnoses[status] = diagnoses + .filter((d) => d.verification_status === status) + .sort((a, b) => Number(b.is_principal) - Number(a.is_principal)); + } + + return groupedDiagnoses; +} + +export default function LegacyDiagnosesList(props: Props) { + const diagnoses = groupDiagnoses(props.diagnoses); + + return ( +
+ {Object.entries(diagnoses).map( + ([status, diagnoses]) => + !!diagnoses.length && ( + + ) + )} +
+ ); +} + +const DefaultShowLimit = 3; + +const DiagnosesOfStatus = ({ diagnoses }: Props) => { + const { t } = useTranslation(); + const [showMore, setShowMore] = useState(false); + + const queryset = showMore ? diagnoses : diagnoses.slice(0, DefaultShowLimit); + + return ( +
+

+ {t(queryset[0].verification_status)} {t("diagnoses")}{" "} + ({t("icd11_as_recommended")}) +

+
    + {queryset.map((diagnosis) => ( +
  • + {diagnosis.diagnosis_object.label} + {diagnosis.is_principal && ( + + + {t("principal")} + + )} +
  • + ))} +
+ + {diagnoses.length > DefaultShowLimit && ( + setShowMore(!showMore)} + className="cursor-pointer text-sm text-blue-600 hover:text-blue-300" + > + {showMore + ? t("hide") + : `... and ${diagnoses.length - queryset.length} more.`} + + )} +
+ ); +}; diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index 1d06bb5535e..2acce781b81 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -41,6 +41,7 @@ import { ConsultationPressureSoreTab } from "./ConsultationPressureSoreTab"; import { ConsultationDialysisTab } from "./ConsultationDialysisTab"; import { ConsultationNeurologicalMonitoringTab } from "./ConsultationNeurologicalMonitoringTab"; import { ConsultationNutritionTab } from "./ConsultationNutritionTab"; +import LegacyDiagnosesList from "../../Diagnosis/LegacyDiagnosesList"; const Loading = lazy(() => import("../../Common/Loading")); const PageTitle = lazy(() => import("../../Common/PageTitle")); @@ -414,12 +415,9 @@ export const ConsultationDetails = (props: any) => {
)*/} - {/* */} + {(consultationData.verified_by_object || consultationData.deprecated_verified_by) && ( diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index c470406749c..0fe1ba1a8bf 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -128,7 +128,8 @@ "submitting": "Submitting", "view_details": "View Details", "type_to_search": "Type to search", - "show_all": "Show All", + "show_all": "Show all", + "hide": "Hide", "select_skills": "Select and add some skills", "contact_your_admin_to_add_skills": "Contact your admin to add skills", "add": "Add", diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json index b96f719c69a..dd36d93e3ec 100644 --- a/src/Locale/en/Diagnosis.json +++ b/src/Locale/en/Diagnosis.json @@ -1,4 +1,6 @@ { + "diagnosis": "Diagnosis", + "diagnoses": "Diagnoses", "diagnosis_already_added": "This diagnosis was already added", "principal": "Principal", "principal_diagnosis": "Principal diagnosis", @@ -16,5 +18,6 @@ "help_confirmed": "There is sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.", "help_refuted": "This condition has been ruled out by subsequent diagnostic and clinical evidence.", "help_entered-in-error": "The statement was entered in error and is not valid.", - "search_icd11_placeholder": "Search for ICD-11 Diagnoses" + "search_icd11_placeholder": "Search for ICD-11 Diagnoses", + "icd11_as_recommended": "As per ICD-11 recommended by WHO" } \ No newline at end of file From 0f1e07907ecfd389cbbc04b8b45fad948f652581 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 31 Oct 2023 15:17:22 +0530 Subject: [PATCH 18/22] fix consultation create --- src/Components/Facility/ConsultationForm.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index ef4ed20a1b2..10397f4e79a 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -712,14 +712,7 @@ export const ConsultationForm = (props: any) => { treatment_plan: state.form.treatment_plan, discharge_date: state.form.discharge_date, patient_no: state.form.patient_no, - // icd11_diagnoses: state.form.icd11_diagnoses_object.map( - // (o: ICD11DiagnosisModel) => o.id - // ), - // icd11_provisional_diagnoses: - // state.form.icd11_provisional_diagnoses_object.map( - // (o: ICD11DiagnosisModel) => o.id - // ), - // icd11_principal_diagnosis: state.form.icd11_principal_diagnosis, + create_diagnoses: isUpdate ? undefined : state.form.create_diagnoses, verified_by: state.form.verified_by, investigation: state.form.InvestigationAdvice, procedure: state.form.procedures, From 427875fd1e5a1c05d8fe20edb257062ac34b970f Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Fri, 3 Nov 2023 22:16:54 +0530 Subject: [PATCH 19/22] Show chapter of diagnosis for principal diagnosis (#6541) * Add PrincipalDiagnosisCard component and update ConsultationDiagnosisBuilder * Add chapter field to ICD11DiagnosisModel --- .../ConsultationDiagnosisBuilder.tsx | 27 +++++++++++++++ .../ConsultationDiagnosisEntry.tsx | 33 ++++++++----------- .../PrincipalDiagnosisCard.tsx | 25 ++++++++++++++ src/Components/Diagnosis/types.ts | 1 + 4 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisCard.tsx diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx index 801265cdb54..4bfe4e85bc8 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx @@ -10,6 +10,7 @@ import ConsultationDiagnosisEntry from "./ConsultationDiagnosisEntry"; import request from "../../../Utils/request/request"; import DiagnosesRoutes from "../routes"; import * as Notification from "../../../Utils/Notifications"; +import PrincipalDiagnosisCard from "./PrincipalDiagnosisCard"; interface CreateDiagnosesProps { className?: string; @@ -18,6 +19,7 @@ interface CreateDiagnosesProps { } export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { + const principalDiagnosis = props.value.find((d) => d.is_principal); return (
@@ -62,6 +64,13 @@ export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { />
+ + {principalDiagnosis?.diagnosis_object && ( + + )}
); }; @@ -75,6 +84,8 @@ export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { const consultation = useSlug("consultation"); const [diagnoses, setDiagnoses] = useState(props.value); + const principalDiagnosis = diagnoses.find((d) => d.is_principal); + return (
@@ -84,6 +95,15 @@ export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { key={index} value={diagnosis} consultationId={consultation} + onChange={(action) => { + setDiagnoses( + diagnoses.map((diagnose, i) => + i === index + ? (action.value as ConsultationDiagnosis) + : diagnose + ) + ); + }} /> ))}
@@ -118,6 +138,13 @@ export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { />
+ + {principalDiagnosis?.diagnosis_object && ( + + )}
); }; diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx index 73bb675ac3c..fd57803893f 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx @@ -22,8 +22,6 @@ interface EditAction { value: CreateDiagnosis | ConsultationDiagnosis; } -type Action = RemoveAction | EditAction; - interface BaseProps { className?: string; } @@ -31,12 +29,13 @@ interface BaseProps { interface ConsultationCreateProps extends BaseProps { consultationId?: undefined; value: CreateDiagnosis; - onChange: (action: Action) => void; + onChange: (action: EditAction | RemoveAction) => void; } interface ConsultationEditProps extends BaseProps { consultationId: string; value: ConsultationDiagnosis; + onChange: (action: EditAction) => void; } type Props = ConsultationCreateProps | ConsultationEditProps; @@ -101,15 +100,12 @@ export default function ConsultationDiagnosisEntry(props: Props) { disabled={disabled} ghost border - onClick={() => { + onClick={async () => { const value = { ...object, is_principal: !object.is_principal }; - - if (props.consultationId === undefined) { - props.onChange({ type: "edit", value }); - return; + if (props.consultationId) { + await handleUpdate(value as ConsultationDiagnosis); } - - handleUpdate(value as ConsultationDiagnosis); + props.onChange({ type: "edit", value }); }} tooltip={object.is_principal ? t("unmark_as_principal") : ""} tooltipClassName="tooltip-bottom -translate-x-1/2 translate-y-1 text-xs" @@ -141,18 +137,15 @@ export default function ConsultationDiagnosisEntry(props: Props) { ? ActiveConditionVerificationStatuses : ConditionVerificationStatuses } - onSelect={(verification_status) => { + onSelect={async (verification_status) => { const value = { ...object, verification_status }; - - if (props.consultationId === undefined) { - props.onChange({ - type: "edit", - value: value as CreateDiagnosis, - }); - return; + if (props.consultationId) { + await handleUpdate(value as ConsultationDiagnosis); } - - handleUpdate(value as ConsultationDiagnosis); + props.onChange({ + type: "edit", + value: value as CreateDiagnosis | ConsultationDiagnosis, + }); }} onRemove={ props.consultationId === undefined diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisCard.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisCard.tsx new file mode 100644 index 00000000000..a87f16b8ef7 --- /dev/null +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisCard.tsx @@ -0,0 +1,25 @@ +import { ICD11DiagnosisModel } from "../types"; + +interface Props { + className?: string; + diagnosis: ICD11DiagnosisModel; +} + +export default function PrincipalDiagnosisCard(props: Props) { + return ( +
+
+

Principal Diagnosis

+ + + {props.diagnosis.label} + + +

This encounter will be categorised under:

+

{props.diagnosis.chapter}

+
+
+
+
+ ); +} diff --git a/src/Components/Diagnosis/types.ts b/src/Components/Diagnosis/types.ts index a9645c134b0..2281f307998 100644 --- a/src/Components/Diagnosis/types.ts +++ b/src/Components/Diagnosis/types.ts @@ -3,6 +3,7 @@ import { PerformedByModel } from "../HCX/misc"; export type ICD11DiagnosisModel = { id: string; label: string; + chapter: string; }; export const ActiveConditionVerificationStatuses = [ From a1e84935eb73ebb8457f8f9371f6902c901e6198 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 6 Nov 2023 16:32:09 +0530 Subject: [PATCH 20/22] fixes #6544; Principal Diagnosis as Dropdown --- .../ConsultationDiagnosisBuilder.tsx | 83 +++++++++++++------ .../ConsultationDiagnosisEntry.tsx | 55 ++---------- .../PrincipalDiagnosisCard.tsx | 25 ------ .../PrincipalDiagnosisSelect.tsx | 66 +++++++++++++++ src/Components/Diagnosis/types.ts | 15 ++-- src/Locale/en/Diagnosis.json | 2 - 6 files changed, 138 insertions(+), 108 deletions(-) delete mode 100644 src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisCard.tsx create mode 100644 src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx index 4bfe4e85bc8..7c076b65298 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx @@ -10,7 +10,7 @@ import ConsultationDiagnosisEntry from "./ConsultationDiagnosisEntry"; import request from "../../../Utils/request/request"; import DiagnosesRoutes from "../routes"; import * as Notification from "../../../Utils/Notifications"; -import PrincipalDiagnosisCard from "./PrincipalDiagnosisCard"; +import PrincipalDiagnosisSelect from "./PrincipalDiagnosisSelect"; interface CreateDiagnosesProps { className?: string; @@ -19,7 +19,6 @@ interface CreateDiagnosesProps { } export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { - const principalDiagnosis = props.value.find((d) => d.is_principal); return (
@@ -30,18 +29,11 @@ export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { value={diagnosis} onChange={(action) => { if (action.type === "remove") { - const diagnoses = [...props.value]; - diagnoses.splice(index, 1); - props.onChange(diagnoses); + props.onChange(props.value.toSpliced(index, 1)); } if (action.type === "edit") { - const diagnoses = action.value.is_principal - ? props.value.map((d) => { - d.is_principal = false; - return d; - }) - : [...props.value]; + const diagnoses = [...props.value]; diagnoses[index] = action.value as CreateDiagnosis; props.onChange(diagnoses); } @@ -65,12 +57,15 @@ export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => {
- {principalDiagnosis?.diagnosis_object && ( - - )} + { + props.onChange( + props.value.map((d) => ({ ...d, is_principal: d === value })) + ); + }} + />
); }; @@ -83,9 +78,6 @@ interface EditDiagnosesProps { export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => { const consultation = useSlug("consultation"); const [diagnoses, setDiagnoses] = useState(props.value); - - const principalDiagnosis = diagnoses.find((d) => d.is_principal); - return (
@@ -139,12 +131,51 @@ export const EditDiagnosesBuilder = (props: EditDiagnosesProps) => {
- {principalDiagnosis?.diagnosis_object && ( - - )} + { + // Unset existing principal diagnoses + await Promise.all( + diagnoses + .filter((d) => d.is_principal) + .map((d) => { + return request(DiagnosesRoutes.updateConsultationDiagnosis, { + pathParams: { consultation, id: d.id }, + body: { ...d, is_principal: false }, + }); + }) + ); + + if (!value) { + setDiagnoses((diagnoses) => + diagnoses.map((d) => ({ ...d, is_principal: false })) + ); + return; + } + + // Set new principal diagnosis + const { res, data, error } = await request( + DiagnosesRoutes.updateConsultationDiagnosis, + { + pathParams: { consultation, id: value.id }, + body: { ...value, is_principal: true }, + } + ); + + if (res?.ok && data) { + setDiagnoses((diagnoses) => + diagnoses.map((d) => + d.id === data.id ? data : { ...d, is_principal: false } + ) + ); + } + + if (error) { + Notification.Error({ msg: error }); + } + }} + />
); }; diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx index fd57803893f..a650358c518 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisEntry.tsx @@ -1,6 +1,3 @@ -import { useTranslation } from "react-i18next"; -import CareIcon from "../../../CAREUI/icons/CareIcon"; -import ButtonV2 from "../../Common/components/ButtonV2"; import ConditionVerificationStatusMenu from "../ConditionVerificationStatusMenu"; import { ActiveConditionVerificationStatuses, @@ -41,8 +38,6 @@ interface ConsultationEditProps extends BaseProps { type Props = ConsultationCreateProps | ConsultationEditProps; export default function ConsultationDiagnosisEntry(props: Props) { - const { t } = useTranslation(); - const [data, setData] = useState(); const [disabled, setDisabled] = useState(false); const handleUpdate = async (value: ConsultationDiagnosis) => { @@ -60,12 +55,11 @@ export default function ConsultationDiagnosisEntry(props: Props) { setDisabled(false); if (res?.ok && data) { - setData(data); + props.onChange({ type: "edit", value: data }); } }; - const object = data ?? props.value; - + const object = props.value; const isActive = ActiveConditionVerificationStatuses.includes( object.verification_status as (typeof ActiveConditionVerificationStatuses)[number] ); @@ -90,43 +84,7 @@ export default function ConsultationDiagnosisEntry(props: Props) { > {object.diagnosis_object?.label} -
- {isActive && ( - { - const value = { ...object, is_principal: !object.is_principal }; - if (props.consultationId) { - await handleUpdate(value as ConsultationDiagnosis); - } - props.onChange({ type: "edit", value }); - }} - tooltip={object.is_principal ? t("unmark_as_principal") : ""} - tooltipClassName="tooltip-bottom -translate-x-1/2 translate-y-1 text-xs" - > - {object.is_principal && ( - - )} - - {object.is_principal ? ( - <> - - {t("principal_diagnosis")} - - {t("principal")} - - ) : ( - t("mark_as_principal") - )} - - - )}
-
-

Principal Diagnosis

- - - {props.diagnosis.label} - - -

This encounter will be categorised under:

-

{props.diagnosis.chapter}

-
-
-
-
- ); -} diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx new file mode 100644 index 00000000000..e0422730358 --- /dev/null +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx @@ -0,0 +1,66 @@ +import { useState } from "react"; +import { + ActiveConditionVerificationStatuses, + ConsultationDiagnosis, + CreateDiagnosis, +} from "../types"; +import { SelectFormField } from "../../Form/FormFields/SelectFormField"; + +type Option = CreateDiagnosis | ConsultationDiagnosis; + +interface Props { + className?: string; + diagnoses: T[]; + onChange: (value?: T) => Promise; +} + +const PrincipalDiagnosisSelect = (props: Props) => { + const [disabled, setDisabled] = useState(false); + const value = props.diagnoses.find((d) => d.is_principal); + const diagnosis = value?.diagnosis_object; + + const options = props.diagnoses.some(isConfirmed) + ? props.diagnoses.filter(isConfirmedOrPrincipal) + : props.diagnoses.filter(isActive); + + return ( +
+
+ d.diagnosis_object?.label} + optionDescription={(d) => ( +

+ Categorised under:{" "} + {d.diagnosis_object?.chapter} +

+ )} + optionValue={(d) => JSON.stringify(d)} // TODO: momentary hack, figure out a better way to do this + onChange={async ({ value }) => { + setDisabled(true); + await props.onChange(value ? (JSON.parse(value) as T) : undefined); + setDisabled(false); + }} + errorClassName="hidden" + /> + {diagnosis && ( + +

This encounter will be categorised under:

+

{diagnosis.chapter}

+
+ )} +
+
+ ); +}; + +export default PrincipalDiagnosisSelect; + +const isConfirmed = (d: Option) => d.verification_status === "confirmed"; +const isConfirmedOrPrincipal = (d: Option) => isConfirmed(d) || d.is_principal; +const isActive = (d: Option) => + ActiveConditionVerificationStatuses.includes(d.verification_status as any); diff --git a/src/Components/Diagnosis/types.ts b/src/Components/Diagnosis/types.ts index 2281f307998..006bb2feb6c 100644 --- a/src/Components/Diagnosis/types.ts +++ b/src/Components/Diagnosis/types.ts @@ -27,19 +27,20 @@ export type ConditionVerificationStatus = (typeof ConditionVerificationStatuses)[number]; export interface ConsultationDiagnosis { - id: string; - diagnosis_object: ICD11DiagnosisModel; + readonly id: string; + diagnosis?: ICD11DiagnosisModel["id"]; + readonly diagnosis_object: ICD11DiagnosisModel; verification_status: ConditionVerificationStatus; is_principal: boolean; - is_migrated: boolean; - created_by: PerformedByModel; - created_date: string; - modified_date: string; + readonly is_migrated: boolean; + readonly created_by: PerformedByModel; + readonly created_date: string; + readonly modified_date: string; } export interface CreateDiagnosis { diagnosis: ICD11DiagnosisModel["id"]; - diagnosis_object?: ICD11DiagnosisModel; + readonly diagnosis_object?: ICD11DiagnosisModel; verification_status: (typeof ActiveConditionVerificationStatuses)[number]; is_principal: boolean; } diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json index dd36d93e3ec..6cb301c058e 100644 --- a/src/Locale/en/Diagnosis.json +++ b/src/Locale/en/Diagnosis.json @@ -4,8 +4,6 @@ "diagnosis_already_added": "This diagnosis was already added", "principal": "Principal", "principal_diagnosis": "Principal diagnosis", - "mark_as_principal": "Mark as principal", - "unmark_as_principal": "Unmark as principal", "unconfirmed": "Unconfirmed", "provisional": "Provisional", "differential": "Differential", From 4064e32af40654ff1294012f99f394b1a8dfd057 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Mon, 6 Nov 2023 18:20:30 +0530 Subject: [PATCH 21/22] fix cypress --- cypress/pageobject/Patient/PatientConsultation.ts | 15 ++++++--------- .../PrincipalDiagnosisSelect.tsx | 1 + 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index bf301641898..ce1fdc1e393 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -44,23 +44,20 @@ export class PatientConsultationPage { cy.get("#height").click().type(weight); cy.get("#patient_no").type(ipNumber); cy.intercept("GET", "**/icd/**").as("getIcdResults"); - cy.get( - "#icd11_diagnoses_object input[placeholder='Select'][role='combobox']" - ) + cy.get("#icd11-search input[role='combobox']") .scrollIntoView() .click() .type("1A"); - cy.get("#icd11_diagnoses_object [role='option']") + cy.get("#icd11-search [role='option']") .contains("1A00 Cholera") .scrollIntoView() .click(); - cy.get("label[for='icd11_diagnoses_object']").click(); + cy.get("#condition-verification-status-menu").click(); + cy.get("#add-icd11-diagnosis-as-confirmed").click(); cy.wait("@getIcdResults").its("response.statusCode").should("eq", 200); - cy.get("#icd11_principal_diagnosis [role='combobox']").click().type("1A"); - cy.get("#icd11_principal_diagnosis [role='option']") - .contains("1A00 Cholera") - .click(); + cy.get("#principal-diagnosis-select").click(); + cy.get("#principal-diagnosis-select [role='option']").first().click(); cy.get("#consultation_notes").click().type(consulationNotes); cy.get("#verified_by") diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx index e0422730358..8018c6480ed 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/PrincipalDiagnosisSelect.tsx @@ -27,6 +27,7 @@ const PrincipalDiagnosisSelect = (props: Props) => {
Date: Mon, 6 Nov 2023 20:00:39 +0530 Subject: [PATCH 22/22] minor fix --- .../ConsultationDiagnosisBuilder.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx index 7c076b65298..04a3eb24e18 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/ConsultationDiagnosisBuilder.tsx @@ -62,7 +62,11 @@ export const CreateDiagnosesBuilder = (props: CreateDiagnosesProps) => { diagnoses={props.value} onChange={async (value) => { props.onChange( - props.value.map((d) => ({ ...d, is_principal: d === value })) + props.value.map((d) => ({ + ...d, + is_principal: + d.diagnosis_object?.id === value?.diagnosis_object?.id, + })) ); }} />