diff --git a/.gatsby-context.js b/.gatsby-context.js deleted file mode 100644 index 62c8acaa..00000000 --- a/.gatsby-context.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -// This file is auto-written and used by Gatsby to require -// files from your pages directory. -module.exports = function (callback) { - var context = require.context('./pages', true); - if (module.hot) { - module.hot.accept(context.id, function () { - context = require.context('./pages', true); - return callback(context); - }); - } - return callback(context); -}; \ No newline at end of file diff --git a/app.js b/app.js index c8950c41..58b203a5 100644 --- a/app.js +++ b/app.js @@ -1,11 +1,11 @@ /* @flow */ exports.loadContext = (cb: Function): Function => { - const ctx = require.context('./pages', true) + const ctx = require.context('./src/pages', true) if (module.hot) { module.hot.accept(ctx.id, function() { - const ctx = require.context('./pages', true) + const ctx = require.context('./src/pages', true) return cb(ctx) }) } diff --git a/components/ApiKey.jsx b/components/ApiKey.jsx deleted file mode 100644 index 2577486e..00000000 --- a/components/ApiKey.jsx +++ /dev/null @@ -1,57 +0,0 @@ -/* @flow */ - -import React from 'react' -import ApiKeyContainer from '../containers/ApiKeyContainer' - -/** - * @description [api key widget for signing up api users] - * @param {Object} props [from ApiKeyContainer. apiKey if requested, onSubmit cb] - */ -const ApiKey = (props: Object) => ( -
-
-
- { - props.showForm === false && - - } - { - !props.apiKey && props.showForm === true && -
- - -
- } - { - props.apiKey && -
- Congrats! Your API Key is: - {props.apiKey} -
- } -
-
-
-) - -ApiKey.displayName = 'components/ApiKey' -export default ApiKeyContainer(ApiKey) diff --git a/components/ApiStatus.jsx b/components/ApiStatus.jsx deleted file mode 100644 index 56d2787a..00000000 --- a/components/ApiStatus.jsx +++ /dev/null @@ -1,126 +0,0 @@ -/* @flow */ - -import React from 'react' -import cx from 'classnames' - -import Hero from './Hero' -import Layout from './Layout' -import ApiStatusContainer from '../containers/ApiStatusContainer' - -type tPROPS = { - data: Array; -}; - -const catMap: Object = Object.freeze({ - 'foodenforcement': 'Foods › Enforcement Reports', - 'foodevent': 'Foods › Adverse Events', - 'drugevent': 'Drugs › Adverse Events', - 'druglabel': 'Drugs › Labeling', - 'drugenforcement': 'Drugs › Enforcement Reports', - 'deviceevent': 'Devices › Adverse Events', - 'devicerecall': 'Devices › Recalls', - 'deviceclass': 'Devices › Classification', - 'devicereglist': 'Devices › Registration', - 'deviceclearance': 'Devices › 510k', - 'devicepma': 'Devices › PMA', - 'deviceudi': 'Devices › UDI', - 'deviceenforcement': 'Devices › Enforcement Reports' -}) - - -const endpointLinkMap: Object = Object.freeze({ - 'foodevent': 'food/event', - 'foodenforcement': 'food/enforcement', - 'drugevent': 'drug/event', - 'druglabel': 'drug/label', - 'drugenforcement': 'drug/enforcement', - 'deviceevent': 'device/event', - 'devicerecall': 'device/recall', - 'deviceclass': 'device/classification', - 'devicereglist': 'device/registrationlisting', - 'deviceclearance': 'device/510k', - 'devicepma': 'device/pma', - 'deviceudi': 'device/udi', - 'deviceenforcement': 'device/enforcement' -}) - -/** - * @description [component for rendering apiStatus page] - * @param {Object} props [from ApiStatusContainer. has response data] - */ -const ApiStatus = (props: tPROPS) => ( - - -
-
    - { - props.data.map((end: Object, i) => { - const { endpoint, status, } = end - - const catCx = cx({ - 'weight-600 marg-b-1': true, - 'clr-secondary': status !== 'GREEN', - 'clr-green': status === 'GREEN', - }) - - const liStyl: Object = Object.freeze({ - borderTop: status === 'GREEN' ? - '5px solid #2e8540' : - '5px solid #e31c3d' - }) - - const pStyl: Object = Object.freeze({ - background: status === 'GREEN' ? '#2e8540' : '#e31c3d', - }) - - return ( -
  • -

    {catMap[endpoint]}

    -

    api.fda.gov/{endpointLinkMap[endpoint]}

    -
      -
    • - Status -

      - { - status === 'GREEN' ? - 'OK' - : - 'OFFLINE' - } -

      -
    • -
    • - Last Updated -

      - {end.last_updated} -

      -
    • -
    • - Total records -

      - {end.documents} -

      -
    • -
    -
  • - ) - }) - } -
-
-
-) - -ApiStatus.displayName = 'component/ApiStatus' -export default ApiStatusContainer(ApiStatus) diff --git a/components/ApiUsage.jsx b/components/ApiUsage.jsx deleted file mode 100644 index dd71c5d3..00000000 --- a/components/ApiUsage.jsx +++ /dev/null @@ -1,242 +0,0 @@ -import React from 'react' -import Charts from 'react-chartjs' -const Line:ReactClass = Charts.Line -import xhrGET from '../utils/xhr' -import bp from '../constants/breakpoints' -import Table from './Table' -import { API_LINK, API_NAME } from '../constants/api' - - -type tPROPS = { - accessSinceLaunch: string, - dynamicDisclaimer: string -}; - - -// mobile sizing for infographic -// window - 40 (margin) - 40 (padding) -const hasWindow: boolean = typeof window !== 'undefined' -let size: number = hasWindow ? window.innerWidth - 80 : 300 - -// desktop sizing is a little more complicated -// we calculate the width based on window -// and what we know about how the layout will be -if (!bp.mob && hasWindow) { - const winWidth: number = window.innerWidth - - // 1400 = site-container width - // .73 = 25% sidebar + 2% margin (100 - 27) - // .67 = width of infographic container - // 40 = padding for infographic container - if (winWidth >= 1400) { - size = (1400) - 340 - } - else if (winWidth >= 1000) { - size = (Number(winWidth)) - 330 - } - // tablet sizing - else { - size = (Number(winWidth)) - 80 - } -} - - -const ApiUsage = (props:tPROPS) => { - - class Usage extends React.Component { - - constructor (props:tPROPS) { - - super(props) - this.nf = Intl.NumberFormat() - - this.state = { - lastThirtyDayUsage: 0, - sinceLaunchUsage: props.accessSinceLaunch, - dynamicDisclaimer: props.dynamicDisclaimer, - clickEndpointDisclaimer: props.clickEndpointDisclaimer, - data: null, - prefix: "1/" + API_NAME + "/", - breadcrumbs: ["1/" + API_NAME + "/"] - } - } - - componentDidMount () { - this.fetchStats() - } - - handleUsageResponse (data) { - - const graphData = { - labels: [], - datasets: [ - { - fillColor: "rgba(172,194,132,0.4)", - strokeColor: "#ACC26D", - pointColor: "#ACC26D", - pointStrokeColor: "#9DB86D", - pointHighlightFill: '#fff', - pointHighlightStroke: '#112e51', - data: [] - } - ], - table: null - } - - if (data) { - - graphData.table = data.table - - data.stats.forEach(function (stat) { - graphData.labels.push(stat.day) - graphData.datasets[0].data.push(stat.totalCount) - }) - - } - this.state.indexInfo = data.indexInfo - this.state.lastThirtyDayUsage = data.lastThirtyDayUsage - - this.state.data = graphData - this.setState(this.state) - } - refreshPrefix (evt) { - this.state.prefix = evt.target.getAttribute('data-prefix') - this.refreshBreadcrumbs() - this.fetchStats() - } - refreshBreadcrumbs () { - - const i = this.state.breadcrumbs.indexOf(this.state.prefix) - if (i < 0) { - this.state.breadcrumbs.push(this.state.prefix) - } - else if (i < (this.state.breadcrumbs.length - 1)) { - this.state.breadcrumbs = this.state.breadcrumbs.slice(0, i + 1) - } - } - - fetchStats () { - - xhrGET(API_LINK + "/usage.json?prefix=" + this.state.prefix, (data) => { - this.handleUsageResponse(data) - }, false) - } - docCount (typeName:string):string { - return this.formatNumber(this.state.indexInfo[typeName]) - } - formatNumber (n:number):string { - return n ? this.nf.format(n) : "0" - } - - totalCount (typeName:string):string { - return this.formatNumber(this.state[typeName]) - } - - - render () { - if (this.state.data) { - - const pathFormat = (cell, row) => { - let p = row.path.length > 60 ? row.path.substring(0, 60) + "..." : row.path - - if (!row.terminal) { - p = this.refreshPrefix(e)} data-prefix={row.descendent_prefix} >{p} - } - return p - } - - return ( -
- - -
-

