@openmrs/esm-stock-management-app 3.0.1-pre.845 → 3.0.1-pre.853

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 (126) hide show
  1. package/.husky/pre-commit +4 -1
  2. package/__mocks__/react-i18next.js +8 -9
  3. package/dist/10.js +1 -1
  4. package/dist/10.js.map +1 -1
  5. package/dist/119.js +1 -1
  6. package/dist/119.js.map +1 -1
  7. package/dist/14.js +1 -1
  8. package/dist/14.js.map +1 -1
  9. package/dist/172.js +1 -1
  10. package/dist/172.js.map +1 -1
  11. package/dist/20.js +1 -1
  12. package/dist/20.js.map +1 -1
  13. package/dist/290.js +1 -1
  14. package/dist/290.js.map +1 -1
  15. package/dist/33.js +1 -0
  16. package/dist/33.js.map +1 -0
  17. package/dist/467.js +1 -1
  18. package/dist/467.js.map +1 -1
  19. package/dist/574.js +1 -1
  20. package/dist/606.js +1 -1
  21. package/dist/606.js.map +1 -1
  22. package/dist/642.js +1 -1
  23. package/dist/642.js.map +1 -1
  24. package/dist/675.js +1 -1
  25. package/dist/675.js.map +1 -1
  26. package/dist/727.js +1 -1
  27. package/dist/727.js.map +1 -1
  28. package/dist/842.js +1 -1
  29. package/dist/842.js.map +1 -1
  30. package/dist/93.js +1 -1
  31. package/dist/93.js.map +1 -1
  32. package/dist/main.js +1 -1
  33. package/dist/main.js.map +1 -1
  34. package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +70 -70
  35. package/dist/routes.json +1 -1
  36. package/jest.config.js +6 -3
  37. package/package.json +1 -1
  38. package/src/core/components/overlay/overlay.scss +1 -1
  39. package/src/core/components/privilages-component/privilages.scss +1 -1
  40. package/src/core/components/table/table.component.tsx +2 -2
  41. package/src/core/components/table/table.scss +1 -1
  42. package/src/core/components/tabs/vertical-tabs.scss +1 -1
  43. package/src/index.ts +5 -5
  44. package/src/stock-items/add-bulk-stock-item/add-stock-items-bulk-import-action-button.component.tsx +3 -3
  45. package/src/stock-items/add-bulk-stock-item/{stock-items-bulk-import.component.tsx → stock-items-bulk-import.modal.tsx} +20 -19
  46. package/src/stock-items/add-bulk-stock-item/stock-items-bulk-import.resource.ts +1 -1
  47. package/src/stock-items/add-bulk-stock-item/stock-items-bulk-import.test.tsx +59 -59
  48. package/src/stock-items/add-stock-item/add-stock-action-button.component.tsx +6 -6
  49. package/src/stock-items/add-stock-item/add-stock-item.component.tsx +6 -4
  50. package/src/stock-items/add-stock-item/add-stock-item.scss +5 -0
  51. package/src/stock-items/add-stock-item/add-stock-item.test.tsx +28 -43
  52. package/src/stock-items/add-stock-item/packaging-units/packaging-units-delete-modal.component.tsx +3 -4
  53. package/src/stock-items/add-stock-item/packaging-units/packaging-units.component.tsx +9 -10
  54. package/src/stock-items/add-stock-item/packaging-units/packaging-units.scss +4 -4
  55. package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.component.tsx +27 -19
  56. package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.scss +1 -1
  57. package/src/stock-items/add-stock-item/stock-item-references/stock-item-references.scss +4 -4
  58. package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.component.tsx +15 -9
  59. package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.scss +1 -0
  60. package/src/stock-items/add-stock-item/stock-item-rules/delete-stock-rule-modal.component.tsx +2 -1
  61. package/src/stock-items/add-stock-item/stock-item-rules/stock-item-rules.component.tsx +14 -16
  62. package/src/stock-items/add-stock-item/stock-item-rules/stock-item-rules.scss +7 -3
  63. package/src/stock-items/add-stock-item/transactions/printout/transactions-print-bincard-preview.modal.tsx +14 -6
  64. package/src/stock-items/add-stock-item/transactions/printout/transactions-print-stockcard-preview.modal.tsx +14 -8
  65. package/src/stock-items/edit-stock-item/edit-stock-item-action-menu.component.tsx +2 -2
  66. package/src/stock-items/stock-item.utils.tsx +3 -5
  67. package/src/stock-items/stock-items-table.component.tsx +47 -45
  68. package/src/stock-items/stock-items-table.resource.ts +2 -2
  69. package/src/stock-items/stock-items-table.scss +9 -8
  70. package/src/stock-items/stock-items-table.test.tsx +106 -65
  71. package/src/stock-items/stock-items.component.tsx +1 -1
  72. package/src/stock-locations/location-admin-form.component.tsx +5 -4
  73. package/src/stock-locations/stock-locations-table.component.tsx +10 -8
  74. package/src/stock-locations/stock-locations.component.tsx +1 -1
  75. package/src/stock-lookups/stock-lookups.resource.ts +3 -2
  76. package/src/stock-management-header/stock-management-header.scss +1 -1
  77. package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operation-expanded-row.scss +1 -1
  78. package/src/stock-operations/stock-operations-dialog/stock-operations-dialog.component.tsx +2 -2
  79. package/src/stock-operations/stock-operations-filters.component.tsx +5 -5
  80. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +11 -11
  81. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +115 -25
  82. package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +107 -65
  83. package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +9 -9
  84. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +35 -153
  85. package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +82 -29
  86. package/src/stock-operations/stock-operations-forms/step1.test.tsx +204 -69
  87. package/src/stock-operations/stock-operations-forms/step2.test.tsx +140 -63
  88. package/src/stock-operations/stock-operations-forms/step3.test.tsx +79 -60
  89. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +6 -5
  90. package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +12 -11
  91. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +1 -0
  92. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +20 -12
  93. package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +1 -0
  94. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +1 -3
  95. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +2 -1
  96. package/src/stock-operations/stock-operations-table.component.tsx +66 -73
  97. package/src/stock-operations/stock-operations-table.scss +18 -9
  98. package/src/stock-operations/stock-operations.component.tsx +1 -1
  99. package/src/stock-reports/generate-report/create-stock-report.scss +3 -2
  100. package/src/stock-reports/generate-report/create-stock-report.workspace.tsx +32 -25
  101. package/src/stock-reports/report-list/stock-report-parameters.component.tsx +1 -1
  102. package/src/stock-reports/report-list/stock-report-status.component.tsx +1 -1
  103. package/src/stock-reports/report-list/stock-reports.component.tsx +24 -25
  104. package/src/stock-reports/report-list/stock-reports.scss +11 -3
  105. package/src/stock-sources/add-stock-sources/add-stock-sources.scss +12 -5
  106. package/src/stock-sources/add-stock-sources/add-stock-sources.test.tsx +38 -36
  107. package/src/stock-sources/add-stock-sources/add-stock-sources.workspace.tsx +35 -30
  108. package/src/stock-sources/delete-stock-modal.component.tsx +2 -1
  109. package/src/stock-sources/delete-stock-modal.scss +1 -1
  110. package/src/stock-sources/stock-sources-delete/stock-sources-delete.test.tsx +27 -36
  111. package/src/stock-sources/stock-sources-filter/stock-sources-filter.component.tsx +33 -21
  112. package/src/stock-sources/stock-sources-items-table.component.tsx +16 -17
  113. package/src/stock-sources/stock-sources-items-table.resource.ts +8 -6
  114. package/src/stock-sources/stock-sources-items-table.test.tsx +60 -37
  115. package/src/stock-sources/stock-sources.component.tsx +1 -1
  116. package/src/stock-sources/stock-sources.scss +6 -2
  117. package/src/stock-user-role-scopes/add-stock-user-scope/add-stock-user-role-scope.scss +5 -13
  118. package/src/stock-user-role-scopes/add-stock-user-scope/add-stock-user-role-scope.workspace.tsx +2 -2
  119. package/src/stock-user-role-scopes/delete-stock-user-scope-modal.component.tsx +2 -1
  120. package/src/stock-user-role-scopes/delete-stock-user-scope-modal.scss +1 -1
  121. package/src/stock-user-role-scopes/stock-user-role-scopes.component.tsx +1 -1
  122. package/src/stock-user-role-scopes/stock-user-role-scopes.scss +1 -1
  123. package/translations/en.json +5 -6
  124. package/tsconfig.json +4 -0
  125. package/dist/627.js +0 -1
  126. package/dist/627.js.map +0 -1
