@palladium-ethiopia/esm-clinical-workflow-app 5.4.2-pre.20

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.
Files changed (89) hide show
  1. package/.turbo/turbo-build.log +14 -0
  2. package/README.md +1 -0
  3. package/dist/152.js +1 -0
  4. package/dist/152.js.map +1 -0
  5. package/dist/159.js +1 -0
  6. package/dist/159.js.map +1 -0
  7. package/dist/208.js +1 -0
  8. package/dist/208.js.map +1 -0
  9. package/dist/209.js +1 -0
  10. package/dist/209.js.map +1 -0
  11. package/dist/363.js +1 -0
  12. package/dist/363.js.map +1 -0
  13. package/dist/410.js +1 -0
  14. package/dist/410.js.map +1 -0
  15. package/dist/442.js +1 -0
  16. package/dist/442.js.map +1 -0
  17. package/dist/466.js +1 -0
  18. package/dist/466.js.map +1 -0
  19. package/dist/484.js +11 -0
  20. package/dist/484.js.map +1 -0
  21. package/dist/540.js +1 -0
  22. package/dist/540.js.map +1 -0
  23. package/dist/545.js +43 -0
  24. package/dist/545.js.map +1 -0
  25. package/dist/61.js +1 -0
  26. package/dist/61.js.map +1 -0
  27. package/dist/677.js +1 -0
  28. package/dist/677.js.map +1 -0
  29. package/dist/689.js +1 -0
  30. package/dist/689.js.map +1 -0
  31. package/dist/697.js +1 -0
  32. package/dist/697.js.map +1 -0
  33. package/dist/712.js +1 -0
  34. package/dist/712.js.map +1 -0
  35. package/dist/771.js +1 -0
  36. package/dist/771.js.map +1 -0
  37. package/dist/789.js +1 -0
  38. package/dist/789.js.map +1 -0
  39. package/dist/ethiopia-esm-clinical-workflow-app.js +6 -0
  40. package/dist/ethiopia-esm-clinical-workflow-app.js.buildmanifest.json +579 -0
  41. package/dist/ethiopia-esm-clinical-workflow-app.js.map +1 -0
  42. package/dist/main.js +16 -0
  43. package/dist/main.js.map +1 -0
  44. package/dist/routes.json +1 -0
  45. package/jest.config.js +3 -0
  46. package/package.json +59 -0
  47. package/rspack.config.js +1 -0
  48. package/src/config-schema.ts +69 -0
  49. package/src/constants.ts +2 -0
  50. package/src/createDashboardLink.tsx +10 -0
  51. package/src/dashboard.meta.ts +6 -0
  52. package/src/declarations.d.ts +3 -0
  53. package/src/helper.ts +115 -0
  54. package/src/index.ts +51 -0
  55. package/src/mru/billing-information/billing-information.resource.ts +139 -0
  56. package/src/mru/billing-information/billing-information.scss +55 -0
  57. package/src/mru/billing-information/billing-information.workspace.tsx +371 -0
  58. package/src/mru/dashboard.component.tsx +18 -0
  59. package/src/mru/mru.component.tsx +106 -0
  60. package/src/mru/mru.scss +28 -0
  61. package/src/patient-registration/patient-registration.resource.tsx +129 -0
  62. package/src/patient-registration/patient.registration.workspace.scss +47 -0
  63. package/src/patient-registration/patient.registration.workspace.tsx +443 -0
  64. package/src/patient-registration/useGenerateIdentifier.ts +26 -0
  65. package/src/patient-scoreboard/appointment-cards/checked-in-appointments.card.tsx +18 -0
  66. package/src/patient-scoreboard/appointment-cards/not-arrived-appointments.card.tsx +18 -0
  67. package/src/patient-scoreboard/appointment-cards/total-appointments.card.tsx +18 -0
  68. package/src/patient-scoreboard/hooks/useAppointmentList.ts +61 -0
  69. package/src/patient-scoreboard/hooks/useVisitList.ts +104 -0
  70. package/src/patient-scoreboard/metrics-card/metrics-card.component.scss +84 -0
  71. package/src/patient-scoreboard/metrics-card/metrics-card.component.tsx +40 -0
  72. package/src/patient-scoreboard/patient-scoreboard.component.scss +47 -0
  73. package/src/patient-scoreboard/patient-scoreboard.component.tsx +70 -0
  74. package/src/patient-scoreboard/visit-cards/active-visits.card.tsx +18 -0
  75. package/src/patient-scoreboard/visit-cards/scheduled-visits.card.tsx +18 -0
  76. package/src/patient-scoreboard/visit-cards/total-visits.card.tsx +18 -0
  77. package/src/patient-scoreboard/visits-table/visits-table.component.scss +31 -0
  78. package/src/patient-scoreboard/visits-table/visits-table.component.tsx +181 -0
  79. package/src/root.component.tsx +20 -0
  80. package/src/root.scss +10 -0
  81. package/src/routes.json +108 -0
  82. package/src/triage/patient-banner.component.tsx +59 -0
  83. package/src/triage/patient-banner.scss +14 -0
  84. package/src/triage/triage-dashboard.component.tsx +116 -0
  85. package/src/triage/triage-dashboard.scss +107 -0
  86. package/src/triage/triage.resource.tsx +44 -0
  87. package/src/triage/useStartVisitAndLaunchTriageForm.ts +156 -0
  88. package/src/types/index.ts +0 -0
  89. package/tsconfig.json +4 -0
