From a5794a6c688d73108a7115fc9facf8c0a07425b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lach=C3=A9=20Melvin?= <55115239+lache-melvin@users.noreply.github.com> Date: Wed, 29 Jan 2025 10:30:08 +1300 Subject: [PATCH 1/7] add next of kin id to default UI patient schema --- .../system/src/Patient/PatientView/DefaultPatientSchema.json | 4 ++++ .../src/Patient/PatientView/DefaultPatientUISchema.json | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json b/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json index b9886eba7d..b0bd3b3ce5 100644 --- a/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json +++ b/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json @@ -52,6 +52,10 @@ "phone": { "description": "Phone number", "type": "string" + }, + "nextOfKinId": { + "description": "ID of the mSupply name record for the patient's next of kin", + "type": "string" } }, "required": ["id", "code", "firstName", "lastName"], diff --git a/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json b/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json index 0629fdd593..1da8bea2da 100644 --- a/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json +++ b/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json @@ -73,6 +73,11 @@ "type": "Control", "scope": "#/properties/phone", "label": "Phone" + }, + { + "type": "Control", + "scope": "#/properties/nextOfKinId", + "label": "Next of Kin" } ] } From d3852438f0b3d4156f33d3d2dc18d31916a8ef02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lach=C3=A9=20Melvin?= <55115239+lache-melvin@users.noreply.github.com> Date: Wed, 29 Jan 2025 13:24:04 +1300 Subject: [PATCH 2/7] add patient input patient edit --- .../JsonForms/components/PatientSearch.tsx | 48 +++++++++++++++++++ .../src/JsonForms/components/index.ts | 1 + .../src/JsonForms/useJsonFormsHandler.tsx | 3 ++ .../PatientView/DefaultPatientUISchema.json | 2 +- client/packages/system/src/Patient/index.ts | 1 + 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 client/packages/programs/src/JsonForms/components/PatientSearch.tsx diff --git a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx new file mode 100644 index 0000000000..11594e4f4e --- /dev/null +++ b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx @@ -0,0 +1,48 @@ +import React, { useEffect } from 'react'; +import { rankWith, ControlProps, uiTypeIs } from '@jsonforms/core'; +import { withJsonFormsControlProps } from '@jsonforms/react'; +import { Box, DetailInputWithLabelRow } from '@openmsupply-client/common'; +import { DefaultFormRowSx, FORM_GAP, FORM_LABEL_WIDTH } from '../common'; +import { + PatientSearchInput, + SearchInputPatient, +} from '@openmsupply-client/system'; + +export const patientSearchTester = rankWith(10, uiTypeIs('PatientSearch')); + +const UIComponent = (props: ControlProps) => { + const { data, handleChange, label, path } = props; + const [patient, setPatient] = React.useState(null); + + const onChangePatient = async (patient: SearchInputPatient) => { + setPatient(patient); + handleChange(path, patient.id); + }; + + useEffect(() => { + if (!data) return; + // todo - set if exists! + // const naiveDoB = DateUtils.getNaiveDate(data.dateOfBirth); + // setDoB(naiveDoB); + }, [data]); + + if (!props.visible) { + return null; + } + + return ( + + + + } + /> + ); +}; + +export const PatientSearch = withJsonFormsControlProps(UIComponent); diff --git a/client/packages/programs/src/JsonForms/components/index.ts b/client/packages/programs/src/JsonForms/components/index.ts index fafca9a7ed..381f4fbde0 100644 --- a/client/packages/programs/src/JsonForms/components/index.ts +++ b/client/packages/programs/src/JsonForms/components/index.ts @@ -10,4 +10,5 @@ export * from './Search/Search'; export * from './ProgramEvent'; export * from './HistoricEncounterData'; export * from './BloodPressure'; +export * from './PatientSearch'; export * from './Prescription/Prescription'; diff --git a/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx b/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx index eed4befa40..2167002ba6 100644 --- a/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx +++ b/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx @@ -37,6 +37,8 @@ import { BloodPressure, Prescription, prescriptionTester, + patientSearchTester, + PatientSearch, } from './components'; import { EnrolmentId, enrolmentIdTester } from './components/EnrolmentId'; import { @@ -83,6 +85,7 @@ const additionalRenderers: JsonFormsRendererRegistryEntry[] = [ { tester: enrolmentIdTester, renderer: EnrolmentId }, { tester: bloodPressureTester, renderer: BloodPressure }, { tester: prescriptionTester, renderer: Prescription }, + { tester: patientSearchTester, renderer: PatientSearch }, ]; /** diff --git a/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json b/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json index 1da8bea2da..dd2163cd82 100644 --- a/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json +++ b/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json @@ -75,7 +75,7 @@ "label": "Phone" }, { - "type": "Control", + "type": "PatientSearch", "scope": "#/properties/nextOfKinId", "label": "Next of Kin" } diff --git a/client/packages/system/src/Patient/index.ts b/client/packages/system/src/Patient/index.ts index c697299a5c..d7effe3fe0 100644 --- a/client/packages/system/src/Patient/index.ts +++ b/client/packages/system/src/Patient/index.ts @@ -3,3 +3,4 @@ export * from './ListView'; export * from './Service'; export * from './api'; export * from './Components'; +export * from './utils'; From 185e655b933098e9a7babd6cf249630e2d84dc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lach=C3=A9=20Melvin?= <55115239+lache-melvin@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:07:31 +1300 Subject: [PATCH 3/7] include next of kin id in backend update --- client/packages/common/src/types/schema.ts | 1 + .../programs/src/mutations/patient/update.rs | 30 ++++++++++--------- .../src/programs/patient/update_patient.rs | 3 ++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/client/packages/common/src/types/schema.ts b/client/packages/common/src/types/schema.ts index 0163918e0e..3bc4490c38 100644 --- a/client/packages/common/src/types/schema.ts +++ b/client/packages/common/src/types/schema.ts @@ -8328,6 +8328,7 @@ export type UpdatePatientInput = { id: Scalars['String']['input']; isDeceased?: InputMaybe; lastName?: InputMaybe; + nextOfKinId?: InputMaybe; phone?: InputMaybe; }; diff --git a/server/graphql/programs/src/mutations/patient/update.rs b/server/graphql/programs/src/mutations/patient/update.rs index 65bc841631..21f6329bd8 100644 --- a/server/graphql/programs/src/mutations/patient/update.rs +++ b/server/graphql/programs/src/mutations/patient/update.rs @@ -9,7 +9,6 @@ use service::{ auth::{Resource, ResourceAccessRequest}, programs::patient::{UpdatePatient, UpdatePatientError}, }; -use util::inline_init; /// All fields in the input object will be used to update the patient record. /// This means that the caller also has to provide the fields that are not going to change. @@ -27,6 +26,7 @@ pub struct UpdatePatientInput { pub phone: Option, pub is_deceased: Option, pub date_of_death: Option, + pub next_of_kin_id: Option, } #[derive(Union)] @@ -49,6 +49,7 @@ pub fn update_patient( phone, is_deceased, date_of_death, + next_of_kin_id, }: UpdatePatientInput, ) -> Result { let user = validate_auth( @@ -63,19 +64,20 @@ pub fn update_patient( let service_provider = ctx.service_provider(); let service_context = service_provider.basic_context()?; - let update_patient = inline_init(|n: &mut UpdatePatient| { - n.id = id; - n.code = code; - n.code_2 = code_2; - n.first_name = first_name; - n.last_name = last_name; - n.gender = gender.map(|g| g.to_domain()); - n.date_of_birth = date_of_birth; - n.address1 = address1; - n.phone = phone; - n.is_deceased = is_deceased; - n.date_of_death = date_of_death; - }); + let update_patient = UpdatePatient { + id, + code, + code_2, + first_name, + last_name, + gender: gender.map(|g| g.to_domain()), + date_of_birth, + address1, + phone, + is_deceased, + date_of_death, + next_of_kin_id, + }; match service_provider.patient_service.update_patient( &service_context, diff --git a/server/service/src/programs/patient/update_patient.rs b/server/service/src/programs/patient/update_patient.rs index 0cbeef2417..ed4187f90a 100644 --- a/server/service/src/programs/patient/update_patient.rs +++ b/server/service/src/programs/patient/update_patient.rs @@ -48,6 +48,7 @@ fn generate(existing: NameRow, update: UpdatePatient) -> NameRow { phone, is_deceased, date_of_death, + next_of_kin_id, } = update; NameRow { @@ -62,6 +63,7 @@ fn generate(existing: NameRow, update: UpdatePatient) -> NameRow { date_of_death, is_deceased: is_deceased.unwrap_or(false), national_health_number: code_2, + next_of_kin_id, ..existing } } @@ -79,6 +81,7 @@ pub struct UpdatePatient { pub phone: Option, pub is_deceased: Option, pub date_of_death: Option, + pub next_of_kin_id: Option, } pub(crate) fn update_patient( From e1b36c14995919e616efdf17c419f4de92e98c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lach=C3=A9=20Melvin?= <55115239+lache-melvin@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:53:49 +1300 Subject: [PATCH 4/7] display existing selected next of kin --- .../src/JsonForms/components/PatientSearch.tsx | 16 ++++++++++------ .../PatientSearchInput/PatientSearchInput.tsx | 2 +- .../src/Patient/PatientView/PatientView.tsx | 1 + .../src/Patient/api/operations.generated.ts | 15 ++++++++------- .../system/src/Patient/api/operations.graphql | 1 + 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx index 11594e4f4e..50d9d5d784 100644 --- a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx +++ b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx @@ -6,6 +6,7 @@ import { DefaultFormRowSx, FORM_GAP, FORM_LABEL_WIDTH } from '../common'; import { PatientSearchInput, SearchInputPatient, + usePatient, } from '@openmsupply-client/system'; export const patientSearchTester = rankWith(10, uiTypeIs('PatientSearch')); @@ -19,12 +20,12 @@ const UIComponent = (props: ControlProps) => { handleChange(path, patient.id); }; + const { data: patientData } = usePatient.document.get(data); + useEffect(() => { - if (!data) return; - // todo - set if exists! - // const naiveDoB = DateUtils.getNaiveDate(data.dateOfBirth); - // setDoB(naiveDoB); - }, [data]); + if (!patientData) return; + setPatient(patientData); + }, [patientData]); if (!props.visible) { return null; @@ -38,7 +39,10 @@ const UIComponent = (props: ControlProps) => { inputAlignment={'start'} Input={ - + {/* todo this */} + {(!data || (!!patientData && patient)) && ( + + )} } /> diff --git a/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx b/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx index de1906065a..f0933acaf6 100644 --- a/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx +++ b/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx @@ -32,7 +32,7 @@ export const PatientSearchInput: FC = ({ isOptionEqualToValue={(option, value) => option.name === value.name} width={`${width}px`} popperMinWidth={width} - value={value && { ...value, label: value.name }} + defaultValue={value && { ...value, label: value.name }} filterOptions={filterByNameAndCode} sx={{ minWidth: width }} noOptionsText="" diff --git a/client/packages/system/src/Patient/PatientView/PatientView.tsx b/client/packages/system/src/Patient/PatientView/PatientView.tsx index 0af656a60e..3be4c39190 100644 --- a/client/packages/system/src/Patient/PatientView/PatientView.tsx +++ b/client/packages/system/src/Patient/PatientView/PatientView.tsx @@ -151,6 +151,7 @@ const PatientDetailView = ({ isDeceased: currentPatient.isDeceased ?? undefined, phone: currentPatient.phone ?? undefined, address1: currentPatient.address1 ?? undefined, + nextOfKinId: currentPatient.nextOfKinId ?? undefined, }, isCreating: false, }; diff --git a/client/packages/system/src/Patient/api/operations.generated.ts b/client/packages/system/src/Patient/api/operations.generated.ts index 1c03c9a00a..ff6a96c4e0 100644 --- a/client/packages/system/src/Patient/api/operations.generated.ts +++ b/client/packages/system/src/Patient/api/operations.generated.ts @@ -5,7 +5,7 @@ import gql from 'graphql-tag'; type GraphQLClientRequestHeaders = RequestOptions['requestHeaders']; export type PatientRowFragment = { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', name: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }; -export type ProgramPatientRowFragment = { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }; +export type ProgramPatientRowFragment = { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }; export type PatientsQueryVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -23,7 +23,7 @@ export type PatientByIdQueryVariables = Types.Exact<{ }>; -export type PatientByIdQuery = { __typename: 'Queries', patients: { __typename: 'PatientConnector', totalCount: number, nodes: Array<{ __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }> } }; +export type PatientByIdQuery = { __typename: 'Queries', patients: { __typename: 'PatientConnector', totalCount: number, nodes: Array<{ __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }> } }; export type PatientSearchQueryVariables = Types.Exact<{ input: Types.PatientSearchInput; @@ -31,7 +31,7 @@ export type PatientSearchQueryVariables = Types.Exact<{ }>; -export type PatientSearchQuery = { __typename: 'Queries', patientSearch: { __typename: 'PatientSearchConnector', totalCount: number, nodes: Array<{ __typename: 'PatientSearchNode', score: number, patient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }> } }; +export type PatientSearchQuery = { __typename: 'Queries', patientSearch: { __typename: 'PatientSearchConnector', totalCount: number, nodes: Array<{ __typename: 'PatientSearchNode', score: number, patient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }> } }; export type CentralPatientSearchQueryVariables = Types.Exact<{ input: Types.CentralPatientSearchInput; @@ -55,7 +55,7 @@ export type InsertProgramPatientMutationVariables = Types.Exact<{ }>; -export type InsertProgramPatientMutation = { __typename: 'Mutations', insertProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type InsertProgramPatientMutation = { __typename: 'Mutations', insertProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type UpdateProgramPatientMutationVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -63,7 +63,7 @@ export type UpdateProgramPatientMutationVariables = Types.Exact<{ }>; -export type UpdateProgramPatientMutation = { __typename: 'Mutations', updateProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type UpdateProgramPatientMutation = { __typename: 'Mutations', updateProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type InsertPatientMutationVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -71,7 +71,7 @@ export type InsertPatientMutationVariables = Types.Exact<{ }>; -export type InsertPatientMutation = { __typename: 'Mutations', insertPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type InsertPatientMutation = { __typename: 'Mutations', insertPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type UpdatePatientMutationVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -79,7 +79,7 @@ export type UpdatePatientMutationVariables = Types.Exact<{ }>; -export type UpdatePatientMutation = { __typename: 'Mutations', updatePatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type UpdatePatientMutation = { __typename: 'Mutations', updatePatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type LatestPatientEncounterQueryVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -147,6 +147,7 @@ export const ProgramPatientRowFragmentDoc = gql` documentDraft isDeceased dateOfDeath + nextOfKinId programEnrolments { ... on ProgramEnrolmentConnector { __typename diff --git a/client/packages/system/src/Patient/api/operations.graphql b/client/packages/system/src/Patient/api/operations.graphql index 40f2262309..b703a1a0f4 100644 --- a/client/packages/system/src/Patient/api/operations.graphql +++ b/client/packages/system/src/Patient/api/operations.graphql @@ -53,6 +53,7 @@ fragment ProgramPatientRow on PatientNode { documentDraft isDeceased dateOfDeath + nextOfKinId programEnrolments { ... on ProgramEnrolmentConnector { __typename From 3cf6f9bd8d2734ad7e9ba390f10a95373af35541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lach=C3=A9=20Melvin?= <55115239+lache-melvin@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:01:34 +1300 Subject: [PATCH 5/7] revert test hacks :) --- .../programs/src/JsonForms/components/PatientSearch.tsx | 5 +---- .../Components/PatientSearchInput/PatientSearchInput.tsx | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx index 50d9d5d784..1d775df861 100644 --- a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx +++ b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx @@ -39,10 +39,7 @@ const UIComponent = (props: ControlProps) => { inputAlignment={'start'} Input={ - {/* todo this */} - {(!data || (!!patientData && patient)) && ( - - )} + } /> diff --git a/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx b/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx index f0933acaf6..de1906065a 100644 --- a/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx +++ b/client/packages/system/src/Patient/Components/PatientSearchInput/PatientSearchInput.tsx @@ -32,7 +32,7 @@ export const PatientSearchInput: FC = ({ isOptionEqualToValue={(option, value) => option.name === value.name} width={`${width}px`} popperMinWidth={width} - defaultValue={value && { ...value, label: value.name }} + value={value && { ...value, label: value.name }} filterOptions={filterByNameAndCode} sx={{ minWidth: width }} noOptionsText="" From 21f6b01682c42691f473558c4f4559441bb901b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lach=C3=A9=20Melvin?= <55115239+lache-melvin@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:14:19 +1300 Subject: [PATCH 6/7] add next of kin id to insert patient --- client/packages/common/src/types/schema.ts | 44 +++++++++++++++++++ .../programs/src/mutations/patient/insert.rs | 3 ++ .../src/programs/patient/insert_patient.rs | 3 ++ 3 files changed, 50 insertions(+) diff --git a/client/packages/common/src/types/schema.ts b/client/packages/common/src/types/schema.ts index a3722628c5..095af51317 100644 --- a/client/packages/common/src/types/schema.ts +++ b/client/packages/common/src/types/schema.ts @@ -928,6 +928,26 @@ export type CentralPatientSearchInput = { export type CentralPatientSearchResponse = CentralPatientSearchConnector | CentralPatientSearchError; +export type CentralPluginMutations = { + __typename: 'CentralPluginMutations'; + installUploadedPlugin: PluginInfoNode; +}; + + +export type CentralPluginMutationsInstallUploadedPluginArgs = { + fileId: Scalars['String']['input']; +}; + +export type CentralPluginQueries = { + __typename: 'CentralPluginQueries'; + uploadedPluginInfo: UploadedPluginInfoResponse; +}; + + +export type CentralPluginQueriesUploadedPluginInfoArgs = { + fileId: Scalars['String']['input']; +}; + export type CentralServerMutationNode = { __typename: 'CentralServerMutationNode'; assetCatalogue: AssetCatalogueMutations; @@ -936,9 +956,15 @@ export type CentralServerMutationNode = { general: CentralGeneralMutations; itemVariant: ItemVariantMutations; logReason: AssetLogReasonMutations; + plugins: CentralPluginMutations; vaccineCourse: VaccineCourseMutations; }; +export type CentralServerQueryNode = { + __typename: 'CentralServerQueryNode'; + plugin: CentralPluginQueries; +}; + export type CentralSyncRequired = AuthTokenErrorInterface & { __typename: 'CentralSyncRequired'; description: Scalars['String']['output']; @@ -2885,6 +2911,7 @@ export type InsertPatientInput = { id: Scalars['String']['input']; isDeceased?: InputMaybe; lastName?: InputMaybe; + nextOfKinId?: InputMaybe; phone?: InputMaybe; }; @@ -5360,6 +5387,11 @@ export type PluginDataSortInput = { key: PluginDataSortFieldInput; }; +export type PluginInfoNode = { + __typename: 'PluginInfoNode'; + backendPluginCodes: Array; +}; + export type PluginNode = { __typename: 'PluginNode'; config: Scalars['String']['output']; @@ -5677,6 +5709,7 @@ export type Queries = { authToken: AuthTokenResponse; barcodeByGtin: BarcodeResponse; centralPatientSearch: CentralPatientSearchResponse; + centralServer: CentralServerQueryNode; clinicians: CliniciansResponse; /** Query omSupply "cold_storage_type" entries */ coldStorageTypes: ColdStorageTypesResponse; @@ -8785,6 +8818,17 @@ export type UpdateVaccineCourseInput = { export type UpdateVaccineCourseResponse = UpdateVaccineCourseError | VaccineCourseNode; +export type UploadedPluginError = { + __typename: 'UploadedPluginError'; + error: UploadedPluginErrorVariant; +}; + +export enum UploadedPluginErrorVariant { + CannotParseFile = 'CANNOT_PARSE_FILE' +} + +export type UploadedPluginInfoResponse = PluginInfoNode | UploadedPluginError; + export type UpsertBundledItemError = { __typename: 'UpsertBundledItemError'; error: UpsertBundledItemErrorInterface; diff --git a/server/graphql/programs/src/mutations/patient/insert.rs b/server/graphql/programs/src/mutations/patient/insert.rs index 54651787ff..e5e2d0d7bf 100644 --- a/server/graphql/programs/src/mutations/patient/insert.rs +++ b/server/graphql/programs/src/mutations/patient/insert.rs @@ -24,6 +24,7 @@ pub struct InsertPatientInput { pub phone: Option, pub is_deceased: Option, pub date_of_death: Option, + pub next_of_kin_id: Option, } #[derive(Union)] @@ -94,6 +95,7 @@ impl InsertPatientInput { phone, date_of_death, is_deceased, + next_of_kin_id, } = self; ServiceInput { @@ -108,6 +110,7 @@ impl InsertPatientInput { phone, date_of_death, is_deceased, + next_of_kin_id, r#type: NameRowType::Patient, } } diff --git a/server/service/src/programs/patient/insert_patient.rs b/server/service/src/programs/patient/insert_patient.rs index d8902cbdcc..0667a4d9a0 100644 --- a/server/service/src/programs/patient/insert_patient.rs +++ b/server/service/src/programs/patient/insert_patient.rs @@ -22,6 +22,7 @@ pub struct InsertPatient { pub is_deceased: Option, pub date_of_death: Option, pub r#type: NameRowType, + pub next_of_kin_id: Option, } #[derive(PartialEq, Debug)] @@ -65,6 +66,7 @@ fn generate(input: InsertPatient, store_id: &str) -> NameRow { date_of_death, is_deceased, r#type, + next_of_kin_id, } = input; NameRow { @@ -85,6 +87,7 @@ fn generate(input: InsertPatient, store_id: &str) -> NameRow { is_deceased: is_deceased.unwrap_or(false), national_health_number: code_2, created_datetime: Some(Utc::now().naive_utc()), + next_of_kin_id, ..Default::default() } } From 10e4d3c75a29a1d4d1d765866b31ef72a0600253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lach=C3=A9=20Melvin?= <55115239+lache-melvin@users.noreply.github.com> Date: Thu, 30 Jan 2025 14:10:05 +1300 Subject: [PATCH 7/7] only query if visible --- .../src/JsonForms/components/PatientSearch.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx index 1d775df861..758b19b67e 100644 --- a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx +++ b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx @@ -13,6 +13,7 @@ export const patientSearchTester = rankWith(10, uiTypeIs('PatientSearch')); const UIComponent = (props: ControlProps) => { const { data, handleChange, label, path } = props; + const [patient, setPatient] = React.useState(null); const onChangePatient = async (patient: SearchInputPatient) => { @@ -27,10 +28,6 @@ const UIComponent = (props: ControlProps) => { setPatient(patientData); }, [patientData]); - if (!props.visible) { - return null; - } - return ( { ); }; -export const PatientSearch = withJsonFormsControlProps(UIComponent); +const UIComponentWrapper = (props: ControlProps) => { + if (!props.visible) { + return null; + } + return ; +}; + +export const PatientSearch = withJsonFormsControlProps(UIComponentWrapper);