Skip to content

BB2-1728: Proof of concept for C4DIC implementation #90

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a37883a
Added sample DIC frontend implementation
loganbertram Jul 3, 2024
4a48f9c
Fixed header typecheck err.
loganbertram Jul 8, 2024
5de2ee2
Updated placeholder values
loganbertram Jul 9, 2024
8af2fca
Change tab title
loganbertram Jul 9, 2024
315d7c6
BB2-3280 FE POC hookup cards with c4dic data, mesc ui layout, dev hel…
JFU-NAVA-PBC Aug 22, 2024
53aa33f
adj layout
JFU-NAVA-PBC Aug 23, 2024
88f59e9
cleanups
JFU-NAVA-PBC Aug 23, 2024
ca10727
added insurance info composition in server component
JFU-NAVA-PBC Aug 24, 2024
8ad0a47
more fix insurance composition, ins flds text font sz + color
JFU-NAVA-PBC Aug 24, 2024
fb981b4
added 'card in new window' link - for dev mode mobile view
JFU-NAVA-PBC Aug 26, 2024
887b3d0
changes made per feedback
JFU-NAVA-PBC Aug 27, 2024
67fdf8b
final touches.
JFU-NAVA-PBC Aug 28, 2024
dde9f77
point to bb2 local from feature branch as server with FHIR_URL=test.b…
JFU-NAVA-PBC Aug 29, 2024
5d48c7d
render c4dic coverage supporting image etc.
JFU-NAVA-PBC Sep 3, 2024
3f19b6d
adjust code to process C4DIC Coverage from BFD TEST, e.g. payer as co…
JFU-NAVA-PBC Sep 4, 2024
644ec1e
Merge pull request #76 from CMSgov/jimfuqian/BB2-3280-POC-from-c4dic-…
JFU-NAVA-PBC Sep 9, 2024
a09c510
BB2-3391: Adjust C4DIC FE sample client (#79)
jimmyfagan Sep 24, 2024
d6290eb
Feature/c4dic jimmy bb2 3391 (#81)
jimmyfagan Oct 16, 2024
e28c765
BB2-3524: Contract ID and formatting updates (#83)
jimmyfagan Nov 19, 2024
152af01
BB2-3555: Final adjustments for C4DIC FE POC (#87)
jimmyfagan Dec 19, 2024
ac6a45d
Adjustments to log statement and sample data
jimmyfagan Dec 20, 2024
90eb9b6
Merge branch 'main' of https://github.com/CMSgov/bluebutton-sample-cl…
jimmyfagan Jan 27, 2025
0abd63b
Fix lint errors
jimmyfagan Jan 28, 2025
b1062ea
Revert changes to eobData.json
jimmyfagan Jan 28, 2025
e9da74b
Revert more unneeded changes
jimmyfagan Jan 28, 2025
e0a95cb
Fix jsonpath-ng install
jimmyfagan Jan 28, 2025
57a3f64
Remove whitespace change
jimmyfagan Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ sandbox.env

config.py
config.json
.bluebutton-config.json
.bluebutton-config.json*

# Generic
*.pyc
Expand Down
93 changes: 57 additions & 36 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,73 @@ import React from 'react';
import Header from '../src/components/header';
import Patient from '../src/components/patient';
import PatientData from './components/patientData';
import InsuranceCard from './components/c4dic'
import Records from './components/records';
import { BrowserRouter as Router} from "react-router-dom";
import { TabPanel, Tabs } from '@cmsgov/design-system';

function App() {
return (
<div className="ds-l-container ds-u-margin-bottom--7 ds-u-padding-bottom--7">
<Header />
<Router>
<Tabs tablistClassName="ds-u-margin-top--3">
<TabPanel id="patient" tab="Patient info">
<h2>Patient information</h2>
<div className="ds-u-display--flex ds-u-flex-direction--column ds-u-lg-flex-direction--row ds-u-flex-wrap--nowrap ds-u-lg-flex-wrap--wrap">
<div className="bb-c-card default-card">
<Patient />
</div>
<div className="bb-c-card default-card">
<PatientData />
</div>
</div>
{}
<Records />
{}
<div>
<div>
{}
</div>
if (window.location.pathname.endsWith('card_only')) {
return (
<div className="ds-l-container ds-u-margin-bottom--7 ds-u-padding-bottom--7">
<Router>
<div className="bb-c-c4dic-card default-card">
<InsuranceCard />
</div>
</TabPanel>
<TabPanel id="summary" tab="Summary">
</Router>
</div>
);
}
else {
return (
<div className="ds-l-container ds-u-margin-bottom--7 ds-u-padding-bottom--7">
<Router>
<Header />
<div>
<p className='ds-u-measure--base'>
Blue Button 2.0 is a standards-based application programming interface (API) that delivers Medicare Part A, B, and D data for over 60 million Medicare beneficiaries. <a href="https://bluebutton.cms.gov/">Learn more about Blue Button 2.0</a>
Blue Button 2.0 is a standards-based application programming interface (API) that delivers Medicare Part A, B, and D data for over 60 million Medicare beneficiaries. <a href="https://bluebutton.cms.gov/">Learn more about Blue Button 2.0</a>
</p>

<p className='ds-u-measure--base'>
The CMS design system is a set of open source design and front-end development resources
for creating Section 508 compliant, responsive, and consistent websites. It builds on the
U.S. Web Design System and extends it to support additional CSS and React components,
utility classes, and a grid framework to allow teams to quickly prototype and build
accessible, responsive, production-ready websites. <a href="https://design.cms.gov/">Learn more about CMS Design System</a>
The CMS design system is a set of open source design and front-end development resources for creating Section 508 compliant, responsive, and consistent websites. It builds on the U.S. Web Design System and extends it to support additional CSS and React components, utility classes, and a grid framework to allow teams to quickly prototype and build accessible, responsive, production-ready websites. <a href="https://design.cms.gov/">Learn more about CMS Design System</a>
</p>
</TabPanel>
</Tabs>
</Router>
</div>
);
</div>

<Tabs tablistClassName="ds-u-margin-top--3">
<TabPanel id="patient" tab="Patient">
<div className="ds-u-display--flex ds-u-flex-direction--column ds-u-lg-flex-direction--row ds-u-flex-wrap--nowrap ds-u-lg-flex-wrap--wrap">
<table>
<tr>
<td>
<div className="bb-c-card default-card">
<Patient />
</div>
</td>
<td>
<div className="bb-c-card default-card">
<PatientData />
</div>
</td>
</tr>
</table>
</div>
</TabPanel>
<TabPanel id="claims" tab="Claims">
<div>
<Records />
</div>
</TabPanel>
<TabPanel id="dic-new-design" tab="Insurance Card">
<a href='/card_only' target="_blank">Show in new window</a>
<div className="bb-c-c4dic-card default-card">
<InsuranceCard />
</div>
</TabPanel>
</Tabs>
</Router>
</div>
);
}
}

export default App;
265 changes: 265 additions & 0 deletions client/src/components/c4dic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
import { Table, TableCaption, TableRow, TableCell, TableHead, TableBody } from '@cmsgov/design-system';
import React, { useEffect, useState } from 'react';

// From C4DIC Patient extract:
// 1. identifier mbi, e.g. 1S00EU7JH47
// 2. name, e.g. Johnie C
// From C4DIC Coverage extract:
// 1. coverage class: by Coverage resource 'class': "Part A"
// 2. status: active or not active
// 3. period, start date: e.g. 2014-02-06
// 4. payor: CMS
// 5. contract number: e.g. Part D , Part C: ptc_cntrct_id_01...12
// 6. reference year: e.g. Part A: 2025, Part B: 2025, etc.
// 7. other info such as: DIB, ESRD etc. can be added as needed

export type CoverageInfo = {
coverageClass: string,
contractId: string,
startDate: string,
endDate: string,
payer: string,
status: string,
medicaidEligibility: string,
referenceYear: string,
entitlementReason: string,
colorPalette: {
foreground: string,
background: string,
highlight: string
},
logo: string,
addlCardInfo: string,
contacts: string[]
}

export type InsuranceInfo = {
name: string,
identifier: string, // mbi
coverages: CoverageInfo[] // e.g. Part A, Part B, Part C, Part D
}

export type ErrorResponse = {
type: string,
content: string,
}

export default function InsuranceCard() {
const [insInfo, setInsInfo] = useState<InsuranceInfo>();
const [message, setMessage] = useState<ErrorResponse>();
/*
* DEVELOPER NOTES:
*/
useEffect(() => {
fetch('/api/data/insurance')
.then(res => {
return res.json();
}).then(insuranceData => {
if (insuranceData.insData) {
const coveragesList: CoverageInfo[] = insuranceData.insData?.coverages.map((c: any) => {
return {
coverageClass: c.coverageClass,
payer: c.payer,
contractId: c.contractId,
startDate: c.startDate,
endDate: c.endDate,
status: c.active,
medicaidEligibility: c.medicaidEligibility,
referenceYear: c.referenceYear,
entitlementReason: c.entitlementReason,
colorPalette: {
foreground: c.colorPalette.foreground,
background: c.colorPalette.background,
highlight: c.colorPalette.highlight
},
logo: c.logo,
addlCardInfo: c.addlCardInfo,
contacts: c.contacts
}
});

setInsInfo(
{
name: insuranceData.insData.name,
identifier: insuranceData.insData.identifier,
coverages: coveragesList
}
);
}
else {
if (insuranceData.message) {
setMessage({"type": "error", "content": insuranceData.message || "Unknown"})
}
}
});
}, [])

if (message) {
return (
<div className='full-width-card'>
<Table className="ds-u-margin-top--2" stackable stackableBreakpoint="md">
<TableCaption>Error Response</TableCaption>
<TableHead>
<TableRow>
<TableCell id="column_1">Type</TableCell>
<TableCell id="column_2">Content</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell stackedTitle="Type" headers="column_1">
{message.type}
</TableCell>
<TableCell stackedTitle="Content" headers="column_2">
{message.content}
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
);
} else {
var backgroundColor = insInfo?.coverages[0]?.colorPalette.background
var highlightColor = insInfo?.coverages[0]?.colorPalette.highlight
var textColor = insInfo?.coverages[0]?.colorPalette.foreground
const root = document.documentElement;
if (backgroundColor != null) {
root.style.setProperty('--c4dic-backgroundColor', backgroundColor);
}
if (highlightColor != null) {
root.style.setProperty('--c4dic-highlightColor', highlightColor);
}
if (textColor != null) {
root.style.setProperty('--c4dic-textColor', textColor);
}
const medicaidEligibility = (insInfo?.coverages[0]?.medicaidEligibility != null) ?
(
<div>
<text className="field-label">Medicaid Eligibility</text>
<br/>
<div className="bb-c-c4dic-badge-container">
<div className="bb-c-c4dic-badge">{insInfo?.coverages[0]?.medicaidEligibility}</div>
</div>
</div>
) : null
return (
<div className="ins-c4dic-card">
<div className="bb-c-c4dic-card-header">
<img src={insInfo?.coverages[0]?.logo} alt="C4DIC Logo" height="48px"/>
<h3>{insInfo?.coverages[0]?.payer}</h3>
</div>
<div className="pii-sec bb-c-c4dic-card-pii-area">
<div className="ins-fld-text patient-name">
<div>
<text className="field-label">Name</text>
<br/>
<text className="field-value">{insInfo?.name||""}</text>
</div>
</div>
<div className="ins-fld-text patient-info">
<div>
<text className="field-label">Medicare Number</text>
<br/>
<text className="field-value">{insInfo?.identifier||""}</text>
</div>
{medicaidEligibility}
</div>
</div>

<div className="coverage-sec bb-c-c4dic-card-coverages-area">
<hr/>
<h6>Benefits</h6>
{insInfo?.coverages.map(c => {
const startDateDiv = (c.startDate !== null && c.startDate !== "") ?
(
<div style={{ width: '70px'}}>
<text className="field-label">Start Date</text>
<br/>
<text className="field-value">{c.startDate}</text>
</div>
) : null
switch (c.coverageClass) {
case "Part A":
return (
<div className="bb-c-c4dic-coverage-a">
<div style={{ width: '60px'}}>
<text className="field-label">Coverage</text>
<br/>
<text className="field-value">Hospital<br/>{c.coverageClass}</text>
</div>
{startDateDiv}
<div>
<text className="field-label">Entitlement Reason</text>
<br/>
<text className="field-value">{c.entitlementReason}</text>
</div>
</div>
)
case "Part B":
return (
<div className="bb-c-c4dic-coverage-b">
<div style={{ width: '60px'}}>
<text className="field-label">Coverage</text>
<br/>
<text className="field-value">Medical<br/>{c.coverageClass}</text>
</div>
{startDateDiv}
</div>
)
case "Part C":

return (
<div className="bb-c-c4dic-coverage-c">
<div style={{ width: '60px'}}>
<text className="field-label">Coverage</text>
<br/>
<text className="field-value">{c.coverageClass}</text>
</div>
<div>
<text className="field-label">Plan #</text>
<br/>
<text className="field-value">{c.contractId}</text>
</div>
</div>
)
case "Part D":
return (
<div className="bb-c-c4dic-coverage-d">
<div style={{ width: '60px'}}>
<text className="field-label">Coverage</text>
<br/>
<text className="field-value">Rx<br/>{c.coverageClass}</text>
</div>
{startDateDiv}
<div>
<text className="field-label">Plan #</text>
<br/>
<text className="field-value">{c.contractId}</text>
</div>
</div>
)
default:
return []
}
})}
</div>
<div className="bb-c-c4dic-card-org-contact">
<hr/>
<h6>Contact</h6>

<text className="field-label">Customer Service</text>
<br/>
<div className="contact-list">
{insInfo?.coverages[0]?.contacts.map(contact => {
return <text className="field-value">{contact}</text>
})}
</div>
<br/>
</div>
<div className="bb-c-c4dic-card-additional-card-info">
<text>{insInfo?.coverages[0]?.addlCardInfo}</text>
</div>
</div>
);
}
}
2 changes: 1 addition & 1 deletion client/src/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function Header() {
</h1>
<div className="ds-u-text-align--center">
<Badge variation="info" size="big">
Medicare Prescription Drug Claims Data
Medicare Coverage and Prescription Drug Claims Data
</Badge>
</div>
</header>
Expand Down
Loading