@kenyaemr/esm-express-workflow-app 5.4.4-pre.43 → 5.4.4-pre.430
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/.turbo/turbo-build.log +14 -7
- package/dist/1084.js +1 -0
- package/dist/1084.js.map +1 -0
- package/dist/1278.js +1 -0
- package/dist/1278.js.map +1 -0
- package/dist/1324.js +1 -0
- package/dist/1324.js.map +1 -0
- package/dist/1375.js +66 -0
- package/dist/1375.js.map +1 -0
- package/dist/1402.js +1 -0
- package/dist/1402.js.map +1 -0
- package/dist/1442.js +1 -0
- package/dist/1442.js.map +1 -0
- package/dist/1520.js +1 -0
- package/dist/1520.js.map +1 -0
- package/dist/1559.js +1 -0
- package/dist/1559.js.map +1 -0
- package/dist/1593.js +1 -0
- package/dist/1593.js.map +1 -0
- package/dist/162.js +1 -0
- package/dist/162.js.map +1 -0
- package/dist/1620.js +1 -0
- package/dist/1620.js.map +1 -0
- package/dist/1658.js +1 -0
- package/dist/1658.js.map +1 -0
- package/dist/1659.js +1 -0
- package/dist/1659.js.map +1 -0
- package/dist/1789.js +1 -0
- package/dist/1789.js.map +1 -0
- package/dist/1827.js +1 -0
- package/dist/1827.js.map +1 -0
- package/dist/1831.js +1 -0
- package/dist/1831.js.map +1 -0
- package/dist/1854.js +1 -0
- package/dist/1854.js.map +1 -0
- package/dist/196.js +1 -0
- package/dist/196.js.map +1 -0
- package/dist/2127.js +1 -0
- package/dist/2127.js.map +1 -0
- package/dist/2152.js +1 -0
- package/dist/2152.js.map +1 -0
- package/dist/2202.js +1 -0
- package/dist/2202.js.map +1 -0
- package/dist/221.js +1 -0
- package/dist/221.js.map +1 -0
- package/dist/2269.js +1 -0
- package/dist/2269.js.map +1 -0
- package/dist/2293.js +1 -0
- package/dist/2293.js.map +1 -0
- package/dist/234.js +1 -0
- package/dist/234.js.map +1 -0
- package/dist/2412.js +1 -1
- package/dist/2412.js.map +1 -1
- package/dist/2466.js +1 -0
- package/dist/2466.js.map +1 -0
- package/dist/2534.js +1 -1
- package/dist/2534.js.map +1 -1
- package/dist/2553.js +1 -0
- package/dist/2553.js.map +1 -0
- package/dist/2556.js +1 -0
- package/dist/2556.js.map +1 -0
- package/dist/2648.js +1 -0
- package/dist/2648.js.map +1 -0
- package/dist/274.js +1 -0
- package/dist/274.js.map +1 -0
- package/dist/2788.js +1 -0
- package/dist/2788.js.map +1 -0
- package/dist/2842.js +1 -0
- package/dist/2842.js.map +1 -0
- package/dist/2874.js +1 -0
- package/dist/2874.js.map +1 -0
- package/dist/2916.js +1 -0
- package/dist/2916.js.map +1 -0
- package/dist/2947.js +1 -1
- package/dist/2947.js.map +1 -1
- package/dist/3012.js +1 -0
- package/dist/3012.js.map +1 -0
- package/dist/3087.js +1 -0
- package/dist/3087.js.map +1 -0
- package/dist/3335.js +1 -0
- package/dist/3335.js.map +1 -0
- package/dist/3378.js +1 -0
- package/dist/3378.js.map +1 -0
- package/dist/3504.js +1 -0
- package/dist/3504.js.map +1 -0
- package/dist/3509.js +1 -1
- package/dist/3509.js.map +1 -1
- package/dist/356.js +1 -0
- package/dist/356.js.map +1 -0
- package/dist/3690.js +1 -0
- package/dist/3690.js.map +1 -0
- package/dist/371.js +1 -0
- package/dist/371.js.map +1 -0
- package/dist/3747.js +1 -0
- package/dist/3747.js.map +1 -0
- package/dist/3819.js +1 -0
- package/dist/3819.js.map +1 -0
- package/dist/3820.js +1 -0
- package/dist/3820.js.map +1 -0
- package/dist/3910.js +1 -0
- package/dist/3910.js.map +1 -0
- package/dist/393.js +6 -0
- package/dist/393.js.map +1 -0
- package/dist/3933.js +1 -0
- package/dist/3933.js.map +1 -0
- package/dist/3989.js +1 -0
- package/dist/3989.js.map +1 -0
- package/dist/3995.js +1 -0
- package/dist/3995.js.map +1 -0
- package/dist/4032.js +1 -0
- package/dist/4032.js.map +1 -0
- package/dist/4145.js +1 -1
- package/dist/4145.js.map +1 -1
- package/dist/4178.js +1 -1
- package/dist/4178.js.map +1 -1
- package/dist/4191.js +1 -0
- package/dist/4191.js.map +1 -0
- package/dist/4212.js +1 -0
- package/dist/4212.js.map +1 -0
- package/dist/4215.js +1 -0
- package/dist/4215.js.map +1 -0
- package/dist/4523.js +1 -0
- package/dist/4523.js.map +1 -0
- package/dist/4588.js +1 -0
- package/dist/4588.js.map +1 -0
- package/dist/4617.js +1 -0
- package/dist/4617.js.map +1 -0
- package/dist/466.js +1 -1
- package/dist/466.js.map +1 -1
- package/dist/4688.js +1 -0
- package/dist/{7288.js.map → 4688.js.map} +1 -1
- package/dist/470.js +1 -0
- package/dist/470.js.map +1 -0
- package/dist/4759.js +1 -0
- package/dist/4759.js.map +1 -0
- package/dist/4818.js +1 -1
- package/dist/4818.js.map +1 -1
- package/dist/5086.js +1 -1
- package/dist/5086.js.map +1 -1
- package/dist/5093.js +1 -0
- package/dist/5093.js.map +1 -0
- package/dist/5097.js +1 -0
- package/dist/5097.js.map +1 -0
- package/dist/510.js +1 -0
- package/dist/510.js.map +1 -0
- package/dist/5117.js +1 -0
- package/dist/5117.js.map +1 -0
- package/dist/5279.js +1 -0
- package/dist/5279.js.map +1 -0
- package/dist/5434.js +1 -0
- package/dist/5434.js.map +1 -0
- package/dist/5514.js +1 -0
- package/dist/5514.js.map +1 -0
- package/dist/5568.js +1 -0
- package/dist/5568.js.map +1 -0
- package/dist/5576.js +1 -1
- package/dist/5576.js.map +1 -1
- package/dist/5630.js +1 -0
- package/dist/5630.js.map +1 -0
- package/dist/5676.js +1 -1
- package/dist/5676.js.map +1 -1
- package/dist/5695.js +1 -0
- package/dist/5695.js.map +1 -0
- package/dist/5697.js +1 -1
- package/dist/5697.js.map +1 -1
- package/dist/5728.js +1 -0
- package/dist/5728.js.map +1 -0
- package/dist/5809.js +1 -1
- package/dist/5809.js.map +1 -1
- package/dist/585.js +1 -0
- package/dist/585.js.map +1 -0
- package/dist/5887.js +1 -0
- package/dist/5887.js.map +1 -0
- package/dist/5958.js +1 -0
- package/dist/5958.js.map +1 -0
- package/dist/5964.js +1 -0
- package/dist/5964.js.map +1 -0
- package/dist/6008.js +1 -0
- package/dist/602.js +1 -0
- package/dist/602.js.map +1 -0
- package/dist/6020.js +1 -0
- package/dist/6020.js.map +1 -0
- package/dist/6161.js +1 -0
- package/dist/6161.js.map +1 -0
- package/dist/6273.js +1 -0
- package/dist/6273.js.map +1 -0
- package/dist/6337.js +1 -0
- package/dist/6337.js.map +1 -0
- package/dist/6427.js +1 -1
- package/dist/6427.js.map +1 -1
- package/dist/6429.js +1 -0
- package/dist/6429.js.map +1 -0
- package/dist/6478.js +7 -0
- package/dist/6478.js.map +1 -0
- package/dist/6508.js +1 -0
- package/dist/6508.js.map +1 -0
- package/dist/6634.js +1 -0
- package/dist/6634.js.map +1 -0
- package/dist/6767.js +1 -0
- package/dist/6767.js.map +1 -0
- package/dist/6783.js +1 -0
- package/dist/6783.js.map +1 -0
- package/dist/6868.js +1 -1
- package/dist/6868.js.map +1 -1
- package/dist/688.js +1 -0
- package/dist/688.js.map +1 -0
- package/dist/689.js +1 -1
- package/dist/689.js.map +1 -1
- package/dist/694.js +1 -0
- package/dist/694.js.map +1 -0
- package/dist/6987.js +1 -0
- package/dist/6987.js.map +1 -0
- package/dist/7061.js +1 -0
- package/dist/7061.js.map +1 -0
- package/dist/7078.js +1 -0
- package/dist/7078.js.map +1 -0
- package/dist/710.js +1 -0
- package/dist/710.js.map +1 -0
- package/dist/7128.js +1 -0
- package/dist/7128.js.map +1 -0
- package/dist/7209.js +1 -0
- package/dist/7209.js.map +1 -0
- package/dist/7424.js +1 -0
- package/dist/7424.js.map +1 -0
- package/dist/770.js +1 -0
- package/dist/770.js.map +1 -0
- package/dist/7707.js +1 -0
- package/dist/7707.js.map +1 -0
- package/dist/7784.js +1 -0
- package/dist/7784.js.map +1 -0
- package/dist/781.js +1 -1
- package/dist/781.js.map +1 -1
- package/dist/7824.js +1 -0
- package/dist/7824.js.map +1 -0
- package/dist/7832.js +1 -0
- package/dist/7832.js.map +1 -0
- package/dist/8178.js +1 -0
- package/dist/8178.js.map +1 -0
- package/dist/820.js +1 -0
- package/dist/820.js.map +1 -0
- package/dist/8224.js +1 -0
- package/dist/8224.js.map +1 -0
- package/dist/8225.js +1 -0
- package/dist/8225.js.map +1 -0
- package/dist/8240.js +1 -1
- package/dist/8240.js.map +1 -1
- package/dist/8258.js +1 -0
- package/dist/8258.js.map +1 -0
- package/dist/8702.js +1 -0
- package/dist/8702.js.map +1 -0
- package/dist/8725.js +1 -0
- package/dist/8725.js.map +1 -0
- package/dist/8762.js +1 -0
- package/dist/8762.js.map +1 -0
- package/dist/8763.js +1 -0
- package/dist/8763.js.map +1 -0
- package/dist/8815.js +1 -0
- package/dist/8815.js.map +1 -0
- package/dist/8882.js +1 -0
- package/dist/8882.js.map +1 -0
- package/dist/8924.js +1 -1
- package/dist/8924.js.map +1 -1
- package/dist/8937.js +1 -0
- package/dist/8937.js.map +1 -0
- package/dist/9.js +1 -1
- package/dist/9.js.map +1 -1
- package/dist/9061.js +1 -0
- package/dist/9061.js.map +1 -0
- package/dist/9087.js +1 -0
- package/dist/9087.js.map +1 -0
- package/dist/9301.js +1 -0
- package/dist/9301.js.map +1 -0
- package/dist/9324.js +1 -0
- package/dist/9324.js.map +1 -0
- package/dist/9497.js +1 -0
- package/dist/9497.js.map +1 -0
- package/dist/9520.js +1 -1
- package/dist/9520.js.map +1 -1
- package/dist/9526.js +1 -0
- package/dist/9526.js.map +1 -0
- package/dist/9621.js +1 -0
- package/dist/9621.js.map +1 -0
- package/dist/9676.js +17 -0
- package/dist/9676.js.map +1 -0
- package/dist/977.js +1 -0
- package/dist/977.js.map +1 -0
- package/dist/9771.js +1 -0
- package/dist/9771.js.map +1 -0
- package/dist/9806.js +1 -0
- package/dist/9806.js.map +1 -0
- package/dist/989.js +1 -0
- package/dist/989.js.map +1 -0
- package/dist/kenyaemr-esm-express-workflow-app.js +6 -5
- package/dist/kenyaemr-esm-express-workflow-app.js.buildmanifest.json +1407 -809
- package/dist/kenyaemr-esm-express-workflow-app.js.map +1 -1
- package/dist/main.js +22 -5
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +4 -6
- package/src/components/admissions/admissions-dashboard.component.tsx +2 -2
- package/src/components/anaesthetic/anaesthetic-dashboard.meta.ts +8 -0
- package/src/components/anaesthetic/anaesthetic-data-form.component.tsx +442 -0
- package/src/components/anaesthetic/anaesthetic-data-form.scss +278 -0
- package/src/components/anaesthetic/anaesthetic-link.component.tsx +21 -0
- package/src/components/anaesthetic/anaesthetic.component.tsx +618 -0
- package/src/components/anaesthetic/anaesthetic.resource.ts +1503 -0
- package/src/components/anaesthetic/anaesthetic.scss +1885 -0
- package/src/components/anaesthetic/forms/anaesthetic-form.component.tsx +304 -0
- package/src/components/anaesthetic/forms/anaesthetic-record-form.component.tsx +707 -0
- package/src/components/anaesthetic/forms/icd11-diagnosis-search.component.tsx +178 -0
- package/src/components/anaesthetic/forms/icd11-diagnosis-search.scss +126 -0
- package/src/components/anaesthetic/forms/index.ts +2 -0
- package/src/components/anaesthetic/forms/interoperative-record-drug-given-form.component.tsx +231 -0
- package/src/components/anaesthetic/forms/post-operative-summary-form.component.tsx +171 -0
- package/src/components/anaesthetic/forms/time-picker-dropdown.component.tsx +202 -0
- package/src/components/anaesthetic/forms/time-picker-dropdown.scss +107 -0
- package/src/components/anaesthetic/forms/time-picker-with-clock.component.tsx +174 -0
- package/src/components/anaesthetic/forms/time-picker-with-clock.scss +178 -0
- package/src/components/anaesthetic/forms/useAnaestheticData.ts +16 -0
- package/src/components/anaesthetic/graphs/anaesthetic-graph-wrapper.component.tsx +266 -0
- package/src/components/anaesthetic/graphs/anaesthetic-graph.component.tsx +185 -0
- package/src/components/anaesthetic/graphs/index.ts +2 -0
- package/src/components/anaesthetic/graphs/interoperative-record-drug-given-graph-wrapper.component.tsx +197 -0
- package/src/components/anaesthetic/graphs/interoperative-record-drug-given-graph.component.tsx +93 -0
- package/src/components/anaesthetic/resources/anaesthetic-amniotic-fluid.resource.ts +277 -0
- package/src/components/anaesthetic/resources/anaesthetic-form.resource.ts +716 -0
- package/src/components/anaesthetic/resources/anaesthetic.resource.ts +378 -0
- package/src/components/anaesthetic/types/index.ts +1349 -0
- package/src/components/consultation/clinical-encounter/clinical-encounter.component.tsx +4 -20
- package/src/components/consultation/clinical-encounter/encounter-details.component.tsx +9 -9
- package/src/components/consultation/clinical-encounter/encounter-details.test.tsx +19 -18
- package/src/components/consultation/consultation.utils.tsx +1 -1
- package/src/components/consultation/dashboard.component.tsx +0 -2
- package/src/components/consultation/index.ts +1 -1
- package/src/components/consultation/tabs/index.ts +67 -0
- package/src/components/facility-dashboard/components/header/home-header.component.tsx +8 -13
- package/src/components/laboratory/index.ts +11 -0
- package/src/components/laboratory/lab-table.component.tsx +46 -12
- package/src/components/laboratory/laboratory-tabs.component.tsx +3 -17
- package/src/components/mch/dashboard.component.tsx +0 -2
- package/src/components/mch/mch.component.tsx +1 -3
- package/src/components/pharmacy/index.ts +1 -1
- package/src/components/pharmacy/orders/pharmacy-orders.component.tsx +44 -6
- package/src/components/pharmacy/orders/pharmacy-orders.test.tsx +8 -7
- package/src/components/pharmacy/pharmacy-tabs.component.tsx +4 -20
- package/src/components/pharmacy/tabs/index.ts +21 -0
- package/src/components/preauth/index.ts +22 -0
- package/src/components/preauth/preauth-dashboard.component.tsx +20 -0
- package/src/components/procedures/index.ts +16 -0
- package/src/components/procedures/procedure-queues/index.ts +13 -0
- package/src/components/procedures/procedure-queues/procedure-form-extras.component.tsx +33 -0
- package/src/components/procedures/procedure-queues/procedure-form-extras.scss +5 -0
- package/src/components/procedures/procedure-queues/procedure-queues.component.tsx +35 -0
- package/src/components/procedures/procedure-queues/procedure-queues.resources.ts +37 -0
- package/src/components/procedures/procedure-queues/procedure-room-tabs.component.tsx +80 -0
- package/src/components/procedures/procedure-queues/procedure-rooms.scss +13 -0
- package/src/components/procedures/procedure-queues/queue-procedure-tabs.component.tsx +34 -0
- package/src/components/procedures/procedure-queues/summary-cards.component.tsx +81 -0
- package/src/components/procedures/procedure-queues/summary-cards.scss +35 -0
- package/src/components/procedures/procedures-table.component.tsx +77 -19
- package/src/components/procedures/procedures-tabs.component.test.tsx +57 -0
- package/src/components/procedures/procedures-tabs.component.tsx +3 -18
- package/src/components/radiology-and-imaging/index.ts +11 -0
- package/src/components/radiology-and-imaging/radiology-and-imaging-table.component.tsx +73 -21
- package/src/components/radiology-and-imaging/radiology-and-imaging.component.tsx +3 -19
- package/src/components/registration/card/HIE-card/hie-card.component.tsx +32 -44
- package/src/components/registration/card/Local-card/local-card.component.tsx +22 -24
- package/src/components/registration/checkin-form-extra/checkin-form-extra.extension.tsx +8 -2
- package/src/components/registration/checkin-form-extra/queue-fields.component.tsx +18 -19
- package/src/components/registration/dependants/dependants.component.tsx +37 -60
- package/src/components/registration/dependants/dependants.resource.ts +75 -46
- package/src/components/registration/end-visit-modal/end-visit-dialog.modal.tsx +320 -0
- package/src/components/registration/end-visit-modal/end-visit-dialog.scss +12 -0
- package/src/components/registration/end-visit-modal/end-visit.resource.tsx +59 -0
- package/src/components/registration/end-visit-modal/sha-end-visit.resource.ts +285 -0
- package/src/components/registration/search-bar/search-bar.resource.ts +32 -93
- package/src/components/registration/start-visit-form/hooks/useDefaultFacilityLocation.tsx +15 -0
- package/src/components/registration/start-visit-form/hooks/useDefaultVisitLocation.tsx +24 -0
- package/src/components/registration/start-visit-form/hooks/useOfflineVisitType.tsx +18 -0
- package/src/components/registration/start-visit-form/hooks/useRecommendedVisitTypes.tsx +36 -0
- package/src/components/registration/start-visit-form/hooks/useVisitAttributeType.tsx +102 -0
- package/src/components/registration/start-visit-form/overflow-menu-extension/custom-end-active-visit.extension.tsx +44 -0
- package/src/components/registration/start-visit-form/overflow-menu-extension/overflow-menu-item.extension.tsx +67 -0
- package/src/components/registration/start-visit-form/overflow-menu-extension/overflow-menu-item.scss +3 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/base-visit-type.component.tsx +126 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/base-visit-type.scss +75 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/exported-visit-form.workspace.tsx +778 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/location-selector.component.tsx +86 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/recommended-visit-type.component.tsx +32 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/visit-attribute-type.component.tsx +257 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/visit-attribute-type.scss +5 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/visit-date-time.component.tsx +193 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/visit-form.resource.ts +390 -0
- package/src/components/registration/start-visit-form/start-visit-workspace/visit-form.scss +144 -0
- package/src/components/registration/start-visit-form/visit-form-workspace/visit-form.workspace.tsx +48 -0
- package/src/components/registration/type/index.ts +101 -0
- package/src/components/reports/index.ts +1 -0
- package/src/components/triage/dashboard.component.tsx +0 -2
- package/src/config-schema.ts +476 -0
- package/src/hooks/useOrders.tsx +2 -2
- package/src/hooks/useServiceQueues.tsx +1 -1
- package/src/index.ts +81 -15
- package/src/routes.json +298 -32
- package/src/shared/dashboard-link/dashboard-link.component.tsx +11 -8
- package/src/shared/orders/OrderTable.scss +7 -0
- package/src/shared/orders/OrderTable.tsx +68 -8
- package/src/shared/orders/print-order/print-order.component.tsx +158 -0
- package/src/shared/orders/print-order/print-order.scss +225 -0
- package/src/shared/orders/print-prescription/print-prescription.component.tsx +65 -0
- package/src/shared/orders/print-prescription/print-prescription.resource.ts +45 -0
- package/src/shared/orders/print-prescription/print-prescription.scss +25 -0
- package/src/shared/otp-verification/index.ts +112 -29
- package/src/shared/otp-verification/otp-verification.modal.tsx +1110 -122
- package/src/shared/otp-verification/otp-verification.scss +374 -0
- package/src/shared/patient-chart/patient-summary-dashboard/patient-summary-dashboard.component.tsx +5 -84
- package/src/shared/pin-put/pinput.component.test.tsx +7 -6
- package/src/shared/tabs/create-tab-extension.tsx +33 -0
- package/src/shared/tabs/extension-tabs.component.tsx +51 -33
- package/src/shared/utils/index.ts +140 -5
- package/src/types/index.ts +12 -0
- package/translations/am.json +443 -131
- package/translations/en.json +327 -15
- package/translations/fr.json +372 -63
- package/translations/sw.json +347 -35
- package/tsconfig.json +1 -0
- package/dist/1049.js +0 -1
- package/dist/1049.js.map +0 -1
- package/dist/1072.js +0 -1
- package/dist/1072.js.map +0 -1
- package/dist/1091.js +0 -1
- package/dist/1091.js.map +0 -1
- package/dist/1172.js +0 -1
- package/dist/1172.js.map +0 -1
- package/dist/132.js +0 -1
- package/dist/132.js.map +0 -1
- package/dist/1354.js +0 -1
- package/dist/1354.js.map +0 -1
- package/dist/1704.js +0 -1
- package/dist/1704.js.map +0 -1
- package/dist/1729.js +0 -17
- package/dist/1729.js.map +0 -1
- package/dist/1757.js +0 -1
- package/dist/1757.js.map +0 -1
- package/dist/1761.js +0 -1
- package/dist/1761.js.map +0 -1
- package/dist/1809.js +0 -7
- package/dist/1809.js.map +0 -1
- package/dist/1842.js +0 -1
- package/dist/1874.js +0 -1
- package/dist/1874.js.map +0 -1
- package/dist/1962.js +0 -1
- package/dist/1962.js.map +0 -1
- package/dist/2007.js +0 -1
- package/dist/2007.js.map +0 -1
- package/dist/2024.js +0 -1
- package/dist/2024.js.map +0 -1
- package/dist/2045.js +0 -1
- package/dist/2045.js.map +0 -1
- package/dist/2163.js +0 -1
- package/dist/2163.js.map +0 -1
- package/dist/2191.js +0 -1
- package/dist/2191.js.map +0 -1
- package/dist/2267.js +0 -1
- package/dist/2267.js.map +0 -1
- package/dist/231.js +0 -1
- package/dist/231.js.map +0 -1
- package/dist/236.js +0 -1
- package/dist/236.js.map +0 -1
- package/dist/2367.js +0 -1
- package/dist/2367.js.map +0 -1
- package/dist/2463.js +0 -1
- package/dist/2463.js.map +0 -1
- package/dist/2561.js +0 -1
- package/dist/2561.js.map +0 -1
- package/dist/2810.js +0 -2
- package/dist/2810.js.map +0 -1
- package/dist/2867.js +0 -1
- package/dist/2867.js.map +0 -1
- package/dist/2909.js +0 -1
- package/dist/2909.js.map +0 -1
- package/dist/2949.js +0 -1
- package/dist/2949.js.map +0 -1
- package/dist/3040.js +0 -1
- package/dist/3119.js +0 -1
- package/dist/3119.js.map +0 -1
- package/dist/3215.js +0 -1
- package/dist/3215.js.map +0 -1
- package/dist/322.js +0 -1
- package/dist/322.js.map +0 -1
- package/dist/3228.js +0 -1
- package/dist/3228.js.map +0 -1
- package/dist/330.js +0 -1
- package/dist/330.js.map +0 -1
- package/dist/3472.js +0 -1
- package/dist/3472.js.map +0 -1
- package/dist/351.js +0 -1
- package/dist/351.js.map +0 -1
- package/dist/3576.js +0 -1
- package/dist/3576.js.map +0 -1
- package/dist/397.js +0 -1
- package/dist/397.js.map +0 -1
- package/dist/4007.js +0 -66
- package/dist/4007.js.map +0 -1
- package/dist/4200.js +0 -1
- package/dist/4200.js.map +0 -1
- package/dist/4224.js +0 -1
- package/dist/4224.js.map +0 -1
- package/dist/43.js +0 -1
- package/dist/43.js.map +0 -1
- package/dist/4308.js +0 -1
- package/dist/4308.js.map +0 -1
- package/dist/4399.js +0 -1
- package/dist/4399.js.map +0 -1
- package/dist/4505.js +0 -1
- package/dist/4505.js.map +0 -1
- package/dist/4724.js +0 -1
- package/dist/4724.js.map +0 -1
- package/dist/498.js +0 -1
- package/dist/498.js.map +0 -1
- package/dist/509.js +0 -1
- package/dist/509.js.map +0 -1
- package/dist/5096.js +0 -1
- package/dist/5096.js.map +0 -1
- package/dist/5159.js +0 -13
- package/dist/5159.js.map +0 -1
- package/dist/5184.js +0 -1
- package/dist/5184.js.map +0 -1
- package/dist/5270.js +0 -1
- package/dist/5270.js.map +0 -1
- package/dist/5361.js +0 -1
- package/dist/5361.js.map +0 -1
- package/dist/5537.js +0 -1
- package/dist/5537.js.map +0 -1
- package/dist/566.js +0 -1
- package/dist/566.js.map +0 -1
- package/dist/5733.js +0 -1
- package/dist/5733.js.map +0 -1
- package/dist/5854.js +0 -1
- package/dist/5854.js.map +0 -1
- package/dist/5882.js +0 -1
- package/dist/6004.js +0 -1
- package/dist/6004.js.map +0 -1
- package/dist/6121.js +0 -3
- package/dist/6121.js.map +0 -1
- package/dist/6137.js +0 -1
- package/dist/6137.js.map +0 -1
- package/dist/6356.js +0 -1
- package/dist/6356.js.map +0 -1
- package/dist/6571.js +0 -1
- package/dist/6571.js.map +0 -1
- package/dist/6721.js +0 -1
- package/dist/6721.js.map +0 -1
- package/dist/6858.js +0 -1
- package/dist/6858.js.map +0 -1
- package/dist/6925.js +0 -1
- package/dist/6925.js.map +0 -1
- package/dist/6960.js +0 -1
- package/dist/6960.js.map +0 -1
- package/dist/7085.js +0 -1
- package/dist/7085.js.map +0 -1
- package/dist/7127.js +0 -1
- package/dist/7176.js +0 -1
- package/dist/7176.js.map +0 -1
- package/dist/7237.js +0 -1
- package/dist/7237.js.map +0 -1
- package/dist/725.js +0 -1
- package/dist/725.js.map +0 -1
- package/dist/7288.js +0 -1
- package/dist/7329.js +0 -1
- package/dist/7329.js.map +0 -1
- package/dist/7334.js +0 -1
- package/dist/7334.js.map +0 -1
- package/dist/7461.js +0 -1
- package/dist/7461.js.map +0 -1
- package/dist/7517.js +0 -1
- package/dist/7517.js.map +0 -1
- package/dist/7837.js +0 -1
- package/dist/7837.js.map +0 -1
- package/dist/8103.js +0 -1
- package/dist/8103.js.map +0 -1
- package/dist/8110.js +0 -1
- package/dist/8110.js.map +0 -1
- package/dist/8179.js +0 -6
- package/dist/8179.js.map +0 -1
- package/dist/8189.js +0 -1
- package/dist/8189.js.map +0 -1
- package/dist/8209.js +0 -1
- package/dist/8209.js.map +0 -1
- package/dist/8249.js +0 -1
- package/dist/8249.js.map +0 -1
- package/dist/8285.js +0 -1
- package/dist/8285.js.map +0 -1
- package/dist/8470.js +0 -1
- package/dist/8470.js.map +0 -1
- package/dist/8502.js +0 -1
- package/dist/8502.js.map +0 -1
- package/dist/866.js +0 -1
- package/dist/866.js.map +0 -1
- package/dist/8889.js +0 -11
- package/dist/8889.js.map +0 -1
- package/dist/8990.js +0 -1
- package/dist/8990.js.map +0 -1
- package/dist/8994.js +0 -1
- package/dist/8994.js.map +0 -1
- package/dist/9049.js +0 -1
- package/dist/9049.js.map +0 -1
- package/dist/9054.js +0 -1
- package/dist/9054.js.map +0 -1
- package/dist/916.js +0 -1
- package/dist/9231.js +0 -1
- package/dist/9231.js.map +0 -1
- package/dist/9408.js +0 -1
- package/dist/9408.js.map +0 -1
- package/dist/9425.js +0 -1
- package/dist/9466.js +0 -1
- package/dist/9466.js.map +0 -1
- package/dist/9919.js +0 -1
- package/dist/9919.js.map +0 -1
- package/dist/9931.js +0 -1
- package/dist/9931.js.map +0 -1
- package/jest.config.js +0 -3
- package/src/shared/orders/OrdersTabs.tsx +0 -58
- package/src/shared/patient-chart/patient-chart.component.tsx +0 -61
- package/src/shared/patient-chart/patient-chart.resources.ts +0 -180
- package/src/shared/patient-chart/patient-chart.scss +0 -15
- package/src/shared/patient-chart/useInitialize.ts +0 -24
- /package/src/shared/{patient-chart/patient-summary-dashboard → tabs}/patient-summary-dashboard.scss +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import React, { useRef, useState, useMemo } from 'react';
|
|
2
|
+
import { Button, ButtonSet, ModalBody, ModalFooter, InlineNotification } from '@carbon/react';
|
|
3
|
+
import { useReactToPrint } from 'react-to-print';
|
|
4
|
+
import { formatDatetime, parseDate, useSession } from '@openmrs/esm-framework';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import styles from './print-order.scss';
|
|
7
|
+
import { Order } from '../../../types/order/order';
|
|
8
|
+
import { documentId } from '../../utils';
|
|
9
|
+
export type OrderDocumentType = 'lab' | 'radiology' | 'procedure';
|
|
10
|
+
|
|
11
|
+
type PrintOrderPreviewModalProps = {
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
orders: Array<Order>;
|
|
14
|
+
orderType: OrderDocumentType;
|
|
15
|
+
patientName?: string;
|
|
16
|
+
patientId?: string;
|
|
17
|
+
patientAge?: string | number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const documentMeta = (
|
|
21
|
+
orderType: OrderDocumentType,
|
|
22
|
+
t: (k: string, d: string) => string,
|
|
23
|
+
): { title: string; orderLabel: string } => {
|
|
24
|
+
switch (orderType) {
|
|
25
|
+
case 'lab':
|
|
26
|
+
return { title: t('labOrderForm', 'Laboratory Order Form'), orderLabel: t('test', 'Test') };
|
|
27
|
+
case 'radiology':
|
|
28
|
+
return { title: t('radiologyOrderForm', 'Radiology Order Form'), orderLabel: t('procedure', 'Procedure') };
|
|
29
|
+
case 'procedure':
|
|
30
|
+
return { title: t('procedureOrderForm', 'Procedure Order Form'), orderLabel: t('procedure', 'Procedure') };
|
|
31
|
+
default:
|
|
32
|
+
return { title: t('orderForm', 'Order Form'), orderLabel: t('order', 'Order') };
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const PrintOrderPreviewModal: React.FC<PrintOrderPreviewModalProps> = ({
|
|
37
|
+
onClose,
|
|
38
|
+
orders,
|
|
39
|
+
orderType,
|
|
40
|
+
patientName,
|
|
41
|
+
patientId,
|
|
42
|
+
patientAge,
|
|
43
|
+
}) => {
|
|
44
|
+
const { t } = useTranslation();
|
|
45
|
+
const [printError, setPrintError] = useState<string | null>(null);
|
|
46
|
+
const printRef = useRef<HTMLDivElement>(null);
|
|
47
|
+
const { sessionLocation, user } = useSession();
|
|
48
|
+
const userDisplay = user ? user.display : '';
|
|
49
|
+
const generationTimestamp = useMemo(() => new Date(), []);
|
|
50
|
+
const { title, orderLabel } = documentMeta(orderType, t);
|
|
51
|
+
|
|
52
|
+
const handlePrint = useReactToPrint({
|
|
53
|
+
content: () => printRef.current,
|
|
54
|
+
documentTitle: title,
|
|
55
|
+
onAfterPrint: () => setPrintError(null),
|
|
56
|
+
onPrintError: (_, error) => {
|
|
57
|
+
setPrintError(error?.message || t('errorOccurredWhilePrinting', 'An error occurred while printing'));
|
|
58
|
+
},
|
|
59
|
+
pageStyle: `
|
|
60
|
+
@page {
|
|
61
|
+
size: A4;
|
|
62
|
+
margin: 15mm;
|
|
63
|
+
}
|
|
64
|
+
`,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<>
|
|
69
|
+
<ModalBody>
|
|
70
|
+
<div className={styles.container}>
|
|
71
|
+
<div ref={printRef} className={styles.printableContent}>
|
|
72
|
+
<div className={styles.printableHeader}>
|
|
73
|
+
<div className={styles.facilityDetails}>
|
|
74
|
+
<div className={styles.facilityName}>{sessionLocation?.display}</div>
|
|
75
|
+
<div className={styles.heading}>{title}</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div className={styles.printableBody}>
|
|
80
|
+
<div className={styles.topInfoRow}>
|
|
81
|
+
<div className={styles.infoItem}>
|
|
82
|
+
<span className={styles.label}>{t('patientName', 'Patient Name:')}</span>
|
|
83
|
+
<span className={styles.value}>{patientName || ''}</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div className={styles.infoItem}>
|
|
86
|
+
<span className={styles.label}>{t('patientNo', 'Patient No:')}</span>
|
|
87
|
+
<span className={styles.value}>{patientId || ''}</span>
|
|
88
|
+
</div>
|
|
89
|
+
<div className={styles.infoItem}>
|
|
90
|
+
<span className={styles.label}>{t('age', 'Age:')}</span>
|
|
91
|
+
<span className={styles.value}>{patientAge ?? ''}</span>
|
|
92
|
+
</div>
|
|
93
|
+
<div className={styles.infoItem}>
|
|
94
|
+
<span className={styles.label}>{t('date', 'Date:')}</span>
|
|
95
|
+
<span className={styles.value}>{formatDatetime(generationTimestamp, { mode: 'standard' })}</span>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<table className={styles.orderTable}>
|
|
100
|
+
<thead>
|
|
101
|
+
<tr>
|
|
102
|
+
<th className={styles.th}>{t('orderNo', 'Order No')}</th>
|
|
103
|
+
<th className={styles.th}>{t('dateOrdered', 'Date Ordered')}</th>
|
|
104
|
+
<th className={styles.th}>{orderLabel}</th>
|
|
105
|
+
<th className={styles.th}>{t('priority', 'Priority')}</th>
|
|
106
|
+
<th className={styles.th}>{t('orderBy', 'Order By')}</th>
|
|
107
|
+
</tr>
|
|
108
|
+
</thead>
|
|
109
|
+
<tbody>
|
|
110
|
+
{orders.map((order) => (
|
|
111
|
+
<tr key={order.uuid}>
|
|
112
|
+
<td className={styles.td}>{order.orderNumber}</td>
|
|
113
|
+
<td className={styles.td}>
|
|
114
|
+
{order.dateActivated
|
|
115
|
+
? formatDatetime(parseDate(order.dateActivated), { mode: 'standard' })
|
|
116
|
+
: '--'}
|
|
117
|
+
</td>
|
|
118
|
+
<td className={styles.td}>{order.concept?.display?.replace('_', ' ') ?? '--'}</td>
|
|
119
|
+
<td className={styles.td}>{order.urgency ?? '--'}</td>
|
|
120
|
+
<td className={styles.td}>{order.orderer?.display ?? '--'}</td>
|
|
121
|
+
</tr>
|
|
122
|
+
))}
|
|
123
|
+
</tbody>
|
|
124
|
+
</table>
|
|
125
|
+
<div className={styles.footer}>
|
|
126
|
+
<div className={styles.footerDetails}>
|
|
127
|
+
<div>
|
|
128
|
+
{documentId()} | {t('generatedBy', 'Generated By')}: {userDisplay}
|
|
129
|
+
</div>
|
|
130
|
+
<div>
|
|
131
|
+
{t('generationTimestamp', 'Generated')}: {formatDatetime(generationTimestamp)} |{' '}
|
|
132
|
+
{t('facility', 'Facility')}: {sessionLocation?.display}
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</ModalBody>
|
|
140
|
+
<ModalFooter>
|
|
141
|
+
<ButtonSet className={styles.btnSet}>
|
|
142
|
+
<Button kind="secondary" onClick={onClose} type="button">
|
|
143
|
+
{t('cancel', 'Cancel')}
|
|
144
|
+
</Button>
|
|
145
|
+
<Button kind="primary" type="button" onClick={handlePrint}>
|
|
146
|
+
{t('print', 'Print')}
|
|
147
|
+
</Button>
|
|
148
|
+
</ButtonSet>
|
|
149
|
+
</ModalFooter>
|
|
150
|
+
|
|
151
|
+
{printError && (
|
|
152
|
+
<InlineNotification kind="error" title={t('printError', 'Error')} subtitle={printError} hideCloseButton />
|
|
153
|
+
)}
|
|
154
|
+
</>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export default PrintOrderPreviewModal;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
|
|
4
|
+
.container {
|
|
5
|
+
padding: layout.$spacing-06;
|
|
6
|
+
margin-bottom: layout.$spacing-05;
|
|
7
|
+
background-color: colors.$white;
|
|
8
|
+
|
|
9
|
+
@media print {
|
|
10
|
+
padding: 0;
|
|
11
|
+
margin: 0;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.printableContent {
|
|
16
|
+
background-color: colors.$white;
|
|
17
|
+
width: 210mm;
|
|
18
|
+
min-height: 297mm;
|
|
19
|
+
margin: 0 auto;
|
|
20
|
+
padding: layout.$spacing-07;
|
|
21
|
+
box-sizing: border-box;
|
|
22
|
+
font-size: 11px;
|
|
23
|
+
line-height: 1.3;
|
|
24
|
+
color: colors.$black;
|
|
25
|
+
|
|
26
|
+
@media print {
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 100%;
|
|
29
|
+
padding: layout.$spacing-07;
|
|
30
|
+
margin: 0;
|
|
31
|
+
box-shadow: none;
|
|
32
|
+
border: none;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.printableHeader {
|
|
37
|
+
text-align: center;
|
|
38
|
+
margin-bottom: layout.$spacing-05;
|
|
39
|
+
padding-bottom: layout.$spacing-03;
|
|
40
|
+
border-bottom: 1px solid colors.$black;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.facilityDetails {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
align-items: center;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.facilityName {
|
|
50
|
+
font-weight: 700;
|
|
51
|
+
color: colors.$black;
|
|
52
|
+
text-transform: uppercase;
|
|
53
|
+
letter-spacing: 2px;
|
|
54
|
+
margin-bottom: layout.$spacing-03;
|
|
55
|
+
font-size: 14px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.heading {
|
|
59
|
+
font-weight: 600;
|
|
60
|
+
color: colors.$black;
|
|
61
|
+
text-transform: uppercase;
|
|
62
|
+
letter-spacing: 1px;
|
|
63
|
+
font-size: 12px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.printableBody {
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: layout.$spacing-05;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.topInfoRow {
|
|
73
|
+
display: grid;
|
|
74
|
+
grid-template-columns: repeat(4, 1fr);
|
|
75
|
+
gap: layout.$spacing-03;
|
|
76
|
+
padding: layout.$spacing-03;
|
|
77
|
+
border: 1px solid colors.$black;
|
|
78
|
+
border-radius: 2px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.infoItem {
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-direction: column;
|
|
84
|
+
gap: layout.$spacing-02;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.label {
|
|
88
|
+
font-weight: 600;
|
|
89
|
+
color: colors.$black;
|
|
90
|
+
font-size: 10px;
|
|
91
|
+
white-space: nowrap;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.value {
|
|
95
|
+
color: colors.$black;
|
|
96
|
+
border-bottom: 1px solid colors.$black;
|
|
97
|
+
padding: layout.$spacing-01;
|
|
98
|
+
min-height: layout.$spacing-04;
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
font-size: 10px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.orderTable {
|
|
105
|
+
width: 100%;
|
|
106
|
+
border-collapse: collapse;
|
|
107
|
+
font-size: 10px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.th {
|
|
111
|
+
border: 1px solid colors.$black;
|
|
112
|
+
padding: layout.$spacing-03;
|
|
113
|
+
text-align: left;
|
|
114
|
+
font-weight: 600;
|
|
115
|
+
background-color: colors.$gray-10;
|
|
116
|
+
text-transform: uppercase;
|
|
117
|
+
font-size: 9px;
|
|
118
|
+
|
|
119
|
+
@media print {
|
|
120
|
+
background-color: colors.$gray-10 !important;
|
|
121
|
+
-webkit-print-color-adjust: exact;
|
|
122
|
+
print-color-adjust: exact;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.td {
|
|
127
|
+
border: 1px solid colors.$black;
|
|
128
|
+
padding: layout.$spacing-03;
|
|
129
|
+
color: colors.$black;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.signaturesSection {
|
|
133
|
+
margin-top: layout.$spacing-05;
|
|
134
|
+
padding-top: layout.$spacing-03;
|
|
135
|
+
border-top: 1px solid colors.$black;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.signatureBlock {
|
|
139
|
+
margin-bottom: layout.$spacing-03;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.signatureRow {
|
|
143
|
+
display: grid;
|
|
144
|
+
grid-template-columns: 2fr 1fr 1fr;
|
|
145
|
+
gap: layout.$spacing-03;
|
|
146
|
+
align-items: center;
|
|
147
|
+
padding: layout.$spacing-02;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.nameField,
|
|
151
|
+
.signField {
|
|
152
|
+
display: flex;
|
|
153
|
+
flex-direction: column;
|
|
154
|
+
gap: layout.$spacing-02;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.nameValue {
|
|
158
|
+
color: colors.$black;
|
|
159
|
+
border-bottom: 1px solid colors.$black;
|
|
160
|
+
padding: layout.$spacing-01;
|
|
161
|
+
min-height: layout.$spacing-04;
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
font-size: 10px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.signatureLine {
|
|
168
|
+
border-bottom: 1px solid colors.$black;
|
|
169
|
+
height: layout.$spacing-04;
|
|
170
|
+
width: 100%;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.btnSet {
|
|
174
|
+
width: 100%;
|
|
175
|
+
margin-top: layout.$spacing-05;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.footer {
|
|
179
|
+
margin-top: layout.$spacing-06;
|
|
180
|
+
padding-top: layout.$spacing-04;
|
|
181
|
+
border-top: 1px solid colors.$black;
|
|
182
|
+
text-align: center;
|
|
183
|
+
page-break-inside: avoid;
|
|
184
|
+
|
|
185
|
+
@media print {
|
|
186
|
+
position: fixed !important;
|
|
187
|
+
bottom: layout.$spacing-05 !important;
|
|
188
|
+
left: 0 !important;
|
|
189
|
+
right: 0 !important;
|
|
190
|
+
width: 100% !important;
|
|
191
|
+
border-top: 0.5pt solid colors.$gray-50 !important;
|
|
192
|
+
box-sizing: border-box !important;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.footerDetails {
|
|
197
|
+
font-size: 7pt;
|
|
198
|
+
color: colors.$gray-70;
|
|
199
|
+
text-align: center;
|
|
200
|
+
line-height: 1.3;
|
|
201
|
+
|
|
202
|
+
div {
|
|
203
|
+
margin-bottom: layout.$spacing-02;
|
|
204
|
+
&:last-child {
|
|
205
|
+
margin-bottom: 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@media print {
|
|
211
|
+
body * {
|
|
212
|
+
visibility: hidden;
|
|
213
|
+
}
|
|
214
|
+
.printableContent,
|
|
215
|
+
.printableContent * {
|
|
216
|
+
visibility: visible;
|
|
217
|
+
}
|
|
218
|
+
.printableContent {
|
|
219
|
+
position: absolute;
|
|
220
|
+
left: 0;
|
|
221
|
+
top: 0;
|
|
222
|
+
width: 100%;
|
|
223
|
+
padding: layout.$spacing-07;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { Button, ButtonSet, ModalBody, ModalFooter, InlineLoading, InlineNotification } from '@carbon/react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { usePrescriptionPdf } from './print-prescription.resource';
|
|
5
|
+
import styles from './print-prescription.scss';
|
|
6
|
+
|
|
7
|
+
type PrintPrescriptionModalProps = {
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
medicationRequestUuids: string[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const PrintPrescriptionModal: React.FC<PrintPrescriptionModalProps> = ({ onClose, medicationRequestUuids }) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
15
|
+
const { pdfUrl, isLoading, error } = usePrescriptionPdf(medicationRequestUuids);
|
|
16
|
+
|
|
17
|
+
const handlePrint = () => {
|
|
18
|
+
if (iframeRef.current?.contentWindow) {
|
|
19
|
+
iframeRef.current.contentWindow.focus();
|
|
20
|
+
iframeRef.current.contentWindow.print();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<ModalBody className={styles.modalBody}>
|
|
27
|
+
{isLoading && (
|
|
28
|
+
<div className={styles.stateContainer}>
|
|
29
|
+
<InlineLoading description={t('loadingPrescription', 'Loading prescription...')} />
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
{error && !isLoading && (
|
|
33
|
+
<div className={styles.stateContainer}>
|
|
34
|
+
<InlineNotification
|
|
35
|
+
kind="error"
|
|
36
|
+
title={t('errorLoadingPrescription', 'Error loading prescription')}
|
|
37
|
+
subtitle={error.message}
|
|
38
|
+
hideCloseButton
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
{pdfUrl && !isLoading && (
|
|
43
|
+
<iframe
|
|
44
|
+
ref={iframeRef}
|
|
45
|
+
src={pdfUrl}
|
|
46
|
+
className={styles.pdfFrame}
|
|
47
|
+
title={t('prescriptionPreview', 'Prescription Preview')}
|
|
48
|
+
/>
|
|
49
|
+
)}
|
|
50
|
+
</ModalBody>
|
|
51
|
+
<ModalFooter>
|
|
52
|
+
<ButtonSet className={styles.btnSet}>
|
|
53
|
+
<Button kind="secondary" onClick={onClose} type="button">
|
|
54
|
+
{t('cancel', 'Cancel')}
|
|
55
|
+
</Button>
|
|
56
|
+
<Button kind="primary" type="button" onClick={handlePrint} disabled={!pdfUrl || isLoading}>
|
|
57
|
+
{t('print', 'Print')}
|
|
58
|
+
</Button>
|
|
59
|
+
</ButtonSet>
|
|
60
|
+
</ModalFooter>
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default PrintPrescriptionModal;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
export function usePrescriptionPdf(medicationRequestUuids: string[]) {
|
|
5
|
+
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
|
|
6
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
7
|
+
const [error, setError] = useState<Error | null>(null);
|
|
8
|
+
|
|
9
|
+
const uuidParam = useMemo(() => medicationRequestUuids.join(','), [medicationRequestUuids]);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!uuidParam) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let objectUrl: string | null = null;
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
setPdfUrl(null);
|
|
19
|
+
setError(null);
|
|
20
|
+
|
|
21
|
+
const url = `/openmrs${restBaseUrl}/palladiumemr/prescription?medicationRequestUuid=${uuidParam}`;
|
|
22
|
+
|
|
23
|
+
fetch(url, { credentials: 'include', headers: { Accept: 'application/pdf' } })
|
|
24
|
+
.then((response) => {
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`${response.status} ${response.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
return response.blob();
|
|
29
|
+
})
|
|
30
|
+
.then((blob) => {
|
|
31
|
+
objectUrl = URL.createObjectURL(new Blob([blob], { type: 'application/pdf' }));
|
|
32
|
+
setPdfUrl(objectUrl);
|
|
33
|
+
})
|
|
34
|
+
.catch((err) => setError(err instanceof Error ? err : new Error(String(err))))
|
|
35
|
+
.finally(() => setIsLoading(false));
|
|
36
|
+
|
|
37
|
+
return () => {
|
|
38
|
+
if (objectUrl) {
|
|
39
|
+
URL.revokeObjectURL(objectUrl);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}, [uuidParam]);
|
|
43
|
+
|
|
44
|
+
return { pdfUrl, isLoading, error };
|
|
45
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
|
|
3
|
+
.modalBody {
|
|
4
|
+
padding: 0;
|
|
5
|
+
min-height: 70vh;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.pdfFrame {
|
|
11
|
+
width: 100%;
|
|
12
|
+
flex: 1;
|
|
13
|
+
min-height: 70vh;
|
|
14
|
+
border: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.stateContainer {
|
|
18
|
+
padding: layout.$spacing-06;
|
|
19
|
+
display: flex;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.btnSet {
|
|
24
|
+
width: 100%;
|
|
25
|
+
}
|
|
@@ -3,7 +3,36 @@ import { default as otpVerificationModal } from './otp-verification.modal';
|
|
|
3
3
|
import { type ModalSize } from '@carbon/react/lib/components/Modal/Modal';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Result returned by onStartBiometric — the caller's `/biometric-authorize`
|
|
7
|
+
* handler resolves with this shape so the modal knows the embed URL to render
|
|
8
|
+
* and the auth code to round-trip on success.
|
|
9
|
+
*/
|
|
10
|
+
export type BiometricStartResult = {
|
|
11
|
+
embed_url: string;
|
|
12
|
+
authorization_code: string;
|
|
13
|
+
consent_token: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Result handed to onBiometricSuccess when the iframe's eKYC capture completes
|
|
18
|
+
* successfully (postMessage from the eKYC origin).
|
|
19
|
+
*/
|
|
20
|
+
export type BiometricSuccessResult = {
|
|
21
|
+
authorization_code: string;
|
|
22
|
+
consent_token: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Options for configuring the OTP / Secure Patient Authentication modal.
|
|
27
|
+
*
|
|
28
|
+
* The modal supports two operating modes:
|
|
29
|
+
*
|
|
30
|
+
* 1. **otp-only** (default, backward compatible) — opens directly into the
|
|
31
|
+
* existing OTP confirm-phone screen. Use this when the only auth path is OTP.
|
|
32
|
+
* All existing consumers don't need to change.
|
|
33
|
+
*
|
|
34
|
+
* 2. **multi** — opens an auth landing screen with three options: biometric,
|
|
35
|
+
* OTP, or whitelist request. The available options depend on `whitelistedForOTP`.
|
|
7
36
|
*
|
|
8
37
|
* @property {number} [otpLength] - The number of digits required for the OTP. Defaults to implementation-specific value.
|
|
9
38
|
* @property {(otp: string) => Promise<void>} [onVerify] - Callback invoked when the user submits the OTP. Should return a promise that resolves on successful verification.
|
|
@@ -15,35 +44,61 @@ import { type ModalSize } from '@carbon/react/lib/components/Modal/Modal';
|
|
|
15
44
|
* @property {number} [expiryMinutes] - The number of minutes after which the OTP expires. Defaults to 5 minutes. This is displayed to the user for clarity.
|
|
16
45
|
* @property {() => void} [onCleanup] - Callback invoked when the modal closes to clean up OTP resources.
|
|
17
46
|
*
|
|
47
|
+
* @property {'otp-only' | 'multi'} [authMode] - When 'multi', shows the auth-landing method picker first (Biometric / OTP / Whitelist). When 'otp-only' or undefined, opens directly to the existing OTP landing.
|
|
48
|
+
* @property {boolean} [whitelistedForOTP] - Whether the patient is approved for OTP whitelist bypass. Drives method picker layout and post-failure recovery options.
|
|
49
|
+
* @property {() => Promise<BiometricStartResult>} [onStartBiometric] - Called when the user picks biometric. Should resolve with the embed_url + auth code from /biometric-authorize.
|
|
50
|
+
* @property {(result: BiometricSuccessResult) => void} [onBiometricSuccess] - Called on successful biometric capture (iframe postMessage SUCCESS).
|
|
51
|
+
* @property {(consentToken: string | null) => void} [onBiometricCancel] - Called when biometric session is cancelled (user closes, timer expires). Backend's /biometric-cancel goes here.
|
|
52
|
+
* @property {() => void} [onRequestWhitelist] - Called when the user clicks "Request OTP Whitelisting" — parent should open the whitelist submission flow.
|
|
53
|
+
* @property {() => void} [onRejected] - Called when the user clicks "Reject" on the auth landing — visit proceeds without consent (administrative override).
|
|
54
|
+
* @property {string} [ekycOrigin] - Expected origin of the eKYC iframe's postMessage events for security validation. Defaults to https://test.ekyc.pesaflow.com.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // OTP-only mode (existing behavior, unchanged)
|
|
58
|
+
* launchOtpVerificationModal({
|
|
59
|
+
* otpLength: 6,
|
|
60
|
+
* phoneNumber: '254700000000',
|
|
61
|
+
* onRequestOtp: async (phone) => sendSHAOtp(crId, codes),
|
|
62
|
+
* onVerify: async (otp) => createSHAVirtualClaim(crId, otp, ...),
|
|
63
|
+
* onVerificationSuccess: () => console.log('verified'),
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
18
66
|
* @example
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
67
|
+
* // Multi-method auth mode (biometric + OTP + whitelist)
|
|
68
|
+
* launchOtpVerificationModal({
|
|
69
|
+
* authMode: 'multi',
|
|
70
|
+
* whitelistedForOTP: patient.whitelisted_for_otp ?? false,
|
|
71
|
+
* phoneNumber: '254700000000',
|
|
72
|
+
*
|
|
73
|
+
* // OTP wiring
|
|
74
|
+
* onRequestOtp: async (phone) => sendSHAOtp(crId, codes),
|
|
75
|
+
* onVerify: async (otp) => createSHAVirtualClaim(crId, otp, ...),
|
|
76
|
+
* onVerificationSuccess: () => { ... },
|
|
77
|
+
*
|
|
78
|
+
* // Biometric wiring
|
|
79
|
+
* onStartBiometric: async () => {
|
|
80
|
+
* const res = await createSHABiometricAuthorize({ ... });
|
|
81
|
+
* if (!res.success || !res.embed_url) throw new Error(res.error);
|
|
82
|
+
* return {
|
|
83
|
+
* embed_url: res.embed_url,
|
|
84
|
+
* authorization_code: res.authorization_code!,
|
|
85
|
+
* consent_token: res.consent_token!,
|
|
86
|
+
* };
|
|
87
|
+
* },
|
|
88
|
+
* onBiometricSuccess: (result) => {
|
|
89
|
+
* shaClaimResponseRef.current = result;
|
|
90
|
+
* },
|
|
91
|
+
* onBiometricCancel: async (consentToken) => {
|
|
92
|
+
* if (consentToken) await cancelBiometricSession(consentToken);
|
|
93
|
+
* },
|
|
94
|
+
*
|
|
95
|
+
* // Escape paths
|
|
96
|
+
* onRequestWhitelist: () => launchWhitelistSubmissionModal({ patientCRId }),
|
|
97
|
+
* onRejected: () => markVisitProceedingWithoutConsent(),
|
|
98
|
+
* });
|
|
45
99
|
*/
|
|
46
100
|
export type OTPVerificationModalOptions = {
|
|
101
|
+
// ── existing OTP props ──
|
|
47
102
|
otpLength?: number;
|
|
48
103
|
onVerify?: (otp: string) => Promise<void>;
|
|
49
104
|
obscureText?: boolean;
|
|
@@ -54,12 +109,40 @@ export type OTPVerificationModalOptions = {
|
|
|
54
109
|
expiryMinutes?: number;
|
|
55
110
|
size?: ModalSize;
|
|
56
111
|
onCleanup?: () => void;
|
|
112
|
+
|
|
113
|
+
// ── new multi-method auth props ──
|
|
114
|
+
/** When 'multi', shows the auth-landing method picker first. Defaults to 'otp-only'. */
|
|
115
|
+
authMode?: 'otp-only' | 'multi';
|
|
116
|
+
|
|
117
|
+
/** Whether the patient is approved for OTP whitelist bypass. */
|
|
118
|
+
whitelistedForOTP?: boolean;
|
|
119
|
+
|
|
120
|
+
/** Called when user picks biometric. Resolve with embed_url + auth code. */
|
|
121
|
+
onStartBiometric?: () => Promise<BiometricStartResult>;
|
|
122
|
+
|
|
123
|
+
/** Called on successful biometric capture (postMessage SUCCESS from eKYC). */
|
|
124
|
+
onBiometricSuccess?: (result: BiometricSuccessResult) => void;
|
|
125
|
+
|
|
126
|
+
/** Called when biometric session is cancelled. Wire to backend /biometric-cancel. */
|
|
127
|
+
onBiometricCancel?: (consentToken: string | null) => void;
|
|
128
|
+
|
|
129
|
+
/** Called when user clicks "Request OTP Whitelisting". */
|
|
130
|
+
onRequestWhitelist?: () => void;
|
|
131
|
+
|
|
132
|
+
/** Called when user clicks "Reject" — visit proceeds without consent. */
|
|
133
|
+
onRejected?: () => void;
|
|
134
|
+
|
|
135
|
+
/** Expected origin of eKYC postMessage events. Defaults to https://test.ekyc.pesaflow.com. */
|
|
136
|
+
ekycOrigin?: string;
|
|
137
|
+
|
|
138
|
+
/** Whether this modal is being used to start or end a visit. Defaults to 'start'. Affects progress message text. */
|
|
139
|
+
visitAction?: 'start' | 'end';
|
|
57
140
|
};
|
|
58
141
|
|
|
59
142
|
/**
|
|
60
|
-
* Launch the OTP
|
|
143
|
+
* Launch the OTP / Secure Patient Authentication modal with the provided options.
|
|
61
144
|
*
|
|
62
|
-
* @param props - Configuration options for the
|
|
145
|
+
* @param props - Configuration options for the modal
|
|
63
146
|
* @returns A dispose function to close the modal programmatically
|
|
64
147
|
*/
|
|
65
148
|
export const launchOtpVerificationModal = (props: OTPVerificationModalOptions) => {
|