@kenyaemr/esm-care-panel-app 5.4.2-pre.2178 → 5.4.2-pre.2188

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/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[],"extensions":[{"name":"care-panel-patient-summary","component":"carePanelPatientSummary","slot":"patient-chart-care-panel-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"care-panel-summary-dashboard-link","component":"carePanelSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":3,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-care-panel-dashboard-slot","layoutMode":"anchored","path":"Care panel"}},{"name":"delete-regimen-confirmation-dialog","component":"deleteRegimenConfirmationDialog"},{"name":"hiv-patient-visit-summary-dashboard-link","component":"hivPatientSummaryDashboardLink","slot":"hiv-care-and-treatment-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-hiv-patient-summary-slot","path":"HIV Patient Summary","layoutMode":"anchored"}},{"name":"hiv-patient-visit-summary","slot":"patient-chart-hiv-patient-summary-slot","component":"hivPatientSummary","order":3,"online":true,"offline":false},{"name":"dispensing-patient-vitals","component":"dispensingPaentientVitals","slot":"dispensing-condition-and-diagnoses","order":1,"online":true,"offline":true}],"workspaces":[{"name":"patient-regimen-workspace","title":"Patient Regimen","component":"regimenFormWorkspace","type":"form","canMaximize":true,"canHide":true,"width":"wider"}],"version":"5.4.2-pre.2178"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[],"extensions":[{"name":"care-panel-patient-summary","component":"carePanelPatientSummary","slot":"patient-chart-care-panel-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"care-panel-summary-dashboard-link","component":"carePanelSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":3,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-care-panel-dashboard-slot","layoutMode":"anchored","path":"Care panel"}},{"name":"delete-regimen-confirmation-dialog","component":"deleteRegimenConfirmationDialog"},{"name":"hiv-patient-visit-summary-dashboard-link","component":"hivPatientSummaryDashboardLink","slot":"hiv-care-and-treatment-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-hiv-patient-summary-slot","path":"HIV Patient Summary","layoutMode":"anchored"}},{"name":"hiv-patient-visit-summary","slot":"patient-chart-hiv-patient-summary-slot","component":"hivPatientSummary","order":3,"online":true,"offline":false},{"name":"dispensing-patient-vitals","component":"dispensingPaentientVitals","slot":"dispensing-condition-and-diagnoses","order":1,"online":true,"offline":true}],"workspaces":[{"name":"patient-regimen-workspace","title":"Patient Regimen","component":"regimenFormWorkspace","type":"form","canMaximize":true,"canHide":true,"width":"wider"}],"version":"5.4.2-pre.2188"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-care-panel-app",
3
- "version": "5.4.2-pre.2178",
3
+ "version": "5.4.2-pre.2188",
4
4
  "description": "Patient care panels microfrontend for the OpenMRS SPA",
5
5
  "browser": "dist/kenyaemr-esm-care-panel-app.js",
6
6
  "main": "src/index.ts",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "lodash-es": "^4.17.15",
