diff --git a/packages/esm-patient-banner-app/src/config-schema.ts b/packages/esm-patient-banner-app/src/config-schema.ts index 60ee3a4b47..0d2c1f702f 100644 --- a/packages/esm-patient-banner-app/src/config-schema.ts +++ b/packages/esm-patient-banner-app/src/config-schema.ts @@ -34,10 +34,27 @@ export const configSchema = { logo: '', }, }, - fields: { - _type: Type.Array, - _description: 'Patient demographics to include in the patient sticker printout', - _default: ['name', 'dob', 'gender', 'identifier', 'age', 'contact', 'address'], + printStickerFields: { + _type: Type.Object, + _description: 'Configuration of the patient sticker fields for the patient identifier stickers', + fields: { + _type: Type.Array, + _description: 'Patient demographics to include in the patient sticker printout', + }, + fieldsTableGroups: { + _type: Type.Array, + _description: + 'Groups of patient demographic fields to be displayed as distinct tables in the patient sticker. Each group contains a set of related fields that will appear together in one table ie a single line.', + }, + fieldsContainerStyleOverrides: { + _type: Type.Object, + _description: 'CSS style elements override how fields appear in the field container.', + }, + _default: { + fields: ['name', 'dob', 'gender', 'identifier', 'age', 'contact', 'address'], + fieldsTableGroups: [], + fieldsContainerStyleOverrides: {}, + }, }, pageSize: { _type: Type.String, @@ -46,11 +63,9 @@ export const configSchema = { _default: 'A4', }, printMultipleStickers: { - enabled: { - _type: Type.Boolean, - _description: 'Whether to allow printing multiple patient ID stickers', - }, - totalStickers: { + _type: Type.Object, + _description: 'Configuration of how many stickers to print, together with the columns and rows to print per page', + numberOfStickers: { _type: Type.Number, _description: 'The number of patient ID stickers to print', }, @@ -64,20 +79,22 @@ export const configSchema = { }, _default: { enabled: false, - totalStickers: 1, + numberOfStickers: 1, stickerColumnsPerPage: 1, stickerRowsPerPage: 1, }, }, stickerSize: { + _type: Type.Object, + _description: 'Configuration of the patient sticker height and width for the patient identifier stickers', height: { _type: Type.String, _description: - 'Specifies the height of each patient ID sticker in the printout in units such as px or rem e.g. "15px", "5rem"', + 'Specifies the height of each patient ID sticker in the printout in units such as inches or centimetres.', }, width: { _type: Type.String, - _description: 'The width of each patient ID sticker in the printout in units such as px or rem', + _description: 'The width of each patient ID sticker in the printout in units such as inches or centimetres.', }, _default: { height: 'auto', @@ -111,11 +128,14 @@ export interface ConfigObject { showLogo: boolean; logo: string; }; - fields: Array; + printStickerFields: { + fields: Array; + fieldsTableGroups: Array>; + fieldsContainerStyleOverrides: Record; + }; pageSize: string; printMultipleStickers: { - enabled: boolean; - totalStickers: number; + numberOfStickers: number; stickerColumnsPerPage: number; stickerRowsPerPage: number; }; diff --git a/packages/esm-patient-banner-app/src/print-identifier-sticker/patient-detail.component.tsx b/packages/esm-patient-banner-app/src/print-identifier-sticker/patient-detail.component.tsx index b1bc02fe2a..750688d251 100644 --- a/packages/esm-patient-banner-app/src/print-identifier-sticker/patient-detail.component.tsx +++ b/packages/esm-patient-banner-app/src/print-identifier-sticker/patient-detail.component.tsx @@ -13,9 +13,7 @@ export const PatientName: React.FC = ({ patient }) => { const { t } = useTranslation(); return (
- - {t('patientNameWithSeparator', 'Patient name:')} - + {t('patientNameWithSeparator', 'Patient name:')} {getPatientName(patient)}
); @@ -25,9 +23,7 @@ export const PatientAge: React.FC = ({ patient }) => { const { t } = useTranslation(); return (
- - {t('patientAge', 'Age:')} - + {t('patientAge', 'Age:')} {age(patient.birthDate)}
); @@ -37,9 +33,7 @@ export const PatientDob: React.FC = ({ patient }) => { const { t } = useTranslation(); return (
- - {t('patientDateOfBirthWithSeparator', 'Date of birth:')} - + {t('patientDateOfBirthWithSeparator', 'Date of birth:')} {dayjs(patient.birthDate).format('DD-MM-YYYY')}
); @@ -63,9 +57,7 @@ export const PatientGender: React.FC = ({ patient }) => { }; return (
- - {t('patientGenderWithSeparator', 'Gender:')} - + {t('patientGenderWithSeparator', 'Gender:')} {getGender(patient.gender)}
); @@ -82,9 +74,7 @@ export const PatientIdentifier: React.FC = ({ patient }) =>
{patientIdentifiers?.map((identifier) => (
- - {identifier.type.text}: - + {identifier.type.text}: {identifier.value}
))} @@ -101,9 +91,7 @@ export const PatientContact: React.FC = ({ patient }) => { return (
- - {t('telephoneNumberWithSeparator', 'Telephone number:')} - + {t('telephoneNumberWithSeparator', 'Telephone number:')} {patient.telecom?.[0]?.value}
); @@ -122,7 +110,7 @@ export const PatientAddress: React.FC = ({ patient }) => { key === 'extension' ? ( address.extension?.[0]?.extension?.map((add, i) => (
- + {getCoreTranslation( getAddressKey(add.url) as CoreTranslationKey, getAddressKey(add.url) as CoreTranslationKey, @@ -134,7 +122,7 @@ export const PatientAddress: React.FC = ({ patient }) => { )) ) : (
- {getCoreTranslation(key as CoreTranslationKey, key)}: + {getCoreTranslation(key as CoreTranslationKey, key)}: {value}
), diff --git a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker-modal.test.tsx b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker-modal.test.tsx index 5f71d53c7c..a17abcaa5b 100644 --- a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker-modal.test.tsx +++ b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker-modal.test.tsx @@ -123,26 +123,4 @@ describe('PrintIdentifierStickerModal', () => { expect(screen.getAllByText(/100008E/i)[0]).toBeInTheDocument(); expect(screen.getAllByText(age(mockFhirPatient.birthDate))[0]).toBeInTheDocument(); }); - - it('should not render multiple sticker inputs if multiple stickers are disabled via config', async () => { - mockedUseConfig.mockReturnValue({ - ...defaultConfig, - printPatientSticker: { - ...defaultConfig.printPatientSticker, - printMultipleStickers: { - enabled: false, - totalStickers: 1, - stickerColumnsPerPage: 1, - stickerRowsPerPage: 1, - }, - stickerSize: { height: '2in', width: '2in' }, - }, - }); - - render(); - - expect(screen.queryByLabelText('columnsPerPage')).not.toBeInTheDocument(); - expect(screen.queryByLabelText('rowsPerPage')).not.toBeInTheDocument(); - expect(screen.queryByLabelText('totalNumber')).not.toBeInTheDocument(); - }); }); diff --git a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.component.tsx b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.component.tsx index 55070d75b3..5242345420 100644 --- a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.component.tsx +++ b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.component.tsx @@ -3,7 +3,7 @@ import Barcode from 'react-barcode'; import { useTranslation } from 'react-i18next'; import { useConfig } from '@openmrs/esm-framework'; import { defaultBarcodeParams, getPatientField } from './print-identifier-sticker.resource'; -import { type ConfigObject } from '../config-schema'; +import { type AllowedPatientFields, type ConfigObject } from '../config-schema'; import styles from './print-identifier-sticker.scss'; interface PrintComponentProps { @@ -12,6 +12,10 @@ interface PrintComponentProps { const PrintComponent: React.FC = ({ patient }) => { const { printPatientSticker } = useConfig(); + const fieldsTableGroups: Array> = + printPatientSticker?.printStickerFields?.fieldsTableGroups; + const individualFields = + printPatientSticker?.printStickerFields.fields?.filter((field) => !fieldsTableGroups.flat().includes(field)) || []; const primaryIdentifierValue = patient?.identifier?.find((identifier) => identifier.use === 'official')?.value; return ( @@ -26,8 +30,12 @@ const PrintComponent: React.FC = ({ patient }) => {
)}
-
- {printPatientSticker?.fields?.map((field) => { + +
+ {individualFields.map((field) => { const Component = getPatientField(field); return (
@@ -36,6 +44,24 @@ const PrintComponent: React.FC = ({ patient }) => { ); })}
+ {fieldsTableGroups.length > 0 + ? fieldsTableGroups.map((group, index) => ( + + + + {group.map((field) => { + const Component = getPatientField(field); + return ( + + ); + })} + + +
+ +
+ )) + : null}
); }; diff --git a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.modal.tsx b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.modal.tsx index afc5569175..5701abd1a3 100644 --- a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.modal.tsx +++ b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.modal.tsx @@ -24,14 +24,14 @@ interface PrintIdentifierStickerProps { patient: fhir.Patient; } -interface PrintMultipleStickersComponentProps extends Partial { +interface PrintMultipleStickersComponentProps + extends Pick { pageSize: string; patient: fhir.Patient; printMultipleStickers: { - enabled: boolean; + numberOfStickers: number; stickerColumnsPerPage: number; stickerRowsPerPage: number; - totalStickers: number; }; stickerSize: { height: string; @@ -153,9 +153,11 @@ const PrintMultipleStickersComponent = forwardRef( printMultipleStickers.stickerRowsPerPage, ); - const [numberOfLabels, setNumberOfLabels] = useState(printMultipleStickers.totalStickers); + const [numberOfLabels, setNumberOfLabels] = useState(printMultipleStickers.numberOfStickers); const [isPreviewVisible, setIsPreviewVisible] = useState(false); - const [isMultipleStickersEnabled, setIsMultipleStickersEnabled] = useState(printMultipleStickers.enabled); + const [isMultipleStickersEnabled, setIsMultipleStickersEnabled] = useState( + printMultipleStickers.numberOfStickers > 1, + ); const labels = Array.from({ length: numberOfLabels }); diff --git a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.resource.ts b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.resource.ts index ef32c1272e..f4faab69f0 100644 --- a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.resource.ts +++ b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.resource.ts @@ -12,7 +12,7 @@ import { } from './patient-detail.component'; export const defaultBarcodeParams: Options = { - width: 2, + width: 3, format: 'CODE39', background: '#f4f4f4', displayValue: true, diff --git a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.scss b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.scss index 870369a06f..00bd34cb14 100644 --- a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.scss +++ b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-identifier-sticker.scss @@ -5,8 +5,6 @@ .stickerContainer { padding: layout.$spacing-03 layout.$spacing-05; - height: var(--omrs-print-label-sticker-height, auto); - width: var(--omrs-print-label-sticker-width, auto); } .gridContainer { @@ -14,10 +12,8 @@ } .documentHeader { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; + display: grid; + grid-template-columns: 3fr 1fr; border-bottom: 1px solid $brand-01; margin-bottom: layout.$spacing-05; } @@ -66,10 +62,8 @@ } } -.strong { - @include type.type-style('heading-04'); - font-weight: 700; - margin-inline-end: layout.$spacing-03; +.patientDetailLabel { + @include type.type-style('heading-03'); } .multipleStickerToggle { @@ -84,12 +78,14 @@ } .patientDetail { - @include type.type-style('heading-03'); + @include type.type-style('heading-04'); + font-weight: 700; + margin-inline-end: layout.$spacing-03; text-align: left; } .implementationLogo { - width: 40%; + display: flex; } .previewContainer { @@ -132,6 +128,11 @@ grid-template-columns: repeat(var(--omrs-print-label-columns, 1), 1fr); grid-template-rows: repeat(var(--omrs-print-label-rows, 1), auto); } + + .stickerContainer { + height: var(--omrs-print-label-sticker-height, auto); + width: var(--omrs-print-label-sticker-width, auto); + } } .printContainer { @@ -161,8 +162,19 @@ display: grid; grid-template-columns: 1fr 1fr; gap: layout.$spacing-05 layout.$spacing-05; + padding-bottom: layout.$spacing-05; } .fieldRow { display: contents; } + +.fieldsTable { + table-layout: fixed; + width: 100%; +} + +.fieldsTableCell div { + display: grid; + gap: layout.$spacing-05; +}