@digihmis/esm-administration-app 1.0.0 → 1.0.2
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/145.js +1 -0
- package/dist/145.js.map +1 -0
- package/dist/153.js +1 -1
- package/dist/153.js.map +1 -1
- package/dist/402.js +1 -0
- package/dist/402.js.map +1 -0
- package/dist/594.js +1 -0
- package/dist/594.js.map +1 -0
- package/dist/598.js +1 -1
- package/dist/598.js.map +1 -1
- package/dist/625.js +15 -0
- package/dist/{916.js.map → 625.js.map} +1 -1
- package/dist/{685.js → 631.js} +1 -1
- package/dist/631.js.map +1 -0
- package/dist/681.js +1 -0
- package/dist/681.js.map +1 -0
- package/dist/737.js +1 -1
- package/dist/737.js.map +1 -1
- package/dist/{266.js → 947.js} +1 -1
- package/dist/947.js.map +1 -0
- package/dist/digihmis-esm-administration-app.js +2 -2
- package/dist/digihmis-esm-administration-app.js.buildmanifest.json +140 -140
- package/dist/digihmis-esm-administration-app.js.map +1 -1
- package/dist/main.js +6 -6
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +3 -2
- package/release-version.js +4 -4
- package/src/billing-management/billing-charge-items/billing-charge-items-modal/billing-charge-items.resource.ts +2 -1
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/billing-charge-items.resource.ts +30 -7
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/billing-charge-service.workspace.tsx +79 -107
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/components/price.component.scss +16 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/components/price.component.tsx +30 -20
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/schemas/form-schemas.ts +19 -14
- package/src/billing-management/billing-charge-items/billing-charge-items.component.tsx +26 -35
- package/src/billing-management/billing-charge-items/billing-charge-items.resource.ts +1 -1
- package/src/billing-management/billing-charge-items/type/index.ts +10 -10
- package/src/billing-management/billing-charge-items/utils/index.ts +32 -74
- package/src/billing-management/billing-payment-modes/billing-payment-modes.component.tsx +24 -166
- package/src/billing-management/billing-payment-modes/billing-payment-modes.resource.ts +24 -14
- package/src/billing-management/billing-payment-points/billing-payment-point-modal/billing-delete-payment-point.modal.tsx +1 -1
- package/src/billing-management/billing-payment-points/billing-payment-point.resource.ts +1 -1
- package/src/billing-management/billing-payment-points/billing-payment-point.scss +47 -0
- package/src/billing-management/billing-payment-points/billing-payment-points-workspace/billing-payment-point.resource.ts +18 -23
- package/src/billing-management/billing-payment-points/billing-payment-points-workspace/billing-payment-points.workspace.tsx +1 -1
- package/src/config-schema.ts +17 -0
- package/src/dashboard.meta.ts +8 -0
- package/src/document-branding/document-branding-workspace/document-branding.workspace.scss +34 -0
- package/src/document-branding/document-branding-workspace/document-branding.workspace.tsx +160 -0
- package/src/document-branding/document-branding.component.tsx +185 -0
- package/src/document-branding/document-branding.resource.ts +54 -0
- package/src/document-branding/document-branding.scss +69 -0
- package/src/index.ts +15 -9
- package/src/routes.json +34 -13
- package/dist/101.js +0 -1
- package/dist/101.js.map +0 -1
- package/dist/190.js +0 -1
- package/dist/190.js.map +0 -1
- package/dist/266.js.map +0 -1
- package/dist/606.js +0 -1
- package/dist/606.js.map +0 -1
- package/dist/685.js.map +0 -1
- package/dist/747.js +0 -1
- package/dist/747.js.map +0 -1
- package/dist/916.js +0 -15
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/billing-charge-item.workspace.tsx +0 -212
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/components/stock-search.component.tsx +0 -107
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useMemo } from 'react';
|
|
2
|
-
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { ButtonSet, Button, Stack, Toggle, InlineNotification, InlineLoading } from '@carbon/react';
|
|
4
|
-
import { Add } from '@carbon/react/icons';
|
|
5
|
-
import { useForm, FormProvider, useFieldArray, Controller } from 'react-hook-form';
|
|
6
|
-
|
|
7
|
-
import { type DefaultWorkspaceProps, useLayoutType, ResponsiveWrapper, showSnackbar, restBaseUrl } from '@openmrs/esm-framework';
|
|
8
|
-
import styles from './global/billing-charge-commodity.scss';
|
|
9
|
-
import classNames from 'classnames';
|
|
10
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
11
|
-
import PriceField from './components/price.component';
|
|
12
|
-
import { billableFormSchema, BillableFormSchema } from './schemas/form-schemas';
|
|
13
|
-
import { handleMutation } from '../../billing-payment-modes/billing-payment-modes-workspace/billing-payment-modes.resource';
|
|
14
|
-
import { formatBillableServicePayloadForSubmission, mapInputToPayloadSchema } from '../utils';
|
|
15
|
-
import { createBillableService } from './billing-charge-items.resource';
|
|
16
|
-
import StockItemSearch from './components/stock-search.component';
|
|
17
|
-
|
|
18
|
-
type CommodityFormProps = DefaultWorkspaceProps & {
|
|
19
|
-
initialValues?: BillableFormSchema;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const CommodityForm: React.FC<CommodityFormProps> = ({
|
|
23
|
-
closeWorkspace,
|
|
24
|
-
closeWorkspaceWithSavedChanges,
|
|
25
|
-
promptBeforeClosing,
|
|
26
|
-
initialValues,
|
|
27
|
-
}) => {
|
|
28
|
-
const { t } = useTranslation();
|
|
29
|
-
const isTablet = useLayoutType() === 'tablet';
|
|
30
|
-
const formMethods = useForm<BillableFormSchema>({
|
|
31
|
-
resolver: zodResolver(billableFormSchema),
|
|
32
|
-
defaultValues: initialValues
|
|
33
|
-
? {
|
|
34
|
-
...mapInputToPayloadSchema(initialValues),
|
|
35
|
-
serviceType: {
|
|
36
|
-
uuid: initialValues.serviceType?.uuid ?? '',
|
|
37
|
-
display: initialValues.serviceType?.display ?? '',
|
|
38
|
-
},
|
|
39
|
-
}
|
|
40
|
-
: { servicePrices: [], serviceStatus: 'ENABLED' },
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const {
|
|
44
|
-
setValue,
|
|
45
|
-
control,
|
|
46
|
-
handleSubmit,
|
|
47
|
-
trigger,
|
|
48
|
-
formState: { errors, isDirty, isSubmitting },
|
|
49
|
-
} = formMethods;
|
|
50
|
-
|
|
51
|
-
const { fields, append, remove } = useFieldArray({
|
|
52
|
-
control,
|
|
53
|
-
name: 'servicePrices',
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
useEffect(() => {
|
|
57
|
-
if (initialValues) {
|
|
58
|
-
trigger();
|
|
59
|
-
}
|
|
60
|
-
}, [initialValues, trigger]);
|
|
61
|
-
|
|
62
|
-
const onSubmit = async (formValues: BillableFormSchema) => {
|
|
63
|
-
const payload = formatBillableServicePayloadForSubmission(formValues, initialValues?.['uuid']);
|
|
64
|
-
try {
|
|
65
|
-
const response = await createBillableService(payload, initialValues?.['uuid']);
|
|
66
|
-
if (response.ok) {
|
|
67
|
-
showSnackbar({
|
|
68
|
-
title: t('commodityBillableCreated', 'Commodity price created successfully'),
|
|
69
|
-
subtitle: t('commodityBillableCreatedSubtitle', 'The commodity price has been created successfully'),
|
|
70
|
-
kind: 'success',
|
|
71
|
-
isLowContrast: true,
|
|
72
|
-
timeoutInMs: 5000,
|
|
73
|
-
});
|
|
74
|
-
handleMutation(`${restBaseUrl}/cashier/billableService?v`);
|
|
75
|
-
closeWorkspaceWithSavedChanges();
|
|
76
|
-
}
|
|
77
|
-
} catch (e) {
|
|
78
|
-
const errorMessage =
|
|
79
|
-
e?.responseBody?.error?.message || e?.message || t('unknownError', 'An unknown error occurred');
|
|
80
|
-
showSnackbar({
|
|
81
|
-
title: t('commodityBillableCreationFailed', 'Commodity price creation failed'),
|
|
82
|
-
subtitle: t(
|
|
83
|
-
'commodityBillableCreationFailedSubtitle',
|
|
84
|
-
'The commodity price creation failed: {{errorMessage}}',
|
|
85
|
-
{
|
|
86
|
-
errorMessage: String(errorMessage).trim(),
|
|
87
|
-
},
|
|
88
|
-
),
|
|
89
|
-
kind: 'error',
|
|
90
|
-
isLowContrast: true,
|
|
91
|
-
timeoutInMs: 5000,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
promptBeforeClosing(() => isDirty);
|
|
98
|
-
}, [isDirty, promptBeforeClosing]);
|
|
99
|
-
|
|
100
|
-
const renderServicePriceFields = useMemo(
|
|
101
|
-
() =>
|
|
102
|
-
fields.map((field, index) => (
|
|
103
|
-
<PriceField
|
|
104
|
-
key={field.id}
|
|
105
|
-
field={field}
|
|
106
|
-
index={index}
|
|
107
|
-
control={control}
|
|
108
|
-
removeServicePrice={remove}
|
|
109
|
-
errors={errors}
|
|
110
|
-
/>
|
|
111
|
-
)),
|
|
112
|
-
[fields, control, remove, errors],
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
function flattenErrors(errors: Record<string, any>): string[] {
|
|
116
|
-
const messages: string[] = [];
|
|
117
|
-
|
|
118
|
-
Object.entries(errors).forEach(([key, value]) => {
|
|
119
|
-
if (Array.isArray(value)) {
|
|
120
|
-
value.forEach((item, index) => {
|
|
121
|
-
Object.entries(item as Record<string, { message: string }>).forEach(([subKey, subVal]) => {
|
|
122
|
-
messages.push(`${key}[${index}].${subKey}: ${subVal.message}`);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
} else if (typeof value === 'object' && value?.message) {
|
|
126
|
-
messages.push(`${key}: ${value.message}`);
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
return messages;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const handleError = (err) => {
|
|
134
|
-
console.error(JSON.stringify(err, null, 2));
|
|
135
|
-
const errorMessage = flattenErrors(err).join('; ');
|
|
136
|
-
showSnackbar({
|
|
137
|
-
title: t('serviceCreationFailed', 'Service creation failed'),
|
|
138
|
-
subtitle: t('serviceCreationFailedSubtitle', 'The service creation failed: {{errorMessage}}', {
|
|
139
|
-
errorMessage,
|
|
140
|
-
}),
|
|
141
|
-
kind: 'error',
|
|
142
|
-
isLowContrast: true,
|
|
143
|
-
timeoutInMs: 5000,
|
|
144
|
-
});
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
return (
|
|
148
|
-
<FormProvider {...formMethods}>
|
|
149
|
-
<form onSubmit={handleSubmit(onSubmit, handleError)} className={styles.form}>
|
|
150
|
-
<div className={styles.formContainer}>
|
|
151
|
-
<Stack className={styles.formStackControl} gap={7}>
|
|
152
|
-
<StockItemSearch setValue={setValue} defaultStockItem={initialValues?.name} />
|
|
153
|
-
{errors.concept && (
|
|
154
|
-
<InlineNotification
|
|
155
|
-
kind="error"
|
|
156
|
-
lowContrast={true}
|
|
157
|
-
title={t('conceptMissing', 'Concept missing for {{name}}', { name: initialValues?.name })}
|
|
158
|
-
subtitle={t('conceptMissingSubtitle', 'Please delete the current item and re-create the charge item')}
|
|
159
|
-
/>
|
|
160
|
-
)}
|
|
161
|
-
<ResponsiveWrapper>
|
|
162
|
-
<Controller
|
|
163
|
-
control={control}
|
|
164
|
-
name="serviceStatus"
|
|
165
|
-
render={({ field }) => (
|
|
166
|
-
<Toggle
|
|
167
|
-
labelText={t('status', 'Status')}
|
|
168
|
-
labelA="Off"
|
|
169
|
-
labelB="On"
|
|
170
|
-
defaultToggled={field.value === 'ENABLED'}
|
|
171
|
-
id="serviceStatus"
|
|
172
|
-
onToggle={(value) => (value ? field.onChange('ENABLED') : field.onChange('DISABLED'))}
|
|
173
|
-
/>
|
|
174
|
-
)}
|
|
175
|
-
/>
|
|
176
|
-
</ResponsiveWrapper>
|
|
177
|
-
{renderServicePriceFields}
|
|
178
|
-
<Button size="sm" kind="tertiary" renderIcon={Add} onClick={() => append({})}>
|
|
179
|
-
{t('addPaymentMethod', 'Add payment method')}
|
|
180
|
-
</Button>
|
|
181
|
-
{!!errors.servicePrices && (
|
|
182
|
-
<InlineNotification
|
|
183
|
-
aria-label="closes notification"
|
|
184
|
-
kind="error"
|
|
185
|
-
lowContrast={true}
|
|
186
|
-
statusIconDescription="notification"
|
|
187
|
-
title={t('paymentMethodRequired', 'Payment method required')}
|
|
188
|
-
subtitle={t('atLeastOnePriceRequired', 'At least one price is required')}
|
|
189
|
-
/>
|
|
190
|
-
)}
|
|
191
|
-
</Stack>
|
|
192
|
-
</div>
|
|
193
|
-
<ButtonSet className={classNames({ [styles.tablet]: isTablet, [styles.desktop]: !isTablet })}>
|
|
194
|
-
<Button style={{ maxWidth: '50%' }} kind="secondary" onClick={() => closeWorkspace()}>
|
|
195
|
-
{t('cancel', 'Cancel')}
|
|
196
|
-
</Button>
|
|
197
|
-
<Button disabled={isSubmitting || !isDirty} style={{ maxWidth: '50%' }} kind="primary" type="submit">
|
|
198
|
-
{isSubmitting ? (
|
|
199
|
-
<span style={{ display: 'flex', justifyItems: 'center' }}>
|
|
200
|
-
{t('submitting', 'Submitting...')} <InlineLoading status="active" iconDescription="Loading" />
|
|
201
|
-
</span>
|
|
202
|
-
) : (
|
|
203
|
-
t('saveAndClose', 'Save & close')
|
|
204
|
-
)}
|
|
205
|
-
</Button>
|
|
206
|
-
</ButtonSet>
|
|
207
|
-
</form>
|
|
208
|
-
</FormProvider>
|
|
209
|
-
);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
export default CommodityForm;
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { FormGroup, Search, InlineLoading } from '@carbon/react';
|
|
4
|
-
import { ErrorState, ResponsiveWrapper, useDebounce } from '@openmrs/esm-framework';
|
|
5
|
-
import type { UseFormSetValue } from 'react-hook-form';
|
|
6
|
-
import styles from '../global/billing-charge-commodity.scss';
|
|
7
|
-
import { formatStockItemToPayload } from '../../utils';
|
|
8
|
-
import { BillableFormSchema } from '../schemas/form-schemas';
|
|
9
|
-
import { useCommodityItem } from '../billing-charge-items.resource';
|
|
10
|
-
|
|
11
|
-
interface StockItem {
|
|
12
|
-
uuid: string;
|
|
13
|
-
commonName: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type StockItemSearchProps = {
|
|
17
|
-
setValue: UseFormSetValue<BillableFormSchema>;
|
|
18
|
-
defaultStockItem?: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const StockItemSearch: React.FC<StockItemSearchProps> = ({ setValue, defaultStockItem }) => {
|
|
22
|
-
const { t } = useTranslation();
|
|
23
|
-
const [inputValue, setInputValue] = useState<string>(defaultStockItem ?? '');
|
|
24
|
-
const [searchTerm, setSearchTerm] = useState<string>(defaultStockItem ? '' : '');
|
|
25
|
-
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
26
|
-
const [selectedStockItem, setSelectedStockItem] = useState<StockItem | null>(null);
|
|
27
|
-
|
|
28
|
-
const { stockItems = [], isLoading, error } = useCommodityItem(debouncedSearchTerm);
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (defaultStockItem && !selectedStockItem) {
|
|
32
|
-
setSelectedStockItem(stockItems.find((item) => item.uuid === defaultStockItem) ?? null);
|
|
33
|
-
}
|
|
34
|
-
}, [defaultStockItem, selectedStockItem, setValue, stockItems]);
|
|
35
|
-
|
|
36
|
-
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
37
|
-
const v = e?.currentTarget?.value ?? '';
|
|
38
|
-
setInputValue(v);
|
|
39
|
-
setSearchTerm(v);
|
|
40
|
-
setSelectedStockItem(null);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const handleClear = () => {
|
|
44
|
-
setInputValue('');
|
|
45
|
-
setSearchTerm('');
|
|
46
|
-
setSelectedStockItem(null);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const handleStockItemSelect = (item: StockItem) => {
|
|
50
|
-
setSelectedStockItem(item);
|
|
51
|
-
setInputValue(item.commonName);
|
|
52
|
-
setSearchTerm(''); // hide results
|
|
53
|
-
const payload = formatStockItemToPayload(item);
|
|
54
|
-
Object.entries(payload).forEach(([key, value]) => {
|
|
55
|
-
setValue(key as keyof BillableFormSchema, value);
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
if (error) {
|
|
60
|
-
return <ErrorState headerTitle={t('stockItemError', 'Stock Item')} error={error} />;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<FormGroup className={styles.formGroupWithConcept} legendText={t('searchForCommodity', 'Search for commodity')}>
|
|
65
|
-
<ResponsiveWrapper>
|
|
66
|
-
<Search
|
|
67
|
-
placeholder={t('searchForCommodity', 'Search for commodity')}
|
|
68
|
-
labelText={t('search', 'Search')}
|
|
69
|
-
closeButtonLabelText={t('clear', 'Clear')}
|
|
70
|
-
value={inputValue}
|
|
71
|
-
onChange={handleInputChange}
|
|
72
|
-
onClear={handleClear}
|
|
73
|
-
disabled={Boolean(defaultStockItem)}
|
|
74
|
-
/>
|
|
75
|
-
</ResponsiveWrapper>
|
|
76
|
-
|
|
77
|
-
{isLoading && (
|
|
78
|
-
<div className={styles.searchResults}>
|
|
79
|
-
<InlineLoading status="active" iconDescription="Loading" description={t('loadingData', 'Loading data...')} />
|
|
80
|
-
</div>
|
|
81
|
-
)}
|
|
82
|
-
|
|
83
|
-
{!isLoading && stockItems.length > 0 && searchTerm && (
|
|
84
|
-
<div className={styles.searchResults} role="listbox">
|
|
85
|
-
{stockItems.map((item) => (
|
|
86
|
-
<div
|
|
87
|
-
key={item.uuid}
|
|
88
|
-
className={styles.searchItem}
|
|
89
|
-
role="option"
|
|
90
|
-
aria-selected={selectedStockItem?.uuid === item.uuid}
|
|
91
|
-
tabIndex={0}
|
|
92
|
-
onClick={() => handleStockItemSelect(item)}
|
|
93
|
-
onKeyPress={(e) => {
|
|
94
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
95
|
-
handleStockItemSelect(item);
|
|
96
|
-
}
|
|
97
|
-
}}>
|
|
98
|
-
{item.commonName}
|
|
99
|
-
</div>
|
|
100
|
-
))}
|
|
101
|
-
</div>
|
|
102
|
-
)}
|
|
103
|
-
</FormGroup>
|
|
104
|
-
);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
export default StockItemSearch;
|