API Calls in the Past 30 Days: {this.totalCount('lastThirtyDayUsage')}

-
{this.state.dynamicDisclaimer}
-
- - -
-

API Calls in Past 30 Days by Dataset

-
{this.state.clickEndpointDisclaimer}
-
- { - this.state.breadcrumbs.map((b, i) => { - if ((this.state.breadcrumbs.length - 1) > i) { - // render link - return ( {(i > 0 ? ' > ' : '') } this.refreshPrefix(e)} data-prefix={b}>{b.substring(0, b.length - 1).split('/').pop()}) - } - else { - // render without link - return ({ (i > 0 ? ' > ' : '') + b.substring(0, b.length - 1).split('/').pop()}) - } - }) - } -
-
- - - - - - - - ) - } - return (Loading....) - - } - - } - return - -} - -ApiUsage.displayName = 'component/ApiUsage' -export default ApiUsage diff --git a/components/BlogRoll.jsx b/components/BlogRoll.jsx deleted file mode 100644 index 3c40acb8..00000000 --- a/components/BlogRoll.jsx +++ /dev/null @@ -1,141 +0,0 @@ -/* @flow */ - -import React from 'react' -import dateFormat from 'dateformat' -import get from 'lodash/get' -import marked from 'marked' - -const Link: ReactClass = require('react-router').Link - -const _sortPosts = posts => { - const filtered = posts.filter(p => p.data.date) - - const sorted = filtered.sort(function (a, b) { - const dateA = new Date(a.data.date).getTime() - const dateB = new Date(b.data.date).getTime() - return dateA > dateB ? 1 : -1 - }).reverse() - - return sorted -} - -type tPROPS = { - posts: Object, - small: boolean -}; - -/** - * @description [reverse chron list of blog posts for home and /updates/] - */ -const BlogRoll = (props: tPROPS) => { - const { - posts, - small - } = props - - // filter out posts without a valid date - // and also sort them reverse chron - const sortedPosts: Array = _sortPosts(posts) - - // increment for every actually rendered post - // this is useful because not everything in - // sortedPosts will get rendered. actually, - // most won't get rendered, since posts - // are really just any markdown file - let tally: number = 0 | 0 - - return ( -
-

Latest News & Updates

-
    - { - sortedPosts.map((post: Object, i: number) => { - // only render markdown files - if (get(post, 'file.ext') !== 'md') return - - // showInList is true by default - // basically, not every post needs to - // be part of the BlogRoll - if (post.data.showInList === false) return - - const { - body, - date, - } = post.data - - const title: string = (get(post, 'data.title') || post.path).substring(0, 40) + '...' - - // level refers to header level. h1, h2, etc - // we start at 2, because h1 is the hero section - // and then we proceed from there - // we do this so we have a logical order of headers - // h1 -> h2 -> h3 and so on til we get to h6 - let level: number = tally === 0 ? 2 : (tally + 2) - // cheap way to keep capped at h6 - if (level > 6) { - level = 6 - } - - // WE DO THIS FOR ACCESSIBILITY - // IT MAY SEEM UNNECESSARY, BUT DO NOT CHANGE - // $FlowIgnore - let Title: React.Element = React.createElement( - `h${level}`, - { - className: 'font-size-3', - tabIndex: 0, - }, - - {title} - - ) - - - // don't remove me - // i keep track of the amount - // of actually rendered blog posts - tally += 1 - - // Cheap way of making post excerpt - const excerpt = body.substring(3, body.search("

    ")).replace(/<(?:.|\n)*?>/gm, '').substring(0, 120) + '...' - - // Post date, if available - let formattedDate = '' - if (date.length > 0) { - formattedDate = dateFormat(date, 'mmmm d, yyyy').toUpperCase() - } - - - return ( -
  • - -

    {title}

    -
    {formattedDate}
    -

    {excerpt}

    - READ MORE - -
  • - ) - }) - } -
