@openmrs/esm-stock-management-app 3.0.1-pre.818 → 3.0.1-pre.826
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/dist/10.js +1 -0
- package/dist/10.js.map +1 -0
- package/dist/165.js +1 -1
- package/dist/165.js.map +1 -1
- package/dist/20.js +1 -1
- package/dist/20.js.map +1 -1
- package/dist/642.js +1 -0
- package/dist/642.js.map +1 -0
- package/dist/675.js +1 -0
- package/dist/675.js.map +1 -0
- package/dist/{880.js → 727.js} +1 -1
- package/dist/727.js.map +1 -0
- package/dist/780.js +1 -0
- package/dist/780.js.map +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-stock-management-app.js +1 -1
- package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +129 -56
- package/dist/openmrs-esm-stock-management-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/index.ts +8 -0
- package/src/routes.json +14 -0
- package/src/stock-items/add-stock-item/add-stock-action-button.component.tsx +2 -3
- package/src/stock-items/add-stock-item/add-stock-item.component.tsx +29 -20
- package/src/stock-items/add-stock-item/add-stock-item.scss +22 -3
- package/src/stock-items/add-stock-item/add-stock-item.test.tsx +11 -11
- 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.resource.tsx +1 -1
- package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.component.tsx +226 -214
- package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.resource.tsx +7 -2
- package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rule-button.component.tsx +6 -4
- package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.component.tsx +162 -166
- package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.scss +19 -11
- package/src/stock-items/add-stock-item/stock-item-rules/edit-stock-rule.component.tsx +8 -5
- package/src/stock-items/edit-stock-item/edit-stock-item-action-menu.component.tsx +2 -2
- package/src/stock-items/stock-item.utils.tsx +7 -50
- package/src/stock-items/stock-items-table.component.tsx +2 -2
- package/src/stock-items/stock-items-table.test.tsx +28 -23
- package/src/stock-items/stock-items.resource.ts +7 -5
- package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +1 -0
- package/dist/600.js +0 -1
- package/dist/600.js.map +0 -1
- package/dist/880.js.map +0 -1
@@ -1,5 +1,24 @@
|
|
1
|
+
@use '@carbon/type';
|
2
|
+
@use '@carbon/layout';
|
3
|
+
@use '@carbon/colors';
|
4
|
+
|
1
5
|
.formContainer {
|
2
|
-
|
3
|
-
|
4
|
-
|
6
|
+
display: flex;
|
7
|
+
flex-direction: column;
|
8
|
+
justify-content: space-between;
|
9
|
+
width: 100%;
|
10
|
+
height: 100%;
|
11
|
+
}
|
12
|
+
|
13
|
+
.button {
|
14
|
+
display: flex;
|
15
|
+
align-content: flex-start;
|
16
|
+
align-items: baseline;
|
17
|
+
min-width: 50%;
|
18
|
+
}
|
19
|
+
|
20
|
+
.buttonSet {
|
21
|
+
display: flex;
|
22
|
+
justify-content: space-between;
|
23
|
+
width: 100%;
|
5
24
|
}
|
@@ -22,8 +22,8 @@ jest.mock('@carbon/react/icons', () => ({
|
|
22
22
|
Save: () => <div>Save Icon</div>,
|
23
23
|
}));
|
24
24
|
|
25
|
-
jest.mock('./stock-item-details/stock-item-details.component', () => ({
|
26
|
-
<div data-testid="stock-item-details">Stock Item Details: {
|
25
|
+
jest.mock('./stock-item-details/stock-item-details.component', () => ({ stockItem }) => (
|
26
|
+
<div data-testid="stock-item-details">Stock Item Details: {stockItem?.uuid}</div>
|
27
27
|
));
|
28
28
|
|
29
29
|
jest.mock('./packaging-units/packaging-units.component', () => ({ stockItemUuid }) => (
|
@@ -120,14 +120,14 @@ describe('AddEditStockItem', () => {
|
|
120
120
|
};
|
121
121
|
|
122
122
|
it('renders correctly with initial state and default selected tab', () => {
|
123
|
-
render(<AddEditStockItem
|
123
|
+
render(<AddEditStockItem stockItem={mockModel} />);
|
124
124
|
expect(screen.getByTestId('stock-item-details')).toBeInTheDocument();
|
125
125
|
expect(screen.getByText('Stock Item Details: test-uuid-123')).toBeInTheDocument();
|
126
126
|
});
|
127
127
|
|
128
128
|
it('changes selected tab when clicking on different tabs', async () => {
|
129
129
|
const user = userEvent.setup();
|
130
|
-
render(<AddEditStockItem
|
130
|
+
render(<AddEditStockItem stockItem={mockModel} />);
|
131
131
|
|
132
132
|
await user.click(screen.getByText('packagingUnits'));
|
133
133
|
expect(screen.getByTestId('packaging-units')).toBeInTheDocument();
|
@@ -139,7 +139,7 @@ describe('AddEditStockItem', () => {
|
|
139
139
|
});
|
140
140
|
|
141
141
|
it('disables tabs when isEditing is false', () => {
|
142
|
-
render(<AddEditStockItem
|
142
|
+
render(<AddEditStockItem />);
|
143
143
|
|
144
144
|
const disabledTabs = [
|
145
145
|
'packagingUnits',
|
@@ -150,13 +150,13 @@ describe('AddEditStockItem', () => {
|
|
150
150
|
'references',
|
151
151
|
];
|
152
152
|
disabledTabs.forEach((tabName) => {
|
153
|
-
const tab = screen.getByRole('
|
153
|
+
const tab = screen.getByRole('button', { name: tabName });
|
154
154
|
expect(tab).toHaveAttribute('aria-disabled', 'true');
|
155
155
|
});
|
156
156
|
});
|
157
157
|
|
158
158
|
it('enables tabs when isEditing is true', () => {
|
159
|
-
render(<AddEditStockItem
|
159
|
+
render(<AddEditStockItem stockItem={mockModel} />);
|
160
160
|
|
161
161
|
const enabledTabs = [
|
162
162
|
'packagingUnits',
|
@@ -167,14 +167,14 @@ describe('AddEditStockItem', () => {
|
|
167
167
|
'references',
|
168
168
|
];
|
169
169
|
enabledTabs.forEach((tabName) => {
|
170
|
-
const tab = screen.getByRole('
|
171
|
-
expect(tab).
|
170
|
+
const tab = screen.getByRole('button', { name: tabName });
|
171
|
+
expect(tab).toHaveAttribute('aria-disabled', 'false');
|
172
172
|
});
|
173
173
|
});
|
174
174
|
|
175
175
|
it('renders correct components based on model prop', async () => {
|
176
176
|
const user = userEvent.setup();
|
177
|
-
render(<AddEditStockItem
|
177
|
+
render(<AddEditStockItem stockItem={mockModel} />);
|
178
178
|
|
179
179
|
expect(screen.getByText('Stock Item Details: test-uuid-123')).toBeInTheDocument();
|
180
180
|
|
@@ -198,7 +198,7 @@ describe('AddEditStockItem', () => {
|
|
198
198
|
});
|
199
199
|
|
200
200
|
it('translates tab names correctly', () => {
|
201
|
-
render(<AddEditStockItem
|
201
|
+
render(<AddEditStockItem stockItem={mockModel} />);
|
202
202
|
|
203
203
|
const tabNames = [
|
204
204
|
'stockItemDetails',
|
@@ -1,7 +1,3 @@
|
|
1
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
2
|
-
import { showSnackbar, restBaseUrl } from '@openmrs/esm-framework';
|
3
|
-
import { useTranslation } from 'react-i18next';
|
4
|
-
import { useStockItemPackageUnitsHook } from './packaging-units.resource';
|
5
1
|
import {
|
6
2
|
Button,
|
7
3
|
DataTable,
|
@@ -14,19 +10,22 @@ import {
|
|
14
10
|
TableHeader,
|
15
11
|
TableRow,
|
16
12
|
} from '@carbon/react';
|
17
|
-
import PackagingUnitsConceptSelector from '../packaging-units-concept-selector/packaging-units-concept-selector.component';
|
18
|
-
import ControlledNumberInput from '../../../core/components/carbon/controlled-number-input/controlled-number-input.component';
|
19
13
|
import { Save } from '@carbon/react/icons';
|
20
|
-
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
21
14
|
import { zodResolver } from '@hookform/resolvers/zod';
|
22
|
-
import {
|
15
|
+
import { restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
|
16
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
17
|
+
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
18
|
+
import { useTranslation } from 'react-i18next';
|
23
19
|
import { type StockItemPackagingUOMDTO } from '../../../core/api/types/stockItem/StockItemPackagingUOM';
|
20
|
+
import ControlledNumberInput from '../../../core/components/carbon/controlled-number-input/controlled-number-input.component';
|
21
|
+
import { handleMutate } from '../../../utils';
|
24
22
|
import { createStockItemPackagingUnit, updateStockItemPackagingUnit } from '../../stock-items.resource';
|
23
|
+
import PackagingUnitsConceptSelector from '../packaging-units-concept-selector/packaging-units-concept-selector.component';
|
25
24
|
import DeleteModalButton from './packaging-units-delete-modal-button.component';
|
26
|
-
import {
|
25
|
+
import { useStockItemPackageUnitsHook } from './packaging-units.resource';
|
26
|
+
import { type PackageUnitFormData, packageUnitSchema } from './validationSchema';
|
27
27
|
|
28
28
|
import styles from './packaging-units.scss';
|
29
|
-
import { closeOverlay } from '../../../core/components/overlay/hook';
|
30
29
|
|
31
30
|
interface PackagingUnitsProps {
|
32
31
|
isEditing?: boolean;
|
@@ -24,7 +24,7 @@ export function useStockItemPackageUnitsHook(v?: ResourceRepresentation) {
|
|
24
24
|
const { items, isLoading, error, mutate } = useStockItemPackagingUOMs(stockItemFilter);
|
25
25
|
|
26
26
|
return {
|
27
|
-
items: items.results,
|
27
|
+
items: items.results ?? [],
|
28
28
|
totalCount: items.totalCount,
|
29
29
|
isLoading,
|
30
30
|
error,
|
@@ -1,239 +1,251 @@
|
|
1
|
-
import
|
2
|
-
import { useTranslation } from 'react-i18next';
|
1
|
+
import { Button, ButtonSet, FormGroup, InlineLoading } from '@carbon/react';
|
3
2
|
import { Save } from '@carbon/react/icons';
|
4
|
-
|
5
|
-
import { Button, FormGroup, InlineLoading } from '@carbon/react';
|
6
|
-
import { type StockItemDTO } from '../../../core/api/types/stockItem/StockItem';
|
7
|
-
import DrugSelector from '../drug-selector/drug-selector.component';
|
8
|
-
import { useForm } from 'react-hook-form';
|
9
3
|
import { zodResolver } from '@hookform/resolvers/zod';
|
10
|
-
import {
|
11
|
-
import
|
4
|
+
import { restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
|
5
|
+
import React, { forwardRef, useMemo } from 'react';
|
6
|
+
import { type SubmitHandler, useForm } from 'react-hook-form';
|
7
|
+
import { useTranslation } from 'react-i18next';
|
8
|
+
import { type StockItemDTO } from '../../../core/api/types/stockItem/StockItem';
|
12
9
|
import ControlledNumberInput from '../../../core/components/carbon/controlled-number-input/controlled-number-input.component';
|
10
|
+
import ControlledRadioButtonGroup from '../../../core/components/carbon/controlled-radio-button-group/controlled-radio-button-group.component';
|
13
11
|
import ControlledTextInput from '../../../core/components/carbon/controlled-text-input/controlled-text-input.component';
|
12
|
+
import { handleMutate } from '../../../utils';
|
13
|
+
import styles from '../../add-stock-item/add-stock-item.scss';
|
14
|
+
import { launchAddOrStockItemWorkspace } from '../../stock-item.utils';
|
15
|
+
import { createStockItem, updateStockItem } from '../../stock-items.resource';
|
16
|
+
import { stockItemDetailsSchema, type StockItemFormData } from '../../validationSchema';
|
17
|
+
import ConceptsSelector from '../concepts-selector/concepts-selector.component';
|
14
18
|
import DispensingUnitSelector from '../dispensing-unit-selector/dispensing-unit-selector.component';
|
19
|
+
import DrugSelector from '../drug-selector/drug-selector.component';
|
15
20
|
import PreferredVendorSelector from '../preferred-vendor-selector/preferred-vendor-selector.component';
|
16
21
|
import StockItemCategorySelector from '../stock-item-category-selector/stock-item-category-selector.component';
|
17
22
|
import StockItemUnitsEdit from '../stock-item-units-edit/stock-item-units-edit.component';
|
18
|
-
import {
|
19
|
-
import ConceptsSelector from '../concepts-selector/concepts-selector.component';
|
20
|
-
import styles from '../../add-stock-item/add-stock-item.scss';
|
21
|
-
import { closeOverlay } from '../../../core/components/overlay/hook';
|
22
|
-
import { expirationOptions, radioOptions } from './stock-item-details.resource';
|
23
|
-
import { restBaseUrl } from '@openmrs/esm-framework';
|
24
|
-
import { handleMutate } from '../../../utils';
|
23
|
+
import { expirationOptions, radioOptions, StockItemType } from './stock-item-details.resource';
|
25
24
|
|
26
25
|
interface StockItemDetailsProps {
|
27
|
-
|
28
|
-
onSave: SaveStockItem;
|
29
|
-
isEditing?: boolean;
|
26
|
+
stockItem?: StockItemDTO;
|
30
27
|
handleTabChange: (index) => void;
|
28
|
+
onCloseWorkspace?: () => void;
|
31
29
|
}
|
32
30
|
|
33
|
-
const StockItemDetails = forwardRef<never, StockItemDetailsProps>(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
const StockItemDetails = forwardRef<never, StockItemDetailsProps>(
|
32
|
+
({ stockItem, handleTabChange, onCloseWorkspace }) => {
|
33
|
+
const { t } = useTranslation();
|
34
|
+
const { handleSubmit, control, formState, watch } = useForm<StockItemFormData>({
|
35
|
+
defaultValues: stockItem ?? {},
|
36
|
+
mode: 'all',
|
37
|
+
resolver: zodResolver(stockItemDetailsSchema),
|
38
|
+
});
|
40
39
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
40
|
+
const { errors } = formState;
|
41
|
+
const handleSave: SubmitHandler<StockItemFormData> = async (formValues) => {
|
42
|
+
try {
|
43
|
+
const response = stockItem
|
44
|
+
? await updateStockItem(stockItem?.uuid, formValues)
|
45
|
+
: await createStockItem(formValues);
|
46
|
+
if (response?.data) {
|
47
|
+
showSnackbar({
|
48
|
+
isLowContrast: true,
|
49
|
+
title: stockItem ? `${t('editStockItem', 'Edit Stock Item')}` : `${t('addStockItem', 'Add Stock Item')}`,
|
50
|
+
kind: 'success',
|
51
|
+
subtitle: stockItem
|
52
|
+
? `${t('stockItemEdited', 'Stock Item Edited Successfully')}`
|
53
|
+
: `${t('stockItemAdded', 'Stock Item Added Successfully')}`,
|
54
|
+
});
|
55
|
+
if (!stockItem) {
|
56
|
+
onCloseWorkspace?.();
|
57
|
+
// launch edit dialog
|
58
|
+
const item = response.data;
|
59
|
+
item.isDrug = !!item.drugUuid;
|
60
|
+
launchAddOrStockItemWorkspace(t, item);
|
61
|
+
}
|
62
|
+
}
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
handleTabChange(1);
|
65
|
+
handleMutate(`${restBaseUrl}/stockmanagement/stockitem`);
|
66
|
+
} catch (e) {
|
67
|
+
// Show notification
|
68
|
+
showSnackbar({
|
69
|
+
title: stockItem
|
70
|
+
? t('errorEditingStockItem', 'Error editing a stock Item')
|
71
|
+
: t('errorAddingStockItem', 'Error adding a stock Item'),
|
72
|
+
kind: 'error',
|
73
|
+
isLowContrast: true,
|
74
|
+
subtitle: e?.responseBody?.error?.message,
|
75
|
+
});
|
76
|
+
}
|
77
|
+
};
|
78
|
+
const [observableIsDrug, observableHasExpiration] = watch(['isDrug', 'hasExpiration']);
|
79
|
+
const selectedItemType = useMemo<StockItemType | null>(() => {
|
80
|
+
if (observableIsDrug === true) return StockItemType.PHARMACEUTICALS;
|
81
|
+
else if (observableIsDrug === false) return StockItemType.NONE_PHARMACEUTICALS;
|
82
|
+
return null;
|
83
|
+
}, [observableIsDrug]);
|
67
84
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
85
|
+
return (
|
86
|
+
<form className={styles.formContainer}>
|
87
|
+
<div>
|
88
|
+
{!stockItem && (
|
89
|
+
<FormGroup
|
90
|
+
className="clear-margin-bottom"
|
91
|
+
legendText={t('itemType', 'Item Type')}
|
92
|
+
title={t('itemType', 'Item Type')}
|
93
|
+
>
|
94
|
+
<ControlledRadioButtonGroup
|
95
|
+
control={control}
|
96
|
+
name="isDrug"
|
97
|
+
controllerName="isDrug"
|
98
|
+
legendText=""
|
99
|
+
invalid={!!errors.isDrug}
|
100
|
+
invalidText={errors.isDrug && errors?.isDrug?.message}
|
101
|
+
options={radioOptions} // Pass radioOptions directly
|
102
|
+
/>
|
103
|
+
</FormGroup>
|
104
|
+
)}
|
105
|
+
{selectedItemType === StockItemType.PHARMACEUTICALS ? (
|
106
|
+
<DrugSelector
|
107
|
+
name="drugUuid"
|
108
|
+
controllerName="drugUuid"
|
109
|
+
control={control}
|
110
|
+
title={t('pleaseSpecify', 'Please specify:')}
|
111
|
+
placeholder="Choose a drug"
|
112
|
+
drugUuid={stockItem?.drugUuid}
|
113
|
+
invalid={!!errors.drugUuid}
|
114
|
+
invalidText={errors.drugUuid && errors?.drugUuid?.message}
|
115
|
+
/>
|
116
|
+
) : selectedItemType === StockItemType.NONE_PHARMACEUTICALS ? (
|
117
|
+
<ConceptsSelector
|
118
|
+
name="conceptUuid"
|
119
|
+
controllerName="conceptUuid"
|
120
|
+
control={control}
|
121
|
+
title={t('pleaseSpecify', 'Please specify') + ':'}
|
122
|
+
placeholder={t('chooseAnItem', 'Choose an item')}
|
123
|
+
invalid={!!errors.drugUuid}
|
124
|
+
invalidText={errors.drugUuid && errors?.drugUuid?.message}
|
125
|
+
/>
|
126
|
+
) : null}
|
127
|
+
<ControlledTextInput
|
128
|
+
id="commonName"
|
129
|
+
name="commonName"
|
77
130
|
control={control}
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
const selectedLabel = selectedOption ? selectedOption.label : '';
|
86
|
-
setIsDrug(selectedValue === 'true');
|
87
|
-
setSelectedItemType(selectedLabel);
|
88
|
-
}}
|
89
|
-
options={radioOptions} // Pass radioOptions directly
|
131
|
+
controllerName="commonName"
|
132
|
+
maxLength={255}
|
133
|
+
size={'md'}
|
134
|
+
value={`${stockItem?.commonName ?? ''}`}
|
135
|
+
labelText={t('commonName', 'Common name') + ':'}
|
136
|
+
invalid={!!errors.commonName}
|
137
|
+
invalidText={errors.commonName && errors?.commonName?.message}
|
90
138
|
/>
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
name="drugUuid"
|
96
|
-
controllerName="drugUuid"
|
97
|
-
control={control}
|
98
|
-
title={t('pleaseSpecify', 'Please specify:')}
|
99
|
-
placeholder="Choose a drug"
|
100
|
-
drugUuid={model.drugUuid}
|
101
|
-
invalid={!!errors.drugUuid}
|
102
|
-
invalidText={errors.drugUuid && errors?.drugUuid?.message}
|
103
|
-
/>
|
104
|
-
) : selectedItemType === 'Non Pharmaceuticals' ? (
|
105
|
-
<ConceptsSelector
|
106
|
-
name="conceptUuid"
|
107
|
-
controllerName="conceptUuid"
|
108
|
-
control={control}
|
109
|
-
title={t('pleaseSpecify', 'Please specify') + ':'}
|
110
|
-
placeholder={t('chooseAnItem', 'Choose an item')}
|
111
|
-
invalid={!!errors.drugUuid}
|
112
|
-
invalidText={errors.drugUuid && errors?.drugUuid?.message}
|
113
|
-
/>
|
114
|
-
) : null}
|
115
|
-
<ControlledTextInput
|
116
|
-
id="commonName"
|
117
|
-
name="commonName"
|
118
|
-
control={control}
|
119
|
-
controllerName="commonName"
|
120
|
-
maxLength={255}
|
121
|
-
size={'md'}
|
122
|
-
value={`${model?.commonName ?? ''}`}
|
123
|
-
labelText={t('commonName', 'Common name') + ':'}
|
124
|
-
invalid={!!errors.commonName}
|
125
|
-
invalidText={errors.commonName && errors?.commonName?.message}
|
126
|
-
/>
|
127
|
-
<ControlledTextInput
|
128
|
-
id="acronym"
|
129
|
-
maxLength={255}
|
130
|
-
name="acronym"
|
131
|
-
control={control}
|
132
|
-
controllerName="acronym"
|
133
|
-
size={'md'}
|
134
|
-
labelText={t('abbreviation', 'Abbreviation') + ':'}
|
135
|
-
invalid={!!errors.acronym}
|
136
|
-
invalidText={errors.acronym && errors?.acronym?.message}
|
137
|
-
/>
|
138
|
-
<div
|
139
|
-
style={{
|
140
|
-
display: 'grid',
|
141
|
-
gridTemplateColumns: '1fr 1fr',
|
142
|
-
justifyContent: 'center',
|
143
|
-
}}
|
144
|
-
>
|
145
|
-
<FormGroup
|
146
|
-
className="clear-margin-bottom"
|
147
|
-
legendText={t('hasExpiration', 'Does the item expire?')}
|
148
|
-
title={t('hasExpiration', 'Does the item expire?')}
|
149
|
-
>
|
150
|
-
<ControlledRadioButtonGroup
|
151
|
-
name="hasExpiration"
|
152
|
-
controllerName="hasExpiration"
|
139
|
+
<ControlledTextInput
|
140
|
+
id="acronym"
|
141
|
+
maxLength={255}
|
142
|
+
name="acronym"
|
153
143
|
control={control}
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
}}
|
160
|
-
options={expirationOptions} // Pass expirationOptions directly
|
144
|
+
controllerName="acronym"
|
145
|
+
size={'md'}
|
146
|
+
labelText={t('abbreviation', 'Abbreviation') + ':'}
|
147
|
+
invalid={!!errors.acronym}
|
148
|
+
invalidText={errors.acronym && errors?.acronym?.message}
|
161
149
|
/>
|
162
|
-
|
150
|
+
<div
|
151
|
+
style={{
|
152
|
+
display: 'grid',
|
153
|
+
gridTemplateColumns: '1fr 1fr',
|
154
|
+
justifyContent: 'center',
|
155
|
+
}}
|
156
|
+
>
|
157
|
+
<FormGroup
|
158
|
+
className="clear-margin-bottom"
|
159
|
+
legendText={t('hasExpiration', 'Does the item expire?')}
|
160
|
+
title={t('hasExpiration', 'Does the item expire?')}
|
161
|
+
>
|
162
|
+
<ControlledRadioButtonGroup
|
163
|
+
name="hasExpiration"
|
164
|
+
controllerName="hasExpiration"
|
165
|
+
control={control}
|
166
|
+
legendText=""
|
167
|
+
invalid={!!errors.hasExpiration}
|
168
|
+
invalidText={errors.hasExpiration && errors?.hasExpiration?.message}
|
169
|
+
options={expirationOptions} // Pass expirationOptions directly
|
170
|
+
/>
|
171
|
+
</FormGroup>
|
163
172
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
173
|
+
{observableHasExpiration && (
|
174
|
+
<FormGroup className="clear-margin-bottom" title={t('expirationNotice', 'Expiration Notice (days)')}>
|
175
|
+
<ControlledNumberInput
|
176
|
+
id="expiryNotice"
|
177
|
+
name="expiryNotice"
|
178
|
+
control={control}
|
179
|
+
controllerName="expiryNotice"
|
180
|
+
min={0}
|
181
|
+
hideSteppers={true}
|
182
|
+
size={'md'}
|
183
|
+
allowEmpty={true}
|
184
|
+
label={t('expiryNoticeDays', 'Expiration Notice (days)')}
|
185
|
+
invalid={!!errors.expiryNotice}
|
186
|
+
invalidText={errors.expiryNotice && errors?.expiryNotice?.message}
|
187
|
+
/>
|
188
|
+
</FormGroup>
|
189
|
+
)}
|
190
|
+
</div>
|
191
|
+
<PreferredVendorSelector
|
192
|
+
name="preferredVendorUuid"
|
193
|
+
controllerName="preferredVendorUuid"
|
194
|
+
control={control}
|
195
|
+
title={t('whoIsThePreferredVendor', 'Who is the preferred vendor?')}
|
196
|
+
placeholder={t('chooseVendor', 'Choose vendor')}
|
197
|
+
invalid={!!errors.preferredVendorUuid}
|
198
|
+
invalidText={errors.preferredVendorUuid && errors?.preferredVendorUuid?.message}
|
199
|
+
/>
|
200
|
+
<StockItemCategorySelector
|
201
|
+
name="categoryUuid"
|
202
|
+
controllerName="categoryUuid"
|
203
|
+
control={control}
|
204
|
+
itemType={
|
205
|
+
selectedItemType === StockItemType.PHARMACEUTICALS
|
206
|
+
? 'Drugs'
|
207
|
+
: selectedItemType === StockItemType.NONE_PHARMACEUTICALS
|
208
|
+
? 'Non Drugs'
|
209
|
+
: undefined
|
210
|
+
}
|
211
|
+
title={t('category', 'Category') + ':'}
|
212
|
+
placeholder={t('chooseACategory', 'Choose a category')}
|
213
|
+
invalid={!!errors.categoryUuid}
|
214
|
+
invalidText={errors.categoryUuid && errors?.categoryUuid?.message}
|
215
|
+
/>
|
216
|
+
{observableIsDrug && (
|
217
|
+
<DispensingUnitSelector
|
218
|
+
name="dispensingUnitUuid"
|
219
|
+
controllerName="dispensingUnitUuid"
|
169
220
|
control={control}
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
allowEmpty={true}
|
175
|
-
label={t('expiryNoticeDays', 'Expiration Notice (days)')}
|
176
|
-
invalid={!!errors.expiryNotice}
|
177
|
-
invalidText={errors.expiryNotice && errors?.expiryNotice?.message}
|
221
|
+
title={t('dispensingUnit', 'Dispensing Unit') + ':'}
|
222
|
+
placeholder={t('dispensingUnitHolder', 'Choose a dispensing unit')}
|
223
|
+
invalid={!!errors.dispensingUnitUuid}
|
224
|
+
invalidText={errors.dispensingUnitUuid && errors?.dispensingUnitUuid?.message}
|
178
225
|
/>
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
placeholder={t('chooseACategory', 'Choose a category')}
|
204
|
-
invalid={!!errors.categoryUuid}
|
205
|
-
invalidText={errors.categoryUuid && errors?.categoryUuid?.message}
|
206
|
-
/>
|
207
|
-
{isDrug && (
|
208
|
-
<DispensingUnitSelector
|
209
|
-
name="dispensingUnitUuid"
|
210
|
-
controllerName="dispensingUnitUuid"
|
211
|
-
control={control}
|
212
|
-
title={t('dispensingUnit', 'Dispensing Unit') + ':'}
|
213
|
-
placeholder={t('dispensingUnitHolder', 'Choose a dispensing unit')}
|
214
|
-
invalid={!!errors.dispensingUnitUuid}
|
215
|
-
invalidText={errors.dispensingUnitUuid && errors?.dispensingUnitUuid?.message}
|
216
|
-
/>
|
217
|
-
)}
|
218
|
-
{isDrug && isEditing && <StockItemUnitsEdit control={control} formState={formState} stockItemUuid={model.uuid} />}
|
219
|
-
|
220
|
-
<div style={{ display: 'flex', flexDirection: 'row-reverse' }}>
|
221
|
-
<Button
|
222
|
-
name="save"
|
223
|
-
type="button"
|
224
|
-
className="submitButton"
|
225
|
-
onClick={handleSubmit(handleSave)}
|
226
|
-
kind="primary"
|
227
|
-
renderIcon={Save}
|
228
|
-
>
|
229
|
-
{isSaving ? <InlineLoading /> : t('save', 'Save')}
|
230
|
-
</Button>
|
231
|
-
<Button kind="secondary" onClick={closeOverlay}>
|
232
|
-
{t('cancel', 'Cancel')}
|
233
|
-
</Button>
|
234
|
-
</div>
|
235
|
-
</form>
|
236
|
-
);
|
237
|
-
});
|
226
|
+
)}
|
227
|
+
{observableIsDrug && stockItem && (
|
228
|
+
<StockItemUnitsEdit control={control} formState={formState} stockItemUuid={stockItem?.uuid} />
|
229
|
+
)}
|
230
|
+
</div>
|
231
|
+
<ButtonSet className={styles.buttonSet}>
|
232
|
+
<Button kind="secondary" onClick={onCloseWorkspace} className={styles.button}>
|
233
|
+
{t('cancel', 'Cancel')}
|
234
|
+
</Button>
|
235
|
+
<Button
|
236
|
+
name="save"
|
237
|
+
type="button"
|
238
|
+
className={styles.button}
|
239
|
+
onClick={handleSubmit(handleSave)}
|
240
|
+
kind="primary"
|
241
|
+
renderIcon={Save}
|
242
|
+
>
|
243
|
+
{formState.isSubmitting ? <InlineLoading /> : t('save', 'Save')}
|
244
|
+
</Button>
|
245
|
+
</ButtonSet>
|
246
|
+
</form>
|
247
|
+
);
|
248
|
+
},
|
249
|
+
);
|
238
250
|
|
239
251
|
export default StockItemDetails;
|
@@ -3,9 +3,14 @@ export interface RadioOption {
|
|
3
3
|
value: boolean;
|
4
4
|
}
|
5
5
|
|
6
|
+
export enum StockItemType {
|
7
|
+
PHARMACEUTICALS = 'Pharmaceuticals',
|
8
|
+
NONE_PHARMACEUTICALS = 'Non Pharmaceuticals',
|
9
|
+
}
|
10
|
+
|
6
11
|
export const radioOptions: RadioOption[] = [
|
7
|
-
{ label:
|
8
|
-
{ label:
|
12
|
+
{ label: StockItemType.PHARMACEUTICALS, value: true },
|
13
|
+
{ label: StockItemType.NONE_PHARMACEUTICALS, value: false },
|
9
14
|
];
|
10
15
|
|
11
16
|
export const expirationOptions: RadioOption[] = [
|