@kenyaemr/esm-ward-app 8.5.1-pre.37 → 8.5.1-pre.44

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.
Files changed (55) hide show
  1. package/.turbo/turbo-build.log +12 -12
  2. package/dist/1160.js +1 -0
  3. package/dist/1160.js.map +1 -0
  4. package/dist/1917.js +1 -1
  5. package/dist/1917.js.map +1 -1
  6. package/dist/4224.js +2 -0
  7. package/dist/4224.js.map +1 -0
  8. package/dist/6009.js +1 -0
  9. package/dist/6009.js.map +1 -0
  10. package/dist/6012.js +1 -1
  11. package/dist/6012.js.map +1 -1
  12. package/dist/6871.js +1 -1
  13. package/dist/6871.js.map +1 -1
  14. package/dist/7059.js +2 -0
  15. package/dist/7059.js.map +1 -0
  16. package/dist/7661.js +1 -1
  17. package/dist/7661.js.map +1 -1
  18. package/dist/8205.js +1 -1
  19. package/dist/8205.js.map +1 -1
  20. package/dist/8308.js +1 -0
  21. package/dist/8308.js.map +1 -0
  22. package/dist/9113.js +1 -0
  23. package/dist/{9880.js.map → 9113.js.map} +1 -1
  24. package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +162 -111
  25. package/dist/main.js +1 -1
  26. package/dist/main.js.map +1 -1
  27. package/dist/routes.json +1 -1
  28. package/package.json +2 -1
  29. package/src/config-schema.ts +28 -0
  30. package/src/discharge-printouts/discharge-printout.preview-modal.tsx +40 -0
  31. package/src/discharge-printouts/discharge-printout.resource.ts +335 -0
  32. package/src/discharge-printouts/discharge-printouts.scss +125 -0
  33. package/src/discharge-printouts/discharge-summary.tsx +170 -0
  34. package/src/discharge-printouts/field-input.tsx +21 -0
  35. package/src/discharge-printouts/gate-pass-printout.tsx +125 -0
  36. package/src/discharge-printouts/lab-results.tsx +96 -0
  37. package/src/hooks/useIpdDischargeEncounter.ts +10 -8
  38. package/src/index.ts +4 -0
  39. package/src/routes.json +4 -0
  40. package/src/ward-patients/admitted-patients.tsx +2 -2
  41. package/src/ward-patients/discharge-in-patients.tsx +22 -18
  42. package/src/ward-patients/discharge-patients.tsx +23 -3
  43. package/src/ward-patients/patient-cells.tsx +4 -10
  44. package/src/ward-workspace/admit-patient-form-workspace/patient-admission.resources.ts +19 -1
  45. package/src/ward-workspace/kenya-emr-patient-discharge/patient-discharge.resource.tsx +2 -1
  46. package/src/ward-workspace/patient-transfer-bed-swap/patient-admit-or-transfer-request-form.component.tsx +1 -1
  47. package/dist/1352.js +0 -2
  48. package/dist/1352.js.map +0 -1
  49. package/dist/3423.js +0 -1
  50. package/dist/3423.js.map +0 -1
  51. package/dist/4701.js +0 -2
  52. package/dist/4701.js.map +0 -1
  53. package/dist/9880.js +0 -1
  54. /package/dist/{1352.js.LICENSE.txt → 4224.js.LICENSE.txt} +0 -0
  55. /package/dist/{4701.js.LICENSE.txt → 7059.js.LICENSE.txt} +0 -0