@@ -1,32 +1,39 @@
1
1
  import React, { useCallback, useMemo } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import {
4
+ Button,
4
5
  DataTable,
5
6
  DataTableSkeleton,
6
- TabPanel,
7
+ InlineLoading,
7
8
  Pagination,
8
9
  Table,
9
10
  TableBody,
10
11
  TableCell,
11
12
  TableContainer,
13
+ TableExpandedRow,
14
+ TableExpandHeader,
15
+ TableExpandRow,
12
16
  TableHead,
13
17
  TableHeader,
14
18
  TableRow,
15
19
  TableToolbar,
20
+ TableToolbarAction,
16
21
  TableToolbarContent,
22
+ TableToolbarMenu,
17
23
  TableToolbarSearch,
24
+ TabPanel,
18
25
  Tile,
19
- Button,
20
- InlineLoading,
21
- TableToolbarMenu,
22
- TableToolbarAction,
23
- TableExpandHeader,
24
- TableExpandRow,
25
- TableExpandedRow,
26
26
  } from '@carbon/react';
27
+ import {
28
+ CheckmarkOutline,
29
+ Copy,
30
+ Download,
31
+ IncompleteCancel,
32
+ MisuseOutline,
33
+ View,
34
+ WarningAltFilled,
35
+ } from '@carbon/react/icons';
27
36
  import { isDesktop, restBaseUrl, useSession } from '@openmrs/esm-framework';