- {small === true && - - VIEW ALL - } -
- ) -} - -BlogRoll.displayName = 'component/BlogRoll' -export default BlogRoll diff --git a/components/Breadcrumbs.jsx b/components/Breadcrumbs.jsx deleted file mode 100644 index 623c8ac1..00000000 --- a/components/Breadcrumbs.jsx +++ /dev/null @@ -1,184 +0,0 @@ -/* @flow */ - -import React from 'react' -import BreadcrumbsContainer from '../containers/BreadcrumbsContainer' -const Link: ReactClass = require('react-router').Link - -const cat_map = { - 'food': { - 'endpoints': { - 'enforcement': { - 'title': 'Recall enforcement reports', - 'url': '/api_endpoints/food/enforcement/' - }, - 'event': { - 'title': 'Food, dietary supplement, and cosmetic adverse event reports', - 'url': '/api_endpoints/food/event/' - } - }, - 'title': 'Foods ', - 'url': '/api_endpoints/food/' - }, - 'device': { - 'endpoints': { - 'event': { - 'title': 'Adverse Event Reports', - 'url': '/api_endpoints/device/event/' - }, - 'classification': { - 'title': 'Classification', - 'url': '/api_endpoints/device/classification/' - }, - '510k': { - 'title': '510(k) clearances', - 'url': '/api_endpoints/device/510k/' - }, - 'pma': { - 'title': 'Premarket approval', - 'url': '/api_endpoints/device/pma/' - }, - 'registrationlisting': { - 'title': 'Registrations and listings', - 'url': '/api_endpoints/device/registrationlisting/' - }, - 'recall': { - 'title': 'Recalls', - 'url': '/api_endpoints/device/recall/' - }, - 'enforcement': { - 'title': 'Recall enforcement reports', - 'url': '/api_endpoints/device/enforcement/' - }, - 'udi': { - 'title': 'Unique device identifier', - 'url': '/api_endpoints/device/udi/' - } - }, - 'title': 'Medical Devices ', - 'url': '/api_endpoints/device/' - }, - 'drug': { - 'endpoints': { - 'enforcement': { - 'title': 'Recall enforcement reports', - 'url': '/api_endpoints/drug/enforcement/' - }, - 'label': { - 'title': 'Product labeling', - 'url': '/api_endpoints/drug/label/' - }, - 'event': { - 'title': 'Adverse events', - 'url': '/api_endpoints/drug/event/' - } - }, - 'title': 'Drugs ', - 'url': '/api_endpoints/drug/' - } -} - -type tPROPS = { - toggleDropdownContent: Function; - hideDropdownContent: Function; - showDropdownContent: Function; - activeDropdown: string; - path: string; -}; - -// if not on top level page, render breadcrumb nav -const BreadCrumbs = (props: tPROPS) => { - const { - hideDropdownContent, - showDropdownContent, - toggleDropdownContent, - activeDropdown, - path - } = props - if (typeof window === 'undefined') return - var crumbs: Array = path.split('/').filter(d => d) - - if (crumbs.length === 0) return - - return ( -
- -
- ) -} - -BreadCrumbs.displayName = 'component/BreadCrumbs' -export default BreadcrumbsContainer(BreadCrumbs) diff --git a/components/CategoryMenu.jsx b/components/CategoryMenu.jsx deleted file mode 100644 index 0005d0cd..00000000 --- a/components/CategoryMenu.jsx +++ /dev/null @@ -1,58 +0,0 @@ -/* @flow */ - -import React from 'react' - -const Link: ReactClass = require('react-router').Link - -const CategoryMenu = () => { - if (typeof window === 'undefined') return - - var path = window.location.pathname - - const endpoints = { - food: [ - 'enforcement', - 'event' - ], - device: [ - 'event', - 'classification', - '510k', - 'pma', - 'registrationlisting', - 'recall', - 'enforcement', - 'udi' - ], - drug: [ - 'event', - 'label', - 'enforcement' - ], - animal_and_veterinary: [] - } - - return ( -
- -
- ) -} - -CategoryMenu.displayName = 'component/CategoryMenu' -export default CategoryMenu diff --git a/components/ChartBar.jsx b/components/ChartBar.jsx deleted file mode 100644 index 5e57e9d5..00000000 --- a/components/ChartBar.jsx +++ /dev/null @@ -1,95 +0,0 @@ -/* @flow */ - -import React from 'react' -import getFieldValues from '../utils/getFieldValues' - -const _renderBars = (data: Array, fieldValues: Object, show: number) => { - const bars: Array = data.slice(0, show) - - // get maximum value - const max: number = bars[0].count - - // max value * this number = 100 - const remainder: number = 100 / max - - return bars.map((result: Object, i: number) => { - if (!result.count) return - - // the max value should equal 100% - const width: string = `${Math.round(result.count * remainder)}%` - // look in both places for term, coerce to string - // because sometimes we have numbers as terms - const term: void|string = result.term || fieldValues[result.term] - - return ( -
  • - { - (typeof term === 'string' || typeof term === 'number') && -
    - - {`${term}`.toLowerCase()} - -  {result.count} records -
    - } - { - !term && -
    -  {result.count} records -
    - } - -
  • - ) - }) -} - -type tPROPS = { - data: Array; - fields: Object; - countParam: string; - show: number; -}; - - -/** - * @description [reactjs chart for endpoint basics pages] - * @param {Array} data [array of data to render. 1 index = 1 bar] - * @param {Object} fields [all data for this endpoint] - * @param {string} countParam [countParam to filter by] - * @param {number} show [number of bars to render] - */ -const ChartBar = ({ data = [{count: 0}], fields, countParam, show = 10 }: tPROPS) => { - const fieldValues: Object = getFieldValues(countParam, fields) - - return ( - - ) -} - -ChartBar.displayName = 'component/ChartBar' -export default ChartBar diff --git a/components/ChartDonut.jsx b/components/ChartDonut.jsx deleted file mode 100644 index ebd82dfb..00000000 --- a/components/ChartDonut.jsx +++ /dev/null @@ -1,147 +0,0 @@ -/* @flow */ - -import React from 'react' -import cx from 'classnames' -import Charts from 'react-chartjs' -import getFieldValues from '../utils/getFieldValues' - -const Doughnut: ReactClass = Charts.Doughnut - -const _getChartColor = function (i: number): string { - const colors: Array = [ - '#025181', - '#4874bd', - '#9bdaf1', - '#2e8540', - '#a1c974', - '#b7e062', - '#571873', - '#9a47aa', - '#ca9af1', - ] - - return colors[i] -} - -const _getChartData = function ( - data: Array, - fieldValues: Object, - colors: Array, - hasLegend: boolean) { - - // $FlowIgnore because of the filter - return data.map((d: Object, i) => { - const color: string = !colors ? _getChartColor(i) : colors[i] - const label: void|string = fieldValues[d.term] || d.term - - // hasLegend === main donut chart, not sidebar record chart - // the sidebar record chart won't have labels, so we - // check for those things so the chart doesn't err - // we also want to limit the things we are rendering - // to be things that are actually in fieldValues - if (hasLegend && typeof label === 'undefined') return - - return { - value: d.count, - color, - label, - } - }).filter(d => d) -} - -type tPROPS = { - colors: Array; - countParam: string; - data: Array; - fields: Object; - hasLegend: boolean; - records: number; - size: string; -}; - -/** - * @description [reactjs chart for endpoint basics pages] - * [slightly different logic depending on placement] - * @param {Array} colors [array of acceptable colors we cycle through] - * @param {string} countParam [filter by value] - * @param {Object} fields [all data for this endpoint] - * @param {boolean} hasLegend [big donut charts get legends, small ones don't] - * @param {number} size [number of pxs to render. small vs big] - */ -const ChartDonut = (props: tPROPS) => { - const { - colors, - countParam, - data, - fields, - hasLegend, - size, - } = props - - const fieldValues: Object = getFieldValues(countParam, fields) - // map over data, return as arr of obj formatted for chart js - const chartData: Array = _getChartData(data, fieldValues, colors, hasLegend) - // always map over all data, sometimes chartData can be a subset - const total: number = data.map(d => d.count).reduce((a, b) => a + b) - - const legendCx = cx({ - 'col t-range-6 d-3 marg-t-2 d-marg-l-2': true, - 'd-pad-l-2 overflow-scroll donut-legend': true, - }) - - const wrapperCx = cx({ - 'flex-row align-center donut-wrap': true, - 'm-hide': !hasLegend, - }) - - return ( -
    - - { - hasLegend && -
      - { - chartData.map((d: Object, i) => { - // get % of records that the current field matches - const porCiento: number = (d.value / total) * 100 | 0 - - return ( -
    • -

      - - {d.label}
      - {porCiento}% - {d.value} records -

      -
    • - ) - }) - } -
    - } -
    - ) -} - -ChartDonut.displayName = 'component/ChartDonut' -export default ChartDonut diff --git a/components/ChartLine.jsx b/components/ChartLine.jsx deleted file mode 100644 index d2481f8d..00000000 --- a/components/ChartLine.jsx +++ /dev/null @@ -1,203 +0,0 @@ -/* @flow */ - -import React from 'react' -import Charts from 'react-chartjs' -import get from 'lodash/get' -import ChartBar from './ChartBar' - -const Line: ReactClass = Charts.Line - -/** - * @description [loops over the data, pulls out each year] - * @param {Object} data [result of the api call] - * @return {Array} [returns array of years] - */ -const _getYearsInData = (data: Array) => { - if (!data[0] || !data[0].time) return - - // get first matching year - // string: 2004 08 19 -> string: 2004 - let year: string = data[0].time.slice(0, 4) - // we'll keep a record of the years so far - // and we'll start with the first one above - const years: Array = [year] - - data.forEach(d => { - // is the year for this bit of data - // already accounted for? - const oldYear: boolean = d.time.indexOf(year) !== -1 - - // if yes, do nothing - // if no, then pull out - // the year and push that up - if (!oldYear) { - const newYear: string = d.time.slice(0, 4) - - year = newYear - return years.push(newYear) - } - }) - - // return final arr of all - // mentioned years - return years -} - -/** - * @description [takes in data and years, then groups said data by year] - * @param {Array} data [result of the api call] - * @param {Array} years [result of _getYearsInData] - * @return {Object} [returns an Object where each key is a year, whose values are an array of records] - */ -const _getRecordsByYear = (data: Array, years: Array) => { - const dataByYear: Object = {} - - years.forEach(y => { - dataByYear[y] = [] - }) - - data.forEach(d => { - const year: string = d.time.slice(0, 4) - return dataByYear[year].push(d) - }) - - return dataByYear -} - -/** - * @description [reduces records, grouped by year] - * @param {Object} data [takes in result of _getRecordsByYear] - * @return {Array} [returns simple array of reduced records] - */ -const _getTotalsByYear = (data: Object) => { - return Object.keys(data).map(y => { - return data[y] - .map(d => d.count) - .reduce((a, b) => a + b) - }) -} - -const _getChartData = (years: Array, totalsByYear: Array) => { - return { - labels: years, - datasets: [{ - data: totalsByYear, - fillColor: 'rgba(17, 46, 81, .3)', - strokeColor: '#112e51', - pointColor: '#112e51', - pointStrokeColor: '#112e51', - pointHighlightFill: '#fff', - pointHighlightStroke: '#112e51', - }], - } -} - -type PROPS = { - countParam: string; - data: Array; - height: string; - fields: Array; - width: string; -}; - -let previousChartData: Object = {} - - -/** - * @description [reactjs chart for endpoint basics pages] - * @param {string} countParam [filter by value] - * @param {Array} data [an array of data cooresponding to DATES or YEARS] - * @param {Object} height [height in px to render] - * @param {boolean} fields [all data for endpoint] - * @param {number} width [width in px to render] - */ -const ChartLine = ({ countParam, data, height, fields, width, }: PROPS) => { - const years: Array = _getYearsInData(data) - let recordsByYear: Object = {} - let totalsByYear: Array = [0] - - // not every line chart is necessarily date based - if (years) { - recordsByYear = _getRecordsByYear(data, years) - totalsByYear = _getTotalsByYear(recordsByYear) - } - - // we keep track so we don't redraw unnecessarily - // chartjs normally takes care of this on it's own - // but because we toggle animations on / off to prevent - // sluggishness / bugginess with big datasets - // we have to check ourselves and then force redraw - // sometimes this results in non-responsiveness - // but it is better than the alternative - - // sluggishness that persists until the user refreshes - const currChartData: Object = previousChartData - const nextChartData: Object = _getChartData(years, totalsByYear) - previousChartData = nextChartData - - let dataChanged: boolean = false - const cData: Array = get(currChartData, 'datasets[0].data') - const nData: Array = get(nextChartData, 'datasets[0].data') - - if (cData && nData) { - // if we have both current and next chart data - // we iterate over the dataset, and if -anything- - // is not the same, we update - dataChanged = cData.some((d, i) => nData[i] !== d) - } - - // if something wrong happened with the years - // try and fall back to a bar chart - if (!years) { - return ( - - ) - } - - return ( - - - - Skip Line Chart. Go to visualization query explorer. - -
      - { - years && - years.length > 0 && - years.map((year: string, i: number) => { - return ( -
    • - Year: {year}. Records: {totalsByYear[i]}. -
    • - ) - }) - } -
    -
    - ) -} - -ChartLine.displayName = 'components/ChartLine' -export default ChartLine diff --git a/components/Content.jsx b/components/Content.jsx deleted file mode 100644 index acde601f..00000000 --- a/components/Content.jsx +++ /dev/null @@ -1,156 +0,0 @@ -/* @flow */ - -import React from 'react' -import marked from 'marked' -import cx from 'classnames' - -import Datasets from './Datasets' -import Downloads from './Downloads' -import MultipleProductTable from './MultipleProductTable' -import RenderContentObject from './RenderContentObject' - -type tPROPS = { - content: Array; - examples: Array; - explorers: Object; - fields: Object; - showMenu: boolean; - meta: Object; -}; - - - -// reads in _content.yaml from ideally anywhere -// and knows what component to render for each field -const Content = (props: tPROPS) => { - const { - content, - examples, - explorers, - fields, - showMenu, - meta, - } = props - - return ( -
    - { - content.map((words: string|Object, i) => { - // lies, IT IS NOT WORDS - // basically, stuff like disclaimer - // or examples, or fields we want to render - // or query explorers, basicaaaaaly - // anything in _content that is not - // a simple string gets passed to this - if (typeof words === 'object') { - return ( - - ) - } - - // stringified markdown -> html - const html: string = marked(words) - - // if header, add header class, etc - const wrapperCx: string = cx({ - 'font-size-2 weight-700 marg-b-2 marg-t-3': html.indexOf('') !== -1, - }) - - // kind of a weird way to do this - // but, it might be easier for non-technical - // people to understand that they just type - // 'downloads' to render that section - if (words === 'downloads') { - return ( - - ) - } - - // as far as i can tell we just - // have the one 'image' for drug/event - if (words === 'datasets') { - return ( - - ) - } - - // as far as i can tell we just - // have the one 'image' for drug/event - if (words === 'image') { - return ( - - ) - } - - // below is where we handle just plain normal text - // but we need to handle some edge cases first - // specifically, all external links need the external link icon - // so we - // 1) check for http:// - // 2) use regex to grab all tags that match - // 3) loop over matches, incrementally wrapping external links - // with our wrapper class (link-external) - // 4) finally output the linkified (or not) text - // - // assume that local links just do /path/path - // instead of http://whatever - const hasLink: boolean = html.indexOf('http://') !== -1 - // regex for matching tags WITH a valid http:// href - const httpRE: RegExp = /]*?href[\s]?=[\s\"\']*(http:\/\/.*?)[\"\']*.*?>([^<]+|.*?)?<\/a>/gm - // if no external links, just output the markdownified text - // otherwise, we'll need to string replace the external links - // with a wrapper element, for the external link icon - let finalOutput: string = html - - if (hasLink) { - // array of matches, we should have at least one - const matches: ?Array = html.match(httpRE) - - // but just to be safe - if (matches) { - for (const match of matches) { - const intermediate: string = finalOutput.replace(match, `${match}`) - finalOutput = intermediate - } - } - } - - return ( -
    - ) - }) - } -
    - ) -} - -Content.displayName = 'component/Content' -export default Content diff --git a/components/ContentWrapper.jsx b/components/ContentWrapper.jsx deleted file mode 100644 index d94c3e13..00000000 --- a/components/ContentWrapper.jsx +++ /dev/null @@ -1,97 +0,0 @@ -/* @flow */ - -import React from 'react' -import cx from 'classnames' - -import EndpointStatus from './EndpointStatus' -import SideBar from './SideBar' -import Content from './Content' -import Hero from './Hero' -import Layout from './Layout' - -import SideBarContainer from '../containers/SideBarContainer' -import InfographicContainer from '../containers/InfographicContainer' - -import mapFields from '../utils/mapFields' -import flattenFields from '../utils/flattenFields' - -type tPROPS = { - content: Array; - explorers: Object; - infographics: Array; - fields: Object; - showMenu: boolean; - meta: Object; -}; - -const wrapperCx = cx({ - 'container t-marg-t-3 marg-b-3 relative row content-wrapper': true, -}) - -// add fixed positioning functinality to reference sidebar -const ComposedSidebar: ReactClass = SideBarContainer(SideBar) - -// i just exist to render the Sidebar, and -// determine whether we render ref specific -// components or not -const ContentWrapper = (props: tPROPS) => { - const { - content, - explorers, - infographics, - fields, - showMenu, - meta - } = props - - let fieldsMapped: Object = {} - let fieldsFlattened: Object = {} - if (explorers && fields) { - fieldsMapped = mapFields(fields.properties) - fieldsFlattened = flattenFields(fieldsMapped) - } - - const contentCx = cx({ - 'float-r': true, - 'ref-content': true, - }) - - return ( - - - { - - } -
    - { - - } -
    - -
    -
    -
    - ) -} - -ContentWrapper.displayName = 'components/ContentWrapper' -ContentWrapper.defaultProps = { - showMenu: false, -} -export default ContentWrapper diff --git a/components/Dataset.jsx b/components/Dataset.jsx deleted file mode 100644 index c504a55c..00000000 --- a/components/Dataset.jsx +++ /dev/null @@ -1,100 +0,0 @@ -/* @flow */ - -import React from 'react' -import marked from 'marked' - -import Hero from './Hero' -import Layout from './Layout' - -const boxCx: string = 'clr-gray b-b-1 marg-b-2' - -type tPROPS = { - meta: Object; -}; - -// pages like /data/faers/ -const Dataset = ({ meta }: tPROPS) => ( - - -
    -
    -
    -
    - { - meta.additionalContent && -

    About {meta.source.name}

    - } - { - meta.additionalContent && - meta.additionalContent.map((para, i) => ( -
    - )) - } - { - meta.source && -
    -

    Learn more

    -

    - General information
    - Learn more about {meta.source.nameLong} -

    - { - meta.source.linkDownload && -

    - Original dataset downloads
    - {meta.source.name} download information -

    - } -
    - } -
    -
    -
    - { - meta.provider && -
    -

    Provider

    -

    {meta.provider.name}

    -
    - } - { - meta.license && -
    -

    License

    -

    {meta.license.name}

    -
    - } - { - meta.time && (meta.time.frequency || meta.time.delay) && -
    -

    Updates

    - {meta.time.frequency &&

    Frequency {meta.time.frequency}

    } - {meta.time.delay &&

    Lag in data updates {meta.time.delay}

    } -
    - } - { - meta.time && (meta.time.start || meta.time.current) && -
    -

    Time period

    - {meta.time.start &&

    Earliest data {meta.time.start}

    } - {meta.time.current &&

    Current through {meta.time.current}

    } -
    - } -
    -
    -
    - -) - -Dataset.displayName = 'components/Dataset' -export default Dataset diff --git a/components/Datasets.jsx b/components/Datasets.jsx deleted file mode 100644 index 05efefdc..00000000 --- a/components/Datasets.jsx +++ /dev/null @@ -1,31 +0,0 @@ -/* @flow */ - -import React from 'react' - -type tPROPS = { - k: number; - meta: Object; -}; - -// used by Content to render out datasets -// used by the current endpoint -const Datasets = (props: tPROPS) => ( -
    -

    Datasets

    -

    The following datasets provide data for this endpoint.

    - { - props.meta.datasets.map((dataset: string, i) => ( - - {dataset} - - )) - } -
    -) - -Datasets.displayName = 'components/Datasets' -export default Datasets diff --git a/components/Disclaimer.jsx b/components/Disclaimer.jsx deleted file mode 100644 index 268c1452..00000000 --- a/components/Disclaimer.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/* @flow */ - -import React from 'react' -import ReactModal from 'react-modal' - -import ComposedDisclaimer from '../containers/DisclaimerContainer' - -const Link: ReactClass = require('react-router').Link - -type tPROPS = { - showModal: boolean, - handleOpenModal: Function, - handleCloseModal: Function, - hideModal: Function -}; - -/** - * @description [renders meta data (yaml usually) as the hero el below breadcrumbs] - * @param {string|React.Element} description [paragraph below title] - * @param {string} label [small text right above the title] - * @param {string} path [the page route, for endpoint pages] - * @param {string} title [the title, used on non-endpoint pages (posts, etc)] - * @param {string} type [endpoint or not, used for styling and tabs] - * @return {React.Element} - */ -const Disclaimer = (props: tPROPS) => { - const { - showModal, - handleOpenModal, - handleCloseModal, - hideModal - } = props - console.log("dumb disclaimer showModal: ", showModal) - - - return ( - -

    Disclaimer

    -
    - Do not rely on openFDA to make decisions regarding medical care. Always speak to your health provider about the risks and benefits of FDA-regulated products. We may limit or otherwise restrict your access to the API in line with our Terms of Service -
    - -
    - ) -} - -Disclaimer.displayName = 'components/Disclaimer' -export default ComposedDisclaimer(Disclaimer) diff --git a/components/Downloads.jsx b/components/Downloads.jsx deleted file mode 100644 index 91c3f40d..00000000 --- a/components/Downloads.jsx +++ /dev/null @@ -1,135 +0,0 @@ -/* @flow */ - -import React from 'react' -import cx from 'classnames' -import DownloadsContainer from '../containers/DownloadsContainer' - -const liCx: string = 'marg-b-1 row col grow-none t-2 d-2' -const mbCx: string = 'clr-gray inline-block' - -const _renderByLimit = (results, limit) => { - const sliced: Array = results.slice(0, limit) - - return sliced.map((s, i) => ( -
  • - - {s.display_name} - - - {s.size_mb} mb - -
  • - )) -} - -const _renderByYear = (results, years) => { - return years.map((y, i) => { - const data: Object = results[y] - - return ( -
  • -

    {y}

    -
      - { - data.map((d, i) => ( -
    • - - {d.display_name} - - { - // inline for ie - } - - {d.size_mb} mb - -
    • - )) - } -
    -
  • - ) - }) -} - -type tPROPS = { - allPartitions: Array; - k: number; - api_path: string; - title: string; - results: Object; - showAllResults: boolean; - toggle: Function; - updated: string; -}; - -const Downloads = (props: tPROPS) => { - const { - allPartitions, - k, - api_path, - title, - results, - showAllResults, - toggle, - updated, - } = props - - const limit: number = 10 | 0 - const years: Array = Object.keys(results) - const btnCx = cx({ - 'clr-white weight-700': true, - 'bg-primary': !showAllResults, - 'bg-primary-darker': showAllResults, - }) - - return ( -
    -

    {title} [{api_path}]

    -

    This endpoint’s data may be downloaded in zipped JSON files. Records are represented in the same format as API calls to this endpoint. Each update to the data in this endpoint could change old records. You need to download all the files to ensure you have a complete and up-to-date dataset, not just the newest files. For more information about openFDA downloads, see the API basics. -

    -

    There are {allPartitions.length} files, last updated on {updated}.

    - { - allPartitions.length > 10 && - - } -
      - { - showAllResults && - _renderByYear(results, years) - } - { - allPartitions.length <= limit && - _renderByLimit(allPartitions, limit) - } -
    -
    - ) -} - -Downloads.displayName = 'components/Downloads' -export default DownloadsContainer(Downloads) diff --git a/components/DrugQueryTable.jsx b/components/DrugQueryTable.jsx deleted file mode 100644 index 731d29b1..00000000 --- a/components/DrugQueryTable.jsx +++ /dev/null @@ -1,45 +0,0 @@ -/* @flow */ - -import React from 'react' - -const cellCx: string = 'b-b-1 b-r-1 font-size-1 pad-2' -const smallCx: string = 'small pad-l-1 inline-block' -const ulCx: string = 'font-size-3 pad-t-1' - -const DrugQueryTable = (props: Object) => ( -
    -
    - Header Information - Report ID, receive date, etc. -
    -
    - Patient information - Age, weight, sex, etc. -
    -
    -
    - Drugs -
      -
    • Drug A suspect
    • -
    • Drug B suspect
    • -
    • Drug C suspect
    • -
    • Drug D concomitant
    • -
    • Drug E concomitant
    • -
    -
    -
    - Patient reactions -
      -
    • Reaction 1
    • -
    • Reaction 2
    • -
    • Reaction 3
    • -
    -
    -
    -
    -) - -DrugQueryTable.displayName = 'components/DrugQueryTable' -export default DrugQueryTable diff --git a/components/EndpointBox.jsx b/components/EndpointBox.jsx deleted file mode 100644 index 990021b2..00000000 --- a/components/EndpointBox.jsx +++ /dev/null @@ -1,137 +0,0 @@ -/* @flow */ - -import React from 'react' - -const Link: ReactClass = require('react-router').Link - -type tPROPS = { - noun_name: string, - endpoint_name: string -}; - -/** - * @description [renders meta data (yaml usually) as the hero el below breadcrumbs] - * @param {string|React.Element} description [paragraph below title] - * @param {string} label [small text right above the title] - * @param {string} path [the page route, for endpoint pages] - * @param {string} title [the title, used on non-endpoint pages (posts, etc)] - * @param {string} type [endpoint or not, used for styling and tabs] - * @return {React.Element} - */ -const EndpointBox = (props: tPROPS) => { - const { - noun_name, - endpoint_name - } = props - - const description = { - 'food': { - 'enforcement': 'Food product recall enforcement reports.', - 'event': 'Food, dietary supplement, and cosmetic adverse event reports.' - }, - 'device': { - 'event': 'Reports of serious injuries, deaths, malfunctions, and other undesirable effects associated with the use of medical devices.', - 'classification': 'Medical device names, their associated product codes, their medical specialty areas (panels) and their classification.', - '510k': 'A 510(k) is a premarket submission made to FDA to demonstrate that the device to be marketed is at least as safe and effective, that is, substantially equivalent, to a legally marketed device.', - 'pma': 'Premarket approval (PMA) is the FDA process of scientific and regulatory review to evaluate the safety and effectiveness of Class III medical devices.', - 'registrationlisting': 'The registration and listing dataset contains the location of medical device establishments and the devices manufactured at those establishments.', - 'recall': 'A recall is an action taken to address a problem with a medical device that violates FDA law. Recalls occur when a medical device is defective, when it could be a risk to health, or when it is both defective and a risk to health.', - 'enforcement': 'Medical device product recall enforcement reports.', - 'udi': 'Global Unique Device Identification Database (GUIDID) Device Identification dataset.' - }, - 'drug': { - 'event': 'Reports of drug side effects, product use errors, product quality problems, and therapeutic failures.', - 'label': 'Structured product information, including prescribing information, for approved drug products.', - 'enforcement': 'Drug product recall enforcement reports.' - }, - } - - const ep_title = { - 'food': { - 'enforcement': 'Recall enforcement reports', - 'event': 'CAERS reports' - }, - 'device': { - 'event': 'Adverse event reports', - 'classification': 'Classification', - '510k': '510(k) clearances', - 'pma': 'Premarket approval', - 'registrationlisting': 'Registrations and listings', - 'recall': 'Recalls', - 'enforcement': 'Recall enforcement reports', - 'udi': 'Unique device identifier' - }, - 'drug': { - 'event': 'Adverse events', - 'label': 'Product labeling', - 'enforcement': 'Recall enforcement reports' - }, - } - const bg_color = { - 'food': {background: "linear-gradient(to right bottom, rgb(143, 209, 100), rgb(81, 161, 22))"}, - 'device': {background: "linear-gradient(to right bottom, rgb(255, 198, 59), rgb(243, 117, 73))"}, - 'drug': {background: "linear-gradient(to right bottom, rgb(220, 141, 188), rgb(153, 88, 163))"} - } - - const icon = { - 'food': { - 'enforcement':
    , - 'event':
    - }, - 'device': { - 'event':
    , - 'classification':
    , - '510k':
    , - 'pma':
    , - 'registrationlisting':
    , - 'recall':
    , - 'enforcement':
    , - 'udi':
    - }, - 'drug': { - 'event':
    , - 'label':
    , - 'enforcement':
    - }, - } - - const ep_path = { - 'food': { - 'enforcement': '/api_endpoints/food/enforcement/', - 'event': '/api_endpoints/food/enforcement' - }, - 'device': { - 'event': '/api_endpoints/device/event/', - 'classification': '/api_endpoints/device/classification', - '510k': '/api_endpoints/device/510k/', - 'pma': '/api_endpoints/device/pma/', - 'registrationlisting': '/api_endpoints/device/registrationlisting/', - 'recall': '/api_endpoints/device/recall/', - 'enforcement': '/api_endpoints/device/enforcement/', - 'udi': '/api_endpoints/device/udi/' - }, - 'drug': { - 'event': '/api_endpoints/drug/event/', - 'label': '/api_endpoints/drug/label/', - 'enforcement': '/api_endpoints/drug/enforcement/' - }, - } - - return ( -
    - -
    - {icon[noun_name][endpoint_name]} -
    -
    -

    {ep_title[noun_name][endpoint_name]}

    - {description[noun_name][endpoint_name]} -
    - LEARN MORE - -
    - ) -} - -EndpointBox.displayName = 'components/EndpointBox' -export default EndpointBox diff --git a/components/EndpointStatus.jsx b/components/EndpointStatus.jsx deleted file mode 100644 index b1f1c479..00000000 --- a/components/EndpointStatus.jsx +++ /dev/null @@ -1,45 +0,0 @@ -/* @flow */ - -import React from 'react' -import EndpointStatusContainer from '../containers/EndpointStatusContainer' - -type tPROPS = { - data: Object; - fullPath: string; -}; - -const EndpointStatus = ({ data, fullPath, }: tPROPS) => { - var date = new Date(data.last_updated) - return ( -
    -
    - Endpoint: - {fullPath} -
    -
    - Status: - { - data.status === 'GREEN' ? - - OK - - : - - DOWN - - } -
    -
    - Last updated: - {date.toDateString()} -
    -
    - Total records: - {data.documents} -
    -
    - ) -} - -EndpointStatus.displayName = 'component/Endpoint_Box' -export default EndpointStatusContainer(EndpointStatus) diff --git a/components/Filter/FilterRadio.jsx b/components/Filter/FilterRadio.jsx deleted file mode 100644 index 3a555ba7..00000000 --- a/components/Filter/FilterRadio.jsx +++ /dev/null @@ -1,76 +0,0 @@ -/* @flow */ - -import React from 'react' -import RadioGroup from 'react-radio-group' - -type PROPS = { - filters: Array; - onChange: Function; - selected: string; -}; - -/** - * @description [used in Infographic when on desktop] - * @param {Array} filters [list of filters. labels + values] - * @param {Function} onChange [callback for handling click] - * @param {string} selected [selected = the currently active radio] - * @return {React.Element} - */ -const FilterRadio = ({ filters, onChange, selected }: PROPS) => { - const _onChange = value => onChange(value) - - return ( - - { - /* eslint-disable */ - (Radio: ReactClass) => { - Radio.displayName = 'Radio Filter Button' - - return ( -
    - - Filter records using example parameters for current visualization. - - { - filters.map((filter: Object, i) => ( - - )) - } -
    - ) - } - /* eslint-enable */ - } -
    - ) -} - -FilterRadio.displayName = 'components/FilterRadio' -export default FilterRadio diff --git a/components/Filter/FilterSelect.jsx b/components/Filter/FilterSelect.jsx deleted file mode 100644 index 510e4f97..00000000 --- a/components/Filter/FilterSelect.jsx +++ /dev/null @@ -1,45 +0,0 @@ -/* @flow */ - -import React from 'react' - -type PROPS = { - filters: Array; - selected: string; - onChange: Function; -}; - -/** - * @description [used in Infographic when on MOBILE or TABLET] - * @param {Array} filters [list of filters. labels + values] - * @param {Function} onChange [callback for handling click] - * @param {string} selected [selected = the currently active radio] - * @return {React.Element} - */ -const FilterSelect = ({ filters, selected, onChange }: tPROPS) => { - const _onChange = e => onChange(e.target.value) - - return ( -
    - -
    - ) -} - -FilterSelect.displayName = 'components/FilterSelect' -export default FilterSelect diff --git a/components/Filter/index.jsx b/components/Filter/index.jsx deleted file mode 100644 index b199dd01..00000000 --- a/components/Filter/index.jsx +++ /dev/null @@ -1,24 +0,0 @@ -/* @flow */ - -import React from 'react' -import FilterRadio from './FilterRadio' -import FilterSelect from './FilterSelect' - -/** - * @description [a wrapper element. renders Radio or Select dep on breakpoint] - * @param {Object} props [breakpoint + all needed props for filtering] - * @return {React.Element} - */ -const Filter = (props: Object) => ( - props.bp.mob ? - - : - -) - -Filter.displayName = 'components/Filter' -export default Filter diff --git a/components/Footer.jsx b/components/Footer.jsx deleted file mode 100644 index 31b67f63..00000000 --- a/components/Footer.jsx +++ /dev/null @@ -1,131 +0,0 @@ -/* @flow */ - -import React from 'react' - -const links: Array = [ - { - txt: 'FDA Home', - url: 'http://www.fda.gov', - }, - { - txt: 'Accessibility', - url: 'http://www.fda.gov/AboutFDA/AboutThisWebsite/Accessibility/default.htm', - }, - { - txt: 'Careers', - url: 'http://www.fda.gov/AboutFDA/WorkingatFDA/default.htm', - }, - { - txt: 'FDA Basics', - url: 'http://www.fda.gov/AboutFDA/Transparency/Basics/default.htm', - }, - { - txt: 'FOIA', - url: 'http://www.fda.gov/RegulatoryInformation/FOI/default.htm', - }, - { - txt: 'No Fear Act', - url: 'http://www.fda.gov/AboutFDA/WorkingatFDA/NoFearAct/default.htm', - }, - { - txt: 'Site Map', - url: 'http://www.fda.gov/SiteMap/default.htm', - }, - { - txt: 'Transparency', - url: 'http://www.fda.gov/AboutFDA/Transparency/default.htm', - }, - { - txt: 'Website', - url: 'http://www.fda.gov/AboutFDA/AboutThisWebsite/WebsitePolicies/default.htm' - }, - { - txt: 'openFDA Terms of Service', - url: '/terms', - }, - { - txt: 'License', - url: 'https://open.fda.gov/license' - }, - { - txt: 'Email the openFDA team', - url: 'mailto:open@fda.hhs.gov', - }, -] - -const aCx: string = 'clr-white inline-block underline pad-r-2 m-marg-b-2 t-marg-b-1 smallest underline' - -// PreFooter should remain stateless -// although, it technically isn't pure -// but links should never change once pulled in -const Footer = () => ( -
    -
    -
      -
    • - - Go to FDA website - -
    • -
    • U.S. Food and Drug Administration
    • -
    • 10903 New Hampshire Avenue
    • -
    • Silver Spring, MD 20993
    • -
    • 1-888-INFO-FDA (1-888-463-6332)
    • -
    • - - Contact FDA - -
    • -
    - -
    -
    -) - -Footer.displayName = 'components/Footer' -export default Footer diff --git a/components/Hero/EndPointButtons.jsx b/components/Hero/EndPointButtons.jsx deleted file mode 100644 index c85972c7..00000000 --- a/components/Hero/EndPointButtons.jsx +++ /dev/null @@ -1,59 +0,0 @@ -/* @flow */ -import React from 'react' -import cx from 'classnames' -import bp from '../../constants/breakpoints' - -const Link: ReactClass = require('react-router').Link - -type tPROPS = { - path: string; -}; - -/** - * @description [the tabs that appear on dataset endpoint pages] - * @param {Object} props [current path. used for determining active tab] - * @return {React.Element} - */ -const EndpointButtons = (props: tPROPS) => { - // Query explorer button === this - // Reference button === this + /reference/ - const isBasics: boolean = props.path.indexOf('reference') === -1 - const path: string = props.path.replace(/(\/reference){1}\/?/, '') - - const btnCx: string = 'btn tab bg-secondary weight-700 m-pad-l-2 m-pad-r-2 pad-t-2 pad-b-2 pad-l-3 pad-r-3' - - const getActiveCx = function (idx: number) { - const isActive = (idx === 0 && isBasics) || (idx !== 0 && !isBasics) - return cx({ - [btnCx]: true, - 'smallest': bp.mob, - 'marg-r-1': idx === 0, - 'clr-white': !isActive, - 'bg-white clr-primary-dark': isActive, - }) - } - - return ( -
    - - Basics - - - Reference guide - -
    - ) -} - -EndpointButtons.displayName = 'components/Hero/EndpointButtons' -export default EndpointButtons diff --git a/components/Hero/index.jsx b/components/Hero/index.jsx deleted file mode 100644 index ec3ae1f3..00000000 --- a/components/Hero/index.jsx +++ /dev/null @@ -1,106 +0,0 @@ -/* @flow */ - -import React from 'react' -import cx from 'classnames' -import BreadCrumbs from '../BreadCrumbs' - - -type tPROPS = { - description: string; - htmlDescription: boolean; - label: string; - path: string; - title: React.Element|string; - type: 'homepage'|'endpoint'; -}; - -/** - * @description [renders meta data (yaml usually) as the hero el below breadcrumbs] - * @param {string|React.Element} description [paragraph below title] - * @param {string} label [small text right above the title] - * @param {string} path [the page route, for endpoint pages] - * @param {string} title [the title, used on non-endpoint pages (posts, etc)] - * @param {string} type [endpoint or not, used for styling and tabs] - * @return {React.Element} - */ -const Hero = (props: tPROPS) => { - const { - description, - htmlDescription, - label, - path, - title, - type - } = props - - const heroCx = cx({ - 'flex-box relative dir-column': true, - 'bg-gray': type !== 'dataset' && type !== 'endpoint', - 'bg-primary': type === 'dataset' - }) - - const bg_image_color = { - food: {background: 'linear-gradient(to bottom right, rgba(81, 161, 22, 1), rgba(143, 209, 100, 1))', backgroundSize: 'contain', backgroundPosition: 'right', height: '240px'}, - device: {background: 'linear-gradient(to right bottom, rgb(232, 92, 44), rgb(236, 169, 6))', backgroundSize: 'contain', backgroundPosition: 'right', height: '240px'}, - drug: {background: 'linear-gradient(to bottom right, rgba(153, 88, 163, 1), rgba(220, 141, 188, 1))', backgroundSize: 'contain', backgroundPosition: 'right', height: '240px'}, - animal_and_veterinary: {background: 'linear-gradient(to bottom right, rgba(249, 157, 28, 1), rgba(252, 215, 112, 1))', backgroundSize: 'contain', backgroundPosition: 'right', height: '240px'}, - other: {backgroundColor: '#5b616b'} - } - const bg_image = { - food: '/img/apple.png', - device: '/img/stethoscope.png', - drug: '/img/pill-bottle.png', - animal_and_veterinary: '/img/dog.png' - } - - if ('path' in props) { - let cat_path = path.split( '/' ) - var cat_name = cat_path[2] - } else { - var cat_name = 'other' - } - - - const desc: void|string = description && description.trim() - - return ( -
    -
    - -
    -

    - {title} -

    -
    - { - desc && htmlDescription && -

    -

    - } - { - desc && !htmlDescription && -

    {desc}

    - } -
    - -
    -
    - ) -} - -Hero.displayName = 'components/Hero' -// using defaultProps just because it gets a little unwiedly up there -Hero.defaultProps = { - description: '', - type: 'landing', - htmlDescription: false -} -export default Hero diff --git a/components/Infographic.jsx b/components/Infographic.jsx deleted file mode 100644 index 714e92e8..00000000 --- a/components/Infographic.jsx +++ /dev/null @@ -1,237 +0,0 @@ -/* @flow */ - -import React from 'react' -import marked from 'marked' - -import ChartBar from './ChartBar' -import ChartDonut from './ChartDonut' -import ChartLine from './ChartLine' -import Filter from './Filter' - -import bp from '../constants/breakpoints' -import BPContainer from '../containers/BreakpointContainer' -import yamlGet from '../utils/yamlGet' - -type tEXPLORER = { - description: Array; - filters: Object; - title: string; - type: 'Bar'|'Line'|'Donut'; -}; - -type tPROPS = { - current: tEXPLORER; - data: Object; - fields: Object; - nextCountParam: string; - onSearchChange: Function; - records: number; - recordsTotal: number; - searchParam: string; - type: string; -}; - -const Infographic = (props: tPROPS) => { - const { - current, - data, - fields, - nextCountParam, - onSearchChange, - records, - recordsTotal, - searchParam, - type, - } = props - - const { - description, - filters, - title, - }: tEXPLORER = current - - // mobile sizing for infographic - // window - 40 (margin) - 40 (padding) - const hasWindow: boolean = typeof window !== 'undefined' - let size: number = hasWindow ? window.innerWidth - 80 : 300 - - // desktop sizing is a little more complicated - // we calculate the width based on window - // and what we know about how the layout will be - if (!bp.mob && hasWindow) { - const winWidth: number = window.innerWidth - - // 1400 = site-container width - // .73 = 25% sidebar + 2% margin (100 - 27) - // .67 = width of infographic container - // 40 = padding for infographic container - if (winWidth >= 1400) { - size = ((1400 * 0.73) * 0.65) - 40 - } - // tablet sizing - else { - size = ((winWidth * 0.73) * 0.65) - 40 - } - } - - // Don't render if there is no data, or the field we are trying to - // count by (visualize) is unknown - const fieldDefinition: void|Object = yamlGet(nextCountParam, fields) - const error: boolean = data.error || !fieldDefinition - - // if fieldDef has description, then markdown-ify it - const markedFieldDef: string = fieldDefinition && - fieldDefinition.description ? - `${marked(fieldDefinition.description)}` : - '' - - // add breakpoint logic to filter - const FilterWithState: ReactClass = BPContainer(Filter, { - filters: filters, - onChange: onSearchChange, - selected: searchParam, - }) - - return ( -
    - { - title && -

    - {title} -

    - } - { - description && - description.map((para, i) => -
    -
    - ) - } - - Skip visualization options. Go to data visualization - -
    - -
    - { - data.error && - - Request returned no response.
    - Change your search and/or count parameters and try again -
    - } - { - !fieldDefinition && - - No Field Definition found in fields yaml.
    - Please fix the missing field and try again -
    - } - { - !error && -
    -

    - {nextCountParam}
    - { - fieldDefinition && - fieldDefinition.description && - - } -

    -
    - } - { - !error && - type === 'Bar' && - - } - { - !error && - (type === 'Pie' || type === 'Donut') && - - } - { - !error && - type === 'Line' && - - } -
    -
    -
    - ) -} - -Infographic.displayName = 'components/Infographic' -export default Infographic diff --git a/components/InfographicExplorer.jsx b/components/InfographicExplorer.jsx deleted file mode 100644 index d2444bcb..00000000 --- a/components/InfographicExplorer.jsx +++ /dev/null @@ -1,134 +0,0 @@ -/* @flow */ - -import React from 'react' - -const paramsCx: string = 'col t-3 t-marg-t-2' -const textAreaCx: string = 'bg-gray-dark clr-gray-lightest block row pad-1 small mono' - -type tPROPS = { - // count parameter to filter by - countParam: string; - // all fields for select dropdown - fieldsFlattened: Object; - // search parameter for text - nextSearchParam: string; - // look for Enter key when typing, then fetch and update - onKeyPress: Function; - // when typing in count field, keep count param up to date - onCountChange: Function; - // on dropDown select - onCountChangeAndUpdate: Function; - // when typing in search field - onSearchChange: Function; - // complete query string - query: string; -}; - -const InfographicExplorer = (props: tPROPS) => { - const { - countParam, - fieldsFlattened, - nextSearchParam, - onKeyPress, - onCountChange, - onCountChangeAndUpdate, - onSearchChange, - query, - } = props - - return ( -
    - - Skip visualization explorer. - -

    - current query -

    -