fhir-react 0.2.1 → 0.3.0
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/.github/workflows/publish_npmjs.yml +18 -0
- package/.storybook/config.js +9 -3
- package/.storybook/presets.js +1 -0
- package/.storybook/preview-head.html +4 -0
- package/README.md +86 -55
- package/package.json +13 -4
- package/src/assets/common/chevron-right.svg +3 -0
- package/src/assets/containers/AllergyIntolerance/allergy-intolerance.svg +9 -0
- package/src/assets/containers/Appointment/appointment.svg +14 -0
- package/src/assets/containers/CarePlan/care-plan.svg +10 -0
- package/src/assets/containers/CareTeam/care-team.svg +10 -0
- package/src/assets/containers/Claim/claim.svg +6 -0
- package/src/assets/containers/ClaimResponse/claim-response.svg +7 -0
- package/src/assets/containers/Condition/condition.svg +11 -0
- package/src/assets/containers/Device/device.svg +8 -0
- package/src/assets/containers/DiagnosticReport/diagnostic-report.svg +14 -0
- package/src/assets/containers/DocumentReference/document-reference.svg +10 -0
- package/src/assets/containers/Encounter/encounter.svg +10 -0
- package/src/assets/containers/ExplanationOfBenefit/explanation-of-benefit.svg +3 -0
- package/src/assets/containers/FamilyMemberHistory/family-member-history.svg +7 -0
- package/src/assets/containers/Goal/goal.svg +11 -0
- package/src/assets/containers/Immunization/immunization.svg +7 -0
- package/src/assets/containers/List/list.svg +3 -0
- package/src/assets/containers/Location/location.svg +4 -0
- package/src/assets/containers/Medication/medication.svg +5 -0
- package/src/assets/containers/MedicationAdministration/medication-administration.svg +6 -0
- package/src/assets/containers/MedicationKnowledge/medication-knowledge.svg +11 -0
- package/src/assets/containers/MedicationStatement/medication-statement.svg +5 -0
- package/src/assets/containers/Observation/observation.svg +12 -0
- package/src/assets/containers/Practitioner/practitioner.svg +5 -0
- package/src/assets/containers/Procedure/procedure.svg +9 -0
- package/src/assets/containers/Questionnaire/questionnaire.svg +6 -0
- package/src/assets/containers/QuestionnaireResponse/questionnaire-response.svg +6 -0
- package/src/assets/containers/QustionnaireResponse/questionnaire-response.svg +6 -0
- package/src/assets/containers/ResearchStudy/research-study.svg +9 -0
- package/src/assets/containers/ResourceCategory/resource-placeholder.svg +3 -0
- package/src/components/containers/Accordion/Accordion.js +80 -0
- package/src/components/containers/Accordion/Accordion.stories.js +76 -0
- package/src/components/containers/Accordion/index.js +3 -0
- package/src/components/containers/ResourceContainer/ResourceContainer.css +0 -1
- package/src/components/containers/ResourceContainer/ResourceContainer.js +1 -1
- package/src/components/datatypes/AccountBalance/AccountBalance.js +33 -0
- package/src/components/datatypes/AccountBalance/index.js +3 -0
- package/src/components/datatypes/Annotation/Annotation.js +1 -1
- package/src/components/datatypes/Coding/Coding.js +1 -1
- package/src/components/datatypes/Date/Date.js +14 -4
- package/src/components/datatypes/DatePeriod/DatePeriod.js +38 -0
- package/src/components/datatypes/DatePeriod/index.js +3 -0
- package/src/components/datatypes/HeaderIcon/HeaderIcon.js +31 -0
- package/src/components/datatypes/HeaderIcon/index.js +3 -0
- package/src/components/datatypes/HumanName/HumanName.js +6 -21
- package/src/components/datatypes/Reference/Reference.js +3 -6
- package/src/components/resources/AdverseEvent/AdverseEvent.test.js +2 -2
- package/src/components/resources/AllergyIntolerance/AllergyIntolerance.test.js +4 -4
- package/src/components/resources/Appointment/Appointment.js +91 -65
- package/src/components/resources/Appointment/Appointment.test.js +3 -3
- package/src/components/resources/Bundle/Bundle.js +2 -2
- package/src/components/resources/Bundle/Bundle.stories.js +78 -12
- package/src/components/resources/Bundle/Bundle.test.js +3 -0
- package/src/components/resources/CarePlan/CarePlan.test.js +4 -4
- package/src/components/resources/CareTeam/CareTeam.js +13 -14
- package/src/components/resources/CareTeam/CareTeam.test.js +4 -4
- package/src/components/resources/Claim/Claim.test.js +6 -6
- package/src/components/resources/ClaimResponse/ClaimResponse.test.js +6 -6
- package/src/components/resources/Condition/Condition.js +63 -47
- package/src/components/resources/Condition/Condition.stories.js +41 -8
- package/src/components/resources/Condition/Condition.test.js +20 -14
- package/src/components/resources/DiagnosticReport/DiagnosticReport.test.js +5 -7
- package/src/components/resources/DocumentReference/DocumentReference.js +1 -1
- package/src/components/resources/DocumentReference/DocumentReference.test.js +3 -3
- package/src/components/resources/Encounter/Encounter.js +66 -36
- package/src/components/resources/Encounter/EncounterParticipants.js +2 -2
- package/src/components/resources/ExplanationOfBenefit/CareTeam.js +2 -2
- package/src/components/resources/ExplanationOfBenefit/Diagnosis.js +31 -5
- package/src/components/resources/ExplanationOfBenefit/ExplanationOfBenefit.js +272 -201
- package/src/components/resources/ExplanationOfBenefit/ExplanationOfBenefit.stories.js +12 -0
- package/src/components/resources/ExplanationOfBenefit/ExplanationOfBenefit.test.js +96 -62
- package/src/components/resources/ExplanationOfBenefit/Items.js +2 -2
- package/src/components/resources/ExplanationOfBenefit/PriceLabel.js +20 -0
- package/src/components/resources/ExplanationOfBenefit/Related.js +3 -3
- package/src/components/resources/ExplanationOfBenefit/SupportingInfo.js +14 -3
- package/src/components/resources/ExplanationOfBenefit/TotalGraph.js +68 -0
- package/src/components/resources/ExplanationOfBenefitGraph/ExplanationOfBenefitGraph.js +89 -0
- package/src/components/resources/ExplanationOfBenefitGraph/ExplanationOfBenefitGraph.stories.js +78 -0
- package/src/components/resources/ExplanationOfBenefitGraph/ExplanationOfBenefitGraph.test.js +51 -0
- package/src/components/resources/ExplanationOfBenefitGraph/index.js +3 -0
- package/src/components/resources/Goal/Goal.test.js +1 -1
- package/src/components/resources/Immunization/Immunization.js +125 -94
- package/src/components/resources/Immunization/Immunization.stories.js +23 -4
- package/src/components/resources/Immunization/Immunization.test.js +17 -12
- package/src/components/resources/List/DrugTierDefinitionExtension.js +139 -0
- package/src/components/resources/List/Entries.js +66 -0
- package/src/components/resources/List/List.js +262 -0
- package/src/components/resources/List/List.stories.js +75 -0
- package/src/components/resources/List/List.test.js +95 -0
- package/src/components/resources/List/index.js +3 -0
- package/src/components/resources/List/utils.js +6 -0
- package/src/components/resources/MedicationAdministration/MedicationAdministration.test.js +7 -7
- package/src/components/resources/MedicationDispense/MedicationDispense.test.js +2 -2
- package/src/components/resources/MedicationKnowledge/MedicationKnowledge.js +217 -0
- package/src/components/resources/MedicationKnowledge/MedicationKnowledge.stories.js +78 -0
- package/src/components/resources/MedicationKnowledge/MedicationKnowledge.test.js +69 -0
- package/src/components/resources/MedicationKnowledge/index.js +3 -0
- package/src/components/resources/MedicationKnowledge/utils.js +8 -0
- package/src/components/resources/MedicationRequest/MedicationRequest.test.js +4 -4
- package/src/components/resources/Observation/Observation.js +72 -54
- package/src/components/resources/Observation/Observation.test.js +6 -18
- package/src/components/resources/Observation/ObservationGraph.js +159 -55
- package/src/components/resources/Observation/ObservationGraph.test.js +47 -26
- package/src/components/resources/Patient/Patient.js +79 -97
- package/src/components/resources/Patient/Patient.test.js +10 -10
- package/src/components/resources/Practitioner/Practitioner.js +80 -60
- package/src/components/resources/Practitioner/Practitioner.test.js +4 -4
- package/src/components/resources/Procedure/Procedure.js +99 -87
- package/src/components/resources/Procedure/Procedure.stories.js +8 -6
- package/src/components/resources/Procedure/Procedure.test.js +11 -8
- package/src/components/resources/Questionnaire/Questionnaire.test.js +3 -3
- package/src/components/resources/QuestionnaireResponse/QuestionnaireResponse.test.js +5 -5
- package/src/components/resources/ReferralRequest/ReferralRequest.test.js +2 -2
- package/src/components/resources/ResearchStudy/ResearchStudy.test.js +1 -1
- package/src/components/resources/ResourceCategory/ResourceCategory.js +56 -0
- package/src/components/resources/ResourceCategory/ResourceCategory.stories.js +29 -0
- package/src/components/resources/ResourceCategory/ResourceCategory.test.js +101 -0
- package/src/components/resources/ResourceCategory/index.js +3 -0
- package/src/components/supportedFhirResourceList.js +4 -0
- package/src/components/ui/_header.scss +3 -0
- package/src/components/ui/bootstrap-reboot.min.css +2 -22
- package/src/components/ui/index.js +191 -29
- package/src/constants/badge-status.jsx +98 -0
- package/src/fixtures/dstu2/resources/condition/condition.svg +35 -0
- package/src/fixtures/dstu2/resources/immunization/immunization.svg +10 -0
- package/src/fixtures/dstu2/resources/list/example1.json +49 -0
- package/src/fixtures/dstu2/resources/list/example2.json +116 -0
- package/src/fixtures/dstu2/resources/list/example3.json +380 -0
- package/src/fixtures/example-icons.jsx +169 -0
- package/src/fixtures/r4/resources/explanationOfBenefit/c4bbExtendedDiagnosis.json +446 -0
- package/src/fixtures/r4/resources/list/example1.json +45 -0
- package/src/fixtures/r4/resources/list/example2.json +282 -0
- package/src/fixtures/r4/resources/list/example3.json +298 -0
- package/src/fixtures/r4/resources/medicationKnowledge/example1.json +42 -0
- package/src/fixtures/r4/resources/medicationKnowledge/example2.json +59 -0
- package/src/fixtures/r4/resources/medicationKnowledge/example3.json +59 -0
- package/src/fixtures/r4/resources/medicationKnowledge/example4.json +59 -0
- package/src/fixtures/stu3/resources/list/example1.json +46 -0
- package/src/fixtures/stu3/resources/list/example2.json +298 -0
- package/src/fixtures/stu3/resources/list/example3.json +115 -0
- package/src/index.js +6 -1
- package/src/style.scss +176 -0
- package/src/utils/formatDate.js +21 -0
- package/src/utils/formatDate.test.js +22 -0
- package/src/utils/getBadgeColor.js +6 -0
- package/src/utils/getBadgeColor.test.js +14 -0
- package/src/utils/isUrl.js +9 -0
- package/src/utils/isUrl.test.js +12 -0
- package/src/utils.js +7 -0
- package/build/bootstrap-reboot.min.css +0 -414
- package/build/index.js +0 -15
- package/build/style.css +0 -459
- package/src/components/datatypes/HumanName/HumanName.css +0 -15
- package/src/components/datatypes/Reference/Reference.css +0 -8
- package/src/components/resources/Observation/ObservationGraph.css +0 -51
- package/src/components/resources/Patient/Patient.css +0 -19
- package/src/components/ui/index.css +0 -123
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render } from '@testing-library/react';
|
|
3
|
-
|
|
4
1
|
import ExplanationOfBenefit from './ExplanationOfBenefit';
|
|
5
|
-
import
|
|
6
|
-
import fhirVersions from '../fhirResourceVersions';
|
|
2
|
+
import React from 'react';
|
|
7
3
|
import dstu2Example1 from '../../../fixtures/dstu2/resources/explanationOfBenefit/example1.json';
|
|
4
|
+
import example1R4 from '../../../fixtures/r4/resources/explanationOfBenefit/personPrimaryCoverage.json';
|
|
8
5
|
import example1Stu3 from '../../../fixtures/stu3/resources/explanationOfBenefit/example1.json';
|
|
9
6
|
import example2Stu3 from '../../../fixtures/stu3/resources/explanationOfBenefit/example2.json';
|
|
10
|
-
import example1R4 from '../../../fixtures/r4/resources/explanationOfBenefit/personPrimaryCoverage.json';
|
|
11
7
|
import exampleC4BB from '../../../fixtures/r4/resources/explanationOfBenefit/c4bbExample.json';
|
|
8
|
+
import exampleC4BBExtendedDiagnosis from '../../../fixtures/r4/resources/explanationOfBenefit/c4bbExtendedDiagnosis.json';
|
|
9
|
+
import fhirVersions from '../fhirResourceVersions';
|
|
10
|
+
import { nbspRegex } from '../../../testUtils';
|
|
11
|
+
import { render } from '@testing-library/react';
|
|
12
12
|
|
|
13
13
|
describe('should render ExplanationOfBenefit component properly', () => {
|
|
14
14
|
it('should render with DSTU2 source data', () => {
|
|
@@ -23,7 +23,7 @@ describe('should render ExplanationOfBenefit component properly', () => {
|
|
|
23
23
|
expect(container).not.toBeNull();
|
|
24
24
|
|
|
25
25
|
expect(getByTestId('title').textContent).toContain('Claim settled as ');
|
|
26
|
-
expect(getByTestId('created').textContent).toContain('2014
|
|
26
|
+
expect(getByTestId('created').textContent).toContain('8/16/2014');
|
|
27
27
|
expect(getByTestId('insurer').textContent).toContain('Organization/2');
|
|
28
28
|
});
|
|
29
29
|
|
|
@@ -39,13 +39,11 @@ describe('should render ExplanationOfBenefit component properly', () => {
|
|
|
39
39
|
expect(container).not.toBeNull();
|
|
40
40
|
|
|
41
41
|
expect(getByTestId('title').textContent).toContain('Claim settled as ');
|
|
42
|
-
expect(getByTestId('created').textContent).toContain('2014
|
|
43
|
-
expect(
|
|
44
|
-
getByTestId('totalCost').textContent.replace(nbspRegex, ' '),
|
|
45
|
-
).toEqual('135.57 USD');
|
|
42
|
+
expect(getByTestId('created').textContent).toContain('8/16/2014');
|
|
43
|
+
expect(getByTestId('metricAmount').textContent).toContain('$135.57');
|
|
46
44
|
expect(
|
|
47
|
-
getByTestId('
|
|
48
|
-
).toContain('96
|
|
45
|
+
getByTestId('planDiscount').textContent.replace(nbspRegex, ' '),
|
|
46
|
+
).toContain('$96.00');
|
|
49
47
|
expect(getByTestId('hasServices').textContent).toContain('(1200)');
|
|
50
48
|
});
|
|
51
49
|
|
|
@@ -71,15 +69,19 @@ describe('should render ExplanationOfBenefit component properly', () => {
|
|
|
71
69
|
fhirVersion: fhirVersions.R4,
|
|
72
70
|
};
|
|
73
71
|
|
|
74
|
-
const {
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
const {
|
|
73
|
+
container,
|
|
74
|
+
getByTestId,
|
|
75
|
+
queryByTestId,
|
|
76
|
+
getAllByTestId,
|
|
77
|
+
getAllByRole,
|
|
78
|
+
} = render(<ExplanationOfBenefit {...defaultProps} />);
|
|
77
79
|
expect(container).not.toBeNull();
|
|
78
80
|
|
|
79
81
|
expect(getByTestId('title').textContent).toEqual(
|
|
80
82
|
'Claim settled as per contract.',
|
|
81
83
|
);
|
|
82
|
-
expect(getByTestId('created').textContent).toEqual('2014
|
|
84
|
+
expect(getByTestId('created').textContent).toEqual('8/16/2014');
|
|
83
85
|
expect(getByTestId('insurer').textContent).toEqual('Organization/3');
|
|
84
86
|
expect(getByTestId('provider').textContent).toEqual('Practitioner/1');
|
|
85
87
|
expect(getByTestId('totalSum').textContent).toContain('135.57');
|
|
@@ -88,38 +90,43 @@ describe('should render ExplanationOfBenefit component properly', () => {
|
|
|
88
90
|
expect(getByTestId('insurance').textContent).toEqual('Coverage/9876B1');
|
|
89
91
|
|
|
90
92
|
expect(queryByTestId('hasServices')).not.toBeNull();
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
tds.push(String(item.textContent).trim());
|
|
98
|
-
});
|
|
99
|
-
tablesContent.push(tds);
|
|
100
|
-
});
|
|
101
|
-
// table header
|
|
102
|
-
expect(tablesContent[0]).toEqual([
|
|
93
|
+
|
|
94
|
+
// checking if text content of each header cell is equal to mocked data
|
|
95
|
+
const headerCells = getAllByRole('columnheader')
|
|
96
|
+
.slice(0, 4)
|
|
97
|
+
.map(x => x.textContent);
|
|
98
|
+
expect(headerCells).toEqual([
|
|
103
99
|
'Service',
|
|
104
100
|
'Service date',
|
|
105
101
|
'Quantity',
|
|
106
102
|
'Item cost',
|
|
107
103
|
]);
|
|
108
104
|
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
// checking if text content of each column is equal to mocked data
|
|
106
|
+
const explanationService = getAllByTestId('explanation.service').map(
|
|
107
|
+
n => n.textContent,
|
|
108
|
+
);
|
|
109
|
+
const expectedArray = ['(1205)', '(group)'];
|
|
110
|
+
explanationService.forEach((x, i) => expect(x).toContain(expectedArray[i]));
|
|
111
|
+
|
|
112
|
+
const explanationServicedDate = getAllByTestId(
|
|
113
|
+
'explanation.servicedDate',
|
|
114
|
+
).map(n => n.textContent);
|
|
115
|
+
expect(explanationServicedDate).toEqual(['8/16/2014', '8/16/2014']);
|
|
116
|
+
|
|
117
|
+
const explanationQuantity = getAllByTestId('explanation.quantity').map(
|
|
118
|
+
n => n.textContent,
|
|
119
|
+
);
|
|
120
|
+
expect(explanationQuantity).toEqual(['-', '-']);
|
|
121
|
+
|
|
122
|
+
const explanationItemCost = getAllByTestId('explanation.itemCost').map(
|
|
123
|
+
n => n.textContent,
|
|
124
|
+
);
|
|
125
|
+
expect(explanationItemCost).toEqual([
|
|
114
126
|
`135.57${String.fromCharCode(160)}USD`,
|
|
115
|
-
]);
|
|
116
|
-
// table 2nd row
|
|
117
|
-
expect(tablesContent[2]).toEqual([
|
|
118
|
-
'(group)',
|
|
119
|
-
'2014-08-16',
|
|
120
|
-
'-',
|
|
121
127
|
`200${String.fromCharCode(160)}USD`,
|
|
122
128
|
]);
|
|
129
|
+
|
|
123
130
|
expect(queryByTestId('hasInformation')).toBeNull();
|
|
124
131
|
expect(queryByTestId('totalBenefit')).toBeNull();
|
|
125
132
|
expect(queryByTestId('totalCost')).toBeNull();
|
|
@@ -155,12 +162,17 @@ describe('should render ExplanationOfBenefit component properly', () => {
|
|
|
155
162
|
withCarinBBProfile: true,
|
|
156
163
|
};
|
|
157
164
|
|
|
158
|
-
const {
|
|
159
|
-
|
|
160
|
-
|
|
165
|
+
const {
|
|
166
|
+
container,
|
|
167
|
+
getByTestId,
|
|
168
|
+
queryByTestId,
|
|
169
|
+
queryAllByTestId,
|
|
170
|
+
getAllByTestId,
|
|
171
|
+
getAllByRole,
|
|
172
|
+
} = render(<ExplanationOfBenefit {...defaultProps} />);
|
|
161
173
|
expect(container).not.toBeNull();
|
|
162
174
|
|
|
163
|
-
expect(getByTestId('created').textContent).toEqual('2017
|
|
175
|
+
expect(getByTestId('created').textContent).toEqual('1/5/2017');
|
|
164
176
|
expect(getByTestId('identifier').textContent).toContain(
|
|
165
177
|
'c145d3fe-d56e-dc26-75e9-01e90672f506',
|
|
166
178
|
);
|
|
@@ -175,7 +187,7 @@ describe('should render ExplanationOfBenefit component properly', () => {
|
|
|
175
187
|
'Organization/iAxXvHiphwGGAL48m3B7XXtKlLZg6yXnC1ch84x1up',
|
|
176
188
|
);
|
|
177
189
|
expect(getByTestId('billablePeriod').textContent).toEqual(
|
|
178
|
-
'From: 2017
|
|
190
|
+
'From: 1/5/2017; To: 1/5/2018',
|
|
179
191
|
);
|
|
180
192
|
expect(getByTestId('patient').textContent).toEqual(
|
|
181
193
|
'Patient/f56391c2-dd54-b378-46ef-87c1643a2ba0',
|
|
@@ -192,32 +204,54 @@ describe('should render ExplanationOfBenefit component properly', () => {
|
|
|
192
204
|
'clmrecvddate',
|
|
193
205
|
);
|
|
194
206
|
expect(getByTestId('supportingInfo.timingDate').textContent).toEqual(
|
|
195
|
-
'2017
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
.
|
|
201
|
-
.
|
|
202
|
-
|
|
203
|
-
el.querySelectorAll('.fhir-ui__TableCell').forEach(item => {
|
|
204
|
-
tds.push(String(item.textContent).trim());
|
|
205
|
-
});
|
|
206
|
-
tablesContent.push(tds);
|
|
207
|
-
});
|
|
208
|
-
// table header
|
|
209
|
-
expect(tablesContent[0]).toEqual([
|
|
207
|
+
'1/5/2017',
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// checking if text content of each header cell is equal to mocked data
|
|
211
|
+
const headerCells = getAllByRole('columnheader')
|
|
212
|
+
.slice(0, 4)
|
|
213
|
+
.map(x => x.textContent);
|
|
214
|
+
expect(headerCells).toEqual([
|
|
210
215
|
'Service',
|
|
211
216
|
'Service date',
|
|
212
217
|
'Quantity',
|
|
213
218
|
'Item cost',
|
|
214
219
|
]);
|
|
215
220
|
|
|
216
|
-
//
|
|
217
|
-
|
|
221
|
+
// checking if text content of first column is equal to mocked data
|
|
222
|
+
const explanationService = getAllByTestId('explanation.service').map(
|
|
223
|
+
n => n.textContent,
|
|
224
|
+
);
|
|
225
|
+
const expectedArray = [
|
|
226
|
+
'Encounter for symptom (185345009)',
|
|
227
|
+
'Acute bronchitis (disorder) (10509002)',
|
|
228
|
+
'Measurement of respiratory function (procedure) (23426006)',
|
|
229
|
+
];
|
|
230
|
+
const replaceWhitespaces = text => text.replace(/\s+/g, ' ');
|
|
231
|
+
explanationService.forEach((x, i) => {
|
|
232
|
+
expect(replaceWhitespaces(x)).toEqual(
|
|
233
|
+
replaceWhitespaces(expectedArray[i]),
|
|
234
|
+
);
|
|
235
|
+
});
|
|
218
236
|
|
|
219
237
|
expect(queryAllByTestId('items.level')).not.toBeNull();
|
|
220
238
|
expect(queryAllByTestId('items.sequence')).not.toBeNull();
|
|
221
239
|
expect(queryAllByTestId('items.sequence')).toHaveLength(3);
|
|
222
240
|
});
|
|
241
|
+
|
|
242
|
+
it('should render C4BB diagnosis fields', () => {
|
|
243
|
+
const defaultProps = {
|
|
244
|
+
fhirResource: exampleC4BBExtendedDiagnosis,
|
|
245
|
+
fhirVersion: fhirVersions.R4,
|
|
246
|
+
withCarinBBProfile: true,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const { container, queryByTestId, getByTestId } = render(
|
|
250
|
+
<ExplanationOfBenefit {...defaultProps} />,
|
|
251
|
+
);
|
|
252
|
+
expect(container).not.toBeNull();
|
|
253
|
+
|
|
254
|
+
expect(getByTestId('diagnosisOnAdmission').textContent).toContain('?');
|
|
255
|
+
expect(queryByTestId('diagnosisPackageCode')).toBeNull();
|
|
256
|
+
});
|
|
223
257
|
});
|
|
@@ -18,7 +18,7 @@ import Period from '../../datatypes/Period';
|
|
|
18
18
|
const Items = ({ fhirData: items = [] }) => {
|
|
19
19
|
if (items.length === 0) return null;
|
|
20
20
|
return (
|
|
21
|
-
<ValueSection label="Items" data-testid="items">
|
|
21
|
+
<ValueSection label="Items" data-testid="items" marginTop>
|
|
22
22
|
<Table>
|
|
23
23
|
<thead>
|
|
24
24
|
<TableRow>
|
|
@@ -33,7 +33,7 @@ const Items = ({ fhirData: items = [] }) => {
|
|
|
33
33
|
<TableHeader>Net</TableHeader>
|
|
34
34
|
</TableRow>
|
|
35
35
|
</thead>
|
|
36
|
-
<tbody>
|
|
36
|
+
<tbody className="border-top-0">
|
|
37
37
|
{items.map((item, idx) => (
|
|
38
38
|
<Item key={idx} item={item} level={0} parentSequences={[]} />
|
|
39
39
|
))}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { parseValueIntoMonetaryValueOfGivenCurrency } from '../../../utils';
|
|
3
|
+
|
|
4
|
+
const PriceLabel = ({ ...props }) => {
|
|
5
|
+
const { totalCost } = props;
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<h3
|
|
9
|
+
className="fw-bold fs-2 mb-0 w-90 title-width-sm"
|
|
10
|
+
data-testid="headerPrice"
|
|
11
|
+
>
|
|
12
|
+
{parseValueIntoMonetaryValueOfGivenCurrency(
|
|
13
|
+
totalCost.value,
|
|
14
|
+
totalCost.code,
|
|
15
|
+
)}
|
|
16
|
+
</h3>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default PriceLabel;
|
|
@@ -15,17 +15,17 @@ const Related = ({ fhirData }) => {
|
|
|
15
15
|
return (
|
|
16
16
|
<div key={`total-${index}`}>
|
|
17
17
|
{claim && (
|
|
18
|
-
<Value label="Claim" data-testid="claim">
|
|
18
|
+
<Value label="Claim" data-testid="claim" dirColumn>
|
|
19
19
|
<Reference fhirData={claim} />
|
|
20
20
|
</Value>
|
|
21
21
|
)}
|
|
22
22
|
{relationship && (
|
|
23
|
-
<Value label="Relationship" data-testid="relationship">
|
|
23
|
+
<Value label="Relationship" data-testid="relationship" dirColumn>
|
|
24
24
|
<CodeableConcept fhirData={relationship} />
|
|
25
25
|
</Value>
|
|
26
26
|
)}
|
|
27
27
|
{reference && (
|
|
28
|
-
<Value label="Reference" data-testid="reference">
|
|
28
|
+
<Value label="Reference" data-testid="reference" dirColumn>
|
|
29
29
|
<Identifier fhirData={reference} />
|
|
30
30
|
</Value>
|
|
31
31
|
)}
|
|
@@ -19,24 +19,34 @@ const SupportingInfo = ({ fhirData }) => {
|
|
|
19
19
|
<ValueSection
|
|
20
20
|
label={`Supporting information ${sequence}.`}
|
|
21
21
|
data-testid="supportingInfo"
|
|
22
|
+
marginTop
|
|
22
23
|
>
|
|
23
24
|
{category && (
|
|
24
|
-
<Value
|
|
25
|
+
<Value
|
|
26
|
+
dirColumn
|
|
27
|
+
label="Category"
|
|
28
|
+
data-testid="supportingInfo.category"
|
|
29
|
+
>
|
|
25
30
|
<CodeableConcept fhirData={category} />
|
|
26
31
|
</Value>
|
|
27
32
|
)}
|
|
28
33
|
{code && (
|
|
29
|
-
<Value label="Code" data-testid="supportingInfo.code">
|
|
34
|
+
<Value dirColumn label="Code" data-testid="supportingInfo.code">
|
|
30
35
|
<CodeableConcept fhirData={code} />
|
|
31
36
|
</Value>
|
|
32
37
|
)}
|
|
33
38
|
{timingDate && (
|
|
34
|
-
<Value
|
|
39
|
+
<Value
|
|
40
|
+
dirColumn
|
|
41
|
+
label="Date"
|
|
42
|
+
data-testid="supportingInfo.timingDate"
|
|
43
|
+
>
|
|
35
44
|
<Date fhirData={timingDate} />
|
|
36
45
|
</Value>
|
|
37
46
|
)}
|
|
38
47
|
{timingPeriodStart && (
|
|
39
48
|
<Value
|
|
49
|
+
dirColumn
|
|
40
50
|
label="Start date"
|
|
41
51
|
data-testid="supportingInfo.timingPeriodStart"
|
|
42
52
|
>
|
|
@@ -45,6 +55,7 @@ const SupportingInfo = ({ fhirData }) => {
|
|
|
45
55
|
)}
|
|
46
56
|
{timingPeriodEnd && (
|
|
47
57
|
<Value
|
|
58
|
+
dirColumn
|
|
48
59
|
label="End date"
|
|
49
60
|
data-testid="supportingInfo.timingPeriodEnd"
|
|
50
61
|
>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Value } from '../../ui/index';
|
|
4
|
+
import { ValueSection } from '../../ui/index';
|
|
5
|
+
import ExplanationOfBenefitGraph from '../ExplanationOfBenefitGraph/ExplanationOfBenefitGraph';
|
|
6
|
+
import { parseValueIntoMonetaryValueOfGivenCurrency } from '../../../utils';
|
|
7
|
+
|
|
8
|
+
const TotalGraph = ({ fhirData }) => {
|
|
9
|
+
const { totalCost, totalBenefit } = fhirData;
|
|
10
|
+
|
|
11
|
+
// currently supported format: STU3
|
|
12
|
+
const getChartData = () => {
|
|
13
|
+
if (totalCost && totalBenefit) {
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
id: 'youPaid',
|
|
17
|
+
label: 'You paid',
|
|
18
|
+
value: totalCost.value - totalBenefit.value,
|
|
19
|
+
color: '#0D6EFD',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'planDiscount',
|
|
23
|
+
label: 'Plan discount',
|
|
24
|
+
value: totalBenefit.value,
|
|
25
|
+
color: '#FFC107',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<ValueSection label="Total" data-testid="total" marginTop>
|
|
33
|
+
<div className="bg-light my-3 py-2 d-flex flex-column flex-sm-row">
|
|
34
|
+
<div className="graph-width-sm">
|
|
35
|
+
<ExplanationOfBenefitGraph
|
|
36
|
+
pieChartProperties={{ isInteractive: false }}
|
|
37
|
+
data={getChartData({ totalCost, totalBenefit })}
|
|
38
|
+
margin={{ top: 20, bottom: 20 }}
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
<div className="my-sm-auto">
|
|
42
|
+
<div className="row justify-content-center">
|
|
43
|
+
{getChartData({ totalCost, totalBenefit }).map((item, index) => (
|
|
44
|
+
<div
|
|
45
|
+
key={`graph-legend-item-${index}`}
|
|
46
|
+
style={{ minWidth: 160 }}
|
|
47
|
+
className="d-flex mb-2 px-3 w-auto"
|
|
48
|
+
>
|
|
49
|
+
<span
|
|
50
|
+
className="me-2 rounded-pill mt-3 mb-2 my-sm-0"
|
|
51
|
+
style={{ width: 4, background: item.color }}
|
|
52
|
+
/>
|
|
53
|
+
<Value dirColumn label={item.label} data-testid={item.id}>
|
|
54
|
+
{parseValueIntoMonetaryValueOfGivenCurrency(
|
|
55
|
+
item.value,
|
|
56
|
+
totalBenefit.code,
|
|
57
|
+
)}
|
|
58
|
+
</Value>
|
|
59
|
+
</div>
|
|
60
|
+
))}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</ValueSection>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default TotalGraph;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Root } from '../../ui';
|
|
4
|
+
import { ResponsivePie } from '@nivo/pie';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
|
|
7
|
+
const ExplanationOfBenefitGraph = props => {
|
|
8
|
+
const {
|
|
9
|
+
data,
|
|
10
|
+
totalLabel,
|
|
11
|
+
height,
|
|
12
|
+
margin,
|
|
13
|
+
enableValueLabels,
|
|
14
|
+
enableLinkLabels,
|
|
15
|
+
pieChartProperties,
|
|
16
|
+
} = props;
|
|
17
|
+
|
|
18
|
+
const getTotalAmount = () => {
|
|
19
|
+
const total = data.reduce((n, { value }) => n + value, 0);
|
|
20
|
+
return `$${Number(total).toFixed(2)}`;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getValidMargin = margin => {
|
|
24
|
+
const resultMargin = {};
|
|
25
|
+
if (margin) {
|
|
26
|
+
if ('top' in margin) resultMargin.top = margin.top;
|
|
27
|
+
if ('right' in margin) resultMargin.right = margin.right;
|
|
28
|
+
if ('bottom' in margin) resultMargin.bottom = margin.bottom;
|
|
29
|
+
if ('left' in margin) resultMargin.left = margin.left;
|
|
30
|
+
}
|
|
31
|
+
return resultMargin;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const CenteredMetric = () => (
|
|
35
|
+
<div className="position-absolute d-flex flex-column w-100 translate-middle-y top-50">
|
|
36
|
+
<h6 className="text-secondary" data-testid="metricText">
|
|
37
|
+
{totalLabel || 'Total'}
|
|
38
|
+
</h6>
|
|
39
|
+
<h5 className="fw-bold text-dark" data-testid="metricAmount">
|
|
40
|
+
{getTotalAmount()}
|
|
41
|
+
</h5>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Root name="ExplanationOfBenefitGraph">
|
|
47
|
+
{/* according to nivo library documentation, to keep Pie Chart svg aligned, 'height' prop has to be constant */}
|
|
48
|
+
<div
|
|
49
|
+
style={{ height: height || 200 }}
|
|
50
|
+
className="position-relative text-center"
|
|
51
|
+
data-testid="responsivePie"
|
|
52
|
+
>
|
|
53
|
+
<ResponsivePie
|
|
54
|
+
data={data}
|
|
55
|
+
margin={getValidMargin(margin)}
|
|
56
|
+
colors={{ datum: 'data.color' }}
|
|
57
|
+
enableArcLabels={enableValueLabels || false}
|
|
58
|
+
enableArcLinkLabels={enableLinkLabels || false}
|
|
59
|
+
innerRadius={0.88}
|
|
60
|
+
activeOuterRadiusOffset={1}
|
|
61
|
+
borderWidth={0.1}
|
|
62
|
+
borderColor={{ from: 'color', modifiers: [['darker', 0.2]] }}
|
|
63
|
+
{...pieChartProperties}
|
|
64
|
+
/>
|
|
65
|
+
<CenteredMetric />
|
|
66
|
+
</div>
|
|
67
|
+
</Root>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
ExplanationOfBenefitGraph.propTypes = {
|
|
72
|
+
data: PropTypes.arrayOf(
|
|
73
|
+
PropTypes.shape({
|
|
74
|
+
id: PropTypes.string.isRequired,
|
|
75
|
+
label: PropTypes.string.isRequired,
|
|
76
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
77
|
+
.isRequired,
|
|
78
|
+
color: PropTypes.string.isRequired,
|
|
79
|
+
}),
|
|
80
|
+
).isRequired,
|
|
81
|
+
height: PropTypes.string,
|
|
82
|
+
margin: PropTypes.shape({}),
|
|
83
|
+
enableValueLabels: PropTypes.bool,
|
|
84
|
+
enableLinkLabels: PropTypes.bool,
|
|
85
|
+
totalLabel: PropTypes.string,
|
|
86
|
+
pieChartProperties: PropTypes.shape({}),
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default ExplanationOfBenefitGraph;
|
package/src/components/resources/ExplanationOfBenefitGraph/ExplanationOfBenefitGraph.stories.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import ExplanationOfBenefitGraph from './ExplanationOfBenefitGraph';
|
|
4
|
+
|
|
5
|
+
export default { title: 'ExplanationOfBenefitGraph' };
|
|
6
|
+
|
|
7
|
+
const CHART_DATA = [
|
|
8
|
+
{
|
|
9
|
+
id: 'a',
|
|
10
|
+
label: 'a',
|
|
11
|
+
value: 35,
|
|
12
|
+
color: '#3498DB',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'b',
|
|
16
|
+
label: 'b',
|
|
17
|
+
value: 200,
|
|
18
|
+
color: '#17A589',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'c',
|
|
22
|
+
label: 'c',
|
|
23
|
+
value: 76,
|
|
24
|
+
color: '#D4AC0D',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'd',
|
|
28
|
+
label: 'd',
|
|
29
|
+
value: 76,
|
|
30
|
+
color: '#EDBB99',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
export const DefaultExplanationOfBenefitGraph = () => {
|
|
35
|
+
return (
|
|
36
|
+
<ExplanationOfBenefitGraph
|
|
37
|
+
data={CHART_DATA}
|
|
38
|
+
margin={{ top: 10, bottom: 10 }}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const ExplanationOfBenefitGraphWithCustomCenteredMetric = () => {
|
|
44
|
+
return <ExplanationOfBenefitGraph data={CHART_DATA} totalLabel="Custom" />;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const ExplanationOfBenefitGraphWithHeightAndMargin = () => {
|
|
48
|
+
return (
|
|
49
|
+
<ExplanationOfBenefitGraph
|
|
50
|
+
data={CHART_DATA}
|
|
51
|
+
margin={{ top: 40, bottom: 40 }}
|
|
52
|
+
height={250}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const ExplanationOfBenefitGraphWithLabels = () => {
|
|
58
|
+
return (
|
|
59
|
+
<ExplanationOfBenefitGraph
|
|
60
|
+
data={CHART_DATA}
|
|
61
|
+
margin={{ top: 20, bottom: 20 }}
|
|
62
|
+
enableLinkLabels
|
|
63
|
+
enableValueLabels
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const ExplanationOfBenefitGraphWithPieChartProperties = () => {
|
|
69
|
+
return (
|
|
70
|
+
<ExplanationOfBenefitGraph
|
|
71
|
+
data={CHART_DATA}
|
|
72
|
+
margin={{ top: 20, bottom: 20 }}
|
|
73
|
+
enableLinkLabels
|
|
74
|
+
enableValueLabels
|
|
75
|
+
pieChartProperties={{ startAngle: 90, cornerRadius: 15, borderWidth: 4 }}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import ExplanationOfBenefitGraph from './ExplanationOfBenefitGraph';
|
|
4
|
+
|
|
5
|
+
const CHART_DATA = [
|
|
6
|
+
{
|
|
7
|
+
id: 'a',
|
|
8
|
+
label: 'a',
|
|
9
|
+
value: 35,
|
|
10
|
+
color: '#3498DB',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 'b',
|
|
14
|
+
label: 'b',
|
|
15
|
+
value: 200,
|
|
16
|
+
color: '#17A589',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'c',
|
|
20
|
+
label: 'c',
|
|
21
|
+
value: 76,
|
|
22
|
+
color: '#D4AC0D',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'd',
|
|
26
|
+
label: 'd',
|
|
27
|
+
value: 76,
|
|
28
|
+
color: '#EDBB99',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
describe('should render ExplanationOfBenefitGraph properly', () => {
|
|
33
|
+
it('should render with ExplanationOfBenefitGraph data', () => {
|
|
34
|
+
const defaultProps = {
|
|
35
|
+
data: CHART_DATA,
|
|
36
|
+
totalLabel: 'Custom',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const { container, getByTestId } = render(
|
|
40
|
+
<ExplanationOfBenefitGraph {...defaultProps} />,
|
|
41
|
+
);
|
|
42
|
+
expect(container).not.toBeNull();
|
|
43
|
+
|
|
44
|
+
expect(getByTestId('responsivePie')).not.toBeNull();
|
|
45
|
+
expect(getByTestId('metricText').textContent).toContain('Custom');
|
|
46
|
+
const totalValue = CHART_DATA.reduce((n, { value }) => n + value, 0);
|
|
47
|
+
expect(getByTestId('metricAmount').textContent).toContain(
|
|
48
|
+
`$${Number(totalValue).toFixed(2)}`,
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -70,7 +70,7 @@ describe('should render Goal component properly', () => {
|
|
|
70
70
|
'Peter James Chalmers',
|
|
71
71
|
);
|
|
72
72
|
|
|
73
|
-
expect(getByTestId('statusDate').textContent).toEqual('2016
|
|
73
|
+
expect(getByTestId('statusDate').textContent).toEqual('2/14/2016');
|
|
74
74
|
|
|
75
75
|
expect(getByTestId('description').textContent).toEqual(
|
|
76
76
|
'Target weight is 160 to 180 lbs.',
|