diff --git a/packages/esm-patient-banner-app/src/config-schema.ts b/packages/esm-patient-banner-app/src/config-schema.ts index d6d652bf37..1f89c37244 100644 --- a/packages/esm-patient-banner-app/src/config-schema.ts +++ b/packages/esm-patient-banner-app/src/config-schema.ts @@ -115,6 +115,11 @@ export const configSchema = { _type: Type.UUID, }, }, + autoPrint: { + _type: Type.Boolean, + _description: 'Whether to print the patient sticker by default', + _default: false, + }, }, useRelationshipNameLink: { _type: Type.Boolean, @@ -150,6 +155,7 @@ export interface ConfigObject { width: string; }; identifiersToDisplay: Array; + autoPrint: boolean; }; useRelationshipNameLink: boolean; } 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 5ff26360c3..666c4919fb 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 @@ -1,7 +1,7 @@ import React from 'react'; import Barcode from 'react-barcode'; import { useTranslation } from 'react-i18next'; -import { useConfig } from '@openmrs/esm-framework'; +import { interpolateUrl, useConfig } from '@openmrs/esm-framework'; import { defaultBarcodeParams, getPatientField } from './print-identifier-sticker.resource'; import { type AllowedPatientFields, type ConfigObject } from '../config-schema'; import styles from './print-identifier-sticker.scss'; @@ -24,92 +24,20 @@ const PrintComponent: React.FC = ({ patient }) => {
{printPatientSticker?.header?.showBarcode && ( - - - +
+
+ +
+
)} {printPatientSticker?.header?.showLogo && ( - +
- +
)}
- - {/* - - - {printPatientSticker?.header?.showBarcode && ( - - - - )} - {printPatientSticker?.header?.showLogo && ( - -
- -
-
- )} -
-
-
- {individualFields.map((field) => { - const Component = getPatientField(field); - return ( - - ); - })} - {fieldsTableGroups.length > 0 - ? fieldsTableGroups.map((group, index) => ( - - - - - {group.map((field) => { - const Component = getPatientField(field); - return ( - - ); - })} - - -
- -
-
- )) - : null} -
-
*/} - - {/* - - - - Barcode - - - logo - - - Patient ID - 100008E - - Patient Name - Joshua Johnson - - Gender - Male - - Date of Birth - - - Age - 25-Sept-2019 - */} -
= ({ patient }) => { )) : null} - - {/* - {printPatientSticker?.header?.showBarcode && ( - - - - )} - {printPatientSticker?.header?.showLogo && ( - -
- -
-
- )} -
*/} - - {/*
- {individualFields.map((field) => { - const Component = getPatientField(field); - return ( -
- -
- ); - })} -
- {fieldsTableGroups.length > 0 - ? fieldsTableGroups.map((group, index) => ( - - - - {group.map((field) => { - const Component = getPatientField(field); - return ( - - ); - })} - - -
- -
- )) - : null} */}
); }; @@ -197,7 +78,7 @@ const ImplementationLogo: React.FC = () => { const { printPatientSticker } = useConfig(); return printPatientSticker?.header?.logo ? ( - {t('implementationLogo', + {t('implementationLogo', ) : ( // TODO: Figure out why #omrs-logo-full-mono sprite is not working void; patient: fhir.Patient; @@ -38,15 +38,18 @@ interface PrintMultipleStickersComponentProps height: string; width: string; }; + stickerSVGDataSource: string; + setStickerSVGDataSource: React.Dispatch>; } const PrintIdentifierSticker: React.FC = ({ closeModal, patient }) => { const { t } = useTranslation(); const { printPatientSticker } = useConfig(); - const { pageSize, printMultipleStickers, stickerSize } = printPatientSticker ?? {}; + const { pageSize, autoPrint, printMultipleStickers, stickerSize } = printPatientSticker ?? {}; const [isPrinting, setIsPrinting] = useState(false); - const headerTitle = t('patientIdentifierSticker', 'Patient identifier sticker'); + const [stickerSVGDataSource, setStickerSVGDataSource] = useState(''); + const headerTitle = t('patientIdentifierSticker', 'Patient identifier sticker'); const contentToPrintRef = useRef(null); const onBeforeGetContentResolve = useRef<() => void | null>(null); @@ -73,18 +76,59 @@ const PrintIdentifierSticker: React.FC = ({ closeMo closeModal(); }, [closeModal]); - const handlePrintWindow = useCallback((printWindow: HTMLIFrameElement | null): Promise => { - return new Promise((resolve) => { - if (printWindow) { - const printContent = printWindow.contentDocument || printWindow.contentWindow?.document; - if (printContent) { - printContent.body.style.overflow = 'initial !important'; - printWindow.contentWindow?.print(); + const handlePrintWindow = useCallback( + (printWindow: HTMLIFrameElement | null): Promise => { + return new Promise((resolve) => { + if (printWindow) { + const printContent = printWindow.contentDocument || printWindow.contentWindow?.document; + if (printContent) { + printContent.body.style.overflow = 'initial !important'; + + const style = printContent.createElement('style'); + style.textContent = ` + @page { + size: ${pageSize}; + margin: 15px 20px 0 20px; + } + + @media print { + #print-wrapper { + width: 100vw !important; + height: 100vh !important; + transform-origin: top left; + transform: scale(var(--print-scale)); + } + + #print-content { + position: absolute; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + } + } + `; + printContent.head.appendChild(style); + + const content = printContent.getElementById('print-wrapper'); + const contentWidth = content.scrollWidth; + const contentHeight = content.scrollHeight; + const pageWidth = window.innerWidth; + const pageHeight = window.innerHeight; + const scaleX = pageWidth / contentWidth; + const scaleY = pageHeight / contentHeight; + const scale = Math.min(scaleX, scaleY) * 0.95; + + printContent.documentElement.style.setProperty('--print-scale', scale.toString()); + + printWindow.contentWindow?.print(); + } } - } - resolve(); - }); - }, []); + resolve(); + }); + }, + [pageSize], + ); const handlePrintError = useCallback((errorLocation, error) => { onBeforeGetContentResolve.current = null; @@ -111,6 +155,12 @@ const PrintIdentifierSticker: React.FC = ({ closeMo copyStyles: true, }); + useEffect(() => { + if (!isPrinting && autoPrint && stickerSVGDataSource && contentToPrintRef.current) { + handlePrint(); + } + }, [autoPrint, handlePrint, isPrinting, stickerSVGDataSource]); + return ( <> = ({ closeMo printMultipleStickers={printMultipleStickers} stickerSize={stickerSize} patient={patient} + stickerSVGDataSource={stickerSVGDataSource} + setStickerSVGDataSource={setStickerSVGDataSource} ref={contentToPrintRef} /> @@ -130,7 +182,12 @@ const PrintIdentifierSticker: React.FC = ({ closeMo -
+
@@ -277,18 +347,18 @@ const PrintMultipleStickersComponent = forwardRef
-
+
{pages.map((pageLabels, pageIndex) => ( -
-
- {pageLabels.map((_label, index) => ( -
- - - -
- ))} -
+ ))}
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 f4faab69f0..bb6a78ef78 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 @@ -14,9 +14,9 @@ import { export const defaultBarcodeParams: Options = { width: 3, format: 'CODE39', - background: '#f4f4f4', + background: '#ffffff', displayValue: true, - renderer: 'img', + renderer: 'svg', font: 'IBM Plex Sans', textAlign: 'center', textPosition: 'bottom', 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 50634690e5..e1e5631954 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 @@ -7,11 +7,17 @@ padding: layout.$spacing-03 layout.$spacing-05; } +.svgContainer { + background-color: white; +} + .gridContainer { padding-left: 0; } .gridHeaderContainer { + display: flex; + gap: 1rem; padding: 0; border-bottom: 1px solid $brand-01; margin-bottom: layout.$spacing-05; @@ -94,9 +100,14 @@ .implementationLogo { display: flex; + align-items: center; height: 100%; } +.stickerBarcode svg { + max-width: 100%; +} + .previewContainer { max-height: layout.$spacing-13; overflow: scroll; @@ -116,6 +127,14 @@ display: none; } +.stickerBarcodeContainer { + flex: 7; +} + +.logoContainer { + flex: 3; +} + .printRoot { @media print { @page { @@ -148,10 +167,25 @@ .implementationLogo { display: flex; + align-items: center; height: 100%; } + .stickerBarcodeContainer { + flex: 7; + } + + .logoContainer { + flex: 3; + } + + .stickerBarcode svg { + max-width: 100%; + } + .gridHeaderContainer { + display: flex; + gap: 1rem; padding: 0; border-bottom: 1px solid $brand-01; margin-bottom: layout.$spacing-05; diff --git a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-size-wrapper.component.tsx b/packages/esm-patient-banner-app/src/print-identifier-sticker/print-size-wrapper.component.tsx deleted file mode 100644 index 118ef236a9..0000000000 --- a/packages/esm-patient-banner-app/src/print-identifier-sticker/print-size-wrapper.component.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import React, { useEffect, useRef } from 'react'; - -const PrintSizeWrapper = ({ children }) => { - const wrapperRef = useRef(null); - - useEffect(() => { - const mediaQueryList = window.matchMedia('print'); - - const handlePrintMedia = (mql) => { - if (!wrapperRef.current) return; - - const style = document.createElement('style'); - style.textContent = ` - @page { - size: auto; - margin: 0mm; - } - - @media print { - .print-wrapper { - width: 100vw !important; - height: 100vh !important; - transform-origin: top left; - transform: scale(var(--print-scale)); - } - - .print-content { - position: absolute; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - } - } - `; - document.head.appendChild(style); - - // Calculate scale on print - window.onbeforeprint = () => { - if (!wrapperRef.current) return; - const content = wrapperRef.current; - const contentWidth = content.scrollWidth; - const contentHeight = content.scrollHeight; - - // Get actual page dimensions from CSS - const pageWidth = window.innerWidth; - const pageHeight = window.innerHeight; - - // Calculate scale to fit - const scaleX = pageWidth / contentWidth; - const scaleY = pageHeight / contentHeight; - const scale = Math.min(scaleX, scaleY) * 0.95; // 95% to ensure margins - - document.documentElement.style.setProperty('--print-scale', scale.toString()); - }; - }; - - mediaQueryList.addListener(handlePrintMedia); - handlePrintMedia(mediaQueryList); - - return () => { - mediaQueryList.removeListener(handlePrintMedia); - window.onbeforeprint = null; - }; - }, []); - - return ( -
-
{children}
-
- ); -}; - -export default PrintSizeWrapper;