41
- "react-to-print": "^2.14.13"
41
+ "react-to-print": "^3.1.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@carbon/react": "1.x",
@@ -0,0 +1,272 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { useSession } from '@openmrs/esm-framework';
4
+ import PatientSummaryRow from './patient-summary-row.component';
5
+ import styles from './patient-summary.scss';
6
+ import { type PatientSummary } from '../types';
7
+
8
+ function capitalizeEveryWord(str) {
9
+ if (!str) {
10
+ return '';
11
+ }
12
+ return str.replace(/\b\w/g, (char) => char.toUpperCase());
13
+ }
14
+
15
+ interface PatientSummaryBodyProps {
16
+ data: PatientSummary;
17
+ }
18
+
19
+ const PatientSummaryBody: React.FC<PatientSummaryBodyProps> = ({ data }) => {
20
+ const { t } = useTranslation();
21
+ const currentUserSession = useSession();
22
+
23
+ return (
24
+ <>
25
+ <PatientSummaryRow
26
+ items={[
27
+ { label: t('reportDate', 'Report Date'), value: data?.reportDate, isDate: true },
28
+ { label: t('clinicName', 'Clinic Name'), value: data?.clinicName },
29
+ { label: t('mflCode', 'MFL Code'), value: data?.mflCode },
30
+ ]}
31
+ />
32
+
33
+ <PatientSummaryRow
34
+ items={[
35
+ { label: t('uniquePatientIdentifier', 'Unique Patient Identifier'), value: data?.uniquePatientIdentifier },
36
+ {
37
+ label: t('nationalUniquePatientIdentifier', 'National Unique Patient Identifier'),
38
+ value: data?.nationalUniquePatientIdentifier,
39
+ },
40
+ { label: t('patientName', 'Patient Name'), value: capitalizeEveryWord(data?.patientName) },
41
+ ]}
42
+ />
43
+
44
+ <PatientSummaryRow
45
+ items={[
46
+ { label: t('birthDate', 'Birth Date'), value: data?.birthDate, isDate: true },
47
+ { label: t('age', 'Age'), value: data?.age },
48
+ { label: t('gender', 'Gender'), value: data?.gender, isGender: true },
49
+ ]}
50
+ />
51
+
52
+ <PatientSummaryRow items={[{ label: t('maritalStatus', 'Marital Status'), value: data?.maritalStatus }]} />
53
+
54
+ <div className={styles.divider} />
55
+
56
+ <PatientSummaryRow
57
+ items={[
58
+ {
59
+ label: t('dateConfirmedPositive', 'Date Confirmed Positive'),
60
+ value: data?.dateConfirmedHIVPositive,
61
+ isDate: true,
62
+ },
63
+ { label: t('firstCD4', 'First CD4'), value: data?.firstCd4 },
64
+ { label: t('dateFirstCD4', 'Date First CD4'), value: data?.firstCd4Date, isNone: true },
65
+ ]}
66
+ />
67
+
68
+ <PatientSummaryRow
69
+ items={[
70
+ { label: t('dateEnrolledToCare', 'Date Enrolled to Care'), value: data?.dateEnrolledIntoCare, isDate: true },
71
+ { label: t('whoAtEnrollment', 'WHO at Enrollment'), value: data?.whoStagingAtEnrollment },
72
+ { label: t('transferInDate', 'Transfer In Date'), value: data?.transferInDate, isNone: true },
73
+ ]}
74
+ />
75
+
76
+ <PatientSummaryRow
77
+ items={[
78
+ { label: t('entryPoint', 'Entry Point'), value: data?.patientEntryPoint },
79
+ { label: t('dateOfEntryPoint', 'Date of Entry Point'), value: data?.patientEntryPointDate, isDate: true },
80
+ { label: t('facilityTransferredFrom', 'Facility Transferred From'), value: data?.transferInFacility },
81
+ ]}
82
+ />
83
+
84
+ <div className={styles.divider} />
85
+
86
+ <PatientSummaryRow
87
+ items={[
88
+ { label: t('weight', 'Weight'), value: data?.weight },
89
+ { label: t('height', 'Height'), value: data?.height },
90
+ { label: t('bmi', 'BMI'), value: data?.bmi },
91
+ ]}
92
+ />
93
+
94
+ <PatientSummaryRow
95
+ items={[
96
+ {
97
+ label: t('bloodPressure', 'Blood Pressure'),
98
+ value: data?.bloodPressure && data?.bpDiastolic ? `${data?.bloodPressure}/${data?.bpDiastolic}` : null,
99
+ },
100
+ { label: t('oxygenSaturation', 'Oxygen Saturation'), value: data?.oxygenSaturation },
101
+ { label: t('respiratoryRate', 'Respiratory Rate'), value: data?.respiratoryRate },
102
+ ]}
103
+ />
104
+
105
+ <PatientSummaryRow
106
+ items={[
107
+ { label: t('pulseRate', 'Pulse Rate'), value: data?.pulseRate },
108
+ { label: t('familyProtection', 'Family Protection'), value: data?.familyProtection },
109
+ { label: t('tbScreeningOutcome', 'TB Screening Outcome'), value: data?.tbScreeningOutcome },
110
+ ]}
111
+ />
112
+
113
+ <PatientSummaryRow
114
+ items={[
115
+ { label: 'chronicDisease', value: data?.chronicDisease },
116
+ { label: 'ioHistory', value: data?.iosResults },
117
+ { label: 'stiScreeningOutcome', value: data?.stiScreeningOutcome },
118
+ ]}
119
+ />
120
+
121
+ <PatientSummaryRow
122
+ items={[
123
+ ...(data?.gender === 'F'
124
+ ? [{ label: t('caxcScreeningOutcome', 'CAXC Screening Outcome'), value: data?.caxcScreeningOutcome }]
125
+ : []),
126
+ { label: t('dateEnrolledInTb', 'Date Enrolled in TB'), value: data?.dateEnrolledInTb, isNone: true },
127
+ { label: t('dateCompletedInTb', 'Date Completed in TB'), value: data?.dateCompletedInTb, isNone: true },
128
+ ...(data?.gender === 'F' ? [{ label: t('lmp', 'LMP'), value: data?.lmp, isDate: true }] : []),
129
+ ]}
130
+ />
131
+
132
+ <div className={styles.divider} />
133
+
134
+ <PatientSummaryRow
135
+ items={[
136
+ {
137
+ label: t('treatmentSupporterName', 'Treatment Supporter Name'),
138
+ value: capitalizeEveryWord(data?.nameOfTreatmentSupporter),
139
+ },
140
+ {
141
+ label: t('treatmentSupporterRelationship', 'Treatment Supporter Relationship'),
142
+ value: data?.relationshipToTreatmentSupporter,
143
+ },
144
+ {
145
+ label: t('treatmentSupporterContact', 'Treatment Supporter Contact'),
146
+ value: data?.contactOfTreatmentSupporter,
147
+ },
148
+ ]}
149
+ />
150
+
151
+ <div className={styles.divider} />
152
+
153
+ <PatientSummaryRow items={[{ label: t('drugAllergies', 'Drug Allergies'), value: data?.allergies }]} />
154
+
155
+ <div className={styles.divider} />
156
+
157
+ <PatientSummaryRow
158
+ items={[
159
+ { label: t('previousART', 'Previous ART'), value: data?.previousArtStatus },
160
+ { label: t('dateStartedART', 'Date Started ART'), value: data?.dateStartedArt, isDate: true },
161
+ { label: t('clinicalStageART', 'Clinical Stage ART'), value: data?.whoStageAtArtStart },
162
+ ]}
163
+ />
164
+
165
+ <PatientSummaryRow
166
+ items={[
167
+ { label: t('purposeDrugs', 'Purpose Drugs'), value: data?.purposeDrugs },
168
+ { label: t('purposeDate', 'Purpose Date'), value: data?.purposeDate, isDate: true },
169
+ { label: t('cd4AtArtStart', 'CD4 at ART Start'), value: data?.cd4AtArtStart },
170
+ ]}
171
+ />
172
+
173
+ <PatientSummaryRow
174
+ items={[
175
+ { label: t('initialRegimen', 'Initial Regimen'), value: data?.firstRegimen?.regimenShortDisplay },
176
+ { label: t('initialRegimenDate', 'Initial Regimen Date'), value: data?.firstRegimen?.startDate },
177
+ { label: t('currentArtRegimen', 'Current ART Regimen'), value: data?.currentArtRegimen?.regimenShortDisplay },
178
+ {
179
+ label: t('currentArtRegimenDate', 'Current ART Regimen Date'),
180
+ value: data?.currentArtRegimen?.startDate,
181
+ isDate: true,
182
+ },
183
+ ]}
184
+ />
185
+
186
+ <div className={styles.divider} />
187
+
188
+ <PatientSummaryRow
189
+ items={[
190
+ { label: t('artInterruptionReason', 'ART Interruption Reason'), value: '--' },
191
+ { label: t('substitutionWithin1stLineRegimen', 'Substitution Within 1st Line Regimen'), value: '--' },
192
+ { label: t('switchTo2ndLineRegimen', 'Switch to 2nd Line Regimen'), value: '--' },
193
+ ]}
194
+ />
195
+
196
+ <PatientSummaryRow
197
+ items={[
198
+ { label: t('dapsone', 'Dapsone'), value: data?.dapsone },
199
+ { label: t('tpt', 'TPT'), value: data?.onIpt },
200
+ { label: t('clinicsEnrolled', 'Clinics Enrolled'), value: data?.clinicsEnrolled },
201
+ ]}
202
+ />
203
+
204
+ <PatientSummaryRow
205
+ items={[
206
+ { label: t('transferOutDate', 'Transfer Out Date'), value: data?.transferOutDate, isNone: true },
207
+ { label: t('transferOutFacility', 'Transfer Out Facility'), value: data?.transferOutFacility },
208
+ { label: t('deathDate', 'Death Date'), value: data?.deathDate, isNone: true },
209
+ ]}
210
+ />
211
+
212
+ <PatientSummaryRow
213
+ items={[
214
+ { label: t('mostRecentCD4', 'Most Recent CD4'), value: data?.mostRecentCd4 },
215
+ { label: t('mostRecentVL', 'Most Recent VL'), value: data?.viralLoadValue },
216
+ { label: t('nextAppointmentDate', 'Next Appointment Date'), value: data?.nextAppointmentDate, isDate: true },
217
+ ]}
218
+ />
219
+
220
+ <div className={styles.container}>
221
+ <div className={styles.content}>
222
+ <p className={styles.label}>{t('viralLoadTrends', 'Viral load trends')}</p>
223
+ {data?.allVlResults?.value?.length > 0
224
+ ? data?.allVlResults?.value?.map((vl, index) => {
225
+ return (
226
+ <div key={`vl-${index}`}>
227
+ <span className={styles.value}> {vl.vl} </span>
228
+ {vl?.vlDate === 'N/A' || vl?.vlDate === '' ? (
229
+ <span>None</span>
230
+ ) : (
231
+ <span>({vl?.vlDate ? vl?.vlDate : '--'})</span>
232
+ )}
233
+ <br />
234
+ </div>
235
+ );
236
+ })
237
+ : '--'}
238
+ </div>
239
+ <div className={styles.content}>
240
+ <p className={styles.label}>{t('cd4Trends', 'CD4 Trends')}</p>
241
+ {data?.allCd4CountResults?.length > 0
242
+ ? data?.allCd4CountResults?.map((cd4, index) => {
243
+ return (
244
+ <div key={`cd4Trend-${cd4?.cd4Count}-${index}`}>
245
+ <span className={styles.value}>{cd4?.cd4Count}</span>
246
+ {cd4?.cd4Count === 'N/A' || cd4?.cd4Count === '' ? (
247
+ <span>None</span>
248
+ ) : (
249
+ <span>( {cd4?.cd4CountDate ? cd4?.cd4CountDate : '--'})</span>
250
+ )}
251
+ <br />
252
+ </div>
253
+ );
254
+ })
255
+ : '--'}
256
+ </div>
257
+ </div>
258
+
259
+ <div className={styles.divider} />
260
+
261
+ <PatientSummaryRow
262
+ items={[
263
+ { label: t('clinicalNotes', 'Clinical Notes'), value: data?.['clinicalNotes'] ?? '--' },
264
+ { label: t('clinicianName', 'Clinician Name'), value: currentUserSession?.user?.person?.display },
265
+ { label: t('clinicianSignature', 'Clinician Signature'), value: currentUserSession?.user?.person?.display },
266
+ ]}
267
+ />
268
+ </>
269
+ );
270
+ };
271
+
272
+ export default PatientSummaryBody;
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button } from '@carbon/react';
4
+ import { useLayoutType } from '@openmrs/esm-framework';
5
+ import { Printer } from '@carbon/react/icons';
6
+ import styles from './patient-summary.scss';
7
+
8
+ interface PatientSummaryHeaderProps {
9
+ onPrint: () => void;
10
+ printMode: boolean;
11
+ }
12
+
13
+ const PatientSummaryHeader: React.FC<PatientSummaryHeaderProps> = ({ onPrint, printMode }) => {
14
+ const { t } = useTranslation();
15
+ const isTablet = useLayoutType() == 'tablet';
16
+
17
+ return (
18
+ <div className={isTablet ? styles.tabletHeading : styles.desktopHeading}>
19
+ <h4 className={styles.title}>{t('patientSummary', 'Patient summary')}</h4>
20
+ {printMode === false && (
21
+ <Button
22
+ size="sm"
23
+ className={styles.btnShow}
24
+ onClick={onPrint}
25
+ kind="tertiary"
26
+ renderIcon={(props) => <Printer size={16} {...props} />}
27
+ iconDescription={t('print', 'Print')}>
28
+ {t('print', 'Print')}
29
+ </Button>
30
+ )}
31
+ </div>
32
+ );
33
+ };
34
+
35
+ export default PatientSummaryHeader;
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { formatDate } from '@openmrs/esm-framework';
4
+ import styles from './patient-summary.scss';
5
+
6
+ interface PatientSummaryRowProps {
7
+ items: Array<{
8
+ label: string;
9
+ value: any;
10
+ isDate?: boolean;
11
+ isGender?: boolean;
12
+ isNone?: boolean;
13
+ }>;
14
+ }
15
+
16
+ const PatientSummaryRow: React.FC<PatientSummaryRowProps> = ({ items }) => {
17
+ const { t } = useTranslation();
18
+
19
+ const getDisplayValue = (item) => {
20
+ if (item.isDate) {
21
+ return item.value ? formatDate(new Date(item.value), { noToday: true }) : '--';
22
+ }
23
+ if (item.isGender) {
24
+ switch (item.value) {
25
+ case 'F':
26
+ return 'Female';
27
+ case 'M':
28
+ return 'Male';
29
+ default:
30
+ return 'Unknown';
31
+ }
32
+ }
33
+ if (item.isNone) {
34
+ return item.value === 'N/A' || item.value === '' ? 'None' : item.value;
35
+ }
36
+ return item.value || '--';
37
+ };
38
+
39
+ return (
40
+ <div className={styles.container}>
41
+ {items.map((item, index) => (
42
+ <div key={`${item.label}-${index}`} className={styles.content}>
43
+ <p className={styles.label}>{t(item.label, item.label)}</p>
44
+ <p>
45
+ <span className={styles.value}>{getDisplayValue(item)}</span>
46
+ </p>
47
+ </div>
48
+ ))}
49
+ </div>
50
+ );
51
+ };
52
+
53
+ export default PatientSummaryRow;
@@ -19,7 +19,7 @@ jest.mock('react-to-print', () => {
19
19
 
20
20
  return {
21
21
  ...originalModule,
22
- useReactToPrint: jest.fn(),
22
+ useReactToPrint: jest.fn().mockReturnValue(jest.fn()),
23
23
  };
24
24
  });
25
25