@kenyaemr/esm-billing-app 5.4.1-pre.2010 → 5.4.1-pre.2018
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/.turbo/turbo-build.log +61 -61
- package/dist/300.js +1 -1
- package/dist/970.js +1 -1
- package/dist/970.js.map +1 -1
- package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +9 -9
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/claims/dashboard/form/claims-explanation-and-justification-form-input.component.tsx +101 -29
- package/src/claims/dashboard/form/claims-form.component.tsx +150 -47
- package/src/claims/dashboard/form/claims-form.scss +3 -1
- package/translations/en.json +2 -0
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"}},{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","slot":"patient-chart-dashboard-slot","meta":{"name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot","path":"insurance-benefits","columns":1,"columnSpan":1},"featureFlag":"healthInformationExchange"},{"component":"benefitsPackage","name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"component":"benefitsEligibilyRequestForm","name":"benefits-eligibility-request-form"},{"component":"benefitsPreAuthForm","name":"benefits-pre-auth-form"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm"},{"name":"require-billing-modal","component":"requirePaymentModal"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"initiate-payment-modal","component":"initiatePaymentDialog"},{"name":"delete-billableservice-modal","component":"deleteBillableServiceModal"},{"name":"refund-bill-modal","component":"refundBillModal"},{"name":"delete-bill-modal","component":"deleteBillModal"},{"name":"lab-order-billable-item","component":"labOrder","slot":"top-of-lab-order-form-slot"},{"name":"procedure-order-billable-item","component":"procedureOrder","slot":"top-of-procedure-order-form-slot"},{"name":"imaging-order-billable-item","component":"imagingOrder","slot":"top-of-imaging-order-form-slot"},{"name":"price-info-order","component":"priceInfoOrder"},{"name":"drug-order-billable-item","component":"drugOrder","slot":"medication-info-slot"},{"name":"order-action-button","component":"orderActionButton","slots":["prescription-action-button-slot","imaging-orders-action","procedure-orders-action","tests-ordered-actions-slot"],"order":0},{"component":"billingOverviewLink","name":"billing-overview-link","order":0,"slot":"billing-dashboard-link-slot"},{"component":"paymentHistoryLink","name":"payment-history-link","slot":"billing-dashboard-link-slot"},{"component":"paymentPointsLink","name":"payment-points-link","slot":"billing-dashboard-link-slot"},{"component":"paymentModesLink","name":"payment-modes-link","slot":"billing-dashboard-link-slot"},{"component":"billManagerLink","name":"bill-manager-link","slot":"billing-dashboard-link-slot"},{"component":"chargeableItemsLink","name":"chargeable-items-link","slot":"billing-dashboard-link-slot"},{"component":"billableExemptionsLink","name":"billable-exemptions-link","slot":"billing-dashboard-link-slot"},{"component":"claimsManagementSideNavGroup","name":"claims-management-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"claims-management","title":"Claims management Overview","slot":"case-management-slot"},"featureFlag":"healthInformationExchange"},{"component":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","order":0,"slot":"claims-management-dashboard-link-slot"},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slot":"claims-management-dashboard-link-slot"},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"component":"waiveBillActionButton","name":"waive-bill-action-button","slot":"bill-actions-slot"},{"component":"deleteBillActionButton","name":"delete-bill-action-button","slot":"bill-actions-slot"},{"component":"refundLineItem","name":"refund-line-item","slot":"bill-actions-overflow-menu-slot"},{"name":"edit-line-item","component":"editLineItem","slot":"bill-actions-overflow-menu-slot"},{"name":"cancel-line-item","component":"cancelLineItem","slot":"bill-actions-overflow-menu-slot"}],"workspaces":[{"name":"create-bill-workspace","component":"createBillWorkspace","title":"Create Bill Workspace","type":"other-form"},{"name":"waive-bill-form","component":"waiveBillForm","title":"Waive Bill Form","type":"other-form"},{"name":"edit-bill-form","component":"editBillForm","title":"Edit Bill Form","type":"other-form"},{"name":"billable-service-form","component":"addServiceForm","title":"Create Charge Item Form","type":"other-form"},{"name":"commodity-form","component":"addCommodityForm","title":"Create Charge Item Form","type":"other-form"},{"name":"billing-form","component":"billingForm","title":"Billing Form","type":"other-form","width":"extra-wide"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","title":"Payment Mode Workspace","type":"other-form"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","title":"Cancel Bill Workspace","type":"other-form"},{"name":"bill-deposit-workspace","component":"billDepositWorkspace","title":"Bill Deposit Workspace","type":"other-form"}],"modals":[{"name":"create-payment-point","component":"createPaymentPoint"},{"name":"clock-out-modal","component":"clockOut"},{"name":"bulk-import-billable-services-modal","component":"bulkImportBillableServicesModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"retry-claim-request-modal","component":"retryClaimRequestModal"},{"name":"paid-bill-receipt-print-preview-modal","component":"paidBillReceiptPrintPreviewModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"create-bill-item-modal","component":"createBillItemModal"}],"version":"5.4.1-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"}},{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","slot":"patient-chart-dashboard-slot","meta":{"name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot","path":"insurance-benefits","columns":1,"columnSpan":1},"featureFlag":"healthInformationExchange"},{"component":"benefitsPackage","name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"component":"benefitsEligibilyRequestForm","name":"benefits-eligibility-request-form"},{"component":"benefitsPreAuthForm","name":"benefits-pre-auth-form"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm"},{"name":"require-billing-modal","component":"requirePaymentModal"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"initiate-payment-modal","component":"initiatePaymentDialog"},{"name":"delete-billableservice-modal","component":"deleteBillableServiceModal"},{"name":"refund-bill-modal","component":"refundBillModal"},{"name":"delete-bill-modal","component":"deleteBillModal"},{"name":"lab-order-billable-item","component":"labOrder","slot":"top-of-lab-order-form-slot"},{"name":"procedure-order-billable-item","component":"procedureOrder","slot":"top-of-procedure-order-form-slot"},{"name":"imaging-order-billable-item","component":"imagingOrder","slot":"top-of-imaging-order-form-slot"},{"name":"price-info-order","component":"priceInfoOrder"},{"name":"drug-order-billable-item","component":"drugOrder","slot":"medication-info-slot"},{"name":"order-action-button","component":"orderActionButton","slots":["prescription-action-button-slot","imaging-orders-action","procedure-orders-action","tests-ordered-actions-slot"],"order":0},{"component":"billingOverviewLink","name":"billing-overview-link","order":0,"slot":"billing-dashboard-link-slot"},{"component":"paymentHistoryLink","name":"payment-history-link","slot":"billing-dashboard-link-slot"},{"component":"paymentPointsLink","name":"payment-points-link","slot":"billing-dashboard-link-slot"},{"component":"paymentModesLink","name":"payment-modes-link","slot":"billing-dashboard-link-slot"},{"component":"billManagerLink","name":"bill-manager-link","slot":"billing-dashboard-link-slot"},{"component":"chargeableItemsLink","name":"chargeable-items-link","slot":"billing-dashboard-link-slot"},{"component":"billableExemptionsLink","name":"billable-exemptions-link","slot":"billing-dashboard-link-slot"},{"component":"claimsManagementSideNavGroup","name":"claims-management-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"claims-management","title":"Claims management Overview","slot":"case-management-slot"},"featureFlag":"healthInformationExchange"},{"component":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","order":0,"slot":"claims-management-dashboard-link-slot"},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slot":"claims-management-dashboard-link-slot"},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"component":"waiveBillActionButton","name":"waive-bill-action-button","slot":"bill-actions-slot"},{"component":"deleteBillActionButton","name":"delete-bill-action-button","slot":"bill-actions-slot"},{"component":"refundLineItem","name":"refund-line-item","slot":"bill-actions-overflow-menu-slot"},{"name":"edit-line-item","component":"editLineItem","slot":"bill-actions-overflow-menu-slot"},{"name":"cancel-line-item","component":"cancelLineItem","slot":"bill-actions-overflow-menu-slot"}],"workspaces":[{"name":"create-bill-workspace","component":"createBillWorkspace","title":"Create Bill Workspace","type":"other-form"},{"name":"waive-bill-form","component":"waiveBillForm","title":"Waive Bill Form","type":"other-form"},{"name":"edit-bill-form","component":"editBillForm","title":"Edit Bill Form","type":"other-form"},{"name":"billable-service-form","component":"addServiceForm","title":"Create Charge Item Form","type":"other-form"},{"name":"commodity-form","component":"addCommodityForm","title":"Create Charge Item Form","type":"other-form"},{"name":"billing-form","component":"billingForm","title":"Billing Form","type":"other-form","width":"extra-wide"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","title":"Payment Mode Workspace","type":"other-form"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","title":"Cancel Bill Workspace","type":"other-form"},{"name":"bill-deposit-workspace","component":"billDepositWorkspace","title":"Bill Deposit Workspace","type":"other-form"}],"modals":[{"name":"create-payment-point","component":"createPaymentPoint"},{"name":"clock-out-modal","component":"clockOut"},{"name":"bulk-import-billable-services-modal","component":"bulkImportBillableServicesModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"retry-claim-request-modal","component":"retryClaimRequestModal"},{"name":"paid-bill-receipt-print-preview-modal","component":"paidBillReceiptPrintPreviewModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"create-bill-item-modal","component":"createBillItemModal"}],"version":"5.4.1-pre.2018"}
|
package/package.json
CHANGED
package/src/claims/dashboard/form/claims-explanation-and-justification-form-input.component.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Column, InlineLoading, InlineNotification, Layer, TextArea } from '@carbon/react';
|
|
2
2
|
import { usePatient } from '@openmrs/esm-framework';
|
|
3
|
-
import React, { useEffect, useMemo } from 'react';
|
|
3
|
+
import React, { useEffect, useMemo, useCallback } from 'react';
|
|
4
4
|
import { Controller, useFormContext } from 'react-hook-form';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { InterventionsFilter, useInterventions } from '../../../hooks/useInterventions';
|
|
@@ -9,50 +9,110 @@ import styles from './claims-form.scss';
|
|
|
9
9
|
|
|
10
10
|
type ClaimExplanationAndJusificationInputProps = {
|
|
11
11
|
patientUuid: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
validationEnabled?: boolean;
|
|
14
|
+
onInteraction?: () => void;
|
|
12
15
|
};
|
|
13
|
-
const ClaimExplanationAndJusificationInput: React.FC<ClaimExplanationAndJusificationInputProps> = ({ patientUuid }) => {
|
|
14
|
-
const { error: patientError, isLoading: isPatientLoading, patient } = usePatient(patientUuid);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
const ClaimExplanationAndJusificationInput: React.FC<ClaimExplanationAndJusificationInputProps> = ({
|
|
18
|
+
patientUuid,
|
|
19
|
+
disabled = false,
|
|
20
|
+
validationEnabled = false,
|
|
21
|
+
onInteraction = () => {},
|
|
22
|
+
}) => {
|
|
23
|
+
const { error: patientError, isLoading: isPatientLoading, patient } = usePatient(patientUuid);
|
|
22
24
|
const { t } = useTranslation();
|
|
25
|
+
const form = useFormContext();
|
|
26
|
+
const { setValue, watch, trigger } = form;
|
|
27
|
+
|
|
28
|
+
const packages = watch('packages');
|
|
29
|
+
const interventions = watch('interventions');
|
|
30
|
+
const currentExplanation = watch('claimExplanation');
|
|
31
|
+
const currentJustification = watch('claimJustification');
|
|
32
|
+
|
|
23
33
|
const { isLoading: packagesLoading, error: packageError, packages: shaPackages } = usePackages();
|
|
24
|
-
|
|
25
|
-
const packagesObservable = form.watch('packages');
|
|
26
|
-
const interventionsObservable = form.watch('interventions');
|
|
34
|
+
|
|
27
35
|
const filters = useMemo<InterventionsFilter>(
|
|
28
36
|
() => ({
|
|
29
|
-
package_code:
|
|
37
|
+
package_code: packages?.join(','),
|
|
30
38
|
applicable_gender: patient?.gender === 'male' ? 'MALE' : 'FEMALE',
|
|
31
39
|
}),
|
|
32
|
-
[
|
|
40
|
+
[packages, patient?.gender],
|
|
33
41
|
);
|
|
42
|
+
|
|
34
43
|
const { error: interventionsError, isLoading: isLoadingInterventions, allInterventions } = useInterventions(filters);
|
|
44
|
+
|
|
35
45
|
const packagesSelected = useMemo(
|
|
36
46
|
() =>
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
packages
|
|
48
|
+
?.map((packageCode) => shaPackages.find((pkg) => pkg.uuid === packageCode))
|
|
39
49
|
?.map((p) => p?.packageName ?? '')
|
|
40
50
|
.filter(Boolean) ?? [],
|
|
41
|
-
[
|
|
51
|
+
[packages, shaPackages],
|
|
42
52
|
);
|
|
53
|
+
|
|
43
54
|
const interventionSelected = useMemo(
|
|
44
55
|
() =>
|
|
45
|
-
|
|
46
|
-
(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
interventions
|
|
57
|
+
?.map(
|
|
58
|
+
(interventionCode) =>
|
|
59
|
+
allInterventions.find((intervention) => intervention.interventionCode === interventionCode)
|
|
60
|
+
?.interventionName,
|
|
61
|
+
)
|
|
62
|
+
.filter(Boolean) ?? [],
|
|
63
|
+
[interventions, allInterventions],
|
|
50
64
|
);
|
|
51
65
|
|
|
66
|
+
const hasPackagesAndInterventions = packagesSelected.length > 0 && interventionSelected.length > 0;
|
|
67
|
+
|
|
68
|
+
const updateFormFields = useCallback(() => {
|
|
69
|
+
if (!packagesLoading && !isLoadingInterventions && hasPackagesAndInterventions) {
|
|
70
|
+
const newExplanation = packagesSelected.join(', ');
|
|
71
|
+
const newJustification = interventionSelected.join(', ');
|
|
72
|
+
|
|
73
|
+
if (newExplanation !== currentExplanation) {
|
|
74
|
+
setValue('claimExplanation', newExplanation, {
|
|
75
|
+
shouldValidate: validationEnabled,
|
|
76
|
+
shouldDirty: true,
|
|
77
|
+
shouldTouch: false,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (newJustification !== currentJustification) {
|
|
82
|
+
setValue('claimJustification', newJustification, {
|
|
83
|
+
shouldValidate: validationEnabled,
|
|
84
|
+
shouldDirty: true,
|
|
85
|
+
shouldTouch: false,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (validationEnabled) {
|
|
90
|
+
trigger(['claimExplanation', 'claimJustification']);
|
|
91
|
+
}
|
|
92
|
+
onInteraction();
|
|
93
|
+
}
|
|
94
|
+
}, [
|
|
95
|
+
packagesLoading,
|
|
96
|
+
isLoadingInterventions,
|
|
97
|
+
hasPackagesAndInterventions,
|
|
98
|
+
packagesSelected,
|
|
99
|
+
interventionSelected,
|
|
100
|
+
currentExplanation,
|
|
101
|
+
currentJustification,
|
|
102
|
+
setValue,
|
|
103
|
+
validationEnabled,
|
|
104
|
+
trigger,
|
|
105
|
+
onInteraction,
|
|
106
|
+
]);
|
|
107
|
+
|
|
52
108
|
useEffect(() => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}, [
|
|
109
|
+
const timer = setTimeout(updateFormFields, 300);
|
|
110
|
+
return () => clearTimeout(timer);
|
|
111
|
+
}, [updateFormFields]);
|
|
112
|
+
|
|
113
|
+
const shouldShowError = (fieldName: string) => {
|
|
114
|
+
return validationEnabled && form.formState.errors[fieldName] && form.formState.touchedFields[fieldName];
|
|
115
|
+
};
|
|
56
116
|
|
|
57
117
|
if (packagesLoading || isPatientLoading || isLoadingInterventions) {
|
|
58
118
|
return (
|
|
@@ -68,11 +128,13 @@ const ClaimExplanationAndJusificationInput: React.FC<ClaimExplanationAndJusifica
|
|
|
68
128
|
lowContrast={true}
|
|
69
129
|
statusIconDescription="notification"
|
|
70
130
|
title={t('errorLoadingpackages', 'Error loading packages')}
|
|
71
|
-
subtitle={packageError?.message ??
|
|
131
|
+
subtitle={packageError?.message ?? patientError?.message ?? interventionsError?.message}
|
|
72
132
|
/>
|
|
73
133
|
);
|
|
74
134
|
}
|
|
75
135
|
|
|
136
|
+
const textAreaDisabled = disabled && !hasPackagesAndInterventions;
|
|
137
|
+
|
|
76
138
|
return (
|
|
77
139
|
<>
|
|
78
140
|
<Column>
|
|
@@ -87,8 +149,13 @@ const ClaimExplanationAndJusificationInput: React.FC<ClaimExplanationAndJusifica
|
|
|
87
149
|
rows={3}
|
|
88
150
|
placeholder="Claim Explanation"
|
|
89
151
|
id="claimExplanation"
|
|
90
|
-
invalid={
|
|
152
|
+
invalid={shouldShowError('claimExplanation')}
|
|
91
153
|
invalidText={error?.message}
|
|
154
|
+
disabled={textAreaDisabled}
|
|
155
|
+
onChange={(e) => {
|
|
156
|
+
field.onChange(e);
|
|
157
|
+
onInteraction();
|
|
158
|
+
}}
|
|
92
159
|
/>
|
|
93
160
|
)}
|
|
94
161
|
/>
|
|
@@ -106,8 +173,13 @@ const ClaimExplanationAndJusificationInput: React.FC<ClaimExplanationAndJusifica
|
|
|
106
173
|
rows={3}
|
|
107
174
|
placeholder="Claim Justification"
|
|
108
175
|
id="claimJustification"
|
|
109
|
-
invalid={
|
|
176
|
+
invalid={shouldShowError('claimJustification')}
|
|
110
177
|
invalidText={error?.message}
|
|
178
|
+
disabled={textAreaDisabled}
|
|
179
|
+
onChange={(e) => {
|
|
180
|
+
field.onChange(e);
|
|
181
|
+
onInteraction();
|
|
182
|
+
}}
|
|
111
183
|
/>
|
|
112
184
|
)}
|
|
113
185
|
/>
|
|
@@ -117,4 +189,4 @@ const ClaimExplanationAndJusificationInput: React.FC<ClaimExplanationAndJusifica
|
|
|
117
189
|
);
|
|
118
190
|
};
|
|
119
191
|
|
|
120
|
-
export default ClaimExplanationAndJusificationInput;
|
|
192
|
+
export default React.memo(ClaimExplanationAndJusificationInput);
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from '@carbon/react';
|
|
16
16
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
17
17
|
import { navigate, showSnackbar, useConfig, useSession } from '@openmrs/esm-framework';
|
|
18
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
|
18
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
19
19
|
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
|
20
20
|
import { useTranslation } from 'react-i18next';
|
|
21
21
|
import { useParams } from 'react-router-dom';
|
|
@@ -29,26 +29,39 @@ import useProvider from '../../../hooks/useProvider';
|
|
|
29
29
|
import { LineItem, MappedBill } from '../../../types';
|
|
30
30
|
import ClaimExplanationAndJusificationInput from './claims-explanation-and-justification-form-input.component';
|
|
31
31
|
import { processClaims, SHAPackagesAndInterventionVisitAttribute, useVisit } from './claims-form.resource';
|
|
32
|
+
|
|
32
33
|
import styles from './claims-form.scss';
|
|
34
|
+
import debounce from 'lodash-es/debounce';
|
|
33
35
|
|
|
34
36
|
type ClaimsFormProps = {
|
|
35
37
|
bill: MappedBill;
|
|
36
38
|
selectedLineItems: LineItem[];
|
|
37
39
|
};
|
|
38
40
|
|
|
41
|
+
const ClaimsFormSchemaBase = z.object({
|
|
42
|
+
claimExplanation: z.string(),
|
|
43
|
+
claimJustification: z.string(),
|
|
44
|
+
diagnoses: z.array(z.string()),
|
|
45
|
+
visitType: z.string(),
|
|
46
|
+
facility: z.string(),
|
|
47
|
+
treatmentStart: z.string(),
|
|
48
|
+
treatmentEnd: z.string(),
|
|
49
|
+
packages: z.array(z.string()),
|
|
50
|
+
interventions: z.array(z.string()),
|
|
51
|
+
provider: z.string(),
|
|
52
|
+
});
|
|
53
|
+
|
|
39
54
|
const ClaimsFormSchema = z.object({
|
|
40
|
-
claimExplanation: z.string().
|
|
41
|
-
claimJustification: z.string().
|
|
42
|
-
diagnoses: z.array(z.string()).
|
|
43
|
-
visitType: z.string().
|
|
44
|
-
facility: z.string().
|
|
45
|
-
treatmentStart: z.string().
|
|
46
|
-
treatmentEnd: z.string().
|
|
47
|
-
packages: z.array(z.string()).
|
|
48
|
-
interventions: z.array(z.string()).min(1, {
|
|
49
|
-
|
|
50
|
-
}),
|
|
51
|
-
provider: z.string().nonempty({ message: 'provider is provider' }),
|
|
55
|
+
claimExplanation: z.string().min(1, { message: 'Claim explanation is required' }),
|
|
56
|
+
claimJustification: z.string().min(1, { message: 'Claim justification is required' }),
|
|
57
|
+
diagnoses: z.array(z.string()).min(1, { message: 'At least one diagnosis is required' }),
|
|
58
|
+
visitType: z.string().min(1, { message: 'Visit type is required' }),
|
|
59
|
+
facility: z.string().min(1, { message: 'Facility is required' }),
|
|
60
|
+
treatmentStart: z.string().min(1, { message: 'Treatment start date is required' }),
|
|
61
|
+
treatmentEnd: z.string().min(1, { message: 'Treatment end date is required' }),
|
|
62
|
+
packages: z.array(z.string()).min(1, { message: 'At least one package is required' }),
|
|
63
|
+
interventions: z.array(z.string()).min(1, { message: 'At least one intervention is required' }),
|
|
64
|
+
provider: z.string().min(1, { message: 'Provider is required' }),
|
|
52
65
|
});
|
|
53
66
|
|
|
54
67
|
const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
@@ -62,6 +75,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
62
75
|
} = useSession();
|
|
63
76
|
const { providerLoading: providerLoading, provider, error: providerError } = useProvider(providerUuid);
|
|
64
77
|
const { visitAttributeTypes } = useConfig<BillingConfig>();
|
|
78
|
+
|
|
65
79
|
const packagesAndinterventions = useMemo(() => {
|
|
66
80
|
if (recentVisit) {
|
|
67
81
|
const values = recentVisit.attributes?.find(
|
|
@@ -77,9 +91,9 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
77
91
|
|
|
78
92
|
const encounterUuid = recentVisit?.encounters[0]?.uuid;
|
|
79
93
|
const visitTypeUuid = recentVisit?.visitType.uuid;
|
|
80
|
-
|
|
81
94
|
const [loading, setLoading] = useState(false);
|
|
82
|
-
const
|
|
95
|
+
const [formInitialized, setFormInitialized] = useState(false);
|
|
96
|
+
const [validationEnabled, setValidationEnabled] = useState(false);
|
|
83
97
|
|
|
84
98
|
const handleNavigateToBillingOptions = () =>
|
|
85
99
|
navigate({
|
|
@@ -87,31 +101,92 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
87
101
|
});
|
|
88
102
|
|
|
89
103
|
const form = useForm<z.infer<typeof ClaimsFormSchema>>({
|
|
90
|
-
mode: '
|
|
91
|
-
resolver: zodResolver(ClaimsFormSchema),
|
|
104
|
+
mode: 'onTouched',
|
|
105
|
+
resolver: zodResolver(validationEnabled ? ClaimsFormSchema : ClaimsFormSchemaBase),
|
|
92
106
|
defaultValues: {
|
|
93
107
|
claimExplanation: '',
|
|
94
108
|
claimJustification: '',
|
|
95
109
|
diagnoses: [],
|
|
96
|
-
visitType:
|
|
97
|
-
facility:
|
|
98
|
-
treatmentStart:
|
|
99
|
-
treatmentEnd:
|
|
110
|
+
visitType: '',
|
|
111
|
+
facility: '',
|
|
112
|
+
treatmentStart: '',
|
|
113
|
+
treatmentEnd: '',
|
|
100
114
|
packages: [],
|
|
101
115
|
interventions: [],
|
|
102
|
-
provider:
|
|
116
|
+
provider: '',
|
|
103
117
|
},
|
|
104
118
|
});
|
|
105
119
|
|
|
106
120
|
const {
|
|
107
121
|
control,
|
|
108
122
|
handleSubmit,
|
|
109
|
-
formState: { errors, isValid },
|
|
123
|
+
formState: { errors, isValid, isDirty, touchedFields },
|
|
110
124
|
setValue,
|
|
111
125
|
reset,
|
|
126
|
+
trigger,
|
|
127
|
+
watch,
|
|
112
128
|
} = form;
|
|
113
129
|
|
|
130
|
+
const packages = watch('packages');
|
|
131
|
+
const interventions = watch('interventions');
|
|
132
|
+
const claimExplanation = watch('claimExplanation');
|
|
133
|
+
const claimJustification = watch('claimJustification');
|
|
134
|
+
|
|
135
|
+
const debouncedValidation = useCallback(
|
|
136
|
+
debounce(() => {
|
|
137
|
+
if (formInitialized) {
|
|
138
|
+
trigger();
|
|
139
|
+
}
|
|
140
|
+
}, 500),
|
|
141
|
+
[formInitialized, trigger],
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
debouncedValidation();
|
|
146
|
+
return () => debouncedValidation.cancel();
|
|
147
|
+
}, [packages, interventions, debouncedValidation]);
|
|
148
|
+
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
if (!visitLoading && !diagnosisLoading && !providerLoading) {
|
|
151
|
+
const updates = {
|
|
152
|
+
diagnoses: diagnoses?.map((d) => d.id) ?? [],
|
|
153
|
+
visitType: recentVisit?.visitType?.display || '',
|
|
154
|
+
facility: `${recentVisit?.location?.display || ''} - ${mflCodeValue || ''}`,
|
|
155
|
+
treatmentStart: recentVisit?.startDatetime ? formatDate(recentVisit.startDatetime) : '',
|
|
156
|
+
treatmentEnd: recentVisit?.stopDatetime ? formatDate(recentVisit.stopDatetime) : '',
|
|
157
|
+
packages: packagesAndinterventions?.packages ?? [],
|
|
158
|
+
interventions: packagesAndinterventions?.interventions ?? [],
|
|
159
|
+
provider: providerUuid,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
Object.entries(updates).forEach(([field, value]) => {
|
|
163
|
+
setValue(field as any, value, { shouldValidate: false, shouldDirty: false, shouldTouch: false });
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
setFormInitialized(true);
|
|
168
|
+
}, 100);
|
|
169
|
+
}
|
|
170
|
+
}, [
|
|
171
|
+
diagnoses,
|
|
172
|
+
recentVisit,
|
|
173
|
+
mflCodeValue,
|
|
174
|
+
setValue,
|
|
175
|
+
provider,
|
|
176
|
+
packagesAndinterventions,
|
|
177
|
+
visitLoading,
|
|
178
|
+
diagnosisLoading,
|
|
179
|
+
providerLoading,
|
|
180
|
+
providerUuid,
|
|
181
|
+
]);
|
|
182
|
+
|
|
114
183
|
const onSubmit = async (data: z.infer<typeof ClaimsFormSchema>) => {
|
|
184
|
+
setValidationEnabled(true);
|
|
185
|
+
const isFormValid = await trigger();
|
|
186
|
+
if (!isFormValid) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
115
190
|
setLoading(true);
|
|
116
191
|
const providedItems = selectedLineItems.reduce((acc, item) => {
|
|
117
192
|
acc[item.uuid] = {
|
|
@@ -127,6 +202,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
127
202
|
};
|
|
128
203
|
return acc;
|
|
129
204
|
}, {});
|
|
205
|
+
|
|
130
206
|
const payload = {
|
|
131
207
|
providedItems,
|
|
132
208
|
claimExplanation: data.claimExplanation,
|
|
@@ -149,6 +225,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
149
225
|
packages: data.packages,
|
|
150
226
|
interventions: data.interventions,
|
|
151
227
|
};
|
|
228
|
+
|
|
152
229
|
try {
|
|
153
230
|
await processClaims(payload);
|
|
154
231
|
showSnackbar({
|
|
@@ -158,18 +235,17 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
158
235
|
timeoutInMs: 3000,
|
|
159
236
|
isLowContrast: true,
|
|
160
237
|
});
|
|
161
|
-
reset();
|
|
162
238
|
setTimeout(() => {
|
|
163
239
|
navigate({
|
|
164
|
-
to: window.getOpenmrsSpaBase() +
|
|
240
|
+
to: window.getOpenmrsSpaBase() + 'home/billing/',
|
|
165
241
|
});
|
|
166
|
-
},
|
|
242
|
+
}, 1000);
|
|
167
243
|
} catch (err) {
|
|
168
244
|
console.error(err);
|
|
169
245
|
showSnackbar({
|
|
170
246
|
kind: 'error',
|
|
171
247
|
title: t('claimError', 'Claim Error'),
|
|
172
|
-
subtitle: t('sendClaimError', 'Request Failed, Please try later
|
|
248
|
+
subtitle: t('sendClaimError', 'Request Failed, Please try later...'),
|
|
173
249
|
timeoutInMs: 2500,
|
|
174
250
|
isLowContrast: true,
|
|
175
251
|
});
|
|
@@ -178,16 +254,6 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
178
254
|
}
|
|
179
255
|
};
|
|
180
256
|
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
setValue('diagnoses', diagnoses?.map((d) => d.id) ?? ([] as any));
|
|
183
|
-
setValue('visitType', recentVisit?.visitType?.display || '');
|
|
184
|
-
setValue('facility', `${recentVisit?.location?.display || ''} - ${mflCodeValue || ''}`);
|
|
185
|
-
setValue('treatmentStart', recentVisit?.startDatetime ? formatDate(recentVisit.startDatetime) : '');
|
|
186
|
-
setValue('treatmentEnd', recentVisit?.stopDatetime ? formatDate(recentVisit.stopDatetime) : '');
|
|
187
|
-
setValue('packages', (packagesAndinterventions?.packages ?? []) as any);
|
|
188
|
-
setValue('interventions', (packagesAndinterventions?.interventions ?? []) as any);
|
|
189
|
-
}, [diagnoses, recentVisit, mflCodeValue, setValue, provider, packagesAndinterventions]);
|
|
190
|
-
|
|
191
257
|
if (visitLoading || diagnosisLoading || providerLoading) {
|
|
192
258
|
return (
|
|
193
259
|
<Layer className={styles.loading}>
|
|
@@ -207,16 +273,33 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
207
273
|
visitError?.message ??
|
|
208
274
|
diagnosisError?.message ??
|
|
209
275
|
providerError?.message ??
|
|
210
|
-
'Error
|
|
276
|
+
'Error occurred while loading claims form'
|
|
211
277
|
}
|
|
212
278
|
lowContrast
|
|
213
279
|
/>
|
|
214
280
|
</Layer>
|
|
215
281
|
);
|
|
216
282
|
}
|
|
283
|
+
|
|
284
|
+
const shouldShowError = (fieldName: string) => {
|
|
285
|
+
return validationEnabled && errors[fieldName] && (touchedFields[fieldName] || formInitialized);
|
|
286
|
+
};
|
|
287
|
+
|
|
217
288
|
return (
|
|
218
289
|
<FormProvider {...form}>
|
|
219
290
|
<Form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
|
|
291
|
+
{!selectedLineItems?.length && (
|
|
292
|
+
<div className={styles.notificationContainer}>
|
|
293
|
+
<InlineNotification
|
|
294
|
+
kind="info"
|
|
295
|
+
title={t('noItemsSelected', 'No items selected')}
|
|
296
|
+
subtitle={t('pleaseSelectItems', 'Please select line items to raise a claim')}
|
|
297
|
+
hideCloseButton={true}
|
|
298
|
+
lowContrast={true}
|
|
299
|
+
className={styles.notification}
|
|
300
|
+
/>
|
|
301
|
+
</div>
|
|
302
|
+
)}
|
|
220
303
|
<Stack gap={4} className={styles.grid}>
|
|
221
304
|
<span className={styles.claimFormTitle}>{t('formTitle', 'Fill in the form details')}</span>
|
|
222
305
|
<Row className={styles.formClaimRow}>
|
|
@@ -295,19 +378,23 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
295
378
|
<Column>
|
|
296
379
|
<Layer className={styles.input}>
|
|
297
380
|
<Controller
|
|
298
|
-
control={
|
|
381
|
+
control={control}
|
|
299
382
|
name="diagnoses"
|
|
300
383
|
render={({ field }) => (
|
|
301
384
|
<MultiSelect
|
|
302
385
|
ref={field.ref}
|
|
303
|
-
invalid={
|
|
304
|
-
invalidText={
|
|
386
|
+
invalid={shouldShowError('diagnoses')}
|
|
387
|
+
invalidText={errors.diagnoses?.message}
|
|
305
388
|
id="diagnoses"
|
|
306
389
|
titleText={t('finalDiagnosis', 'Final Diagnosis')}
|
|
307
390
|
selectedItems={field.value}
|
|
308
391
|
label="Choose option"
|
|
309
392
|
items={diagnoses.map((r) => r.id)}
|
|
310
393
|
itemToString={(item) => diagnoses.find((r) => r.id === item)?.text ?? ''}
|
|
394
|
+
onChange={(e) => {
|
|
395
|
+
field.onChange(e.selectedItems);
|
|
396
|
+
setValidationEnabled(true);
|
|
397
|
+
}}
|
|
311
398
|
/>
|
|
312
399
|
)}
|
|
313
400
|
/>
|
|
@@ -322,14 +409,15 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
322
409
|
render={({ field }) => (
|
|
323
410
|
<Dropdown
|
|
324
411
|
ref={field.ref}
|
|
325
|
-
invalid={
|
|
326
|
-
invalidText={
|
|
412
|
+
invalid={shouldShowError('provider')}
|
|
413
|
+
invalidText={errors.provider?.message}
|
|
327
414
|
id="provider"
|
|
328
415
|
titleText={t('provider', 'Provider')}
|
|
329
416
|
onChange={(e) => {
|
|
330
417
|
field.onChange(e.selectedItem);
|
|
418
|
+
setValidationEnabled(true);
|
|
331
419
|
}}
|
|
332
|
-
initialSelectedItem={
|
|
420
|
+
initialSelectedItem={provider.uuid}
|
|
333
421
|
label="Choose option"
|
|
334
422
|
items={[provider].map((r) => r.uuid)}
|
|
335
423
|
itemToString={(item) =>
|
|
@@ -345,16 +433,31 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
345
433
|
</Layer>
|
|
346
434
|
</Column>
|
|
347
435
|
</Row>
|
|
348
|
-
<ClaimExplanationAndJusificationInput
|
|
436
|
+
<ClaimExplanationAndJusificationInput
|
|
437
|
+
patientUuid={patientUuid}
|
|
438
|
+
disabled={!packages?.length || !interventions?.length}
|
|
439
|
+
validationEnabled={validationEnabled}
|
|
440
|
+
onInteraction={() => setValidationEnabled(true)}
|
|
441
|
+
/>
|
|
349
442
|
<ButtonSet className={styles.buttonSet}>
|
|
350
443
|
<Button className={styles.button} kind="secondary" onClick={handleNavigateToBillingOptions}>
|
|
351
444
|
{t('discardClaim', 'Discard Claim')}
|
|
352
445
|
</Button>
|
|
353
|
-
<Button
|
|
446
|
+
<Button
|
|
447
|
+
className={styles.button}
|
|
448
|
+
kind="primary"
|
|
449
|
+
type="submit"
|
|
450
|
+
onClick={() => setValidationEnabled(true)}
|
|
451
|
+
disabled={
|
|
452
|
+
loading || !isValid || !packages?.length || !interventions?.length || !selectedLineItems?.length
|
|
453
|
+
}
|
|
454
|
+
tooltipPosition="top"
|
|
455
|
+
tooltipAlignment="center"
|
|
456
|
+
renderIcon={loading ? InlineLoading : undefined}>
|
|
354
457
|
{loading ? (
|
|
355
458
|
<InlineLoading description={t('processing', 'Processing...')} />
|
|
356
459
|
) : (
|
|
357
|
-
t('processClaim', 'Process Claim')
|
|
460
|
+
<>{t('processClaim', 'Process Claim')}</>
|
|
358
461
|
)}
|
|
359
462
|
</Button>
|
|
360
463
|
</ButtonSet>
|
package/translations/en.json
CHANGED
|
@@ -173,6 +173,7 @@
|
|
|
173
173
|
"noBillsFoundDescription": "No bills found for this patient",
|
|
174
174
|
"noCashPoints": "No Cash Points",
|
|
175
175
|
"noCashPointsConfigured": "There are no cash points configured for this location",
|
|
176
|
+
"noItemsSelected": "No items selected",
|
|
176
177
|
"noMatchingBillsToDisplay": "No matching bills to display",
|
|
177
178
|
"noMatchingItemsToDisplay": "No matching items to display",
|
|
178
179
|
"noPaymentModes": "No payment modes found",
|
|
@@ -211,6 +212,7 @@
|
|
|
211
212
|
"payments": "Payments",
|
|
212
213
|
"paymentType": "Payment Type",
|
|
213
214
|
"Phone Number": "Phone Number",
|
|
215
|
+
"pleaseSelectItems": "Please select line items to raise a claim",
|
|
214
216
|
"policyNumber": "Policy number",
|
|
215
217
|
"preathsRequests": "Preauth Requests",
|
|
216
218
|
"preauthRequest": "Preauth requests",
|