@@ -0,0 +1,170 @@
1
+ import { InlineLoading, InlineNotification } from '@carbon/react';
2
+ import { useEmrConfiguration, usePatient, useSession } from '@openmrs/esm-framework';
3
+ import dayjs from 'dayjs';
4
+ import React, { type FC, useMemo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { useEncounterDetails } from '../hooks/useIpdDischargeEncounter';
7
+ import { useProvider } from '../ward-workspace/admit-patient-form-workspace/patient-admission.resources';
8
+ import {
9
+ DATE_FORMART,
10
+ getTreatmentDisplayText,
11
+ usePatientDiagnosis,
12
+ usePatientOrders,
13
+ } from './discharge-printout.resource';
14
+ import styles from './discharge-printouts.scss';
15
+ import FieldInput from './field-input';
16
+ import LabResults from './lab-results';
17
+
18
+ type DischargeSummaryProps = {
19
+ dischargeEncounterUuid: string;
20
+ patient: {
21
+ uuid: string;
22
+ openmrsId: string;
23
+ name: string;
24
+ };
25
+ };
26
+
27
+ const DischargeSummary: FC<DischargeSummaryProps> = ({ dischargeEncounterUuid, patient: _patient }) => {
28
+ const { t } = useTranslation();
29
+ const { encounter, error, isLoading } = useEncounterDetails(dischargeEncounterUuid);
30
+ const { isLoading: isLoadingPatient, patient, error: patientError } = usePatient(_patient.uuid);
31
+ const {
32
+ isLoading: isLoadingDiagnosis,
33
+ error: diagnosisError,
34
+ display: diagnoses,
35
+ } = usePatientDiagnosis(dischargeEncounterUuid);
36
+ const session = useSession();
37
+ const { error: errorProvider, isLoading: isLoadingProvider, provider } = useProvider(session.currentProvider.uuid);
38
+ const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
39
+ const {
40
+ isLoading: isLoadingOders,
41
+ error: orderserror,
42
+ drugOrders,
43
+ testOrders,
44
+ complaints,
45
+ drugReactions,
46
+ orderEncounters,
47
+ dischargeinstructions,
48
+ physicalExaminations,
49
+ } = usePatientOrders(dischargeEncounterUuid);
50
+ const admissionDate = useMemo(() => {
51
+ const admisionEncounter = encounter?.visit?.encounters?.find(
52
+ (e) => e.encounterType.uuid === emrConfiguration?.admissionEncounterType?.uuid,
53
+ );
54
+ if (!admisionEncounter || !admisionEncounter.encounterDatetime) return null;
55
+ return admisionEncounter.encounterDatetime;
56
+ }, [encounter, emrConfiguration]);
57
+
58
+ if (
59
+ isLoading ||
60
+ isLoadingPatient ||
61
+ isLoadingEmrConfiguration ||
62
+ isLoadingDiagnosis ||
63
+ isLoadingProvider ||
64
+ isLoadingOders
65
+ )
66
+ return <InlineLoading />;
67
+ if (error || patientError || errorFetchingEmrConfiguration || diagnosisError || errorProvider || orderserror)
68
+ return (
69
+ <InlineNotification
70
+ kind="error"
71
+ title={
72
+ error?.message ??
73
+ patientError?.message ??
74
+ errorFetchingEmrConfiguration?.message ??
75
+ diagnosisError?.message ??
76
+ errorProvider?.message ??
77
+ orderserror?.message
78
+ }
79
+ />
80
+ );
81
+ return (
82
+ <div className={styles.content}>
83
+ <div className={styles.header}>
84
+ <h5>{session.sessionLocation.display}</h5>
85
+ <h5>{t('dischargeSummary', 'Discharge Summary')}</h5>
86
+ </div>
87
+ <div className={styles.cols3}>
88
+ <FieldInput name={t('name', 'Name')} value={_patient.name} />
89
+ <FieldInput name={t('ipNo', 'IP No')} value={_patient.openmrsId} />
90
+ <FieldInput
91
+ name={t('age', 'Age')}
92
+ value={`${Math.abs(dayjs(patient.birthDate).diff(dayjs(), 'years'))} years`}
93
+ />
94
+ </div>
95
+ <div className={styles.cols3}>
96
+ <FieldInput name={t('sex', 'Sex')} value={patient.gender} />
97
+ <FieldInput name={t('dateOfAdmissionAbrv', 'DOA')} value={dayjs(admissionDate).format(DATE_FORMART)} />
98
+ <FieldInput
99
+ name={t('dateOfDischargeAbrv', 'DOD')}
100
+ value={dayjs(encounter.encounterDatetime).format(DATE_FORMART)}
101
+ />
102
+ </div>
103
+ <div className={styles.cols2}>
104
+ <FieldInput name={t('nameOfConsultant', 'Name of consultant')} value={provider?.display?.split('-')?.at(-1)} />
105
+ <FieldInput name={t('department', 'Department')} value={encounter.location?.display} />
106
+ </div>
107
+
108
+ <div>
109
+ <strong className={styles.txtUpper}>{t('diagnosis', 'Diagnosis')}</strong>
110
+ <p className={styles.txtTitle}>{diagnoses ?? t('noDiagnoses', 'No Diagnoses')}</p>
111
+ </div>
112
+ <div>
113
+ <strong className={styles.txtUpper}>{t('history', 'History')}</strong>
114
+ <p>
115
+ {`${complaints ? 'Presented with ' + complaints + '.' : ''}${
116
+ drugReactions
117
+ ? t('knownDrugAllergies', 'Known drug allergies') + ': ' + drugReactions
118
+ : t('noKnownDrugAllergies', 'No known drug allergies')
119
+ }`}
120
+ </p>
121
+ </div>
122
+ <div>
123
+ <strong className={styles.txtUpper}>{t('physicalExamination', 'Physical Examination')}</strong>
124
+ {physicalExaminations?.length ? (
125
+ physicalExaminations?.map((examination, i) => (
126
+ <p key={i} className={styles.txtTitle}>
127
+ {examination}
128
+ </p>
129
+ ))
130
+ ) : (
131
+ <p>{t('noExaminations', 'No Examinations')}</p>
132
+ )}
133
+ </div>
134
+ <div>
135
+ <strong className={styles.txtUpper}>{t('investigation', 'Investigation')}</strong>
136
+ <p>
137
+ {testOrders.map((order) => (
138
+ <LabResults
139
+ order={order}
140
+ key={order.uuid}
141
+ labEncounter={orderEncounters.find((e) => e.uuid === order.encounter.uuid)}
142
+ />
143
+ ))}
144
+ </p>
145
+ </div>
146
+ <div>
147
+ <strong className={styles.txtUpper}>{t('treatment', 'Treatment')}</strong>
148
+ <div>
149
+ {drugOrders.map((order) => (
150
+ <p key={order.uuid}>{getTreatmentDisplayText(order)}</p>
151
+ ))}
152
+ </div>
153
+ </div>
154
+ <div>
155
+ <strong className={styles.txtUpper}>{t('dischargeInstructions', 'Discharge Instructions')}</strong>
156
+ <p>{dischargeinstructions ?? t('noInstructions', 'No instructions')}</p>
157
+ </div>
158
+ <div className={styles.cols2}>
159
+ <FieldInput name={t('name', 'Name')} value={provider?.display?.split('-')?.at(-1)} />
160
+ <FieldInput name={t('signature', 'Signature')} />
161
+ </div>
162
+ <div className={styles.cols2}>
163
+ <FieldInput name={t('destination', 'Destination')} value={t('discharge', 'Discharge')} />
164
+ <FieldInput name={t('date', 'Date')} value={dayjs().format(DATE_FORMART)} />
165
+ </div>
166
+ </div>
167
+ );
168
+ };
169
+
170
+ export default DischargeSummary;
@@ -0,0 +1,21 @@
1
+ import React, { type FC } from 'react';
2
+ import styles from './discharge-printouts.scss';
3
+ type FieldInputProps = {
4
+ name: string;
5
+ value?: string;
6
+ delimiter?: string;
7
+ };
8
+
9
+ const FieldInput: FC<FieldInputProps> = ({ name: fieldName, value, delimiter = ':' }) => {
10
+ return (
11
+ <div className={styles.field}>
12
+ <span className={styles.name}>
13
+ {fieldName}
14
+ {delimiter && `${delimiter} `}
15
+ </span>
16
+ <strong className={styles.value}>{value}</strong>
17
+ </div>
18
+ );
19
+ };
20
+
21
+ export default FieldInput;
@@ -0,0 +1,125 @@
1
+ import { InlineLoading, InlineNotification } from '@carbon/react';
2
+ import { useEmrConfiguration, usePatient, useSession } from '@openmrs/esm-framework';
3
+ import dayjs from 'dayjs';
4
+ import React, { useMemo, type FC } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { useEncounterDetails } from '../hooks/useIpdDischargeEncounter';
7
+ import styles from './discharge-printouts.scss';
8
+ import FieldInput from './field-input';
9
+ import { DATE_FORMART, TIME_FORMART } from './discharge-printout.resource';
10
+
11
+ type GatePassPrintoutProps = {
12
+ dischargeEncounterUuid: string;
13
+ patient: {
14
+ uuid: string;
15
+ openmrsId: string;
16
+ name: string;
17
+ };
18
+ };
19
+
20
+ const GatePassPrintout: FC<GatePassPrintoutProps> = ({ dischargeEncounterUuid, patient: _patient }) => {
21
+ const { t } = useTranslation();
22
+
23
+ const { encounter, error, isLoading } = useEncounterDetails(dischargeEncounterUuid);
24
+ const { isLoading: isLoadingPatient, patient, error: patientError } = usePatient(_patient.uuid);
25
+ const session = useSession();
26
+ const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
27
+
28
+ const admissionDate = useMemo(() => {
29
+ const admisionEncounter = encounter?.visit?.encounters?.find(
30
+ (e) => e.encounterType.uuid === emrConfiguration?.admissionEncounterType?.uuid,
31
+ );
32
+ if (!admisionEncounter || !admisionEncounter.encounterDatetime) return null;
33
+ return admisionEncounter.encounterDatetime;
34
+ }, [encounter, emrConfiguration]);
35
+
36
+ if (isLoading || isLoadingPatient || isLoadingEmrConfiguration) return <InlineLoading />;
37
+ if (error || patientError || errorFetchingEmrConfiguration)
38
+ return (
39
+ <InlineNotification
40
+ kind="error"
41
+ title={error?.message ?? patientError?.message ?? errorFetchingEmrConfiguration?.message}
42
+ />
43
+ );
44
+
45
+ return (
46
+ <div className={styles.content}>
47
+ <div className={styles.header}>
48
+ <h5>{session?.sessionLocation?.display}</h5>
49
+ <h5>{t('wardGatePass', 'Ward gate pass')}</h5>
50
+ </div>
51
+ <div className={styles.cols4}>
52
+ <FieldInput name={t('paperNo', 'Paper No')} value={_patient.openmrsId} />
53
+ <FieldInput name={t('patientNo', 'Patient No')} value={_patient.openmrsId} />
54
+ <FieldInput name={t('date', 'Date')} value={dayjs().format(DATE_FORMART)} />
55
+ <FieldInput name={t('time', 'Time')} value={dayjs().format(TIME_FORMART)} />
56
+ </div>
57
+ <div className={styles.cols2}>
58
+ <FieldInput name={t('patientNames', 'Patient names')} value={_patient.name} />
59
+ <FieldInput
60
+ name={t('age', 'Age')}
61
+ value={`${Math.abs(dayjs(patient.birthDate).diff(dayjs(), 'years'))} years`}
62
+ />
63
+ </div>
64
+ <div className={styles.cols2}>
65
+ <FieldInput name={t('dateOfAdmissionAbrv', 'DOA')} value={dayjs(admissionDate).format(DATE_FORMART)} />
66
+ <FieldInput
67
+ name={t('dateOfDischargeAbrv', 'DOD')}
68
+ value={dayjs(encounter.encounterDatetime).format(DATE_FORMART)}
69
+ />
70
+ </div>
71
+
72
+ <div>
73
+ <p>{t('methodsOfPayment', 'Method of payment (tick as approximately)')}</p>
74
+ <br />
75
+ <div className={styles.cols7}>
76
+ <span>{t('cashCheckBox', 'Cash [ ]')}</span>
77
+ <span>{t('chequCheckBox', 'Cheque [ ]')}</span>
78
+ <span>{t('shaCheckBox', 'SHA [ ]')}</span>
79
+ <span>{t('scheme', 'Scheme [ ]')}</span>
80
+ <span>{t('mrm', 'M.R.M [ ]')}</span>
81
+ <FieldInput name={t('other', 'Other')} />
82
+ <FieldInput name="." delimiter="." />
83
+ </div>
84
+ </div>
85
+ <p>
86
+ <strong>{t('approvedBy', 'Approved By')}</strong>
87
+ </p>
88
+ <div className={styles.cols4}>
89
+ <FieldInput name={t('accountOfficer', 'Account Ofiicer')} />
90
+ <FieldInput name="." delimiter="." />
91
+ <FieldInput name={t('sign', 'Sign')} />
92
+ <FieldInput name={t('date', 'Date')} />
93
+ </div>
94
+ <div className={styles.cols4}>
95
+ <FieldInput name={t('healthRecordOfficer', 'Health Record Officer')} />
96
+ <FieldInput name="." delimiter="." />
97
+ <FieldInput name={t('sign', 'Sign')} />
98
+ <FieldInput name={t('date', 'Date')} />
99
+ </div>
100
+ <div className={styles.cols4}>
101
+ <FieldInput name={t('nurseInCharge', 'Nurse In Charge')} />
102
+ <FieldInput name="." delimiter="." />
103
+ <FieldInput name={t('sign', 'Sign')} />
104
+ <FieldInput name={t('date', 'Date')} />
105
+ </div>
106
+ <div className={styles.cols4}>
107
+ <FieldInput name={t('securityGuard', 'Security Guard')} />
108
+ <FieldInput name="." delimiter="." />
109
+ <FieldInput name={t('sign', 'Sign')} />
110
+ <FieldInput name={t('date', 'Date')} />
111
+ </div>
112
+ <p>
113
+ <strong>{t('note', 'N/B')}:</strong>
114
+ <span>
115
+ {t(
116
+ 'noteText',
117
+ 'This form should be filled in duplicate, one copy to be retained in the ward and the other to be left in the main gate',
118
+ )}
119
+ </span>
120
+ </p>
121
+ </div>
122
+ );
123
+ };
124
+
125
+ export default GatePassPrintout;
@@ -0,0 +1,96 @@
1
+ import { InlineLoading, InlineNotification } from '@carbon/react';
2
+ import { type Encounter } from '@openmrs/esm-framework';
3
+ import type { Order } from '@openmrs/esm-patient-common-lib';
4
+ import React, { type FC, useMemo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { getObservationDisplayValue, useOrderConceptByUuid } from './discharge-printout.resource';
7
+ import styles from './discharge-printouts.scss';
8
+ type LabResultsProps = {
9
+ order: Order;
10
+ labEncounter?: Encounter;
11
+ };
12
+
13
+ const LabResults: FC<LabResultsProps> = ({ order, labEncounter: encounter }) => {
14
+ const { concept, isLoading: isLoadingTestConcepts, error } = useOrderConceptByUuid(order?.concept?.uuid);
15
+ const testResultObs = useMemo(() => {
16
+ if (!encounter || !concept) return null;
17
+ return encounter.obs?.find((obs) => obs.concept.uuid === concept.uuid);
18
+ }, [concept, encounter]);
19
+ const { t } = useTranslation();
20
+ const EMPTY_TEXT = t('noResults', 'No results');
21
+
22
+ const testResults = useMemo(() => {
23
+ if (!concept) return [];
24
+
25
+ // For panel tests (with set members)
26
+ if (concept.setMembers && concept.setMembers.length > 0) {
27
+ return concept.setMembers.map((memberConcept) => {
28
+ const memberObs = testResultObs?.groupMembers?.find((obs) => obs.concept.uuid === memberConcept.uuid);
29
+ let resultValue: string;
30
+ if (memberObs) {
31
+ resultValue = getObservationDisplayValue(memberObs.value ?? (memberObs as any));
32
+ } else {
33
+ resultValue = EMPTY_TEXT;
34
+ }
35
+
36
+ return {
37
+ id: memberConcept.uuid,
38
+ testType: memberConcept.display || EMPTY_TEXT,
39
+ result: resultValue,
40
+ normalRange:
41
+ memberConcept.hiNormal && memberConcept.lowNormal
42
+ ? `${memberConcept.lowNormal} - ${memberConcept.hiNormal}`
43
+ : 'N/A',
44
+ };
45
+ });
46
+ }
47
+
48
+ // For single tests (no set members)
49
+ let resultValue: string;
50
+ if (testResultObs) {
51
+ resultValue = getObservationDisplayValue(testResultObs.value ?? (testResultObs as any));
52
+ } else {
53
+ resultValue = EMPTY_TEXT;
54
+ }
55
+
56
+ return [
57
+ {
58
+ id: concept.uuid,
59
+ testType: concept.display || EMPTY_TEXT,
60
+ result: resultValue,
61
+ normalRange: concept.hiNormal && concept.lowNormal ? `${concept.lowNormal} - ${concept.hiNormal}` : 'N/A',
62
+ },
63
+ ];
64
+ }, [concept, testResultObs, EMPTY_TEXT]);
65
+
66
+ if (isLoadingTestConcepts)
67
+ return (
68
+ <InlineLoading
69
+ status="active"
70
+ iconDescription="Loading"
71
+ description={t('loadinglabresults', 'Loading lab results') + '...'}
72
+ />
73
+ );
74
+
75
+ if (error)
76
+ return (
77
+ <InlineNotification
78
+ kind="error"
79
+ title={t('labResultError', 'Error loading lab results')}
80
+ subtitle={error?.message}
81
+ />
82
+ );
83
+
84
+ return (
85
+ <div key={order.uuid} className={styles.txtTitle}>
86
+ {testResults.map((res) => (
87
+ <p key={res.id}>
88
+ <strong>{res.testType.toLowerCase()}: </strong>
89
+ <span>{res.result}</span>
90
+ </p>
91
+ ))}
92
+ </div>
93
+ );
94
+ };
95
+
96
+ export default LabResults;
@@ -94,10 +94,12 @@ export const useIpdDischargeEncounter = () => {
94
94
  const { isLoadingLocation, location, errorFetchingLocation } = useWardLocation();
95
95
  const pageSizes = [10, 20, 50, 100];
96
96
  const [currPageSize, setCurrPageSize] = useState(10);
97
- const urls =
98
- !location || emrConfiguration
99
- ? null
100
- : `${fhirBaseUrl}/Encounter?_summary=data&type=${emrConfiguration?.exitFromInpatientEncounterType}&location=${location?.uuid}`;
97
+
98
+ const urls = useMemo(() => {
99
+ if (!location || !emrConfiguration?.exitFromInpatientEncounterType?.uuid) return null;
100
+ else
101
+ return `${fhirBaseUrl}/Encounter?_summary=data&type=${emrConfiguration?.exitFromInpatientEncounterType?.uuid}&location=${location?.uuid}`;
102
+ }, [location, emrConfiguration]);
101
103
  const { data, isLoading, error, paginated, currentPage, goTo, totalCount, currentPageSize } =
102
104
  useFhirPagination<Entry>(urls, currPageSize);
103
105
  const encounters = useMemo(() => {
@@ -126,10 +128,10 @@ export const useIpdDischargeEncounter = () => {
126
128
  };
127
129
  };
128
130
 
129
- export const useEncounterDetails = (encounterUuid: string) => {
130
- const rep =
131
- 'custom:(uuid,display,encounterDatetime,visit:(uuid,display,encounters:(uuid,display,encounterType:(uuid,display),encounterDatetime)))';
132
- const url = `${restBaseUrl}/encounter/${encounterUuid}?v=${rep}`;
131
+ export const useEncounterDetails = (encounterUuid: string, rep?: string) => {
132
+ const _rep =
133
+ 'custom:(uuid,display,location:(display),encounterDatetime,visit:(uuid,display,encounters:(uuid,display,encounterType:(uuid,display),encounterDatetime)))';
134
+ const url = `${restBaseUrl}/encounter/${encounterUuid}?v=${rep ?? _rep}`;
133
135
  const { data, error, isLoading } = useSWR<FetchResponse<Encounter>>(url, openmrsFetch);
134
136
  return {
135
137
  isLoading,
package/src/index.ts CHANGED
@@ -128,6 +128,10 @@ export const wardPatientWorkspaceBanner = getAsyncLifecycle(
128
128
  () => import('./ward-workspace/patient-banner/patient-banner.component'),
129
129
  options,
130
130
  );
131
+ export const patientDischargeDocumentPreview = getAsyncLifecycle(
132
+ () => import('./discharge-printouts/discharge-printout.preview-modal'),
133
+ options,
134
+ );
131
135
 
132
136
  export function startupApp() {
133
137
  registerBreadcrumbs([]);
package/src/routes.json CHANGED
@@ -85,6 +85,10 @@
85
85
  "name": "maternal-ward",
86
86
  "slot": "maternal-ward"
87
87
  },
88
+ {
89
+ "component": "patientDischargeDocumentPreview",
90
+ "name": "patient-discharge-document-preview-modal"
91
+ },
88
92
  {
89
93
  "component": "wardPatientWorkspaceBanner",
90
94
  "name": "ward-patient-workspace-banner",
@@ -18,7 +18,7 @@ import {
18
18
  parseDate,
19
19
  useAppContext,
20
20
  useConfig,
21
- usePagination
21
+ usePagination,
22
22
  } from '@openmrs/esm-framework';
23
23
  import { usePaginationInfo } from '@openmrs/esm-patient-common-lib';
24
24
  import dayjs from 'dayjs';
@@ -109,7 +109,7 @@ const AdmittedPatients = () => {
109
109
  action: (
110
110
  <OverflowMenu size={'sm'} flipped>
111
111
  <OverflowMenuItem
112
- itemText={t('tranfer', 'Tranfer')}
112
+ itemText={t('interWardTransfer', 'Interward Trasfer')}
113
113
  onClick={() =>
114
114
  launchWorkspace('patient-transfer-swap-workspace', {
115
115
  workspaceTitle: 'Trasfer',
@@ -1,43 +1,40 @@
1
1
  import {
2
+ DataTable,
2
3
  OverflowMenu,
3
4
  OverflowMenuItem,
4
- DataTable,
5
- TableContainer,
5
+ Pagination,
6
6
  Table,
7
- TableHead,
8
- TableRow,
9
- TableHeader,
10
7
  TableBody,
11
8
  TableCell,
12
- Pagination,
9
+ TableContainer,
10
+ TableHead,
11
+ TableHeader,
12
+ TableRow,
13
13
  } from '@carbon/react';
14
- import React, { useMemo, useState } from 'react';
15
- import { useTranslation } from 'react-i18next';
16
- import { EmptyState } from './table-state-components';
17
14
  import {
18
15
  type Encounter,
19
16
  formatDatetime,
20
- launchWorkspace,
21
- type OpenmrsResource,
22
17
  parseDate,
23
18
  useAppContext,
24
19
  useConfig,
25
20
  useEmrConfiguration,
26
21
  usePagination,
27
22
  } from '@openmrs/esm-framework';
28
- import { type WardPatient, type WardViewContext } from '../types';
29
- import { bedLayoutToBed, getOpenmrsId } from '../ward-view/ward-view.resource';
30
- import dayjs from 'dayjs';
31
23
  import { usePaginationInfo } from '@openmrs/esm-patient-common-lib';
24
+ import dayjs from 'dayjs';
25
+ import React, { useMemo, useState } from 'react';
26
+ import { useTranslation } from 'react-i18next';
32
27
  import { type WardConfigObject } from '../config-schema';
33
- import { HyperLinkPatientCell, PatientBillStatus, UnAssignPatientBedAction } from './patient-cells';
28
+ import { type WardPatient, type WardViewContext } from '../types';
29
+ import { bedLayoutToBed, getOpenmrsId } from '../ward-view/ward-view.resource';
34
30
  import { usePatientDischarge } from '../ward-workspace/kenya-emr-patient-discharge/patient-discharge.resource';
31
+ import { HyperLinkPatientCell, PatientBillStatus, UnAssignPatientBedAction } from './patient-cells';
32
+ import { EmptyState } from './table-state-components';
35
33
 
36
34
  const DischargeInPatients = () => {
37
35
  const { t } = useTranslation();
38
36
  const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
39
37
  const { bedLayouts, wardAdmittedPatientsWithBed, isLoading } = wardPatientGroupDetails ?? {};
40
- //TODO remove (added for demo purposes)
41
38
  const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
42
39
  const { handleDischarge } = usePatientDischarge();
43
40
 
@@ -130,15 +127,22 @@ const DischargeInPatients = () => {
130
127
  <UnAssignPatientBedAction
131
128
  patientUuid={patient.patient.uuid}
132
129
  encounterUuid={encounterAssigningToCurrentInpatientLocation?.uuid}
130
+ loading={wardPatientGroupDetails?.admissionLocationResponse?.isLoading || isLoadingEmrConfiguration}
133
131
  onClick={async () => {
134
- await handleDischarge({} as Encounter, patient, emrConfiguration as Record<string, any>, patient.visit);
132
+ await handleDischarge(
133
+ {} as Encounter,
134
+ patient,
135
+ emrConfiguration as Record<string, any>,
136
+ patient.visit,
137
+ wardPatientGroupDetails?.admissionLocationResponse?.admissionLocation?.ward,
138
+ );
135
139
  }}
136
140
  />
137
141
  </OverflowMenu>
138
142
  ),
139
143
  };
140
144
  });
141
- }, [results, t, emrConfiguration, handleDischarge]);
145
+ }, [results, t, emrConfiguration, handleDischarge, wardPatientGroupDetails, isLoadingEmrConfiguration]);
142
146
 
143
147
  if (!patients.length) return <EmptyState message={t('noDischargeInpatients', 'No Discharge in patients')} />;
144
148
 
@@ -16,7 +16,7 @@ import React, { useMemo } from 'react';
16
16
  import { useTranslation } from 'react-i18next';
17
17
  import { EmptyState, ErrorState } from './table-state-components';
18
18
  import { useIpdDischargeEncounter } from '../hooks/useIpdDischargeEncounter';
19
- import { formatDatetime, parseDate } from '@openmrs/esm-framework';
19
+ import { formatDatetime, parseDate, showModal } from '@openmrs/esm-framework';
20
20
  import {
21
21
  HyperLinkPatientCell,
22
22
  PatientAdmissionDateCell,
@@ -24,6 +24,8 @@ import {
24
24
  PatientDayInWardCell,
25
25
  PatientGenderCell,
26
26
  } from './patient-cells';
27
+ import DischargeSummary from '../discharge-printouts/discharge-summary';
28
+ import GatePassPrintout from '../discharge-printouts/gate-pass-printout';
27
29
 
28
30
  const DischargePatients = () => {
29
31
  const { t } = useTranslation();
@@ -64,8 +66,26 @@ const DischargePatients = () => {
64
66
  daysAdmitted: <PatientDayInWardCell patientUuid={encounter.patient.uuid} encounterUuid={encounter.uuid} />,
65
67
  action: (
66
68
  <OverflowMenu size={'sm'} flipped>
67
- <OverflowMenuItem itemText={t('dischargeSummary', 'Discharge Summary')} onClick={() => {}} />
68
- <OverflowMenuItem itemText={t('gatePass', 'Gate Pass')} onClick={() => {}} />
69
+ <OverflowMenuItem
70
+ itemText={t('dischargeSummary', 'Discharge Summary')}
71
+ onClick={() => {
72
+ const dispose = showModal('patient-discharge-document-preview-modal', {
73
+ size: 'lg',
74
+ onClose: () => dispose(),
75
+ printout: <DischargeSummary dischargeEncounterUuid={encounter.uuid} patient={encounter.patient} />,
76
+ });
77
+ }}
78
+ />
79
+ <OverflowMenuItem
80
+ itemText={t('gatePass', 'Gate Pass')}
81
+ onClick={() => {
82
+ const dispose = showModal('patient-discharge-document-preview-modal', {
83
+ size: 'lg',
84
+ onClose: () => dispose(),
85
+ printout: <GatePassPrintout dischargeEncounterUuid={encounter.uuid} patient={encounter.patient} />,
86
+ });
87
+ }}
88
+ />
69
89
  </OverflowMenu>
70
90
  ),
71
91
  };
@@ -1,16 +1,8 @@
1
1
  import { InlineLoading, OverflowMenuItem, Tag } from '@carbon/react';
2
- import {
3
- ConfigurableLink,
4
- formatDatetime,
5
- parseDate,
6
- useConfig,
7
- useEmrConfiguration,
8
- usePatient,
9
- } from '@openmrs/esm-framework';
2
+ import { ConfigurableLink, formatDatetime, parseDate, useEmrConfiguration, usePatient } from '@openmrs/esm-framework';
10
3
  import dayjs from 'dayjs';
11
4
  import React, { type FC, useMemo } from 'react';
12
5
  import { useTranslation } from 'react-i18next';
13
- import { type WardConfigObject } from '../config-schema';
14
6
  import { useEncounterDetails } from '../hooks/useIpdDischargeEncounter';
15
7
  import { usePatientBills } from '../ward-workspace/kenya-emr-patient-discharge/patient-discharge.resource';
16
8
 
@@ -127,11 +119,13 @@ export const PatientBillStatus: FC<PatientAdmissionCellProps> = ({ patientUuid,
127
119
 
128
120
  type UnAssignPatientBedActionProps = PatientAdmissionCellProps & {
129
121
  onClick?: () => void;
122
+ loading?: boolean;
130
123
  };
131
124
  export const UnAssignPatientBedAction: FC<UnAssignPatientBedActionProps> = ({
132
125
  encounterUuid,
133
126
  patientUuid,
134
127
  onClick,
128
+ loading,
135
129
  }) => {
136
130
  const { encounter, error, isLoading } = useEncounterDetails(encounterUuid);
137
131
  const { t } = useTranslation();
@@ -156,7 +150,7 @@ export const UnAssignPatientBedAction: FC<UnAssignPatientBedActionProps> = ({
156
150
  dailyBedFeeSettled,
157
151
  } = usePatientBills(patientUuid, startDate?.toDate(), endDateDate.toDate());
158
152
 
159
- if (isLoading || isLoadingBills) return <InlineLoading />;
153
+ if (isLoading || isLoadingBills || loading) return <InlineLoading />;
160
154
  if (error || billsError) return null;
161
155
  if (bills.length === 0) return null;
162
156
  if (pendingBills.length > 0) return null;