28
- import NewReportActionButton from './new-report-button.component';
29
- import styles from './stock-reports.scss';
30
37
  import { useGetReports } from '../stock-reports.resource';
31
38
  import {
32
39
  URL_BATCH_JOB_ARTIFACT,
@@ -41,19 +48,12 @@ import {
41
48
  BatchJobStatusFailed,
42
49
  BatchJobStatusPending,
43
50
  } from '../../core/api/types/BatchJob';
44
- import {
45
- CheckmarkOutline,
46
- Copy,
47
- Download,
48
- IncompleteCancel,
49
- MisuseOutline,
50
- View,
51
- WarningAltFilled,
52
- } from '@carbon/react/icons';
53
51
  import { handleMutate } from '../../utils';
54
52
  import { PrivilagedView } from '../../core/components/privilages-component/privilages.component';
53
+ import NewReportActionButton from './new-report-button.component';
55
54
  import StockReportStatus from './stock-report-status.component';
56
55
  import StockReportParameters from './stock-report-parameters.component';
56
+ import styles from './stock-reports.scss';
57
57
 
58
58
  const StockReports: React.FC = () => {
59
59
  const { t } = useTranslation();
@@ -202,12 +202,9 @@ const StockReports: React.FC = () => {
202
202
  }
203
203
 
204
204
  return (
205
- <div className={styles.tableOverride}>
205
+ <div className={styles.container}>
206
206
  <TabPanel>{t('ReportDescription', 'List of reports requested by users')}</TabPanel>
207
- <div id="table-tool-bar">
208
- <div></div>
209
- <div className="right-filters"></div>
210
- </div>
207
+
211
208
  <DataTable
212
209
  rows={tableRows}
213
210
  headers={tableHeaders}
@@ -225,7 +222,9 @@ const StockReports: React.FC = () => {
225
222
  <TableToolbarContent className={styles.toolbarContent}>
226
223
  <TableToolbarSearch persistent onChange={onInputChange} />
227
224
  <TableToolbarMenu>
228
- <TableToolbarAction onClick={handleRefresh}>Refresh</TableToolbarAction>
225
+ <TableToolbarAction className={styles.toolbarMenuAction} onClick={handleRefresh}>
226
+ {t('refresh', 'Refresh')}
227
+ </TableToolbarAction>
229
228
  </TableToolbarMenu>
230
229
  {canCreateReport && <NewReportActionButton />}
231
230
  </TableToolbarContent>
@@ -1,7 +1,11 @@
1
- @use '@carbon/styles/scss/colors';
2
- @use '@carbon/styles/scss/type';
1
+ @use '@carbon/colors';
3
2
  @use '@carbon/layout';
4
- @use '~@openmrs/esm-styleguide/src/vars' as *;
3
+ @use '@carbon/type';
4
+ @use '@openmrs/esm-styleguide/src/vars' as *;
5
+
6
+ .container {
7
+ margin: layout.$spacing-05;
8
+ }
5
9
 
6
10
  .content {
7
11
  @include type.type-style('heading-compact-02');
@@ -78,3 +82,7 @@
78
82
  margin-right: 4px;
79
83
  }
80
84
  }
85
+
86
+ .toolbarMenuAction {
87
+ max-width: none;
88
+ }
@@ -1,10 +1,6 @@
1
1
  @use '@carbon/layout';
2
2
  @use '@carbon/type';
3
- @use '~@openmrs/esm-styleguide/src/vars' as *;
4
-
5
- .section {
6
- margin: layout.$spacing-03;
7
- }
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
8
4
 
9
5
  .sectionTitle {
10
6
  @include type.type-style('heading-compact-02');
@@ -15,6 +11,7 @@
15
11
  .modalBody {
16
12
  padding-bottom: layout.$spacing-05;
17
13
  }
14
+
18
15
  .formContainer {
19
16
  display: flex;
20
17
  flex-direction: column;
@@ -24,6 +21,7 @@
24
21
  }
25
22
 
26
23
  .button {
24
+ height: layout.$spacing-10;
27
25
  display: flex;
28
26
  align-content: flex-start;
29
27
  align-items: baseline;
@@ -39,3 +37,12 @@
39
37
  .body {
40
38
  padding: 1rem;
41
39
  }
40
+
41
+ .tablet {
42
+ padding: layout.$spacing-06 layout.$spacing-05;
43
+ background-color: white;
44
+ }
45
+
46
+ .desktop {
47
+ padding: 0;
48
+ }
@@ -1,24 +1,16 @@
1
1
  import React from 'react';
2
- import { render, screen } from '@testing-library/react';
3
2
  import userEvent from '@testing-library/user-event';
4
- import '@testing-library/jest-dom/extend-expect';
5
- import StockSourcesAddOrUpdate from './add-stock-sources.workspace';
3
+ import { render, screen } from '@testing-library/react';
4
+ import { type FetchResponse, useConfig } from '@openmrs/esm-framework';
5
+ import { type StockSource } from '../../core/api/types/stockOperation/StockSource';
6
6
  import { createOrUpdateStockSource } from '../stock-sources.resource';
7
- import { useConfig } from '@openmrs/esm-framework';
7
+ import StockSourcesAddOrUpdate from './add-stock-sources.workspace';
8
8
 
9
- import { type StockSource } from '../../core/api/types/stockOperation/StockSource';
9
+ const mockCreateOrUpdateStockSource = jest.mocked(createOrUpdateStockSource);
10
+ const mockUseConfig = jest.mocked(useConfig);
10
11
 
11
- jest.mock('../stock-sources.resource');
12
- jest.mock('@openmrs/esm-framework', () => ({
13
- showSnackbar: jest.fn(),
14
- useConfig: jest.fn(),
15
- getCoreTranslation: jest.fn((key, defaultValue) => {
16
- const translations: Record<string, string> = {
17
- cancel: 'Cancel',
18
- save: 'Save',
19
- };
20
- return translations[key] ?? defaultValue;
21
- }),
12
+ jest.mock('../stock-sources.resource', () => ({
13
+ createOrUpdateStockSource: jest.fn(),
22
14
  }));
23
15
 
24
16
  jest.mock('../../stock-lookups/stock-lookups.resource', () => ({
@@ -34,7 +26,7 @@ jest.mock('../../stock-lookups/stock-lookups.resource', () => ({
34
26
 
35
27
  describe('StockSourcesAddOrUpdate', () => {
36
28
  beforeEach(() => {
37
- (useConfig as jest.Mock).mockReturnValue({ stockSourceTypeUUID: 'mock-uuid' });
29
+ mockUseConfig.mockReturnValue({ stockSourceTypeUUID: 'mock-uuid' });
38
30
  });
39
31
 
40
32
  it('renders correctly without model prop', () => {
@@ -46,9 +38,9 @@ describe('StockSourcesAddOrUpdate', () => {
46
38
  promptBeforeClosing={jest.fn()}
47
39
  />,
48
40
  );
49
- expect(screen.getByLabelText('Full Name')).toBeInTheDocument();
50
- expect(screen.getByLabelText('Acronym/Code')).toBeInTheDocument();
51
- expect(screen.getByLabelText('Source Type')).toBeInTheDocument();
41
+ expect(screen.getByLabelText(/full name/i)).toBeInTheDocument();
42
+ expect(screen.getByLabelText(/acronym\/code/i)).toBeInTheDocument();
43
+ expect(screen.getByLabelText(/source type/i)).toBeInTheDocument();
52
44
  });
53
45
 
54
46
  it('renders correctly with model prop', () => {
@@ -110,9 +102,9 @@ describe('StockSourcesAddOrUpdate', () => {
110
102
  promptBeforeClosing={jest.fn()}
111
103
  />,
112
104
  );
113
- expect(screen.getByLabelText('Full Name')).toHaveValue('Test Source');
114
- expect(screen.getByLabelText('Acronym/Code')).toHaveValue('TS');
115
- expect(screen.getByLabelText('Source Type')).toHaveValue('type1');
105
+ expect(screen.getByLabelText(/full name/i)).toHaveValue('Test Source');
106
+ expect(screen.getByLabelText(/acronym\/code/i)).toHaveValue('TS');
107
+ expect(screen.getByLabelText(/source type/i)).toHaveValue('type1');
116
108
  });
117
109
 
118
110
  it('updates form fields correctly on user input', async () => {
@@ -126,16 +118,21 @@ describe('StockSourcesAddOrUpdate', () => {
126
118
  />,
127
119
  );
128
120
 
129
- await user.type(screen.getByLabelText('Full Name'), 'New Source');
130
- await user.type(screen.getByLabelText('Acronym/Code'), 'NS');
121
+ await user.type(screen.getByLabelText(/full name/i), 'New Source');
122
+ await user.type(screen.getByLabelText(/acronym\/code/i), 'NS');
131
123
 
132
- expect(screen.getByLabelText('Full Name')).toHaveValue('New Source');
133
- expect(screen.getByLabelText('Acronym/Code')).toHaveValue('NS');
124
+ expect(screen.getByLabelText(/full name/i)).toHaveValue('New Source');
125
+ expect(screen.getByLabelText(/acronym\/code/i)).toHaveValue('NS');
134
126
  });
135
127
 
136
128
  it('calls createOrUpdateStockSource with correct data on form submission', async () => {
137
129
  const user = userEvent.setup();
138
- (createOrUpdateStockSource as jest.Mock).mockResolvedValue({});
130
+ mockCreateOrUpdateStockSource.mockResolvedValue({
131
+ data: {},
132
+ ok: true,
133
+ status: 200,
134
+ statusText: 'OK',
135
+ } as unknown as FetchResponse);
139
136
 
140
137
  render(
141
138
  <StockSourcesAddOrUpdate
@@ -146,15 +143,20 @@ describe('StockSourcesAddOrUpdate', () => {
146
143
  />,
147
144
  );
148
145
 
149
- await user.type(screen.getByLabelText('Full Name'), 'New Source');
150
- await user.type(screen.getByLabelText('Acronym/Code'), 'NS');
151
- await user.selectOptions(screen.getByLabelText('Source Type'), 'type2');
146
+ await user.type(screen.getByLabelText(/full name/i), 'New Source');
147
+ await user.type(screen.getByLabelText(/acronym\/code/i), 'NS');
148
+ await user.selectOptions(screen.getByLabelText(/source type/i), 'type2');
152
149
  await user.click(screen.getByText('Save'));
153
150
  });
154
151
 
155
152
  it('shows success message and closes overlay on successful submission', async () => {
156
153
  const user = userEvent.setup();
157
- (createOrUpdateStockSource as jest.Mock).mockResolvedValue({});
154
+ mockCreateOrUpdateStockSource.mockResolvedValue({
155
+ data: {},
156
+ ok: true,
157
+ status: 200,
158
+ statusText: 'OK',
159
+ } as unknown as FetchResponse);
158
160
 
159
161
  render(
160
162
  <StockSourcesAddOrUpdate
@@ -165,12 +167,12 @@ describe('StockSourcesAddOrUpdate', () => {
165
167
  />,
166
168
  );
167
169
 
168
- await user.click(screen.getByText('Save'));
170
+ await user.click(screen.getByText(/save/i));
169
171
  });
170
172
 
171
173
  it('shows error message on failed submission', async () => {
172
174
  const user = userEvent.setup();
173
- (createOrUpdateStockSource as jest.Mock).mockRejectedValue(new Error('API Error'));
175
+ mockCreateOrUpdateStockSource.mockRejectedValue(new Error('API Error'));
174
176
 
175
177
  render(
176
178
  <StockSourcesAddOrUpdate
@@ -181,7 +183,7 @@ describe('StockSourcesAddOrUpdate', () => {
181
183
  />,
182
184
  );
183
185
 
184
- await user.click(screen.getByText('Save'));
186
+ await user.click(screen.getByText(/save/i));
185
187
  });
186
188
 
187
189
  it('closes overlay when cancel button is clicked', async () => {
@@ -195,6 +197,6 @@ describe('StockSourcesAddOrUpdate', () => {
195
197
  />,
196
198
  );
197
199
 
198
- await user.click(screen.getByText('Cancel'));
200
+ await user.click(screen.getByText(/cancel/i));
199
201
  });
200
202
  });
@@ -1,20 +1,22 @@
1
- import { Button, Form, Select, TextInput, SelectItem, ButtonSet } from '@carbon/react';
2
1
  import React, { type ChangeEvent, useCallback, useState } from 'react';
3
- import styles from './add-stock-sources.scss';
4
- import { useConcept } from '../../stock-lookups/stock-lookups.resource';
5
- import { type StockSource } from '../../core/api/types/stockOperation/StockSource';
6
- import { createOrUpdateStockSource } from '../stock-sources.resource';
2
+ import classNames from 'classnames';
3
+ import { Button, ButtonSet, Select, SelectItem, Stack, TextInput } from '@carbon/react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { Save } from '@carbon/react/icons';
7
6
  import {
8
- type DefaultWorkspaceProps,
7
+ getCoreTranslation,
9
8
  restBaseUrl,
10
9
  showSnackbar,
10
+ type DefaultWorkspaceProps,
11
11
  useConfig,
12
- getCoreTranslation,
12
+ useLayoutType,
13
13
  } from '@openmrs/esm-framework';
14
- import { useTranslation } from 'react-i18next';
14
+ import { useConcept } from '../../stock-lookups/stock-lookups.resource';
15
+ import { type StockSource } from '../../core/api/types/stockOperation/StockSource';
16
+ import { createOrUpdateStockSource } from '../stock-sources.resource';
15
17
  import { type ConfigObject } from '../../config-schema';
16
18
  import { handleMutate } from '../../utils';
17
- import { Save } from '@carbon/react/icons';
19
+ import styles from './add-stock-sources.scss';
18
20
 
19
21
  type AddStockSourceProps = DefaultWorkspaceProps & {
20
22
  model?: StockSource;
@@ -22,6 +24,7 @@ type AddStockSourceProps = DefaultWorkspaceProps & {
22
24
 
23
25
  const StockSourcesAddOrUpdate: React.FC<AddStockSourceProps> = ({ model, closeWorkspace }) => {
24
26
  const { t } = useTranslation();
27
+ const isTablet = useLayoutType() === 'tablet';
25
28
  const { stockSourceTypeUUID } = useConfig<ConfigObject>();
26
29
 
27
30
  // get stock sources
@@ -47,9 +50,11 @@ const StockSourcesAddOrUpdate: React.FC<AddStockSourceProps> = ({ model, closeWo
47
50
  const handleSave = useCallback(
48
51
  (event) => {
49
52
  event.preventDefault();
53
+
50
54
  if (model) {
51
55
  formModel.uuid = model.uuid;
52
56
  }
57
+
53
58
  createOrUpdateStockSource(formModel)
54
59
  .then(
55
60
  () => {
@@ -82,51 +87,51 @@ const StockSourcesAddOrUpdate: React.FC<AddStockSourceProps> = ({ model, closeWo
82
87
  return (
83
88
  <div className={styles.formContainer}>
84
89
  <div className={styles.body}>
85
- <section className={styles.section}>
90
+ <Stack gap={5}>
86
91
  <TextInput
87
92
  id="fullname"
88
- type="text"
89
- labelText={t('fullName', 'Full Name')}
90
- size="md"
93
+ labelText={t('fullName', 'Full name')}
91
94
  onChange={onNameChanged}
92
- value={model?.name}
93
95
  placeholder="e.g National Medical Stores"
96
+ size="md"
97
+ type="text"
98
+ value={model?.name}
94
99
  />
95
- </section>
96
- <section className={styles.section}>
97
100
  <TextInput
98
101
  id="acronym"
99
- type="text"
100
- size="md"
101
- placeholder="e.g NMS"
102
+ labelText={t('acronymOrCode', 'Acronym/Code')}
102
103
  onChange={onAcronymChanged}
104
+ placeholder="e.g NMS"
105
+ size="md"
106
+ type="text"
103
107
  value={model?.acronym}
104
- labelText={t('acronym', 'Acronym/Code')}
105
108
  />
106
- </section>
107
- <section className={styles.section}>
108
109
  <Select
109
- name="sourceType"
110
110
  className="select-field"
111
- labelText={t('sourceType', 'Source Type')}
112
111
  id="sourceType"
113
- value={formModel?.sourceType ? formModel.sourceType.uuid : ''}
112
+ labelText={t('sourceType', 'Source Type')}
113
+ name="sourceType"
114
114
  onChange={onSourceTypeChange}
115
+ value={formModel?.sourceType ? formModel.sourceType.uuid : ''}
115
116
  >
116
117
  <SelectItem disabled hidden value="" text={t('chooseSourceType', 'Choose a source type')} />
117
118
  {items?.answers?.map((sourceType) => (
118
119
  <SelectItem key={sourceType.uuid} value={sourceType.uuid} text={sourceType.display} />
119
120
  ))}
120
121
  </Select>
121
- </section>
122
+ </Stack>
122
123
  </div>
123
-
124
- <ButtonSet className={styles.buttonSet}>
124
+ <ButtonSet
125
+ className={classNames(styles.buttonSet, {
126
+ [styles.tablet]: isTablet,
127
+ [styles.desktop]: !isTablet,
128
+ })}
129
+ >
125
130
  <Button kind="secondary" onClick={closeWorkspace} className={styles.button}>
126
- {getCoreTranslation('cancel', 'Cancel')}
131
+ {getCoreTranslation('cancel')}
127
132
  </Button>
128
133
  <Button type="submit" className={styles.button} onClick={handleSave} kind="primary" renderIcon={Save}>
129
- {getCoreTranslation('save', 'Save')}
134
+ {getCoreTranslation('save')}
130
135
  </Button>
131
136
  </ButtonSet>
132
137
  </div>
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { Button, ModalHeader, ModalBody, ModalFooter } from '@carbon/react';
4
+ import { getCoreTranslation } from '@openmrs/esm-framework';
4
5
  import styles from './delete-stock-modal.scss';
5
6
 
6
7
  interface DeleteConfirmationProps {
@@ -28,7 +29,7 @@ const DeleteConfirmation: React.FC<DeleteConfirmationProps> = ({ close, onConfir
28
29
  </ModalBody>
29
30
  <ModalFooter>
30
31
  <Button size="lg" kind="secondary" onClick={handleCancel}>
31
- {t('cancel', 'Cancel')}
32
+ {getCoreTranslation('cancel')}
32
33
  </Button>
33
34
  <Button autoFocus kind="danger" onClick={handleDelete} size="lg">
34
35
  {t('delete', 'Delete')}
@@ -1,6 +1,6 @@
1
1
  @use '@carbon/layout';
2
2
  @use '@carbon/type';
3
- @use '~@openmrs/esm-styleguide/src/vars' as *;
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
4
4
 
5
5
  .bodyText {
6
6
  @include type.type-style('body-long-01');
@@ -1,24 +1,16 @@
1
1
  import React from 'react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import { render, screen } from '@testing-library/react';
4
- import '@testing-library/jest-dom/extend-expect';
5
- import { showModal, showSnackbar } from '@openmrs/esm-framework';
4
+ import { type FetchResponse, showModal, showSnackbar } from '@openmrs/esm-framework';
6
5
  import { deleteStockSource } from '../stock-sources.resource';
7
- import StockSourcesDeleteActionMenu from './stock-sources-delete.component';
8
- import DeleteConfirmation from '../../stock-user-role-scopes/delete-stock-user-scope-modal.component';
9
6
  import { handleMutate } from '../../utils';
7
+ import DeleteConfirmation from '../../stock-user-role-scopes/delete-stock-user-scope-modal.component';
8
+ import StockSourcesDeleteActionMenu from './stock-sources-delete.component';
10
9
 
11
- jest.mock('react-i18next', () => ({
12
- useTranslation: () => ({
13
- t: (key) => key,
14
- }),
15
- }));
16
-
17
- jest.mock('@openmrs/esm-framework', () => ({
18
- showModal: jest.fn(),
19
- showSnackbar: jest.fn(),
20
- restBaseUrl: 'http://localhost:8080',
21
- }));
10
+ const mockDeleteStockSource = jest.mocked(deleteStockSource);
11
+ const mockHandleMutate = jest.mocked(handleMutate);
12
+ const mockShowModal = jest.mocked(showModal);
13
+ const mockShowSnackbar = jest.mocked(showSnackbar);
22
14
 
23
15
  jest.mock('../stock-sources.resource', () => ({
24
16
  deleteStockSource: jest.fn(),
@@ -34,7 +26,8 @@ describe('StockSourcesDeleteActionMenu', () => {
34
26
 
35
27
  it('renders the delete button correctly', () => {
36
28
  render(<StockSourcesDeleteActionMenu uuid={uuid} />);
37
- const button = screen.getByRole('button', { name: 'deleteSource' });
29
+
30
+ const button = screen.getByRole('button', { name: /delete source/i });
38
31
  expect(button).toBeInTheDocument();
39
32
  });
40
33
 
@@ -42,9 +35,10 @@ describe('StockSourcesDeleteActionMenu', () => {
42
35
  const user = userEvent.setup();
43
36
  render(<StockSourcesDeleteActionMenu uuid={uuid} />);
44
37
 
45
- const button = screen.getByRole('button', { name: 'deleteSource' });
38
+ const button = screen.getByRole('button', { name: /delete source/i });
46
39
  await user.click(button);
47
- expect(showModal).toHaveBeenCalledWith(
40
+
41
+ expect(mockShowModal).toHaveBeenCalledWith(
48
42
  'delete-stock-modal',
49
43
  expect.objectContaining({
50
44
  close: expect.any(Function),
@@ -61,9 +55,9 @@ describe('StockSourcesDeleteActionMenu', () => {
61
55
 
62
56
  render(<DeleteConfirmation close={mockClose} onConfirmation={mockOnConfirmation} />);
63
57
 
64
- expect(screen.getByText(/deleteStockUserScope/i)).toBeInTheDocument();
58
+ expect(screen.getByText(/delete stock user scope/i)).toBeInTheDocument();
65
59
 
66
- const deleteButton = screen.getByRole('button', { name: /delete/i });
60
+ const deleteButton = screen.getByRole('button', { name: /danger delete/i });
67
61
  await user.click(deleteButton);
68
62
 
69
63
  expect(mockOnConfirmation).toHaveBeenCalledTimes(1);
@@ -85,7 +79,7 @@ describe('StockSourcesDeleteActionMenu', () => {
85
79
  />,
86
80
  );
87
81
 
88
- const deleteButton = screen.getByRole('button', { name: /delete/i });
82
+ const deleteButton = screen.getByRole('button', { name: /danger delete/i });
89
83
  await user.click(deleteButton);
90
84
 
91
85
  expect(mockOnConfirmation).toHaveBeenCalledTimes(1);
@@ -94,7 +88,7 @@ describe('StockSourcesDeleteActionMenu', () => {
94
88
 
95
89
  it('calls handleMutate with the correct URL on successful deletion', async () => {
96
90
  const user = userEvent.setup();
97
- (deleteStockSource as jest.Mock).mockResolvedValueOnce({});
91
+ mockDeleteStockSource.mockResolvedValueOnce({} as FetchResponse<any>);
98
92
 
99
93
  const mockOnConfirmation = jest.fn();
100
94
  const mockClose = jest.fn();
@@ -109,18 +103,17 @@ describe('StockSourcesDeleteActionMenu', () => {
109
103
  />,
110
104
  );
111
105
 
112
- const deleteButton = screen.getByRole('button', { name: /delete/i });
106
+ const deleteButton = screen.getByRole('button', { name: /danger delete/i });
113
107
  await user.click(deleteButton);
114
108
 
115
- expect(deleteStockSource).toHaveBeenCalledWith([uuid]);
116
- expect(handleMutate).toHaveBeenCalledWith('/openmrs/ws/rest/v1/stocksource');
109
+ expect(mockDeleteStockSource).toHaveBeenCalledWith([uuid]);
110
+ expect(mockHandleMutate).toHaveBeenCalledWith('/openmrs/ws/rest/v1/stocksource');
117
111
  });
118
112
 
119
113
  it('calls showSnackbar with the correct parameters on deletion error', async () => {
120
114
  const user = userEvent.setup();
121
- (deleteStockSource as jest.Mock).mockRejectedValueOnce(new Error('Deletion failed'));
115
+ mockDeleteStockSource.mockRejectedValueOnce(new Error('Deletion failed'));
122
116
 
123
- const mockOnConfirmation = jest.fn();
124
117
  const mockClose = jest.fn();
125
118
 
126
119
  render(
@@ -139,11 +132,11 @@ describe('StockSourcesDeleteActionMenu', () => {
139
132
  />,
140
133
  );
141
134
 
142
- const deleteButton = screen.getByRole('button', { name: /delete/i });
135
+ const deleteButton = screen.getByRole('button', { name: /danger delete/i });
143
136
  await user.click(deleteButton);
144
137
 
145
- expect(deleteStockSource).toHaveBeenCalledWith([uuid]);
146
- expect(showSnackbar).toHaveBeenCalledWith({
138
+ expect(mockDeleteStockSource).toHaveBeenCalledWith([uuid]);
139
+ expect(mockShowSnackbar).toHaveBeenCalledWith({
147
140
  title: 'stockSourceDeleteError',
148
141
  kind: 'error',
149
142
  });
@@ -151,9 +144,8 @@ describe('StockSourcesDeleteActionMenu', () => {
151
144
 
152
145
  it('handles the error state correctly when the delete action fails', async () => {
153
146
  const user = userEvent.setup();
154
- (deleteStockSource as jest.Mock).mockRejectedValueOnce(new Error('Deletion failed'));
147
+ mockDeleteStockSource.mockRejectedValueOnce(new Error('Deletion failed'));
155
148
 
156
- const mockOnConfirmation = jest.fn();
157
149
  const mockClose = jest.fn();
158
150
 
159
151
  render(
@@ -172,12 +164,11 @@ describe('StockSourcesDeleteActionMenu', () => {
172
164
  />,
173
165
  );
174
166
 
175
- const deleteButton = screen.getByRole('button', { name: /delete/i });
167
+ const deleteButton = screen.getByRole('button', { name: /danger delete/i });
176
168
  await user.click(deleteButton);
177
169
 
178
- expect(deleteStockSource).toHaveBeenCalledWith([uuid]);
179
-
180
- expect(showSnackbar).toHaveBeenCalledWith({
170
+ expect(mockDeleteStockSource).toHaveBeenCalledWith([uuid]);
171
+ expect(mockShowSnackbar).toHaveBeenCalledWith({
181
172
  title: 'stockSourceDeleteError',
182
173
  kind: 'error',
183
174
  });