@@ -0,0 +1 @@
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.24.0"},"pages":[],"extensions":[{"name":"clinical-workflow-triage-dashboard-link","component":"triageDashboardLink","slot":"homepage-dashboard-slot","order":0,"meta":{"name":"clinical-workflow-triage","slot":"clinical-workflow-triage-dashboard-slot","title":"clinical-workflow-triage"}},{"name":"clinical-workflow-triage-dashboard","component":"triageDashboard","slot":"clinical-workflow-triage-dashboard-slot"},{"name":"ewf-mru-dashboard-link","component":"mruLeftPanelLink","slot":"homepage-dashboard-slot","order":1,"meta":{"name":"mru","title":"MRU","path":"mru","slot":"mru-dashboard-slot"}},{"name":"ewf-mru-dashboard","component":"mruDashboard","slot":"mru-dashboard-slot","online":true,"offline":false},{"name":"patient-scoreboard-link","component":"patientScoreboardLink","slot":"homepage-dashboard-slot","order":1,"meta":{"name":"patient-scoreboard","title":"Patient Scoreboard","path":"patient-scoreboard","slot":"patient-scoreboard-slot"}},{"name":"patient-scoreboard","component":"patientScoreboard","slot":"patient-scoreboard-slot","online":true,"offline":false}],"workspaces":[{"name":"triage-workspace","component":"triageWorkspace","title":"Triage Form","canMaximize":true,"type":"clinical-form"},{"name":"patient-registration-workspace","component":"patientRegistrationWorkspace","title":"Patient Registration","canMaximize":true,"type":"registration-form"},{"name":"billing-information-workspace","component":"billingInformationWorkspace","title":"Billing Information Workspace","type":"clinical-form"}],"workspaces2":[{"name":"clinical-workflow-patient-form-entry-workspace","component":"@openmrs/esm-patient-forms-app#exportedPatientFormEntryWorkspace","window":"clinical-workflow-window"}],"workspaceWindows2":[{"name":"clinical-workflow-window","group":"clinical-workflow-group","width":"wider","canMaximize":true}],"workspaceGroups2":[{"name":"clinical-workflow-group","overlay":true,"persistence":"closable"}],"version":"5.4.2-pre.20"}
package/jest.config.js ADDED
@@ -0,0 +1,3 @@
1
+ const rootConfig = require('../../jest.config.js');
2
+
3
+ module.exports = rootConfig;
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@palladium-ethiopia/esm-clinical-workflow-app",
3
+ "version": "5.4.2-pre.20",
4
+ "description": "Express workflow app for OpenMRS 3",
5
+ "keywords": [
6
+ "openmrs",
7
+ "ethiopiaemr"
8
+ ],
9
+ "homepage": "https://github.com/palladium-group/ethiopiaemr-esm-3.x#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/palladium-group/ethiopiaemr-esm-3.x/issues"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/palladium-group/ethiopiaemr-esm-3.x.git"
16
+ },
17
+ "license": "MPL-2.0",
18
+ "main": "src/index.ts",
19
+ "source": true,
20
+ "browser": "dist/ethiopia-esm-clinical-workflow-app.js",
21
+ "scripts": {
22
+ "analyze": "rspack --mode=production --env analyze=true",
23
+ "build": "rspack --mode=production",
24
+ "coverage": "yarn test --coverage",
25
+ "debug": "npm run serve",
26
+ "extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.extension.tsx' 'src/**/*modal.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js",
27
+ "lint": "cross-env eslint src --ext ts,tsx",
28
+ "serve": "rspack serve --mode=development",
29
+ "start": "openmrs develop",
30
+ "test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests --color",
31
+ "test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js --color",
32
+ "typescript": "tsc"
33
+ },
34
+ "browserslist": [
35
+ "extends browserslist-config-openmrs"
36
+ ],
37
+ "dependencies": {
38
+ "@carbon/react": "^1.83.0",
39
+ "@hookform/resolvers": "^3.9.1",
40
+ "@superset-ui/embedded-sdk": "^0.2.0",
41
+ "classnames": "^2.3.2",
42
+ "lodash-es": "^4.17.15",
43
+ "react-hook-form": "^7.54.0",
44
+ "react-otp-input": "^3.1.1",
45
+ "zod": "^3.24.1"
46
+ },
47
+ "peerDependencies": {
48
+ "@openmrs/esm-framework": "8.x",
49
+ "dayjs": "1.x",
50
+ "react": "18.x",
51
+ "react-i18next": "11.x",
52
+ "react-router-dom": "6.x",
53
+ "swr": "2.x"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "stableVersion": "5.4.1"
59
+ }
@@ -0,0 +1 @@
1
+ module.exports = require('openmrs/default-rspack-config');
@@ -0,0 +1,69 @@
1
+ import { Type } from '@openmrs/esm-framework';
2
+
3
+ export const configSchema = {
4
+ triageLocationForms: {
5
+ _type: Type.Object,
6
+ _description:
7
+ 'Mapping of location UUIDs to their triage form configurations. Each location can have one triage form.',
8
+ _default: {
9
+ '44c3efb0-2583-4c80-a79e-1f756a03c0a1': {
10
+ formUuid: '35093e6c-f35e-48a7-ae42-17b988d86c17',
11
+ name: 'Central Triage Form',
12
+ },
13
+ '8d9045ad-50f0-45b8-93c8-3ed4bce19dbf': {
14
+ formUuid: 'ffbe6be3-3b72-4271-a2f4-803907ca4ef4',
15
+ name: 'Emergency Triage Form',
16
+ },
17
+ },
18
+ },
19
+ billingVisitAttributeTypes: {
20
+ _type: Type.Object,
21
+ _description: 'Visit attribute type UUIDs for billing information',
22
+ _default: {
23
+ paymentMethod: 'e6cb0c3b-04b0-4117-9bc6-ce24adbda802',
24
+ creditType: '5cd1eb62-e006-4146-bd22-80bc4d5bd2f7',
25
+ creditTypeDetails: 'd824aa96-d2c7-4a52-aa8d-03f60a516083',
26
+ freeType: '7523ecfe-b8f1-4e7f-80a7-1a495b15ace4',
27
+ },
28
+ },
29
+ visitTypeUuid: {
30
+ _type: Type.String,
31
+ _description: 'Visit type UUID',
32
+ _default: '7b0f5697-27e3-40c4-8bae-f4049abfb4ed', // Outpatient
33
+ },
34
+ identifierSourceUuid: {
35
+ _type: Type.String,
36
+ _description: 'Identifier source UUID',
37
+ _default: '8549f706-7e85-4c1d-9424-217d50a2988b',
38
+ },
39
+ defaultIdentifierTypeUuid: {
40
+ _type: Type.String,
41
+ _description: 'OpenMRS ID',
42
+ _default: '05a29f94-c0ed-11e2-94be-8c13b969e334',
43
+ },
44
+ medicoLegalCasesAttributeTypeUuid: {
45
+ _type: Type.String,
46
+ _description: 'Patient attribute type UUID for Medico Legal Cases',
47
+ _default: '',
48
+ },
49
+ };
50
+
51
+ export type ClinicalWorkflowConfig = {
52
+ triageLocationForms: Record<
53
+ string,
54
+ {
55
+ formUuid: string;
56
+ name: string;
57
+ }
58
+ >;
59
+ billingVisitAttributeTypes: {
60
+ paymentMethod: string;
61
+ creditType: string;
62
+ creditTypeDetails: string;
63
+ freeType: string;
64
+ };
65
+ visitTypeUuid: string;
66
+ identifierSourceUuid: string;
67
+ defaultIdentifierTypeUuid: string;
68
+ medicoLegalCasesAttributeTypeUuid: string;
69
+ };
@@ -0,0 +1,2 @@
1
+ export const moduleName = '@palladium-ethiopia/esm-clinical-workflow-app';
2
+ export const spaBasePath = `${window.spaBase}/home`;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { BrowserRouter } from 'react-router-dom';
3
+ import { DashboardExtension, type DashboardExtensionProps } from '@openmrs/esm-framework';
4
+
5
+ export const createDashboardLink = (config: Omit<DashboardExtensionProps, 'icon'> & { icon?: any }) => () =>
6
+ (
7
+ <BrowserRouter>
8
+ <DashboardExtension path={config.path} title={config.title} basePath={config.basePath} icon={config.icon} />
9
+ </BrowserRouter>
10
+ );
@@ -0,0 +1,6 @@
1
+ export const dashboardMeta = {
2
+ path: 'clinical-workflow-triage',
3
+ slot: 'clinical-workflow-triage-dashboard-slot',
4
+ title: 'Triage',
5
+ basePath: `${window.spaBase}/home`,
6
+ } as const;
@@ -0,0 +1,3 @@
1
+ declare module '*.png';
2
+ declare module '*.svg';
3
+ declare module '*.scss';
package/src/helper.ts ADDED
@@ -0,0 +1,115 @@
1
+ import { Encounter, fetchCurrentPatient, launchWorkspace2, showModal, showSnackbar } from '@openmrs/esm-framework';
2
+ import { createVisitForPatient, getCurrentVisitForPatient } from './triage/triage.resource';
3
+
4
+ export const handleStartVisitAndLaunchTriageForm = async (
5
+ patientUuid: string,
6
+ formUuid: string,
7
+ formName: string,
8
+ visitTypeUuid: string,
9
+ ) => {
10
+ if (!patientUuid?.trim()) {
11
+ showSnackbar({
12
+ title: 'Error',
13
+ kind: 'error',
14
+ subtitle: 'Patient UUID is required',
15
+ isLowContrast: true,
16
+ });
17
+ return;
18
+ }
19
+
20
+ if (!formUuid?.trim()) {
21
+ showSnackbar({
22
+ title: 'Error',
23
+ kind: 'error',
24
+ subtitle: 'Form UUID is required',
25
+ isLowContrast: true,
26
+ });
27
+ return;
28
+ }
29
+
30
+ if (!formName?.trim()) {
31
+ showSnackbar({
32
+ title: 'Error',
33
+ kind: 'error',
34
+ subtitle: 'Form name is required',
35
+ isLowContrast: true,
36
+ });
37
+ return;
38
+ }
39
+
40
+ if (!visitTypeUuid?.trim()) {
41
+ showSnackbar({
42
+ title: 'Error',
43
+ kind: 'error',
44
+ subtitle: 'Visit type UUID is required',
45
+ isLowContrast: true,
46
+ });
47
+ return;
48
+ }
49
+
50
+ try {
51
+ const patient = await fetchCurrentPatient(patientUuid);
52
+
53
+ if (!patient) {
54
+ throw new Error('Failed to fetch patient data');
55
+ }
56
+
57
+ let activeVisit = await getCurrentVisitForPatient(patientUuid);
58
+ if (!activeVisit) {
59
+ const visitResponse = await createVisitForPatient(patientUuid, visitTypeUuid);
60
+ if (!visitResponse.ok) {
61
+ throw new Error(visitResponse.data?.error?.message || 'Error starting visit for patient');
62
+ }
63
+ activeVisit = visitResponse.data;
64
+ }
65
+
66
+ if (!activeVisit?.uuid || !activeVisit?.visitType?.uuid) {
67
+ throw new Error('Invalid visit data received');
68
+ }
69
+
70
+ const handleShowModal = (encounter: Encounter) => {
71
+ const dispose = showModal('transition-patient-to-latest-queue-modal', {
72
+ activeVisit: activeVisit,
73
+ closeModal: () => dispose(),
74
+ });
75
+ };
76
+
77
+ launchWorkspace2(
78
+ 'clinical-workflow-patient-form-entry-workspace',
79
+ {
80
+ formEntryWorkspaceName: formName,
81
+ patient: patient,
82
+ visitContext: activeVisit,
83
+ form: {
84
+ visitUuid: activeVisit.uuid,
85
+ uuid: formUuid,
86
+ visitTypeUuid: activeVisit.visitType.uuid,
87
+ },
88
+ encounterUuid: '',
89
+ handlePostResponse: handleShowModal,
90
+ },
91
+ {
92
+ patientUuid: patientUuid,
93
+ patient: patient,
94
+ visitContext: activeVisit,
95
+ },
96
+ );
97
+
98
+ // Set z-index for workspace container
99
+ setTimeout(() => {
100
+ const workspaceContainer = document.getElementById('omrs-workspaces-container');
101
+ if (workspaceContainer) {
102
+ workspaceContainer.style.zIndex = '100';
103
+ }
104
+ }, 0);
105
+ } catch (err) {
106
+ const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred';
107
+
108
+ showSnackbar({
109
+ title: 'Error starting visit for patient',
110
+ kind: 'error',
111
+ subtitle: errorMessage,
112
+ isLowContrast: true,
113
+ });
114
+ }
115
+ };
package/src/index.ts ADDED
@@ -0,0 +1,51 @@
1
+ import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle } from '@openmrs/esm-framework';
2
+ import { createDashboardLink } from './createDashboardLink';
3
+ import { configSchema } from './config-schema';
4
+ import { dashboardMeta } from './dashboard.meta';
5
+ import MRUDashboard from './mru/dashboard.component';
6
+ import { spaBasePath } from './constants';
7
+ import BillingInformationWorkspace from './mru/billing-information/billing-information.workspace';
8
+ import PatientScoreboard from './patient-scoreboard/patient-scoreboard.component';
9
+
10
+ const moduleName = '@ethiopia/esm-clinical-workflow-app';
11
+
12
+ const options = {
13
+ featureName: 'clinical-workflow',
14
+ moduleName,
15
+ };
16
+
17
+ export function startupApp() {
18
+ defineConfigSchema(moduleName, configSchema);
19
+ }
20
+
21
+ export const root = getAsyncLifecycle(() => import('./root.component'), options);
22
+
23
+ export const triageDashboardLink = getSyncLifecycle(createDashboardLink(dashboardMeta), options);
24
+ export const triageDashboard = getAsyncLifecycle(() => import('./triage/triage-dashboard.component'), options);
25
+ export const patientRegistrationWorkspace = getAsyncLifecycle(
26
+ () => import('./patient-registration/patient.registration.workspace'),
27
+ options,
28
+ );
29
+
30
+ export const mruDashboard = getSyncLifecycle(MRUDashboard, options);
31
+ export const mruLeftPanelLink = getSyncLifecycle(
32
+ createDashboardLink({
33
+ path: 'mru',
34
+ title: 'MRU',
35
+ basePath: spaBasePath,
36
+ }),
37
+ options,
38
+ );
39
+
40
+ export const billingInformationWorkspace = getSyncLifecycle(BillingInformationWorkspace, options);
41
+
42
+ export const patientScoreboardLink = getSyncLifecycle(
43
+ createDashboardLink({
44
+ path: 'patient-scoreboard',
45
+ title: 'Patient Scoreboard',
46
+ basePath: spaBasePath,
47
+ }),
48
+ options,
49
+ );
50
+
51
+ export const patientScoreboard = getSyncLifecycle(PatientScoreboard, options);
@@ -0,0 +1,139 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { z } from 'zod';
3
+ // Create the billing form schema factory with conditional validation based on skip logic
4
+ import type { TFunction } from 'i18next';
5
+
6
+ export const createBillingFormSchema = (t: TFunction) => {
7
+ return z
8
+ .object({
9
+ billingType: z.enum(['credit', 'free', 'cash']).optional(),
10
+ creditType: z.string().optional(),
11
+ name: z.string().optional(),
12
+ code: z.string().optional(),
13
+ id: z.string().optional(),
14
+ expiryDate: z.string().optional(),
15
+ zone: z.string().optional(),
16
+ freeType: z.string().optional(),
17
+ })
18
+ .superRefine((data, ctx) => {
19
+ // Billing type is required on submit
20
+ if (!data.billingType) {
21
+ ctx.addIssue({
22
+ code: z.ZodIssueCode.custom,
23
+ message: t('billingTypeRequired', 'Billing type is required'),
24
+ path: ['billingType'],
25
+ });
26
+ return;
27
+ }
28
+
29
+ // Credit billing type validation
30
+ if (data.billingType === 'credit') {
31
+ // Credit type is required
32
+ if (!data.creditType || data.creditType.trim() === '') {
33
+ ctx.addIssue({
34
+ code: z.ZodIssueCode.custom,
35
+ message: t('creditTypeRequired', 'Credit type is required'),
36
+ path: ['creditType'],
37
+ });
38
+ }
39
+
40
+ // If creditType is insurance, require additional fields
41
+ if (data.creditType === 'insurance') {
42
+ if (!data.id || data.id.trim() === '') {
43
+ ctx.addIssue({
44
+ code: z.ZodIssueCode.custom,
45
+ message: t('idRequired', 'ID is required'),
46
+ path: ['id'],
47
+ });
48
+ }
49
+ }
50
+ }
51
+
52
+ // Free billing type validation
53
+ if (data.billingType === 'free') {
54
+ if (!data.freeType || data.freeType.trim() === '') {
55
+ ctx.addIssue({
56
+ code: z.ZodIssueCode.custom,
57
+ message: t('freeTypeRequired', 'Free type is required'),
58
+ path: ['freeType'],
59
+ });
60
+ }
61
+ }
62
+ });
63
+ };
64
+
65
+ export type BillingFormData = z.infer<ReturnType<typeof createBillingFormSchema>>;
66
+
67
+ const transformFormObjectToVisitAttributes = (
68
+ formObject: Record<string, any>,
69
+ visitAttributeTypeUuidsMap: Record<string, string>,
70
+ ) => {
71
+ return Object.entries(formObject)
72
+ .map(([key, value]) => ({
73
+ attributeType: visitAttributeTypeUuidsMap[key],
74
+ value: value,
75
+ }))
76
+ .filter((item) => {
77
+ // Filter out undefined, null, or empty string values
78
+ if (item.value === undefined || item.value === null || item.value === '') {
79
+ return false;
80
+ }
81
+ // Filter out empty creditTypeDetails object
82
+ if (item.value && typeof item.value === 'object' && !Array.isArray(item.value)) {
83
+ const creditDetails = item.value as Record<string, any>;
84
+ const hasAnyValue = Object.values(creditDetails).some((val) => val !== undefined && val !== null && val !== '');
85
+ if (!hasAnyValue) {
86
+ return false;
87
+ }
88
+ }
89
+ return true;
90
+ })
91
+ .map((item) => ({
92
+ attributeType: item.attributeType,
93
+ value: item.value && typeof item.value === 'object' ? JSON.stringify(item.value) : item.value,
94
+ }));
95
+ };
96
+
97
+ export const createBillingInformationVisitAttribute = (
98
+ billingFormData: BillingFormData,
99
+ visitAttributeTypeUuidsMap: {
100
+ paymentMethod: string;
101
+ creditType: string;
102
+ creditTypeDetails: string;
103
+ freeType: string;
104
+ },
105
+ ) => {
106
+ const { billingType, creditType, name, code, id, expiryDate, zone, freeType } = billingFormData;
107
+
108
+ const formObject = {
109
+ paymentMethod: billingType,
110
+ creditType: creditType,
111
+ creditTypeDetails: {
112
+ name: name,
113
+ code: code,
114
+ id: id,
115
+ expiryDate: expiryDate,
116
+ zone: zone,
117
+ },
118
+ freeType: freeType,
119
+ };
120
+
121
+ const visitAttributePayload = transformFormObjectToVisitAttributes(formObject, visitAttributeTypeUuidsMap);
122
+
123
+ return visitAttributePayload;
124
+ };
125
+
126
+ export const updateVisitWithBillingInformation = (
127
+ visitAttributePayload: Array<{ attributeType: string; value: string }>,
128
+ visitUuid: string,
129
+ ) => {
130
+ return openmrsFetch(`${restBaseUrl}/visit/${visitUuid}`, {
131
+ method: 'POST',
132
+ headers: {
133
+ 'Content-type': 'application/json',
134
+ },
135
+ body: {
136
+ attributes: visitAttributePayload,
137
+ },
138
+ });
139
+ };
@@ -0,0 +1,55 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/type';
3
+ @use '@carbon/layout';
4
+ @use '@carbon/colors';
5
+
6
+ .sectionTitle {
7
+ @include type.type-style('label-01');
8
+ color: colors.$gray-70;
9
+ margin-bottom: spacing.$spacing-03;
10
+ }
11
+
12
+ .buttonSet {
13
+ width: 100%;
14
+ padding-top: spacing.$spacing-05;
15
+ background-color: colors.$white-0;
16
+ justify-content: space-between;
17
+ bottom: 0;
18
+ position: absolute;
19
+ & > button {
20
+ max-width: 50% !important;
21
+ width: 50%;
22
+ }
23
+ }
24
+
25
+ .billingInformationContainer {
26
+ margin: spacing.$spacing-05;
27
+ height: 100%;
28
+ overflow-y: auto;
29
+ }
30
+
31
+ .creditDetailsContainer {
32
+ display: flex;
33
+ flex-direction: column;
34
+ gap: spacing.$spacing-05;
35
+ margin-top: spacing.$spacing-03;
36
+ min-height: 45rem;
37
+ border: 1px solid colors.$gray-20;
38
+ padding: spacing.$spacing-03;
39
+ }
40
+
41
+ .freeDetailsContainer {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: spacing.$spacing-05;
45
+ margin-top: spacing.$spacing-03;
46
+ min-height: 20rem;
47
+ border: 1px solid colors.$gray-20;
48
+ padding: spacing.$spacing-03;
49
+ }
50
+
51
+ .creditTypeDetailsContainer {
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: spacing.$spacing-03;
55
+ }