fhir-react
Version:
React component library for displaying FHIR Resources
413 lines (378 loc) • 12.4 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import _get from 'lodash/get';
import { isNotEmptyArray } from '../../../utils';
import fhirVersions from '../fhirResourceVersions';
import Coding from '../../datatypes/Coding';
import DateType from '../../datatypes/Date';
import Identifier from '../../datatypes/Identifier';
import Money from '../../datatypes/Money';
import Reference from '../../datatypes/Reference';
import UnhandledResourceDataStructure from '../UnhandledResourceDataStructure';
import Items from './Items';
import AddedItems from './AddedItems';
import './ClaimResponse.css';
import {
Badge,
Body,
Header,
MissingValue,
Root,
Title,
Value,
ValueSection,
BadgeSecondary,
} from '../../ui';
const commonDTO = fhirResource => {
const id = _get(fhirResource, 'id');
const created = _get(fhirResource, 'created');
const disposition = _get(fhirResource, 'disposition');
const requestReference = _get(fhirResource, 'request');
const totalCost = _get(fhirResource, 'totalCost');
const totalBenefit = _get(fhirResource, 'totalBenefit');
return {
id,
created,
disposition,
requestReference,
totalCost,
totalBenefit,
};
};
const dstu2DTO = fhirResource => {
const outcome = _get(fhirResource, 'outcome');
const paymentTypeCoding = null;
const paymentAmount = _get(fhirResource, 'paymentAmount');
const paymentDate = _get(fhirResource, 'paymentDate');
const paymentRef = _get(fhirResource, 'paymentRef');
function mapAdjudication(adjudication) {
const category = _get(adjudication, 'code');
const amount = _get(adjudication, 'amount');
const value = _get(adjudication, 'value');
return { category, amount, value };
}
function mapItem(item, level) {
const sequenceLinkId = _get(item, 'sequenceLinkId');
const adjudication = _get(item, 'adjudication', []).map(mapAdjudication);
let subItemProperty;
if (level === 0) subItemProperty = 'detail';
else if (level === 1) subItemProperty = 'subDetail';
const subItems = subItemProperty
? _get(item, subItemProperty, []).map(subItem =>
mapItem(subItem, level + 1),
)
: [];
return { sequenceLinkId, adjudication, subItems };
}
function mapAddedItem(addedItem, level) {
const sequenceLinkId = _get(addedItem, 'sequenceLinkId');
const service = _get(addedItem, 'service');
const fee = _get(addedItem, 'fee');
const adjudication = _get(addedItem, 'adjudication', []).map(
mapAdjudication,
);
let subItemProperty;
if (level === 0) subItemProperty = 'detail';
else if (level === 1) subItemProperty = 'subDetail';
const subItems = subItemProperty
? _get(addedItem, subItemProperty, []).map(subItem =>
mapItem(subItem, level + 1),
)
: [];
return { sequenceLinkId, service, fee, adjudication, subItems };
}
const items = _get(fhirResource, 'item', []).map(item => mapItem(item, 0));
const addedItems = _get(fhirResource, 'addItem', []).map(item =>
mapAddedItem(item, 0),
);
return {
outcome,
payment: {
typeCoding: paymentTypeCoding,
amount: paymentAmount,
date: paymentDate,
ref: paymentRef,
},
items,
addedItems,
};
};
const stu3DTO = fhirResource => {
const outcome =
_get(fhirResource, 'outcome.coding[0].display') ||
_get(fhirResource, 'outcome.coding[0].code');
const paymentTypeCoding = _get(fhirResource, 'payment.type.coding[0]');
const paymentAmount = _get(fhirResource, 'payment.amount');
const paymentDate = _get(fhirResource, 'payment.date');
const paymentRef = _get(fhirResource, 'payment.identifier');
const status = _get(fhirResource, 'status');
function mapAdjudication(adjudication) {
const category = _get(adjudication, 'category.coding[0]');
const amount = _get(adjudication, 'amount');
const value = _get(adjudication, 'value');
return { category, amount, value };
}
function mapItem(item, level) {
const sequenceLinkId = _get(item, 'sequenceLinkId');
const adjudication = _get(item, 'adjudication', []).map(mapAdjudication);
let subItemProperty;
if (level === 0) subItemProperty = 'detail';
else if (level === 1) subItemProperty = 'subDetail';
const subItems = subItemProperty
? _get(item, subItemProperty, []).map(subItem =>
mapItem(subItem, level + 1),
)
: [];
return { sequenceLinkId, adjudication, subItems };
}
function mapAddedItem(addedItem, level) {
const sequenceLinkId = _get(addedItem, 'sequenceLinkId');
const service = _get(addedItem, 'service.coding[0]');
const fee = _get(addedItem, 'fee');
const adjudication = _get(addedItem, 'adjudication', []).map(
mapAdjudication,
);
let subItemProperty;
if (level === 0) subItemProperty = 'detail';
else if (level === 1) subItemProperty = 'subDetail';
const subItems = subItemProperty
? _get(addedItem, subItemProperty, []).map(subItem =>
mapItem(subItem, level + 1),
)
: [];
return { sequenceLinkId, service, fee, adjudication, subItems };
}
const items = _get(fhirResource, 'item', []).map(item => mapItem(item, 0));
const addedItems = _get(fhirResource, 'addItem', []).map(item =>
mapAddedItem(item, 0),
);
return {
outcome,
payment: {
typeCoding: paymentTypeCoding,
amount: paymentAmount,
date: paymentDate,
ref: paymentRef,
},
items,
addedItems,
status,
};
};
const r4DTO = fhirResource => {
const outcome =
_get(fhirResource, 'outcome.coding[0].display') ||
_get(fhirResource, 'outcome.coding[0].code');
const paymentTypeCoding = _get(fhirResource, 'payment.type.coding[0]');
const paymentAmount = _get(fhirResource, 'payment.amount');
const paymentDate = _get(fhirResource, 'payment.date');
const paymentRef = _get(fhirResource, 'payment.identifier');
const status = _get(fhirResource, 'status');
const totalCostsArr = _get(fhirResource, 'total', []).map(item => ({
category:
_get(item, 'category.coding[0].code') || _get(item, 'category.text'),
amount: item.amount,
}));
function mapAdjudication(adjudication) {
const category = _get(adjudication, 'category.coding[0]');
const amount = _get(adjudication, 'amount');
const value = _get(adjudication, 'value');
return { category, amount, value };
}
function mapItem(item, level) {
const sequenceLinkId =
_get(item, 'itemSequence') || _get(item, 'detailSequence');
const adjudication = _get(item, 'adjudication', []).map(mapAdjudication);
let subItemProperty;
if (level === 0) subItemProperty = 'detail';
else if (level === 1) subItemProperty = 'subDetail';
const subItems = subItemProperty
? _get(item, subItemProperty, []).map(subItem =>
mapItem(subItem, level + 1),
)
: [];
return { sequenceLinkId, adjudication, subItems };
}
function mapAddedItem(addedItem, level) {
const sequenceLinkId = _get(addedItem, 'itemSequence.0');
const service = _get(addedItem, 'productOrService.coding[0]');
const fee = _get(addedItem, 'net');
const adjudication = _get(addedItem, 'adjudication', []).map(
mapAdjudication,
);
let subItemProperty;
if (level === 0) subItemProperty = 'detail';
else if (level === 1) subItemProperty = 'subDetail';
const subItems = subItemProperty
? _get(addedItem, subItemProperty, []).map(subItem =>
mapItem(subItem, level + 1),
)
: [];
return { sequenceLinkId, service, fee, adjudication, subItems };
}
const items = _get(fhirResource, 'item', []).map(item => mapItem(item, 0));
const addedItems = _get(fhirResource, 'addItem', []).map(item =>
mapAddedItem(item, 0),
);
return {
outcome,
payment: {
typeCoding: paymentTypeCoding,
amount: paymentAmount,
date: paymentDate,
ref: paymentRef,
},
items,
addedItems,
totalCostsArr,
status,
};
};
const resourceDTO = (fhirVersion, fhirResource) => {
switch (fhirVersion) {
case fhirVersions.DSTU2: {
return {
...commonDTO(fhirResource),
...dstu2DTO(fhirResource),
};
}
case fhirVersions.STU3: {
return {
...commonDTO(fhirResource),
...stu3DTO(fhirResource),
};
}
case fhirVersions.R4: {
return {
...commonDTO(fhirResource),
...r4DTO(fhirResource),
};
}
default:
throw Error('Unrecognized the fhir version property type.');
}
};
// Is any of payment fields not empty
const hasPaymentInfo = payment => {
return Object.values(payment).filter(item => item).length > 0;
};
const ClaimResponse = props => {
const { fhirVersion, fhirResource } = props;
let fhirResourceData = {};
try {
fhirResourceData = resourceDTO(fhirVersion, fhirResource);
} catch (error) {
console.warn(error.message);
return <UnhandledResourceDataStructure resourceName="ClaimResponse" />;
}
const {
id,
outcome,
created,
disposition,
requestReference,
totalCost,
totalBenefit,
payment,
items,
addedItems,
totalCostsArr,
status,
} = fhirResourceData;
const hasItems = items.length > 0;
const hasAddedItems = addedItems.length > 0;
const hasPayment = hasPaymentInfo(payment);
return (
<Root name="ClaimResponse">
<Header>
<Title>Claim response #{id}</Title>
{outcome && <Badge data-testid="outcome">{outcome}</Badge>}
{status && (
<BadgeSecondary data-testid="status">{status}</BadgeSecondary>
)}
</Header>
<Body>
{created && (
<Value label="Created At" data-testid="created">
<DateType fhirData={created} />
</Value>
)}
{requestReference && (
<Value label="Request claim" data-testid="request">
<Reference fhirData={requestReference} />
</Value>
)}
{disposition && (
<Value label="Disposition" data-testid="disposition">
{disposition}
</Value>
)}
{totalCost && (
<Value label="Total cost" data-testid="totalCost">
<Money fhirData={totalCost} />
</Value>
)}
{totalBenefit && (
<Value label="Total benefit" data-testid="totalBenefit">
<Money fhirData={totalBenefit} />
</Value>
)}
{isNotEmptyArray(totalCostsArr) && (
<ValueSection label="Total" data-testid="totalSection">
{totalCostsArr.map(
({ category, amount }, i) =>
category && (
<Value label={category} key={`total-value-${i}`}>
<Money fhirData={amount} />
</Value>
),
)}
</ValueSection>
)}
{hasPayment && (
<ValueSection label="Payment" data-testid="paymentSection">
<Value label="Type" data-testid="payment.type">
{payment.typeCoding ? (
<Coding fhirData={payment.typeCoding} />
) : (
<MissingValue />
)}
</Value>
<Value label="Amount" data-testid="payment.amount">
{payment.amount ? (
<Money fhirData={payment.amount} />
) : (
<MissingValue />
)}
</Value>
<Value label="Date" data-testid="payment.date">
{payment.date ? (
<DateType fhirData={payment.date} />
) : (
<MissingValue />
)}
</Value>
<Value label="Reference" data-testid="payment.ref">
{payment.ref ? (
<Identifier fhirData={payment.ref} />
) : (
<MissingValue />
)}
</Value>
</ValueSection>
)}
{hasAddedItems && <AddedItems addedItems={addedItems} />}
{hasItems && <Items items={items} />}
</Body>
</Root>
);
};
ClaimResponse.propTypes = {
fhirResource: PropTypes.shape({}).isRequired,
fhirVersion: PropTypes.oneOf([
fhirVersions.DSTU2,
fhirVersions.STU3,
fhirVersions.R4,
]).isRequired,
};
export default ClaimResponse;