@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.
- package/.husky/pre-commit +4 -1
- package/__mocks__/react-i18next.js +8 -9
- package/dist/10.js +1 -1
- package/dist/10.js.map +1 -1
- package/dist/119.js +1 -1
- package/dist/119.js.map +1 -1
- package/dist/14.js +1 -1
- package/dist/14.js.map +1 -1
- package/dist/172.js +1 -1
- package/dist/172.js.map +1 -1
- package/dist/20.js +1 -1
- package/dist/20.js.map +1 -1
- package/dist/290.js +1 -1
- package/dist/290.js.map +1 -1
- package/dist/33.js +1 -0
- package/dist/33.js.map +1 -0
- package/dist/467.js +1 -1
- package/dist/467.js.map +1 -1
- package/dist/574.js +1 -1
- package/dist/606.js +1 -1
- package/dist/606.js.map +1 -1
- package/dist/642.js +1 -1
- package/dist/642.js.map +1 -1
- package/dist/675.js +1 -1
- package/dist/675.js.map +1 -1
- package/dist/727.js +1 -1
- package/dist/727.js.map +1 -1
- package/dist/842.js +1 -1
- package/dist/842.js.map +1 -1
- package/dist/93.js +1 -1
- package/dist/93.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +70 -70
- package/dist/routes.json +1 -1
- package/jest.config.js +6 -3
- package/package.json +1 -1
- package/src/core/components/overlay/overlay.scss +1 -1
- package/src/core/components/privilages-component/privilages.scss +1 -1
- package/src/core/components/table/table.component.tsx +2 -2
- package/src/core/components/table/table.scss +1 -1
- package/src/core/components/tabs/vertical-tabs.scss +1 -1
- package/src/index.ts +5 -5
- package/src/stock-items/add-bulk-stock-item/add-stock-items-bulk-import-action-button.component.tsx +3 -3
- package/src/stock-items/add-bulk-stock-item/{stock-items-bulk-import.component.tsx → stock-items-bulk-import.modal.tsx} +20 -19
- package/src/stock-items/add-bulk-stock-item/stock-items-bulk-import.resource.ts +1 -1
- package/src/stock-items/add-bulk-stock-item/stock-items-bulk-import.test.tsx +59 -59
- package/src/stock-items/add-stock-item/add-stock-action-button.component.tsx +6 -6
- package/src/stock-items/add-stock-item/add-stock-item.component.tsx +6 -4
- package/src/stock-items/add-stock-item/add-stock-item.scss +5 -0
- package/src/stock-items/add-stock-item/add-stock-item.test.tsx +28 -43
- package/src/stock-items/add-stock-item/packaging-units/packaging-units-delete-modal.component.tsx +3 -4
- package/src/stock-items/add-stock-item/packaging-units/packaging-units.component.tsx +9 -10
- package/src/stock-items/add-stock-item/packaging-units/packaging-units.scss +4 -4
- package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.component.tsx +27 -19
- package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.scss +1 -1
- package/src/stock-items/add-stock-item/stock-item-references/stock-item-references.scss +4 -4
- package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.component.tsx +15 -9
- package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.scss +1 -0
- package/src/stock-items/add-stock-item/stock-item-rules/delete-stock-rule-modal.component.tsx +2 -1
- package/src/stock-items/add-stock-item/stock-item-rules/stock-item-rules.component.tsx +14 -16
- package/src/stock-items/add-stock-item/stock-item-rules/stock-item-rules.scss +7 -3
- package/src/stock-items/add-stock-item/transactions/printout/transactions-print-bincard-preview.modal.tsx +14 -6
- package/src/stock-items/add-stock-item/transactions/printout/transactions-print-stockcard-preview.modal.tsx +14 -8
- package/src/stock-items/edit-stock-item/edit-stock-item-action-menu.component.tsx +2 -2
- package/src/stock-items/stock-item.utils.tsx +3 -5
- package/src/stock-items/stock-items-table.component.tsx +47 -45
- package/src/stock-items/stock-items-table.resource.ts +2 -2
- package/src/stock-items/stock-items-table.scss +9 -8
- package/src/stock-items/stock-items-table.test.tsx +106 -65
- package/src/stock-items/stock-items.component.tsx +1 -1
- package/src/stock-locations/location-admin-form.component.tsx +5 -4
- package/src/stock-locations/stock-locations-table.component.tsx +10 -8
- package/src/stock-locations/stock-locations.component.tsx +1 -1
- package/src/stock-lookups/stock-lookups.resource.ts +3 -2
- package/src/stock-management-header/stock-management-header.scss +1 -1
- package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operation-expanded-row.scss +1 -1
- package/src/stock-operations/stock-operations-dialog/stock-operations-dialog.component.tsx +2 -2
- package/src/stock-operations/stock-operations-filters.component.tsx +5 -5
- package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +11 -11
- package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +115 -25
- package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +107 -65
- package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +9 -9
- package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +35 -153
- package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +82 -29
- package/src/stock-operations/stock-operations-forms/step1.test.tsx +204 -69
- package/src/stock-operations/stock-operations-forms/step2.test.tsx +140 -63
- package/src/stock-operations/stock-operations-forms/step3.test.tsx +79 -60
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +6 -5
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +12 -11
- package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +1 -0
- package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +20 -12
- package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +1 -0
- package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +1 -3
- package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +2 -1
- package/src/stock-operations/stock-operations-table.component.tsx +66 -73
- package/src/stock-operations/stock-operations-table.scss +18 -9
- package/src/stock-operations/stock-operations.component.tsx +1 -1
- package/src/stock-reports/generate-report/create-stock-report.scss +3 -2
- package/src/stock-reports/generate-report/create-stock-report.workspace.tsx +32 -25
- package/src/stock-reports/report-list/stock-report-parameters.component.tsx +1 -1
- package/src/stock-reports/report-list/stock-report-status.component.tsx +1 -1
- package/src/stock-reports/report-list/stock-reports.component.tsx +24 -25
- package/src/stock-reports/report-list/stock-reports.scss +11 -3
- package/src/stock-sources/add-stock-sources/add-stock-sources.scss +12 -5
- package/src/stock-sources/add-stock-sources/add-stock-sources.test.tsx +38 -36
- package/src/stock-sources/add-stock-sources/add-stock-sources.workspace.tsx +35 -30
- package/src/stock-sources/delete-stock-modal.component.tsx +2 -1
- package/src/stock-sources/delete-stock-modal.scss +1 -1
- package/src/stock-sources/stock-sources-delete/stock-sources-delete.test.tsx +27 -36
- package/src/stock-sources/stock-sources-filter/stock-sources-filter.component.tsx +33 -21
- package/src/stock-sources/stock-sources-items-table.component.tsx +16 -17
- package/src/stock-sources/stock-sources-items-table.resource.ts +8 -6
- package/src/stock-sources/stock-sources-items-table.test.tsx +60 -37
- package/src/stock-sources/stock-sources.component.tsx +1 -1
- package/src/stock-sources/stock-sources.scss +6 -2
- package/src/stock-user-role-scopes/add-stock-user-scope/add-stock-user-role-scope.scss +5 -13
- package/src/stock-user-role-scopes/add-stock-user-scope/add-stock-user-role-scope.workspace.tsx +2 -2
- package/src/stock-user-role-scopes/delete-stock-user-scope-modal.component.tsx +2 -1
- package/src/stock-user-role-scopes/delete-stock-user-scope-modal.scss +1 -1
- package/src/stock-user-role-scopes/stock-user-role-scopes.component.tsx +1 -1
- package/src/stock-user-role-scopes/stock-user-role-scopes.scss +1 -1
- package/translations/en.json +5 -6
- package/tsconfig.json +4 -0
- package/dist/627.js +0 -1
- 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
|
-
|
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.
|
205
|
+
<div className={styles.container}>
|
206
206
|
<TabPanel>{t('ReportDescription', 'List of reports requested by users')}</TabPanel>
|
207
|
-
|
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}>
|
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/
|
2
|
-
@use '@carbon/styles/scss/type';
|
1
|
+
@use '@carbon/colors';
|
3
2
|
@use '@carbon/layout';
|
4
|
-
@use '
|
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 '
|
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/
|
5
|
-
import
|
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
|
7
|
+
import StockSourcesAddOrUpdate from './add-stock-sources.workspace';
|
8
8
|
|
9
|
-
|
9
|
+
const mockCreateOrUpdateStockSource = jest.mocked(createOrUpdateStockSource);
|
10
|
+
const mockUseConfig = jest.mocked(useConfig);
|
10
11
|
|
11
|
-
jest.mock('../stock-sources.resource')
|
12
|
-
jest.
|
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
|
-
|
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(
|
50
|
-
expect(screen.getByLabelText(
|
51
|
-
expect(screen.getByLabelText(
|
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(
|
114
|
-
expect(screen.getByLabelText(
|
115
|
-
expect(screen.getByLabelText(
|
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(
|
130
|
-
await user.type(screen.getByLabelText(
|
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(
|
133
|
-
expect(screen.getByLabelText(
|
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
|
-
|
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(
|
150
|
-
await user.type(screen.getByLabelText(
|
151
|
-
await user.selectOptions(screen.getByLabelText(
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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(
|
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
|
4
|
-
import {
|
5
|
-
import {
|
6
|
-
import {
|
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
|
-
|
7
|
+
getCoreTranslation,
|
9
8
|
restBaseUrl,
|
10
9
|
showSnackbar,
|
10
|
+
type DefaultWorkspaceProps,
|
11
11
|
useConfig,
|
12
|
-
|
12
|
+
useLayoutType,
|
13
13
|
} from '@openmrs/esm-framework';
|
14
|
-
import {
|
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
|
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
|
-
<
|
90
|
+
<Stack gap={5}>
|
86
91
|
<TextInput
|
87
92
|
id="fullname"
|
88
|
-
|
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
|
-
|
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
|
-
|
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
|
-
</
|
122
|
+
</Stack>
|
122
123
|
</div>
|
123
|
-
|
124
|
-
|
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'
|
131
|
+
{getCoreTranslation('cancel')}
|
127
132
|
</Button>
|
128
133
|
<Button type="submit" className={styles.button} onClick={handleSave} kind="primary" renderIcon={Save}>
|
129
|
-
{getCoreTranslation('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
|
-
{
|
32
|
+
{getCoreTranslation('cancel')}
|
32
33
|
</Button>
|
33
34
|
<Button autoFocus kind="danger" onClick={handleDelete} size="lg">
|
34
35
|
{t('delete', 'Delete')}
|
@@ -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 '@
|
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.
|
12
|
-
|
13
|
-
|
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
|
-
|
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:
|
38
|
+
const button = screen.getByRole('button', { name: /delete source/i });
|
46
39
|
await user.click(button);
|
47
|
-
|
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(/
|
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
|
-
|
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(
|
116
|
-
expect(
|
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
|
-
|
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(
|
146
|
-
expect(
|
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
|
-
|
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(
|
179
|
-
|
180
|
-
expect(showSnackbar).toHaveBeenCalledWith({
|
170
|
+
expect(mockDeleteStockSource).toHaveBeenCalledWith([uuid]);
|
171
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
181
172
|
title: 'stockSourceDeleteError',
|
182
173
|
kind: 'error',
|
183
174
|
});
|