@openmrs/esm-form-engine-lib 4.2.1-pre.2435 → 4.2.1-pre.2439
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/form-engine.component.js +9 -2
- package/dist/processors/encounter/encounter-processor-helper.js +15 -5
- package/dist/src/form-engine.component.d.ts.map +1 -1
- package/dist/src/processors/encounter/encounter-processor-helper.d.ts +9 -7
- package/dist/src/processors/encounter/encounter-processor-helper.d.ts.map +1 -1
- package/dist/src/utils/common-utils.d.ts +8 -0
- package/dist/src/utils/common-utils.d.ts.map +1 -1
- package/dist/utils/common-utils.js +16 -0
- package/package.json +1 -1
- package/src/form-engine.component.tsx +6 -2
- package/src/processors/encounter/encounter-processor-helper.ts +35 -7
- package/src/utils/common-utils.ts +19 -1
|
@@ -8,6 +8,7 @@ import { init, teardown } from "./lifecycle.js";
|
|
|
8
8
|
import { isEmpty, useFormJson } from "./index.js";
|
|
9
9
|
import { formEngineAppName } from "./globals.js";
|
|
10
10
|
import { reportError } from "./utils/error-utils.js";
|
|
11
|
+
import { getDateWithinVisitWindow } from "./utils/common-utils.js";
|
|
11
12
|
import { useFormCollapse } from "./hooks/useFormCollapse.js";
|
|
12
13
|
import { useFormWorkspaceSize } from "./hooks/useFormWorkspaceSize.js";
|
|
13
14
|
import { usePageObserver } from "./components/sidebar/usePageObserver.js";
|
|
@@ -22,9 +23,15 @@ const FormEngine = ({ formJson, patientUUID, formUUID, encounterUUID, visit, for
|
|
|
22
23
|
const { t } = useTranslation();
|
|
23
24
|
const session = useSession();
|
|
24
25
|
const ref = useRef(null);
|
|
26
|
+
const rawSessionDate = useRef(new Date());
|
|
27
|
+
// Recompute when the visit bounds arrive or change; the visit prop may not be
|
|
28
|
+
// fully loaded when the form mounts.
|
|
25
29
|
const sessionDate = useMemo(()=>{
|
|
26
|
-
return
|
|
27
|
-
}, [
|
|
30
|
+
return getDateWithinVisitWindow(rawSessionDate.current, visit);
|
|
31
|
+
}, [
|
|
32
|
+
visit?.startDatetime,
|
|
33
|
+
visit?.stopDatetime
|
|
34
|
+
]);
|
|
28
35
|
const workspaceSize = useFormWorkspaceSize(ref);
|
|
29
36
|
const { patient, isLoadingPatient } = usePatientData(patientUUID);
|
|
30
37
|
const [isLoadingDependencies, setIsLoadingDependencies] = useState(false);
|
|
@@ -32,7 +32,9 @@ export function prepareEncounter(context, encounterDate, encounterRole, encounte
|
|
|
32
32
|
];
|
|
33
33
|
}
|
|
34
34
|
// TODO: Question: Should we be editing the location, form and visit here?
|
|
35
|
-
|
|
35
|
+
if (encounterDate) {
|
|
36
|
+
encounterForSubmission.encounterDatetime = encounterDate;
|
|
37
|
+
}
|
|
36
38
|
encounterForSubmission.location = location;
|
|
37
39
|
encounterForSubmission.form = {
|
|
38
40
|
uuid: formJson.uuid
|
|
@@ -46,7 +48,6 @@ export function prepareEncounter(context, encounterDate, encounterRole, encounte
|
|
|
46
48
|
} else {
|
|
47
49
|
encounterForSubmission = {
|
|
48
50
|
patient: patient.id,
|
|
49
|
-
encounterDatetime: encounterDate,
|
|
50
51
|
location: location,
|
|
51
52
|
encounterType: formJson.encounterType,
|
|
52
53
|
encounterProviders: [
|
|
@@ -63,6 +64,9 @@ export function prepareEncounter(context, encounterDate, encounterRole, encounte
|
|
|
63
64
|
orders: ordersForSubmission,
|
|
64
65
|
diagnoses: diagnosesForSubmission
|
|
65
66
|
};
|
|
67
|
+
if (encounterDate) {
|
|
68
|
+
encounterForSubmission.encounterDatetime = encounterDate;
|
|
69
|
+
}
|
|
66
70
|
}
|
|
67
71
|
return encounterForSubmission;
|
|
68
72
|
}
|
|
@@ -134,16 +138,22 @@ export function saveAttachments(fields, encounter, abortController) {
|
|
|
134
138
|
return Promise.all(allPromises);
|
|
135
139
|
}
|
|
136
140
|
export function getMutableSessionProps(context) {
|
|
137
|
-
const { formFields, location, currentProvider, customDependencies, domainObjectValue: encounter } = context;
|
|
141
|
+
const { formFields, location, currentProvider, customDependencies, sessionDate, domainObjectValue: encounter, visit } = context;
|
|
138
142
|
const { defaultEncounterRole } = customDependencies;
|
|
139
143
|
const encounterRole = formFields.find((field)=>field.type === 'encounterRole')?.meta.submission?.newValue || defaultEncounterRole?.uuid;
|
|
140
144
|
const encounterProvider = formFields.find((field)=>field.type === 'encounterProvider')?.meta.submission?.newValue || currentProvider.uuid;
|
|
141
|
-
const
|
|
145
|
+
const explicitEncounterDate = formFields.find((field)=>field.type === 'encounterDatetime')?.meta.submission?.newValue;
|
|
146
|
+
// Stopped visits need an explicit datetime because the backend defaults omitted
|
|
147
|
+
// encounter datetimes to server "now", which can be outside the visit window.
|
|
148
|
+
// Active visits should use the backend default so client clock skew does not
|
|
149
|
+
// submit future encounter datetimes.
|
|
150
|
+
const defaultEncounterDate = visit?.stopDatetime ? sessionDate : undefined;
|
|
151
|
+
const encounterDate = explicitEncounterDate ?? (encounter?.encounterDatetime ? new Date(encounter.encounterDatetime) : defaultEncounterDate);
|
|
142
152
|
const encounterLocation = formFields.find((field)=>field.type === 'encounterLocation')?.meta.submission?.newValue || encounter?.location?.uuid || location.uuid;
|
|
143
153
|
return {
|
|
144
154
|
encounterRole: encounterRole,
|
|
145
155
|
encounterProvider: encounterProvider,
|
|
146
|
-
encounterDate
|
|
156
|
+
encounterDate,
|
|
147
157
|
encounterLocation: encounterLocation
|
|
148
158
|
};
|
|
149
159
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-engine.component.d.ts","sourceRoot":"","sources":["../../src/form-engine.component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAIjF,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"form-engine.component.d.ts","sourceRoot":"","sources":["../../src/form-engine.component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAIjF,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAWhE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAQtF,UAAU,eAAe;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,6BAA6B,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAkLD,iBAAS,aAAa,CAAC,KAAK,EAAE,eAAe,qBAM5C;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { type FormField, type FormProcessorContextProps, type OpenmrsEncounter, type PatientIdentifier, type PatientProgram, type PatientProgramPayload, type PersonAttribute } from '../../types';
|
|
2
2
|
import { type FormContextProps } from '../../provider/form-provider';
|
|
3
|
-
|
|
3
|
+
type MutableSessionProps = {
|
|
4
|
+
encounterRole: string;
|
|
5
|
+
encounterProvider: string;
|
|
6
|
+
encounterDate?: Date;
|
|
7
|
+
encounterLocation: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function prepareEncounter(context: FormContextProps, encounterDate: Date | undefined, encounterRole: string, encounterProvider: string, location: string): OpenmrsEncounter;
|
|
4
10
|
export declare function preparePatientIdentifiers(fields: FormField[], encounterLocation: string): PatientIdentifier[];
|
|
5
11
|
export declare function savePatientIdentifiers(patient: fhir.Patient, identifiers: PatientIdentifier[]): Promise<import("@openmrs/esm-api").FetchResponse<any>>[];
|
|
6
12
|
export declare function preparePersonAttributes(fields: FormField[]): PersonAttribute[];
|
|
@@ -8,12 +14,8 @@ export declare function savePersonAttributes(patient: fhir.Patient, attributes:
|
|
|
8
14
|
export declare function preparePatientPrograms(fields: FormField[], patient: fhir.Patient, currentPatientPrograms: Array<PatientProgram>): Array<PatientProgramPayload>;
|
|
9
15
|
export declare function savePatientPrograms(patientPrograms: PatientProgramPayload[]): Promise<import("@openmrs/esm-api").FetchResponse<any>[]>;
|
|
10
16
|
export declare function saveAttachments(fields: FormField[], encounter: OpenmrsEncounter, abortController: AbortController): any[] | Promise<import("@openmrs/esm-api").FetchResponse<any>[]>;
|
|
11
|
-
export declare function getMutableSessionProps(context: FormContextProps):
|
|
12
|
-
encounterRole: string;
|
|
13
|
-
encounterProvider: string;
|
|
14
|
-
encounterDate: Date;
|
|
15
|
-
encounterLocation: string;
|
|
16
|
-
};
|
|
17
|
+
export declare function getMutableSessionProps(context: FormContextProps): MutableSessionProps;
|
|
17
18
|
export declare function inferInitialValueFromDefaultFieldValue(field: FormField): any;
|
|
18
19
|
export declare function hydrateRepeatField(field: FormField, encounter: OpenmrsEncounter, initialValues: Record<string, any>, context: FormProcessorContextProps): Promise<FormField[]>;
|
|
20
|
+
export {};
|
|
19
21
|
//# sourceMappingURL=encounter-processor-helper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encounter-processor-helper.d.ts","sourceRoot":"","sources":["../../../../src/processors/encounter/encounter-processor-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EAErB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAQrE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"encounter-processor-helper.d.ts","sourceRoot":"","sources":["../../../../src/processors/encounter/encounter-processor-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EAErB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAQrE,KAAK,mBAAmB,GAAG;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,IAAI,GAAG,SAAS,EAC/B,aAAa,EAAE,MAAM,EACrB,iBAAiB,EAAE,MAAM,EACzB,QAAQ,EAAE,MAAM,oBAiEjB;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,iBAAiB,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAI7G;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,4DAI7F;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,eAAe,EAAE,CAI9E;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,4DAIxF;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EAAE,EACnB,OAAO,EAAE,IAAI,CAAC,OAAO,EACrB,sBAAsB,EAAE,KAAK,CAAC,cAAc,CAAC,GAC5C,KAAK,CAAC,qBAAqB,CAAC,CA+B9B;AAED,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,qBAAqB,EAAE,4DAG3E;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,oEAcjH;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,mBAAmB,CAmCrF;AA4FD,wBAAgB,sCAAsC,CAAC,KAAK,EAAE,SAAS,OAetE;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,gBAAgB,EAC3B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,SAAS,EAAE,CAAC,CAwEtB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type FormSchema, type FormField, type OpenmrsObs, type RenderType } from '../types';
|
|
2
|
+
import { type Visit } from '@openmrs/esm-framework';
|
|
2
3
|
export declare function flattenObsList(obsList: OpenmrsObs[]): OpenmrsObs[];
|
|
3
4
|
export declare function hasRendering(field: FormField, rendering: RenderType): boolean;
|
|
4
5
|
export declare function clearSubmission(field: FormField): void;
|
|
@@ -6,6 +7,13 @@ export declare function gracefullySetSubmission(field: FormField, newValue: any,
|
|
|
6
7
|
export declare function hasSubmission(field: FormField): boolean;
|
|
7
8
|
export declare function isViewMode(sessionMode: string): sessionMode is "view" | "embedded-view";
|
|
8
9
|
export declare function parseToLocalDateTime(dateString: string): Date;
|
|
10
|
+
/**
|
|
11
|
+
* Returns `date` if it falls within the visit's start/stop window, otherwise the
|
|
12
|
+
* visit's start datetime. This keeps default encounter datetimes valid when filling
|
|
13
|
+
* forms against a past (stopped) visit via retrospective data entry; the backend
|
|
14
|
+
* rejects encounters dated outside the visit window.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDateWithinVisitWindow(date: Date, visit?: Visit): Date;
|
|
9
17
|
export declare function formatDateAsDisplayString(field: FormField, date: Date): string;
|
|
10
18
|
/**
|
|
11
19
|
* Creates a new copy of `formJson` with updated references at the page and section levels.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common-utils.d.ts","sourceRoot":"","sources":["../../../src/utils/common-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"common-utils.d.ts","sourceRoot":"","sources":["../../../src/utils/common-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAE7F,OAAO,EAAsC,KAAK,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAExF,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAgBlE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,WAEnE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,QAS/C;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,OAWxF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,WAE7C;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,2CAE7C;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAgB7D;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAUxE;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,UAQrE;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,UAAU;;;;;;;;;;;;;;;eAjG5C,CAAC;cACd,CAAC;;;;;;;;gBAWD,CAAC;4BAA0B,CAAC;;;;EA2FlC;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAW,UAExD"}
|
|
@@ -69,6 +69,22 @@ export function parseToLocalDateTime(dateString) {
|
|
|
69
69
|
}
|
|
70
70
|
return dateObj;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns `date` if it falls within the visit's start/stop window, otherwise the
|
|
74
|
+
* visit's start datetime. This keeps default encounter datetimes valid when filling
|
|
75
|
+
* forms against a past (stopped) visit via retrospective data entry; the backend
|
|
76
|
+
* rejects encounters dated outside the visit window.
|
|
77
|
+
*/ export function getDateWithinVisitWindow(date, visit) {
|
|
78
|
+
if (!visit) {
|
|
79
|
+
return date;
|
|
80
|
+
}
|
|
81
|
+
const visitStart = visit.startDatetime ? new Date(visit.startDatetime) : null;
|
|
82
|
+
const visitStop = visit.stopDatetime ? new Date(visit.stopDatetime) : null;
|
|
83
|
+
if (visitStart && date < visitStart || visitStop && date > visitStop) {
|
|
84
|
+
return visitStart ?? visitStop;
|
|
85
|
+
}
|
|
86
|
+
return date;
|
|
87
|
+
}
|
|
72
88
|
export function formatDateAsDisplayString(field, date) {
|
|
73
89
|
const options = {
|
|
74
90
|
noToday: true
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import { init, teardown } from './lifecycle';
|
|
|
8
8
|
import { isEmpty, useFormJson } from '.';
|
|
9
9
|
import { formEngineAppName } from './globals';
|
|
10
10
|
import { reportError } from './utils/error-utils';
|
|
11
|
+
import { getDateWithinVisitWindow } from './utils/common-utils';
|
|
11
12
|
import { useFormCollapse } from './hooks/useFormCollapse';
|
|
12
13
|
import { useFormWorkspaceSize } from './hooks/useFormWorkspaceSize';
|
|
13
14
|
import { usePageObserver } from './components/sidebar/usePageObserver';
|
|
@@ -58,9 +59,12 @@ const FormEngine = ({
|
|
|
58
59
|
const { t } = useTranslation();
|
|
59
60
|
const session = useSession();
|
|
60
61
|
const ref = useRef(null);
|
|
62
|
+
const rawSessionDate = useRef(new Date());
|
|
63
|
+
// Recompute when the visit bounds arrive or change; the visit prop may not be
|
|
64
|
+
// fully loaded when the form mounts.
|
|
61
65
|
const sessionDate = useMemo(() => {
|
|
62
|
-
return
|
|
63
|
-
}, []);
|
|
66
|
+
return getDateWithinVisitWindow(rawSessionDate.current, visit);
|
|
67
|
+
}, [visit?.startDatetime, visit?.stopDatetime]);
|
|
64
68
|
const workspaceSize = useFormWorkspaceSize(ref);
|
|
65
69
|
const { patient, isLoadingPatient } = usePatientData(patientUUID);
|
|
66
70
|
const [isLoadingDependencies, setIsLoadingDependencies] = useState(false);
|
|
@@ -21,9 +21,16 @@ import { assignedOrderIds } from '../../adapters/orders-adapter';
|
|
|
21
21
|
import { type OpenmrsResource } from '@openmrs/esm-framework';
|
|
22
22
|
import { assignedDiagnosesIds } from '../../adapters/encounter-diagnosis-adapter';
|
|
23
23
|
|
|
24
|
+
type MutableSessionProps = {
|
|
25
|
+
encounterRole: string;
|
|
26
|
+
encounterProvider: string;
|
|
27
|
+
encounterDate?: Date;
|
|
28
|
+
encounterLocation: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
24
31
|
export function prepareEncounter(
|
|
25
32
|
context: FormContextProps,
|
|
26
|
-
encounterDate: Date,
|
|
33
|
+
encounterDate: Date | undefined,
|
|
27
34
|
encounterRole: string,
|
|
28
35
|
encounterProvider: string,
|
|
29
36
|
location: string,
|
|
@@ -54,7 +61,9 @@ export function prepareEncounter(
|
|
|
54
61
|
];
|
|
55
62
|
}
|
|
56
63
|
// TODO: Question: Should we be editing the location, form and visit here?
|
|
57
|
-
|
|
64
|
+
if (encounterDate) {
|
|
65
|
+
encounterForSubmission.encounterDatetime = encounterDate;
|
|
66
|
+
}
|
|
58
67
|
encounterForSubmission.location = location;
|
|
59
68
|
encounterForSubmission.form = {
|
|
60
69
|
uuid: formJson.uuid,
|
|
@@ -68,7 +77,6 @@ export function prepareEncounter(
|
|
|
68
77
|
} else {
|
|
69
78
|
encounterForSubmission = {
|
|
70
79
|
patient: patient.id,
|
|
71
|
-
encounterDatetime: encounterDate,
|
|
72
80
|
location: location,
|
|
73
81
|
encounterType: formJson.encounterType,
|
|
74
82
|
encounterProviders: [
|
|
@@ -85,6 +93,9 @@ export function prepareEncounter(
|
|
|
85
93
|
orders: ordersForSubmission,
|
|
86
94
|
diagnoses: diagnosesForSubmission,
|
|
87
95
|
};
|
|
96
|
+
if (encounterDate) {
|
|
97
|
+
encounterForSubmission.encounterDatetime = encounterDate;
|
|
98
|
+
}
|
|
88
99
|
}
|
|
89
100
|
return encounterForSubmission;
|
|
90
101
|
}
|
|
@@ -171,14 +182,31 @@ export function saveAttachments(fields: FormField[], encounter: OpenmrsEncounter
|
|
|
171
182
|
return Promise.all(allPromises);
|
|
172
183
|
}
|
|
173
184
|
|
|
174
|
-
export function getMutableSessionProps(context: FormContextProps) {
|
|
175
|
-
const {
|
|
185
|
+
export function getMutableSessionProps(context: FormContextProps): MutableSessionProps {
|
|
186
|
+
const {
|
|
187
|
+
formFields,
|
|
188
|
+
location,
|
|
189
|
+
currentProvider,
|
|
190
|
+
customDependencies,
|
|
191
|
+
sessionDate,
|
|
192
|
+
domainObjectValue: encounter,
|
|
193
|
+
visit,
|
|
194
|
+
} = context;
|
|
176
195
|
const { defaultEncounterRole } = customDependencies;
|
|
177
196
|
const encounterRole =
|
|
178
197
|
formFields.find((field) => field.type === 'encounterRole')?.meta.submission?.newValue || defaultEncounterRole?.uuid;
|
|
179
198
|
const encounterProvider =
|
|
180
199
|
formFields.find((field) => field.type === 'encounterProvider')?.meta.submission?.newValue || currentProvider.uuid;
|
|
181
|
-
const
|
|
200
|
+
const explicitEncounterDate = formFields.find((field) => field.type === 'encounterDatetime')?.meta.submission
|
|
201
|
+
?.newValue as Date | undefined;
|
|
202
|
+
// Stopped visits need an explicit datetime because the backend defaults omitted
|
|
203
|
+
// encounter datetimes to server "now", which can be outside the visit window.
|
|
204
|
+
// Active visits should use the backend default so client clock skew does not
|
|
205
|
+
// submit future encounter datetimes.
|
|
206
|
+
const defaultEncounterDate = visit?.stopDatetime ? sessionDate : undefined;
|
|
207
|
+
const encounterDate =
|
|
208
|
+
explicitEncounterDate ??
|
|
209
|
+
(encounter?.encounterDatetime ? new Date(encounter.encounterDatetime) : defaultEncounterDate);
|
|
182
210
|
const encounterLocation =
|
|
183
211
|
formFields.find((field) => field.type === 'encounterLocation')?.meta.submission?.newValue ||
|
|
184
212
|
encounter?.location?.uuid ||
|
|
@@ -186,7 +214,7 @@ export function getMutableSessionProps(context: FormContextProps) {
|
|
|
186
214
|
return {
|
|
187
215
|
encounterRole: encounterRole as string,
|
|
188
216
|
encounterProvider: encounterProvider as string,
|
|
189
|
-
encounterDate
|
|
217
|
+
encounterDate,
|
|
190
218
|
encounterLocation: encounterLocation as string,
|
|
191
219
|
};
|
|
192
220
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
import { type FormSchema, type FormField, type OpenmrsObs, type RenderType } from '../types';
|
|
3
3
|
import { isEmpty } from '../validators/form-validator';
|
|
4
|
-
import { formatDate, type FormatDateOptions } from '@openmrs/esm-framework';
|
|
4
|
+
import { formatDate, type FormatDateOptions, type Visit } from '@openmrs/esm-framework';
|
|
5
5
|
|
|
6
6
|
export function flattenObsList(obsList: OpenmrsObs[]): OpenmrsObs[] {
|
|
7
7
|
const flattenedList: OpenmrsObs[] = [];
|
|
@@ -75,6 +75,24 @@ export function parseToLocalDateTime(dateString: string): Date {
|
|
|
75
75
|
return dateObj;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Returns `date` if it falls within the visit's start/stop window, otherwise the
|
|
80
|
+
* visit's start datetime. This keeps default encounter datetimes valid when filling
|
|
81
|
+
* forms against a past (stopped) visit via retrospective data entry; the backend
|
|
82
|
+
* rejects encounters dated outside the visit window.
|
|
83
|
+
*/
|
|
84
|
+
export function getDateWithinVisitWindow(date: Date, visit?: Visit): Date {
|
|
85
|
+
if (!visit) {
|
|
86
|
+
return date;
|
|
87
|
+
}
|
|
88
|
+
const visitStart = visit.startDatetime ? new Date(visit.startDatetime) : null;
|
|
89
|
+
const visitStop = visit.stopDatetime ? new Date(visit.stopDatetime) : null;
|
|
90
|
+
if ((visitStart && date < visitStart) || (visitStop && date > visitStop)) {
|
|
91
|
+
return visitStart ?? visitStop;
|
|
92
|
+
}
|
|
93
|
+
return date;
|
|
94
|
+
}
|
|
95
|
+
|
|
78
96
|
export function formatDateAsDisplayString(field: FormField, date: Date) {
|
|
79
97
|
const options: Partial<FormatDateOptions> = { noToday: true };
|
|
80
98
|
if (field.datePickerFormat === 'calendar') {
|