-
{title}
-
-
- {textFields.map((val, i) => {
- return val.type === 'number' ? (
-
-
- (
- checkValidity(e.target.value, onChange)}
- style={{ ...textFieldStyles }}
- ref={ref}
- title={val.name}
- type={val.type}
- value={value}
+ <>
+
+
+ {label}
+
+ {Boolean(hasAbnormalValue) ? (
+
+ ) : null}
+
+ {showInvalidInputError ? (
+
+
+
+ ) : null}
+
+
+
+ {fieldProperties.map((fieldProperty) => {
+ if (fieldProperty.type === 'number') {
+ const numberInputClasses = classNames(styles.numberInput, fieldProperty.className);
+
+ return (
+
+
+ {
+ return (
+ handleFocusChange(false)}
+ onChange={(event: React.ChangeEvent) =>
+ checkValidity(event.target.value, onChange)
+ }
+ onFocus={() => handleFocusChange(true)}
+ placeholder={generatePlaceholder(fieldProperty.name)}
+ readOnly={readOnly}
+ ref={ref}
+ style={{ ...fieldStyles }}
+ title={fieldProperty.name}
+ type={fieldProperty.type}
+ value={value}
+ />
+ );
+ }}
/>
- )}
- />
-
- {val?.separator}
-
- ) : (
-
- (
-
+ {fieldProperty?.separator}
+
+ );
+ }
+
+ if (fieldProperty.type === 'textarea') {
+ return (
+
+ (
+
- );
- })}
-
- {unitSymbol}
+
+ );
+ }
+ })}
+
+ {Boolean(unitSymbol) && {unitSymbol}
}
+
- {(!isWithinNormalRange || invalid) && (
-
- {t('numericInputError', 'Must be a number with in acceptable ranges')}
+
+ {showInvalidInputError && (
+
+ {t('validationInputError', `Value must be between {{min}} and {{max}}`, {
+ min: fieldProperties[0].min,
+ max: fieldProperties[0].max,
+ })}
)}
-
+ >
);
};
-function ResponsiveWrapper({ children, isTablet }: { children: React.ReactNode; isTablet: boolean }) {
- return isTablet ?
{children} : <>{children}>;
+function ResponsiveWrapper({ children, isTablet }: ResponsiveWrapperProps) {
+ return isTablet ?
{children} :
{children};
}
-export default VitalsBiometricInput;
+export default VitalsAndBiometricsInput;
diff --git a/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.scss b/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.scss
index 4d0e7dbd3c..dd0c4ec903 100644
--- a/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.scss
+++ b/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.scss
@@ -15,19 +15,19 @@
@include type.type-style("heading-04");
}
-.inputContainer {
+.container {
width: 11.625rem;
border-bottom: 1px solid $ui-04;
- margin-bottom: spacing.$spacing-05;
+ margin-bottom: spacing.$spacing-03;
}
-.vitalsBiometricInputLabel01 {
+.label {
@extend .label01;
color: $text-02;
margin-bottom: spacing.$spacing-03;
}
-.textInput {
+.numberInput {
border: none;
@extend .productiveHeading04;
text-align: center;
@@ -45,25 +45,44 @@
:global(.cds--number--nosteppers input[type="number"]) {
padding-right: 1rem !important;
}
+
+ ::placeholder {
+ color: $text-03;
+ }
}
-.textInputContainer {
+.inputContainer {
@extend .productiveHeading04;
height: 4.875rem;
display: flex;
justify-content: center;
flex-direction: column;
text-align: center;
- padding: spacing.$spacing-03;
color: $text-02;
background-color: $ui-01;
+
+ &.focused {
+ outline: 2px solid colors.$blue-60;
+
+ input {
+ outline: none !important;
+ }
+
+ input[data-invalid]:not(:focus) {
+ outline: none;
+ }
+
+ svg {
+ display: none;
+ }
+ }
}
-:global(.omrs-breakpoint-lt-desktop) .textInputContainer {
+:global(.omrs-breakpoint-lt-desktop) .inputContainer {
background-color: $ui-02;
}
-.textInputContainer {
+.inputContainer {
&:global(.red) {
background-color: colors.$red-20;
@@ -71,6 +90,7 @@
background-color: colors.$red-20;
}
}
+
&:global(.green) {
background-color: colors.$green-20;
@@ -78,6 +98,7 @@
background-color: colors.$green-20;
}
}
+
&:global(.yellow) {
background-color: colors.$yellow-10;
input {
@@ -86,6 +107,16 @@
}
}
+.numberInput {
+ svg {
+ display: none;
+ }
+
+ input[data-invalid]:not(:focus) {
+ outline: none !important;
+ }
+}
+
.textarea {
border: none;
@extend .bodyLong01;
@@ -93,10 +124,14 @@
textarea {
border-bottom: none;
+
+ &:focus {
+ outline: none;
+ }
}
}
-.centerDiv {
+.centered {
display: flex;
flex-direction: row;
align-items: center;
@@ -111,18 +146,100 @@
margin-top: spacing.$spacing-03;
}
-.disabledInput {
- background-color: $ui-01 !important;
+.invalidInputError {
+ max-width: 11rem;
+ color: $danger;
+ margin-bottom: spacing.$spacing-03;
+}
- :global(.cds--number input[type="number"]) {
- background-color: $ui-01 !important;
+.layer {
+ width: 100%;
+}
+
+.labelContainer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.invalidInput {
+ outline: 2px solid $danger;
+
+ &.focused {
+ border: none;
}
}
-.danger {
- color: $danger;
+.invalidInputIcon {
+ svg {
+ color: $danger;
+ }
}
-.layer {
- width: 100%;
-}
\ No newline at end of file
+.critical-value {
+ background-color: colors.$red-10;
+ .numberInput {
+ svg {
+ display: none;
+ }
+
+ input {
+ background-color: colors.$red-10;
+ }
+
+ input[data-invalid]:not(:focus) {
+ outline: none;
+ }
+
+ }
+}
+
+.critically-low, .critically-high, .low, .high {
+ &::after {
+ @include type.type-style('heading-compact-01');
+ color: $text-02;
+ }
+}
+
+.low::after {
+ content: " ↓";
+}
+
+.critically-low::after {
+ content: " ↓↓";
+}
+
+.high::after {
+ content: " ↑";
+}
+
+.critically-high::after {
+ content: " ↑↑";
+}
+
+.inputInTabletView {
+ &.inputWithAbnormalValue {
+ .inputContainer {
+ background-color: colors.$red-20;
+
+ .numberInput {
+ input {
+ background-color: colors.$red-20;
+ outline: none;
+ }
+ }
+ }
+ }
+}
+
+.readonly {
+ cursor: default;
+}
+
+:global(.omrs-breakpoint-lt-desktop) .readonly {
+ background-color: colors.$gray-10;
+}
+
+:global(.omrs-breakpoint-gt-tablet) .readonly {
+ background-color: colors.$white-0;
+}
diff --git a/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.test.tsx b/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.test.tsx
index bd86824290..f5ee1b0dac 100644
--- a/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.test.tsx
+++ b/packages/esm-patient-vitals-app/src/vitals/vitals-biometrics-form/vitals-biometrics-input.test.tsx
@@ -1,9 +1,8 @@
import React from 'react';
import { screen, render } from '@testing-library/react';
-import VitalsBiometricsInput from './vitals-biometrics-input.component';
-import userEvent from '@testing-library/user-event';
-
-const mockOnChange = jest.fn();
+import { useConfig } from '@openmrs/esm-framework';
+import { assessValue, getReferenceRangesForConcept } from '../vitals.resource';
+import VitalsAndBiometricsInput from './vitals-biometrics-input.component';
jest.mock('react-hook-form', () => ({
...jest.requireActual('react-hook-form'),
@@ -57,81 +56,346 @@ jest.mock('react-hook-form', () => ({
}),
}));
-describe('VitalsBiometricsInput', () => {
- const mockProps = {
- title: 'Heart Rate',
- textFields: [
+const mockConceptMetadata = [
+ {
+ uuid: '5085AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Systolic blood pressure',
+ hiNormal: 140,
+ hiAbsolute: 250,
+ hiCritical: 180,
+ lowNormal: 100,
+ lowAbsolute: 0,
+ lowCritical: 85,
+ units: 'mmHg',
+ },
+ {
+ uuid: '5086AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Diastolic blood pressure',
+ hiNormal: 90,
+ hiAbsolute: 150,
+ hiCritical: 120,
+ lowNormal: 55,
+ lowAbsolute: 0,
+ lowCritical: 40,
+ units: 'mmHg',
+ },
+ {
+ uuid: '5088AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Temperature (c)',
+ hiNormal: null,
+ hiAbsolute: 43,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: 25,
+ lowCritical: null,
+ units: 'DEG C',
+ },
+ {
+ uuid: '5090AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Height (cm)',
+ hiNormal: null,
+ hiAbsolute: 272,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: 10,
+ lowCritical: null,
+ units: 'cm',
+ },
+ {
+ uuid: '5089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Weight (kg)',
+ hiNormal: null,
+ hiAbsolute: 250,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: 0,
+ lowCritical: null,
+ units: 'kg',
+ },
+ {
+ uuid: '5087AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Pulse',
+ hiNormal: 100,
+ hiAbsolute: 230,
+ hiCritical: 130,
+ lowNormal: 55,
+ lowAbsolute: 0,
+ lowCritical: 49,
+ units: 'beats/min',
+ },
+ {
+ uuid: '5092AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Arterial blood oxygen saturation (pulse oximeter)',
+ hiNormal: null,
+ hiAbsolute: 100,
+ hiCritical: null,
+ lowNormal: 95,
+ lowAbsolute: 0,
+ lowCritical: 90,
+ units: '%',
+ },
+ {
+ uuid: '1343AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Mid-upper arm circumference',
+ hiNormal: null,
+ hiAbsolute: null,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: null,
+ lowCritical: null,
+ units: 'cm',
+ },
+ {
+ uuid: '5242AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Respiratory rate',
+ hiNormal: 18,
+ hiAbsolute: 999,
+ hiCritical: 26,
+ lowNormal: 12,
+ lowAbsolute: 0,
+ lowCritical: 8,
+ units: 'breaths/min',
+ },
+ {
+ uuid: '5283AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Karnofsky performance score',
+ hiNormal: null,
+ hiAbsolute: null,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: null,
+ lowCritical: null,
+ units: '%',
+ },
+];
+
+jest.mock('@openmrs/esm-patient-common-lib', () => {
+ const originalModule = jest.requireActual('@openmrs/esm-patient-common-lib');
+
+ return {
+ ...originalModule,
+ useVitalsConceptMetadata: jest.fn().mockImplementation(() => ({
+ data: new Map([
+ ['5085AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'mmHg'],
+ ['5086AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'mmHg'],
+ ['5088AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'DEG C'],
+ ['5090AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'cm'],
+ ['5089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'kg'],
+ ['5087AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'beats/min'],
+ ['5092AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', '%'],
+ ['1343AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'cm'],
+ ['5242AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'breaths/min'],
+ ['5283AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', '%'],
+ ]),
+ conceptMetadata: [
+ {
+ uuid: '5085AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Systolic blood pressure',
+ hiNormal: 140,
+ hiAbsolute: 250,
+ hiCritical: 180,
+ lowNormal: 100,
+ lowAbsolute: 0,
+ lowCritical: 85,
+ units: 'mmHg',
+ },
+ {
+ uuid: '5086AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Diastolic blood pressure',
+ hiNormal: 90,
+ hiAbsolute: 150,
+ hiCritical: 120,
+ lowNormal: 55,
+ lowAbsolute: 0,
+ lowCritical: 40,
+ units: 'mmHg',
+ },
+ {
+ uuid: '5088AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Temperature (c)',
+ hiNormal: null,
+ hiAbsolute: 43,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: 25,
+ lowCritical: null,
+ units: 'DEG C',
+ },
+ {
+ uuid: '5090AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Height (cm)',
+ hiNormal: null,
+ hiAbsolute: 272,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: 10,
+ lowCritical: null,
+ units: 'cm',
+ },
+ {
+ uuid: '5089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Weight (kg)',
+ hiNormal: null,
+ hiAbsolute: 250,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: 0,
+ lowCritical: null,
+ units: 'kg',
+ },
+ {
+ uuid: '5087AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Pulse',
+ hiNormal: 100,
+ hiAbsolute: 230,
+ hiCritical: 130,
+ lowNormal: 55,
+ lowAbsolute: 0,
+ lowCritical: 49,
+ units: 'beats/min',
+ },
+ {
+ uuid: '5092AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Arterial blood oxygen saturation (pulse oximeter)',
+ hiNormal: null,
+ hiAbsolute: 100,
+ hiCritical: null,
+ lowNormal: 95,
+ lowAbsolute: 0,
+ lowCritical: 90,
+ units: '%',
+ },
+ {
+ uuid: '1343AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Mid-upper arm circumference',
+ hiNormal: null,
+ hiAbsolute: null,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: null,
+ lowCritical: null,
+ units: 'cm',
+ },
+ {
+ uuid: '5242AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Respiratory rate',
+ hiNormal: 18,
+ hiAbsolute: 999,
+ hiCritical: 26,
+ lowNormal: 12,
+ lowAbsolute: 0,
+ lowCritical: 8,
+ units: 'breaths/min',
+ },
+ {
+ uuid: '5283AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ display: 'Karnofsky performance score',
+ hiNormal: null,
+ hiAbsolute: null,
+ hiCritical: null,
+ lowNormal: null,
+ lowAbsolute: null,
+ lowCritical: null,
+ units: '%',
+ },
+ ],
+ })),
+ };
+});
+
+jest.mock('@openmrs/esm-framework', () => {
+ const originalModule = jest.requireActual('@openmrs/esm-framework');
+
+ return {
+ ...originalModule,
+ useConfig: jest.fn().mockReturnValue({
+ concepts: {
+ pulseUuid: '5087AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ },
+ }),
+ };
+});
+
+const testProps = {
+ control: undefined,
+ isWithinNormalRange: true,
+ fieldProperties: [],
+ interpretation: undefined,
+ placeholder: '',
+ label: '',
+ unitSymbol: '',
+};
+
+describe('VitalsAndBiometricsInput', () => {
+ it('renders number inputs based correctly on the props provided', () => {
+ testProps.fieldProperties = [
{
- name: 'heartRate',
+ id: 'pulse',
+ name: 'Heart rate',
type: 'number',
- value: 120,
},
- ],
- unitSymbol: 'bpm',
- };
+ ];
+ testProps.label = 'Heart rate';
+ testProps.unitSymbol = 'bpm';
- it('should display the correct text input with correct value', async () => {
- const user = userEvent.setup();
-
- render(
-
,
- );
+ renderVitalsBiometricsInput();
- expect(screen.getByText(/Heart Rate/i)).toBeInTheDocument();
+ const heartRateInput = screen.getByRole('spinbutton', { name: /heart rate/i });
+ expect(heartRateInput).toBeInTheDocument();
+ expect(screen.getByPlaceholderText('--')).toBeInTheDocument();
+ expect(screen.getByTitle(/heart rate/i)).toBeInTheDocument();
expect(screen.getByText(/bpm/i)).toBeInTheDocument();
- expect(screen.getByRole('spinbutton')).toBeInTheDocument();
-
- const inputTextBox = await screen.findByRole('spinbutton');
- await user.type(inputTextBox, '75');
});
- it('should display the correct text area with correct value', async () => {
- render(
-
,
- );
+ it('renders textarea inputs correctly based on the props provided', () => {
+ testProps.fieldProperties = [
+ {
+ id: 'generalPatientNote',
+ name: 'Notes',
+ type: 'textarea',
+ },
+ ];
+ testProps.placeholder = 'Type any additional notes here';
+ testProps.label = 'Notes';
+
+ renderVitalsBiometricsInput();
- expect(screen.getByRole('textbox')).toBeInTheDocument();
+ const noteInput = screen.getByRole('textbox', { name: /notes/i });
+ expect(noteInput).toBeInTheDocument();
+ expect(screen.getByPlaceholderText(/type any additional notes here/i)).toBeInTheDocument();
+ expect(screen.getByTitle(/notes/i)).toBeInTheDocument();
});
- it('should disable input when the disabled prop is set to `true`', async () => {
- const user = userEvent.setup();
-
- render(
-
,
- );
+ it('should validate the input based on the provided interpretation and reference range values', () => {
+ const config = useConfig();
- expect(screen.getByText(/Heart Rate/i)).toBeInTheDocument();
- expect(screen.getByText(/bpm/i)).toBeInTheDocument();
- expect(screen.getByRole('spinbutton')).toBeInTheDocument();
+ testProps.fieldProperties = [
+ {
+ id: 'pulse',
+ name: 'Heart rate',
+ min: 0,
+ max: 230,
+ type: 'number',
+ },
+ ];
+ testProps.interpretation = assessValue(
+ 300,
+ getReferenceRangesForConcept(config.concepts.pulseUuid, mockConceptMetadata),
+ );
+ testProps.label = 'Heart rate';
+ testProps.unitSymbol = 'bpm';
- const inputTextBox = await screen.findByRole('spinbutton');
+ renderVitalsBiometricsInput();
- await user.type(inputTextBox, '7');
+ screen.findByRole('spinbutton');
- expect(inputTextBox).toHaveProperty('disabled');
+ expect(screen.getByRole('spinbutton', { name: /heart rate/i })).toBeInTheDocument();
+ const abnormalValueFlag = screen.getByTitle(/abnormal value/i);
+ expect(abnormalValueFlag).toBeInTheDocument();
+ expect(abnormalValueFlag).toHaveClass('critically-high');
});
});
+
+function renderVitalsBiometricsInput() {
+ render(
);
+}
diff --git a/packages/esm-patient-vitals-app/src/vitals/vitals-chart.component.tsx b/packages/esm-patient-vitals-app/src/vitals/vitals-chart.component.tsx
index 99dadbc04a..6913479f4d 100644
--- a/packages/esm-patient-vitals-app/src/vitals/vitals-chart.component.tsx
+++ b/packages/esm-patient-vitals-app/src/vitals/vitals-chart.component.tsx
@@ -30,34 +30,34 @@ interface VitalsChartData {
const VitalsChart: React.FC
= ({ patientVitals, conceptUnits, config }) => {
const { t } = useTranslation();
const [selectedVitalSign, setSelectedVitalsSign] = React.useState({
- title: `BP (${conceptUnits.get(config.concepts.systolicBloodPressureUuid)})`,
+ title: `${t('bp', 'BP')} (${conceptUnits.get(config.concepts.systolicBloodPressureUuid)})`,
value: 'systolic',
});
const vitalSigns = [
{
id: 'bloodPressure',
- title: withUnit('BP', conceptUnits.get(config.concepts.systolicBloodPressureUuid) ?? '-'),
+ title: withUnit(t('bp', 'BP'), conceptUnits.get(config.concepts.systolicBloodPressureUuid) ?? '-'),
value: 'systolic',
},
{
id: 'oxygenSaturation',
- title: withUnit('SPO2', conceptUnits.get(config.concepts.oxygenSaturationUuid) ?? '-'),
+ title: withUnit(t('spo2', 'SpO2'), conceptUnits.get(config.concepts.oxygenSaturationUuid) ?? '-'),
value: 'spo2',
},
{
id: 'temperature',
- title: withUnit('Temp', conceptUnits.get(config.concepts.temperatureUuid) ?? '-'),
+ title: withUnit(t('temp', 'Temp'), conceptUnits.get(config.concepts.temperatureUuid) ?? '-'),
value: 'temperature',
},
{
id: 'respiratoryRate',
- title: withUnit('R. Rate', conceptUnits.get(config.concepts.respiratoryRateUuid) ?? '-'),
+ title: withUnit(t('respiratoryRate', 'R. rate'), conceptUnits.get(config.concepts.respiratoryRateUuid) ?? '-'),
value: 'respiratoryRate',
},
{
id: 'pulse',
- title: withUnit('Pulse', conceptUnits.get(config.concepts.pulseUuid) ?? '-'),
+ title: withUnit(t('pulse', 'Pulse'), conceptUnits.get(config.concepts.pulseUuid) ?? '-'),
value: 'pulse',
},
];
@@ -100,7 +100,7 @@ const VitalsChart: React.FC = ({ patientVitals, conceptUnits,
title: selectedVitalSign.title,
axes: {
bottom: {
- title: 'Date',
+ title: t('date', 'Date'),
mapsTo: 'key',
scaleType: ScaleTypes.LABELS,
},
diff --git a/packages/esm-patient-vitals-app/src/vitals/vitals.resource.tsx b/packages/esm-patient-vitals-app/src/vitals/vitals.resource.tsx
index db4b27167c..73108bc6d4 100644
--- a/packages/esm-patient-vitals-app/src/vitals/vitals.resource.tsx
+++ b/packages/esm-patient-vitals-app/src/vitals/vitals.resource.tsx
@@ -309,3 +309,23 @@ export function interpretBloodPressure(systolic, diastolic, concepts, conceptMet
return 'normal';
}
+
+export function generatePlaceholder(value: string) {
+ switch (value) {
+ case 'BMI':
+ return '';
+
+ case 'Temperature':
+ case 'Weight':
+ return '--.-';
+
+ case 'Height':
+ case 'diastolic':
+ case 'systolic':
+ case 'Pulse':
+ return '---';
+
+ default:
+ return '--';
+ }
+}
diff --git a/packages/esm-patient-vitals-app/translations/am.json b/packages/esm-patient-vitals-app/translations/am.json
index 67ac95f417..3d4885be6a 100644
--- a/packages/esm-patient-vitals-app/translations/am.json
+++ b/packages/esm-patient-vitals-app/translations/am.json
@@ -1,4 +1,5 @@
{
+ "abnormalValue": "Abnormal value",
"add": "Add",
"additionalNoteText": "Type any additional notes here",
"bloodPressure": "Blood Pressure",
@@ -6,6 +7,7 @@
"bp": "BP",
"calculatedBmi": "BMI (calc.)",
"checkForValidity": "Some of the values entered are invalid",
+ "date": "Date",
"diastolic": "diastolic",
"discard": "Discard",
"error": "Error",
@@ -18,7 +20,6 @@
"muac": "MUAC",
"noDataRecorded": "No data has been recorded for this patient",
"notes": "Notes",
- "numericInputError": "Must be a number with in acceptable ranges",
"other": "Other",
"overdue": "Overdue",
"oxygenSaturation": "Oxygen Saturation",
@@ -28,7 +29,7 @@
"pulse": "Pulse",
"recordBiometrics": "Record biometrics",
"recordVitals": "Record vitals",
- "respirationRate": "Respiration Rate",
+ "respirationRate": "Respiration rate",
"respiratoryRate": "R. rate",
"saveAndClose": "Save and close",
"seeAll": "See all",
@@ -38,6 +39,7 @@
"temperature": "Temperature",
"temperatureAbbreviated": "Temp",
"unknown": "Unknown",
+ "validationInputError": "Value must be between {{min}} and {{max}}",
"vitals": "Vitals",
"vitalsAndBiometrics": "Vitals and biometrics",
"vitalsAndBiometricsNowAvailable": "They are now visible on the Vitals and Biometrics page",
diff --git a/packages/esm-patient-vitals-app/translations/ar.json b/packages/esm-patient-vitals-app/translations/ar.json
index c3a63e2da6..fd26b1b22c 100644
--- a/packages/esm-patient-vitals-app/translations/ar.json
+++ b/packages/esm-patient-vitals-app/translations/ar.json
@@ -1,4 +1,5 @@
{
+ "abnormalValue": "Abnormal value",
"add": "أضف",
"additionalNoteText": "اكتب أي ملاحظات إضافية هنا",
"bloodPressure": "ضغط الدم",
@@ -6,6 +7,7 @@
"bp": "ضغط الدم",
"calculatedBmi": "مؤشر كتلة الجسم (محسوب)",
"checkForValidity": "بعض القيم المدخلة غير صالحة",
+ "date": "Date",
"diastolic": "الانقباضي",
"discard": "تجاهل",
"error": "خطأ",
@@ -18,7 +20,6 @@
"muac": "MUAC",
"noDataRecorded": "لم يتم تسجيل أي بيانات لهذا المريض",
"notes": "ملاحظات",
- "numericInputError": "يجب أن يكون رقمًا ضمن النطاقات المقبولة",
"other": "أخرى",
"overdue": "متأخر",
"oxygenSaturation": "تشبع الأكسجين",
@@ -38,6 +39,7 @@
"temperature": "درجة الحرارة",
"temperatureAbbreviated": "درجة الحرارة",
"unknown": "غير معروف",
+ "validationInputError": "Value must be between {{min}} and {{max}}",
"vitals": "العلامات الحيوية",
"vitalsAndBiometrics": "العلامات الحيوية والقياسات البيومترية",
"vitalsAndBiometricsNowAvailable": "هم الآن مرئيون على صفحة العلامات الحيوية والقياسات البيومترية",
diff --git a/packages/esm-patient-vitals-app/translations/en.json b/packages/esm-patient-vitals-app/translations/en.json
index 7fa9487de6..7433cc54de 100644
--- a/packages/esm-patient-vitals-app/translations/en.json
+++ b/packages/esm-patient-vitals-app/translations/en.json
@@ -1,4 +1,5 @@
{
+ "abnormalValue": "Abnormal value",
"add": "Add",
"additionalNoteText": "Type any additional notes here",
"bloodPressure": "Blood Pressure",
@@ -6,6 +7,7 @@
"bp": "BP",
"calculatedBmi": "BMI (calc.)",
"checkForValidity": "Some of the values entered are invalid",
+ "date": "Date",
"diastolic": "diastolic",
"discard": "Discard",
"error": "Error",
@@ -18,7 +20,6 @@
"muac": "MUAC",
"noDataRecorded": "No data has been recorded for this patient",
"notes": "Notes",
- "numericInputError": "Must be a number within acceptable ranges",
"other": "Other",
"overdue": "Overdue",
"oxygenSaturation": "Oxygen Saturation",
@@ -28,8 +29,8 @@
"pulse": "Pulse",
"recordBiometrics": "Record biometrics",
"recordVitals": "Record vitals",
- "respirationRate": "Respiration Rate",
- "respiratoryRate": "R. Rate",
+ "respirationRate": "Respiration rate",
+ "respiratoryRate": "R. rate",
"saveAndClose": "Save and close",
"seeAll": "See all",
"spo2": "SpO2",
@@ -38,6 +39,7 @@
"temperature": "Temperature",
"temperatureAbbreviated": "Temp",
"unknown": "Unknown",
+ "validationInputError": "Value must be between {{min}} and {{max}}",
"vitals": "Vitals",
"vitalsAndBiometrics": "Vitals and biometrics",
"vitalsAndBiometricsNowAvailable": "They are now visible on the Vitals and Biometrics page",
diff --git a/packages/esm-patient-vitals-app/translations/es.json b/packages/esm-patient-vitals-app/translations/es.json
index 0f4044e389..6cfdd4b6b2 100644
--- a/packages/esm-patient-vitals-app/translations/es.json
+++ b/packages/esm-patient-vitals-app/translations/es.json
@@ -1,4 +1,5 @@
{
+ "abnormalValue": "Abnormal value",
"add": "Añadir",
"additionalNoteText": "Escriba aquí cualquier nota adicional",
"bloodPressure": "Presión arterial",
@@ -6,6 +7,7 @@
"bp": "PA",
"calculatedBmi": "IMC (calc.)",
"checkForValidity": "Algunos de los valores introducidos no son válidos",
+ "date": "Date",
"diastolic": "diastólica",
"discard": "Descartar",
"error": "Error",
@@ -18,7 +20,6 @@
"muac": "PB/MUAC",
"noDataRecorded": "No se han registrado datos para este paciente",
"notes": "Notas",
- "numericInputError": "Debe ser un número dentro de los rangos aceptables",
"other": "Otro",
"overdue": "Atrasado",
"oxygenSaturation": "Saturación de oxígeno",
@@ -38,6 +39,7 @@
"temperature": "Temperatura",
"temperatureAbbreviated": "Temp",
"unknown": "Desconocido",
+ "validationInputError": "Value must be between {{min}} and {{max}}",
"vitals": "Signos vitales",
"vitalsAndBiometrics": "Signos vitales y biométricos",
"vitalsAndBiometricsNowAvailable": "Ahora son visibles en la página de Signos vitales y biométricos",
diff --git a/packages/esm-patient-vitals-app/translations/fr.json b/packages/esm-patient-vitals-app/translations/fr.json
index 0ffec1ce79..b3f5672e8f 100644
--- a/packages/esm-patient-vitals-app/translations/fr.json
+++ b/packages/esm-patient-vitals-app/translations/fr.json
@@ -1,4 +1,5 @@
{
+ "abnormalValue": "Abnormal value",
"add": "Ajouter",
"additionalNoteText": "Tapez les notes supplémentaires ici",
"bloodPressure": "Pression sanguine",
@@ -6,6 +7,7 @@
"bp": "Pression sanguine",
"calculatedBmi": "IMC (calc.)",
"checkForValidity": "Certaines des valeurs saisies ne sont pas valides.",
+ "date": "Date",
"diastolic": "diastolique",
"discard": "Abandonner",
"error": "Error",
@@ -18,7 +20,6 @@
"muac": "Circonférence du bras moyen",
"noDataRecorded": "Aucune donnée n'a été enregistrée pour ce patient",
"notes": "Notes",
- "numericInputError": "Doit être un nombre dans des intervalles acceptables",
"other": "Other",
"overdue": "Overdue",
"oxygenSaturation": "Saturation d'oxygène",
@@ -38,6 +39,7 @@
"temperature": "Température",
"temperatureAbbreviated": "Temp",
"unknown": "Unknown",
+ "validationInputError": "Value must be between {{min}} and {{max}}",
"vitals": "Signes vitaux",
"vitalsAndBiometrics": "Signes vitaux et biométrie",
"vitalsAndBiometricsNowAvailable": "Ils sont désormais visibles sur la page Signes vitaux et biométrie",
diff --git a/packages/esm-patient-vitals-app/translations/he.json b/packages/esm-patient-vitals-app/translations/he.json
index 6c0370095c..8c4034c80b 100644
--- a/packages/esm-patient-vitals-app/translations/he.json
+++ b/packages/esm-patient-vitals-app/translations/he.json
@@ -1,4 +1,5 @@
{
+ "abnormalValue": "Abnormal value",
"add": "הוסף",
"additionalNoteText": "הקלד הערות נוספות כאן",
"bloodPressure": "לחץ דם",
@@ -6,6 +7,7 @@
"bp": "ל.דם",
"calculatedBmi": "BMI (חישוב)",
"checkForValidity": "חלק מהערכים שהוזנו אינם תקפים",
+ "date": "Date",
"diastolic": "דיאסטולי",
"discard": "בטל",
"error": "Error",
@@ -18,7 +20,6 @@
"muac": "MUAC",
"noDataRecorded": "לא נרשמו נתונים עבור מטופל זה",
"notes": "הערות",
- "numericInputError": "חייב להיות מספר בטווח התקין",
"other": "Other",
"overdue": "מאחר",
"oxygenSaturation": "רווי חמצן",
@@ -38,6 +39,7 @@
"temperature": "טמפרטורה",
"temperatureAbbreviated": "טמפ'",
"unknown": "Unknown",
+ "validationInputError": "Value must be between {{min}} and {{max}}",
"vitals": "מדדים חיוניים",
"vitalsAndBiometrics": "מדדים חיוניים וביומטרים",
"vitalsAndBiometricsNowAvailable": "הם כעת זמינים בדף מדדים חיוניים וביומטרים",
diff --git a/packages/esm-patient-vitals-app/translations/km.json b/packages/esm-patient-vitals-app/translations/km.json
index cec1ed6a56..2b9ba27ba8 100644
--- a/packages/esm-patient-vitals-app/translations/km.json
+++ b/packages/esm-patient-vitals-app/translations/km.json
@@ -1,49 +1,51 @@
{
+ "abnormalValue": "Abnormal value",
"add": "បន្ថែម",
"additionalNoteText": "វាយបញ្ចូលកំណត់ចំណាំបន្ថែមនៅទីនេះ",
"bloodPressure": "សម្ពាធឈាម",
"bmi": "សន្ទស្សន៍ទម្ងន់ខ្លួន",
"bp": "សម្ពាធឈាម",
"calculatedBmi": "សន្ទស្សន៍ទម្ងន់ខ្លួន(calc.)",
- "checkForValidity": "Some of the values entered are invalid",
+ "checkForValidity": "តម្លៃមួយចំនួនដែលបានបញ្ចូលមិនត្រឹមត្រូវទេ",
+ "date": "កាលបរិច្ឆេទ",
"diastolic": "ដឺដ្យាស្តូលីក",
"discard": "បោះបង់",
- "error": "Error",
- "female": "Female",
+ "error": "មានបញ្ហាបច្ចេកទេស",
+ "female": "ស្រី",
"goToSummary": "ចូលទៅកាន់ ការសង្ខេប",
"heartRate": "ចង្វាក់បេះដូង",
"height": "កម្ពស់",
"loading": "កំពុងផ្ទុក",
- "male": "Male",
- "muac": "MUAC",
+ "male": "ប្រុស",
+ "muac": "រង្វង់ដើមដៃពាក់ផ្នែកខាងលើ(MUAC)",
"noDataRecorded": "មិនមានទិន្នន័យត្រូវបានកត់ត្រាសម្រាប់អ្នកជំងឺនេះទេ",
"notes": "កំណត់សម្គាល់",
- "numericInputError": "ត្រូវតែជាលេខ",
- "other": "Other",
- "overdue": "Overdue",
+ "other": "ផ្សេងៗ",
+ "overdue": "ហួសពេលកំណត់",
"oxygenSaturation": "ការឆ្អែតអុកស៊ីសែន",
- "pleaseFillField": "Please fill at least one field",
- "print": "Print",
- "printedBy": "Printed by",
+ "pleaseFillField": "សូមបំពេញយ៉ាងហោចណាស់នៅក្នុងប្រអប់មួយ",
+ "print": "បោះពុម្ព",
+ "printedBy": "បោះពុម្ពដោយ",
"pulse": "ជីពចរ",
"recordBiometrics": "កត់ត្រាជីវមាត្រ",
"recordVitals": "កត់ត្រាសញ្ញាជីវិត",
"respirationRate": "ចង្វាក់ដង្ហើម",
"respiratoryRate": "ចង្វាក់ដង្ហើម",
"saveAndClose": "រក្សាទុក និងបិទ",
- "seeAll": "See all",
- "spo2": "SpO2",
+ "seeAll": "ឃើញទាំងអស់",
+ "spo2": "កំហាប់អុកស៊ីសែន",
"systolic": "ស៊ីស្តូលិក",
"temp": "សីតុណ្ហភាព",
"temperature": "សីតុណ្ហភាព",
"temperatureAbbreviated": "សីតុណ្ហភាព",
- "unknown": "Unknown",
+ "unknown": "មិនដឹង",
+ "validationInputError": "Value must be between {{min}} and {{max}}",
"vitals": "សញ្ញាជីវិត",
"vitalsAndBiometrics": "សញ្ញាជីវិត និងជីវមាត្រ",
"vitalsAndBiometricsNowAvailable": "ឥឡូវនេះពួកវាអាចមើលឃើញនៅលើទំព័រ សញ្ញាជីវិត និងជីវមាត្រ",
"vitalsAndBiometricsRecorded": "សញ្ញាជីវិត និងជីវមាត្រត្រូវបានរក្សាទុក",
"vitalsAndBiometricsSaveError": "កំហុសក្នុងការរក្សាទុកសញ្ញាជីវិត និងជីវមាត្រ",
- "vitalsHistory": "Vitals history",
+ "vitalsHistory": "ប្រវត្តិសញ្ញាជីវិត",
"vitalSignDisplayed": "សញ្ញាជីវិតត្រូវបានបង្ហាញ",
"vitalSigns": "សញ្ញាជីវិត",
"weight": "ទម្ងន់"
diff --git a/yarn.lock b/yarn.lock
index 706d599752..ffc1a9ec57 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6932,6 +6932,7 @@ __metadata:
"@typescript-eslint/eslint-plugin": ^6.7.3
"@typescript-eslint/parser": ^6.7.3
babel-preset-minify: ^0.5.2
+ classnames: ^2.3.2
concurrently: ^8.2.1
cross-env: ^7.0.3
css-loader: ^6.6.0
@@ -7280,37 +7281,36 @@ __metadata:
linkType: hard
"@openmrs/ngx-formentry@npm:next":
- version: 4.0.1-pre.287
- resolution: "@openmrs/ngx-formentry@npm:4.0.1-pre.287"
+ version: 4.0.1-pre.323
+ resolution: "@openmrs/ngx-formentry@npm:4.0.1-pre.323"
dependencies:
tslib: ^2.3.0
peerDependencies:
- "@angular-extensions/elements": ^12.6.0
- "@angular/animations": ">=11.2.14 <=12.0.4"
- "@angular/cdk": ">=11.2.13 <=12.0.4"
- "@angular/common": ">=11.2.14 <=12.0.4"
- "@angular/compiler": ">=11.2.14 <=12.0.4"
- "@angular/core": ">=11.2.14 <=12.0.4"
- "@angular/forms": ">=11.2.14 <=12.0.4"
+ "@angular/animations": ^14.3.0
+ "@angular/cdk": ^14.2.7
+ "@angular/common": ^14.3.0
+ "@angular/compiler": ^14.3.0
+ "@angular/compiler-cli": ^14.3.0
+ "@angular/core": ^14.3.0
+ "@angular/forms": ^14.3.0
"@carbon/styles": ^1.11.0
- "@ng-select/ng-select": ^6.1.0
- "@ngx-translate/core": ^13.0.0
- hammerjs: ^2.0.8
- lodash: ^4.17.4
- moment: ^2.17.1
- ngx-file-uploader: ^0.0.18
- ngx-webcam: ^0.2.2
- reflect-metadata: ^0.1.9
- shelljs: ^0.7.0
+ "@ng-select/ng-select": ^9.1.0
+ "@ngx-translate/core": ^14.0.0
+ "@openmrs/ngx-file-uploader": "*"
+ lodash: "*"
+ moment: ^2.29.4
+ ngx-webcam: ^0.4.1
+ reflect-metadata: ^0.1.13
+ shelljs: ^0.7.8
slick-carousel: ^1.6.0
tree-model: ^1.0.5
- checksum: 8f3a07a3fc38b8dea5c4a1027a401e81f154a4860801fb8566b24c700498a1522fcda8b9c8703ab00fe9a42690e21a1596413779bf8dc7cc7311a92a394f78b1
+ checksum: 081135cf83056cdc3e1e834d3ff8f9af4fc14ff5830335ff5e9f556dfe32986ab69752239d6c3a6f64362dd9d7881930ac733e3f026223dc0f066f12dc261327
languageName: node
linkType: hard
"@openmrs/openmrs-form-engine-lib@npm:next":
- version: 1.0.0-pre.402
- resolution: "@openmrs/openmrs-form-engine-lib@npm:1.0.0-pre.402"
+ version: 1.0.0-pre.412
+ resolution: "@openmrs/openmrs-form-engine-lib@npm:1.0.0-pre.412"
dependencies:
ace-builds: ^1.4.12
enzyme: ^3.11.0
@@ -7332,7 +7332,7 @@ __metadata:
react: ^18.2.0
react-i18next: 11.x
rxjs: 6.x
- checksum: b59bdf7274795b2cb0dadc6791e903152eed7518aca51934522d079f33635452768a8563214ddc940e9a16843730c1234f24db824d4b9d713f8afec58c10f1fc
+ checksum: 03bb6790c76ab61fb0bc081ce47df40fc307d142567232e459392b3695a49cf8ddd7c93f8f68404224eb05197273cdb16163bf322a968da0450ae3b742ffb051
languageName: node
linkType: hard
@@ -12235,7 +12235,7 @@ __metadata:
languageName: node
linkType: hard
-"classnames@npm:2.3.2":
+"classnames@npm:2.3.2, classnames@npm:^2.3.2":
version: 2.3.2
resolution: "classnames@npm:2.3.2"
checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e