Skip to content
This repository has been archived by the owner on Jan 7, 2020. It is now read-only.

Commit

Permalink
Merge pull request #26 from cfpb/agg
Browse files Browse the repository at this point in the history
Sets up aggregate and disclosure flows
  • Loading branch information
wpears authored Apr 13, 2018
2 parents 8381611 + 3959414 commit a7930e1
Show file tree
Hide file tree
Showing 21 changed files with 1,002 additions and 345 deletions.
2 changes: 1 addition & 1 deletion nginx/nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ http {
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';

# CSP
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' data: https://www.googletagmanager.com https://www.google-analytics.com; img-src 'self' https://www.google-analytics.com; style-src 'self'; font-src 'self'; object-src 'none'; frame-src ##APP_SERVER## https://www.youtube.com/; connect-src ##APP_SERVER## ##HMDA_API_SERVER## https://ffiec-api.cfpb.gov https://www.google-analytics.com;";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' data: https://www.googletagmanager.com https://www.google-analytics.com; img-src 'self' https://www.google-analytics.com; style-src 'self'; font-src 'self'; object-src 'none'; frame-src ##APP_SERVER## https://www.youtube.com/; connect-src ##APP_SERVER## ##HMDA_API_SERVER## https://ffiec-api.cfpb.gov https://www.google-analytics.com https://s3.amazonaws.com;";

# Prevent buffer tampering
client_body_buffer_size 16k;
Expand Down
28 changes: 28 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import AppHeader from './common/AppHeader.jsx'
import Footer from './common/Footer.jsx'
import Home from './Home.jsx'
import ModifiedLar from './reports/modified-lar/index.jsx'
import Disclosure from './reports/disclosure/index.jsx'
import Aggregate from './reports/aggregate/index.jsx'
import MsaMds from './reports/MsaMds.jsx'
import Reports from './reports/Reports.jsx'
import Report from './reports/Report.jsx'
import NotFound from './common/NotFound.jsx'

const App = () => {
Expand All @@ -15,6 +20,29 @@ const App = () => {
<Route exact path="/" component={Home} />
<Route path="/modified-lar/*" component={NotFound} />
<Route path="/modified-lar" component={ModifiedLar} />
<Route
path="/disclosure-reports/institution/:institutionId/msa-md/:msaMdId/report/:reportId"
component={Report}
/>
<Route
path="/disclosure-reports/institution/:institutionId/msa-md/:msaMdId"
component={Reports}
/>
<Route
path="/disclosure-reports/institution/:institutionId"
component={MsaMds}
/>
<Route path="/disclosure-reports" component={Disclosure} />
<Route
path="/aggregate-reports/state/:stateId/msa-md/:msaMdId/report/:reportId"
component={Report}
/>
<Route
path="/aggregate-reports/state/:stateId/msa-md/:msaMdId"
component={Reports}
/>
<Route path="/aggregate-reports/state/:stateId" component={MsaMds} />
<Route path="/aggregate-reports" component={Aggregate} />
<Route component={NotFound} />
</Switch>
<Footer />
Expand Down
14 changes: 8 additions & 6 deletions src/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Home extends Component {
<div className="home">
<div className="usa-grid">
<div className="usa-width-one-whole">
<Header type="main" headingText="HMDA Data Publication">
<Header type={1} headingText="HMDA Data Publication">
<p className="usa-font-lead">
The HMDA data and reports are the most comprehensive publicly
available information on mortgage market activity. The data and
Expand All @@ -33,25 +33,27 @@ class Home extends Component {
paragraphText="The modified LAR provides loan-level data for an individual
financial institution, as modified by the Bureau to protect applicant and
borrower privacy."
type="sub"
type={4}
/>
</div>

<div className="card">
<Header
headingLink="/disclosure-reports"
headingText="Disclosure Reports"
paragraphText="These reports summarize lending activity for individual
institutions, both nationwide and by MSA/MD."
type="sub"
type={4}
/>
<span className="usa-label">Coming Soon</span>
</div>

<div className="card">
<Header
headingLink="/aggregate-reports"
headingText="MSA/MD Aggregate Reports"
paragraphText="These reports summarize lending activity by MSA/MD."
type="sub"
type={4}
/>
<span className="usa-label">Coming Soon</span>
</div>
Expand All @@ -62,7 +64,7 @@ class Home extends Component {
paragraphText="These reports summarize nationwide lending activity.
They indicate the number and dollar amounts of loan applications,
cross-tabulated by loan, borrower and geographic characteristics."
type="sub"
type={4}
/>
<span className="usa-label">Coming Soon</span>
</div>
Expand All @@ -75,7 +77,7 @@ class Home extends Component {
paragraphText="The snapshot file contains the national loan-level
dataset as of a specific point in time for all HMDA reporters, as
modified by the Bureau to protect applicant and borrower privacy."
type="sub"
type={4}
/>
<span className="usa-label">Expected May 2018</span>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@
@import 'common/LoadingIcon.scss';
@import 'reports/modified-lar/Modified-LAR.scss';
@import 'reports/modified-lar/Results.scss';
@import 'reports/disclosure/Disclosure.scss';
@import 'reports/disclosure/tables/tables.scss';
15 changes: 8 additions & 7 deletions src/common/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ const makeHeadingLink = (headingText, headingLink) => {
}

const renderHeading = (type, heading) => {
if (type === 'main') return <h1>{heading}</h1>
if (type === 'sub') return <h4>{heading}</h4>
if (type === 1) return <h1>{heading}</h1>
if (type === 2) return <h2>{heading}</h2>
if (type === 4) return <h4>{heading}</h4>
}

const renderParagraph = (type, paragraphText) => {
if (type === 'main') return <p className="usa-font-lead">{paragraphText}</p>
if (type === 'sub') return <p>{paragraphText}</p>
if (type === 1) return <p className="usa-font-lead">{paragraphText}</p>
if (type === 4) return <p>{paragraphText}</p>
}

const Header = props => {
let style = { marginBottom: '3em' }
if (props.type === 'sub') style = { marginBottom: '1em' }
let style = { marginBottom: '1em' }
if (props.type === 1) style = { marginBottom: '3em' }

let heading = props.headingText
if (props.headingLink)
Expand All @@ -38,7 +39,7 @@ const Header = props => {
}

Header.propTypes = {
type: PropTypes.oneOf(['main', 'sub']),
type: PropTypes.oneOf([1, 2, 4]),
headingText: PropTypes.string,
paragraphText: PropTypes.string,
headingLink: PropTypes.string
Expand Down
8 changes: 7 additions & 1 deletion src/common/Header.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
.header {
h1,
h2,
h4 {
margin-bottom: 0;
}
.usa-font-lead {
h4 {
margin-top: 4em;
}

.usa-font-lead,
p {
color: $color-gray;
margin-top: 0;
}
Expand Down
119 changes: 119 additions & 0 deletions src/reports/MsaMds.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React from 'react'
import Header from '../common/Header.jsx'

const MSAMDS = [
{ id: '25420', name: 'Harrisburg-Carlisle, PA' },
{ id: '25180', name: 'Hagerstown-Martinsburg, MD-WV' },
{ id: '25060', name: 'Gulfport-Biloxi, MS' },
{ id: '25020', name: 'Guayama, PR' },
{ id: '24860', name: 'Greenville, SC' },
{ id: '24780', name: 'Greenville, NC' },
{ id: '25500', name: 'Harrisonburg, VA' },
{ id: '25540', name: 'Hartford-West Hartford-East Hartford, CT' },
{ id: '25620', name: 'Hattiesburg, MS' },
{ id: '25860', name: 'Hickory-Lenoir-Morganton, NC' },
{ id: '25980', name: 'Hinesville-Fort Stewart, GA' },
{ id: '26100', name: 'Holland-Grand Haven, MI' },
{ id: '26180', name: 'Honolulu, HI' },
{ id: '26300', name: 'Hot Springs, AR' },
{ id: '26380', name: 'Houma-Bayou Cane-Thibodaux, LA' }
]

class MsaMds extends React.Component {
constructor(props) {
super(props)

this.state = {
error: null,
isLoaded: false,
msamds: [],
selectValue: ''
}

this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}

componentDidMount() {
// TODO: load either MSA/MDs for an institution or for a state
let fetchURL = ''
if (this.props.match.params.institutionId)
fetchURL = `https://ffiec-api.cfpb.gov/public/filers/${
this.props.match.params.institutionId
}/msamds`
if (this.props.match.params.stateId)
fetchURL = `https://ffiec-api.cfpb.gov/public/msamds?state=${
this.props.match.params.stateId
}`

this.setState({ msamds: MSAMDS, isLoaded: true, selectValue: MSAMDS[0].id })
/*
fetch(fetchURL)
.then(res => res.json())
.then(
result => {
this.setState({
isLoaded: true,
msamds: result.msamds
})
},
error => {
this.setState({
isLoaded: true,
error
})
}
)*/
}

handleChange(event) {
this.setState({ selectValue: event.target.value })
}

handleSubmit(event) {
this.props.history.push({
pathname: `${this.props.match.url}/msa-md/${this.state.selectValue}`
})
event.preventDefault()
}

render() {
let msaMdsFor = ''
if (this.props.match.params.institutionId)
msaMdsFor = this.props.match.params.institutionId
if (this.props.match.params.stateId)
msaMdsFor = this.props.match.params.stateId

return (
<div className="usa-grid msa-mds" id="main-content">
<Header
type={1}
headingText={`Choose an available MSA/MD for ${msaMdsFor}`}
/>

<form onSubmit={this.handleSubmit}>
<label htmlFor="states">Select a MSA/MD</label>

<select
name="msamds"
id="msamds"
value={this.state.selectValue}
onChange={this.handleChange}
>
{this.state.msamds.map((msamd, index) => {
return (
<option key={index} value={msamd.id}>
{msamd.id} - {msamd.name}
</option>
)
})}
</select>

<input type="submit" value="Next - Find a Report" />
</form>
</div>
)
}
}

export default MsaMds
112 changes: 112 additions & 0 deletions src/reports/Report.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react'
import Header from '../common/Header.jsx'
import FiveDashOne from './disclosure/tables/FiveDashOne.jsx'

class Report extends React.Component {
constructor(props) {
super(props)

this.state = {
error: null,
isLoaded: false,
report: null
}
}

componentDidMount() {
let fetchURL = 'https://s3.amazonaws.com/cfpb-hmda-public/prod/reports'
if (this.props.match.params.institutionId)
fetchURL = `${fetchURL}/disclosure`
if (this.props.match.params.stateId) fetchURL = `${fetchURL}/aggregate`

fetchURL = `${fetchURL}/2017/${this.props.match.params.msaMdId}/${
this.props.match.params.reportId
}.txt`

fetch(fetchURL)
.then(res => res.json())
.then(
result => {
this.setState({
isLoaded: true,
report: result
})
},
error => {
this.setState({
isLoaded: true,
error
})
}
)
}

render() {
if (this.state.error) {
const { params } = this.props.match

let alertHeading = 'Report not found'
if (params.stateId)
alertHeading = `Report ${params.reportId} for 2017 -> ${
params.stateId
} -> ${params.msaMdId} not found`
if (params.institutionId)
alertHeading = `Report ${params.reportId} for 2017 -> ${
params.institutionId
} -> ${params.msaMdId} not found`

return (
<div
className="usa-grid"
id="main-content"
style={{ marginTop: '3em' }}
>
<div className="usa-alert usa-alert-error" role="alert">
<div className="usa-alert-body">
<h3 className="usa-alert-heading">{alertHeading}</h3>
<p className="usa-alert-text">
Sorry, we couldn't find that report. Try to refresh the page. If
the problem persists please contact HMDA Help.
</p>
</div>
</div>
</div>
)
}

if (this.state.report === null) return null

const report = this.state.report
const headingText = report
? `Table ${report.table}: ${report.description}, ${report.year}`
: null
return (
<div className="report" id="main-content">
<Header type={4} headingText={headingText}>
<React.Fragment>
<p style={{ width: '50%', display: 'inline-block' }}>
Institution: {report.respondentId} - {report.institutionName}
</p>
<p
style={{
width: '50%',
display: 'inline-block',
textAlign: 'right'
}}
>
MSA/MD: {report.msa.id} - {report.msa.name}
</p>
</React.Fragment>
</Header>

<FiveDashOne report={report} />

<p className="usa-text-small report-date">
Report date: {report.reportDate}
</p>
</div>
)
}
}

export default Report
Loading

0 comments on commit a7930e1

Please sign in to comment.