From e88df6caeaf6987b755e5381d06e0bc8658bc07f Mon Sep 17 00:00:00 2001 From: Ayer <59009@icf.com> Date: Thu, 29 Jan 2026 10:14:53 -0600 Subject: [PATCH 1/2] Updated endpoint components --- src/components/EndpointBox.tsx | 225 +++------------------ src/components/EndpointStatus.tsx | 30 +-- src/constants/endpoint_box.ts | 145 +++++++++++++ src/constants/index.ts | 1 + src/containers/EndpointStatusContainer.tsx | 41 +--- src/types/endpoint.types.ts | 54 +++++ src/types/index.ts | 2 + 7 files changed, 252 insertions(+), 246 deletions(-) create mode 100644 src/constants/endpoint_box.ts create mode 100644 src/constants/index.ts create mode 100644 src/types/endpoint.types.ts diff --git a/src/components/EndpointBox.tsx b/src/components/EndpointBox.tsx index 9a9273cd7..39c8cb5e3 100644 --- a/src/components/EndpointBox.tsx +++ b/src/components/EndpointBox.tsx @@ -5,33 +5,8 @@ import React from 'react' import Link from 'gatsby-link' import '../css/components/EndpointBox.scss' - -type NounName = 'animalandveterinary' | 'food' | 'device' | 'drug' | 'other' | 'tobacco' | 'transparency'; -type EndpointName = - | 'event' - | 'enforcement' - | 'classification' - | '510k' - | 'pma' - | 'registrationlisting' - | 'recall' - | 'udi' - | 'covid19serology' - | 'label' - | 'ndc' - | 'drugsfda' - | 'drugshortages' - | 'historicaldocument' - | 'nsde' - | 'substance' - | 'unii' - | 'problem' - | 'completeresponseletters'; - -type tPROPS = { - noun_name: NounName, - endpoint_name: EndpointName -}; +import { NounName, EndpointName, endpointBoxProps } from '../types' +import { ep_title, description, ep_path, bg_color } from '../constants' /** * @description [renders meta data (yaml usually) as the hero el below breadcrumbs] @@ -42,195 +17,53 @@ type tPROPS = { * @param {string} type [endpoint or not, used for styling and tabs] * @return {React.Element} */ -const EndpointBox = (props: tPROPS) => { +const EndpointBox = (props: endpointBoxProps) => { const { noun_name, endpoint_name } = props - const description: Record>> = { - 'animalandveterinary': { - 'event': 'Reports of drug side effects, product use errors, product quality problems, and therapeutic failures.' - }, - 'food': { - 'enforcement': 'Food product recall enforcement reports.', - 'event': 'Food, dietary supplement, and cosmetic adverse event reports.' - }, - 'cosmetic': { - 'event': '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.', - 'covid19serology': 'Serology tests detect the presence of antibodies in the blood when the body is responding to a specific infection, like COVID-19.' - }, - '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.', - 'ndc': 'NDC directory containing information on the National Drug Code (NDC)', - 'enforcement': 'Drug product recall enforcement reports.', - 'drugsfda': 'Drugs@FDA includes most of the drug products approved since 1939.', - 'drugshortages': 'Drug Shortages can occur for many reasons, including manufacturing and quality problems, delays, and discontinuations.' - }, - 'other': { - 'historicaldocument': 'FDA Press Releases, 1913-2014, in searchable format', - 'nsde': 'Comprehensive NDC SPL Data Elements File', - 'substance': 'Substance information that is precise to the molecular level for use internally and externally (where appropriate).', - 'unii': 'Unique Ingredient Identifier list.' - }, - 'tobacco': { - 'problem': 'Reports about tobacco products that are damaged, defective, contaminated, smell or taste wrong, or cause undesirable health effects.' - }, - 'transparency': { - 'crl': 'Centralized database of Complete Response Letters (CRLs)', - } - } - - const ep_title: Record>> = { - 'animalandveterinary': { - 'event': 'Adverse event reports' - }, - 'food': { - 'enforcement': 'Recall enforcement reports', - 'event': 'CAERS reports' - }, - 'cosmetic': { - 'event': 'Adverse event 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', - 'covid19serology': 'COVID-19 serological testing evaluations' - }, - 'drug': { - 'event': 'Adverse events', - 'label': 'Product labeling', - 'ndc': 'NDC Directory', - 'enforcement': 'Recall enforcement reports', - 'drugsfda': 'Drugs@FDA', - 'drugshortages': 'Drug shortages' - }, - 'other': { - 'historicaldocument': 'Historical Documents', - 'nsde': 'NDC SPL Data Elements', - 'substance': 'Substance Data', - 'unii': 'UNII' - }, - 'tobacco': { - 'problem': 'Tobacco Problem Reports' - }, - 'transparency': { - 'crl': 'Complete Response Letters', - } - } - const bg_color: Record = { - 'animalandveterinary': {background: "linear-gradient(to right bottom, #9cf6f6, #007CBA)"}, - 'food': {background: "linear-gradient(to right bottom, rgb(143, 209, 100), rgb(81, 161, 22))"}, - 'cosmetic': {background: "linear-gradient(to right bottom, #CFA1CF, #592680)"}, - 'device': {background: "linear-gradient(to right bottom, #ff8989, #c94747)"}, - 'drug': {background: "linear-gradient(to right bottom, rgb(220, 141, 188), rgb(153, 88, 163))"}, - 'other': {background: "linear-gradient(to right bottom, #9cf6f6, #099db7)"}, - 'tobacco': {background: "linear-gradient(to right bottom, #e6ccb3, #6d5843)"}, - 'transparency': {background: "linear-gradient(to right bottom, rgb(241 238 237), rgb(133 133 132))"}, - } - const icon: Record>> = { 'animalandveterinary': { - 'event':
- }, - 'food': { - 'enforcement':
, - 'event':
- }, - 'cosmetic': { - 'event':
- }, - 'device': { - 'event':
, - 'classification':
, - '510k':
, - 'pma':
, - 'registrationlisting':
, - 'recall':
, - 'enforcement':
, - 'udi':
, - 'covid19serology':
- }, - 'drug': { - 'event':
, - 'label':
, - 'ndc':
, - 'enforcement':
, - 'drugsfda':
, - 'drugshortages':
- }, - 'other': { - 'historicaldocument':
, - 'nsde':
, - 'substance':
, - 'unii':
- }, - 'tobacco': { - 'problem':
- }, - 'transparency': { - 'crl':
- } - } - - const ep_path: Record>> = { - 'animalandveterinary': { - 'event': '/apis/animalandveterinary/event/' + 'event':
}, 'food': { - 'enforcement': '/apis/food/enforcement/', - 'event': '/apis/food/event/' + 'enforcement':
, + 'event':
}, 'cosmetic': { - 'event': '/apis/cosmetic/event/' + 'event':
}, 'device': { - 'event': '/apis/device/event/', - 'classification': '/apis/device/classification/', - '510k': '/apis/device/510k/', - 'pma': '/apis/device/pma/', - 'registrationlisting': '/apis/device/registrationlisting/', - 'recall': '/apis/device/recall/', - 'enforcement': '/apis/device/enforcement/', - 'udi': '/apis/device/udi/', - 'covid19serology': '/apis/device/covid19serology/' + 'event':
, + 'classification':
, + '510k':
, + 'pma':
, + 'registrationlisting':
, + 'recall':
, + 'enforcement':
, + 'udi':
, + 'covid19serology':
}, 'drug': { - 'event': '/apis/drug/event/', - 'label': '/apis/drug/label/', - 'ndc': '/apis/drug/ndc/', - 'enforcement': '/apis/drug/enforcement/', - 'drugsfda': '/apis/drug/drugsfda/', - 'drugshortages': '/apis/drug/drugshortages/' + 'event':
, + 'label':
, + 'ndc':
, + 'enforcement':
, + 'drugsfda':
, + 'drugshortages':
}, 'other': { - 'historicaldocument': '/apis/other/historicaldocument/', - 'nsde': '/apis/other/nsde/', - 'substance': '/apis/other/substance/', - 'unii': '/apis/other/unii/' + 'historicaldocument':
, + 'nsde':
, + 'substance':
, + 'unii':
}, 'tobacco': { - 'problem': '/apis/tobacco/problem/' + 'problem':
}, 'transparency': { - 'crl': '/apis/transparency/completeresponseletters/' + 'crl':
} } @@ -244,7 +77,7 @@ const EndpointBox = (props: tPROPS) => {

{ep_title[noun_name][endpoint_name]}

{description[noun_name][endpoint_name]} - LEARN MORE + LEARN MORE ) diff --git a/src/components/EndpointStatus.tsx b/src/components/EndpointStatus.tsx index c4c614577..f5e8b2513 100644 --- a/src/components/EndpointStatus.tsx +++ b/src/components/EndpointStatus.tsx @@ -3,19 +3,9 @@ import React from 'react' import EndpointStatusContainer from '../containers/EndpointStatusContainer' import '../css/components/EndpointStatus.scss' +import type { endpointStatusProps } from '../types' -type EndpointStatusData = { - last_updated: string; - status: string; - documents: number; -} | Record | null; - -type tPROPS = { - data: EndpointStatusData | null; - fullPath: string; -}; - -const EndpointStatus = ({ data, fullPath, }: tPROPS) => { +const EndpointStatus = ({ data, fullPath, }: endpointStatusProps) => { const date = data ? new Date(data.last_updated) : null; return (
@@ -28,14 +18,14 @@ const EndpointStatus = ({ data, fullPath, }: tPROPS) => { { data ? (data.status === 'GREEN' ? - - OK - - : - - DOWN - - ) + + OK + + : + + DOWN + + ) : N/A } diff --git a/src/constants/endpoint_box.ts b/src/constants/endpoint_box.ts new file mode 100644 index 000000000..874f2411e --- /dev/null +++ b/src/constants/endpoint_box.ts @@ -0,0 +1,145 @@ + +import React from 'react'; +import { NounName, EndpointName } from '../types'; + +export const description: Record>> = { + 'animalandveterinary': { + 'event': 'Reports of drug side effects, product use errors, product quality problems, and therapeutic failures.' + }, + 'food': { + 'enforcement': 'Food product recall enforcement reports.', + 'event': 'Food, dietary supplement, and cosmetic adverse event reports.' + }, + 'cosmetic': { + 'event': '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.', + 'covid19serology': 'Serology tests detect the presence of antibodies in the blood when the body is responding to a specific infection, like COVID-19.' + }, + '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.', + 'ndc': 'NDC directory containing information on the National Drug Code (NDC)', + 'enforcement': 'Drug product recall enforcement reports.', + 'drugsfda': 'Drugs@FDA includes most of the drug products approved since 1939.', + 'drugshortages': 'Drug Shortages can occur for many reasons, including manufacturing and quality problems, delays, and discontinuations.' + }, + 'other': { + 'historicaldocument': 'FDA Press Releases, 1913-2014, in searchable format', + 'nsde': 'Comprehensive NDC SPL Data Elements File', + 'substance': 'Substance information that is precise to the molecular level for use internally and externally (where appropriate).', + 'unii': 'Unique Ingredient Identifier list.' + }, + 'tobacco': { + 'problem': 'Reports about tobacco products that are damaged, defective, contaminated, smell or taste wrong, or cause undesirable health effects.' + }, + 'transparency': { + 'crl': 'Centralized database of Complete Response Letters (CRLs)', + } +} + +export const ep_title: Record>> = { + 'animalandveterinary': { + 'event': 'Adverse event reports' + }, + 'food': { + 'enforcement': 'Recall enforcement reports', + 'event': 'CAERS reports' + }, + 'cosmetic': { + 'event': 'Adverse event 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', + 'covid19serology': 'COVID-19 serological testing evaluations' + }, + 'drug': { + 'event': 'Adverse events', + 'label': 'Product labeling', + 'ndc': 'NDC Directory', + 'enforcement': 'Recall enforcement reports', + 'drugsfda': 'Drugs@FDA', + 'drugshortages': 'Drug shortages' + }, + 'other': { + 'historicaldocument': 'Historical Documents', + 'nsde': 'NDC SPL Data Elements', + 'substance': 'Substance Data', + 'unii': 'UNII' + }, + 'tobacco': { + 'problem': 'Tobacco Problem Reports' + }, + 'transparency': { + 'crl': 'Complete Response Letters', + } +} +export const bg_color: Record = { + 'animalandveterinary': { background: "linear-gradient(to right bottom, #9cf6f6, #007CBA)" }, + 'food': { background: "linear-gradient(to right bottom, rgb(143, 209, 100), rgb(81, 161, 22))" }, + 'cosmetic': { background: "linear-gradient(to right bottom, #CFA1CF, #592680)" }, + 'device': { background: "linear-gradient(to right bottom, #ff8989, #c94747)" }, + 'drug': { background: "linear-gradient(to right bottom, rgb(220, 141, 188), rgb(153, 88, 163))" }, + 'other': { background: "linear-gradient(to right bottom, #9cf6f6, #099db7)" }, + 'tobacco': { background: "linear-gradient(to right bottom, #e6ccb3, #6d5843)" }, + 'transparency': { background: "linear-gradient(to right bottom, rgb(241 238 237), rgb(133 133 132))" }, +} + +export const ep_path: Record>> = { + 'animalandveterinary': { + 'event': '/apis/animalandveterinary/event/' + }, + 'food': { + 'enforcement': '/apis/food/enforcement/', + 'event': '/apis/food/event/' + }, + 'cosmetic': { + 'event': '/apis/cosmetic/event/' + }, + 'device': { + 'event': '/apis/device/event/', + 'classification': '/apis/device/classification/', + '510k': '/apis/device/510k/', + 'pma': '/apis/device/pma/', + 'registrationlisting': '/apis/device/registrationlisting/', + 'recall': '/apis/device/recall/', + 'enforcement': '/apis/device/enforcement/', + 'udi': '/apis/device/udi/', + 'covid19serology': '/apis/device/covid19serology/' + }, + 'drug': { + 'event': '/apis/drug/event/', + 'label': '/apis/drug/label/', + 'ndc': '/apis/drug/ndc/', + 'enforcement': '/apis/drug/enforcement/', + 'drugsfda': '/apis/drug/drugsfda/', + 'drugshortages': '/apis/drug/drugshortages/' + }, + 'other': { + 'historicaldocument': '/apis/other/historicaldocument/', + 'nsde': '/apis/other/nsde/', + 'substance': '/apis/other/substance/', + 'unii': '/apis/other/unii/' + }, + 'tobacco': { + 'problem': '/apis/tobacco/problem/' + }, + 'transparency': { + 'crl': '/apis/transparency/completeresponseletters/' + } +} \ No newline at end of file diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 000000000..27ef618a7 --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1 @@ +export * from './endpoint_box'; \ No newline at end of file diff --git a/src/containers/EndpointStatusContainer.tsx b/src/containers/EndpointStatusContainer.tsx index 6c8a19e9b..74e95dba8 100644 --- a/src/containers/EndpointStatusContainer.tsx +++ b/src/containers/EndpointStatusContainer.tsx @@ -4,32 +4,14 @@ import React from 'react' import find from 'lodash/find' import xhrGET from '../utils/xhr' import { API_LINK } from '../constants/api' -import { attributesToProps } from 'html-react-parser'; +import type { endpointStatusContainerProps, endpointStatusContainerState } from '../types/endpoint.types' -type tPROPS = { - endpoint: string; - path: string; - status: string; - fullPath: string; - data: Object | null; - className?: string; - style?: Object; - [key: string]: any; -}; - -type tSTATE = { - data: Object | null; -}; - -type PROPS = { - -} // A state wrapper for the api status component // just fetches data and then passes it down as props -const EndpointStatusContainer = function (ComposedEndpointStatus: React.ComponentType): React.ComponentType { +const EndpointStatusContainer = function (ComposedEndpointStatus: React.ComponentType): React.ComponentType { // this is a higher order component - class HOC extends React.Component { - static defaultProps: tPROPS = { + class HOC extends React.Component { + static defaultProps: endpointStatusContainerProps = { path: '', status: '', endpoint: '', @@ -39,11 +21,11 @@ const EndpointStatusContainer = function (ComposedEndpointStatus: React.Componen fullPath: '' }; - state: tSTATE = { + state: endpointStatusContainerState = { data: null, }; - _getStatus () { + _getStatus() { const _handleResponse = (data: any) => { const path = this.props.path.replace(/(\/api_endpoints){1}/g, '').replace(/(\/reference){1}/g, '') const key = this.props.status ? @@ -53,7 +35,6 @@ const EndpointStatusContainer = function (ComposedEndpointStatus: React.Componen // pull the relevant endpoint status from the api response const relevant: Object = find(data, d => d.endpoint === key) - this.setState({ data: relevant, }) @@ -62,11 +43,11 @@ const EndpointStatusContainer = function (ComposedEndpointStatus: React.Componen xhrGET(API_LINK + '/status', _handleResponse) } - componentDidMount () { + componentDidMount() { this._getStatus() } - render (): any { + render(): any { if (!this.state.data) return const path: string = this.props?.path.replace(/(\/api_endpoints){1}/g, '').replace(/(\/reference){1}/g, '') @@ -74,9 +55,9 @@ const EndpointStatusContainer = function (ComposedEndpointStatus: React.Componen return ( + {...this.props} + {...this.state} + fullPath={fullPath} /> ) } } diff --git a/src/types/endpoint.types.ts b/src/types/endpoint.types.ts new file mode 100644 index 000000000..94f06c3f4 --- /dev/null +++ b/src/types/endpoint.types.ts @@ -0,0 +1,54 @@ +export type NounName = 'animalandveterinary' | 'food' | 'device' | 'drug' | 'other' | 'tobacco' | 'transparency' | 'cosmetic'; + +export type EndpointName = + | 'event' + | 'enforcement' + | 'classification' + | '510k' + | 'pma' + | 'registrationlisting' + | 'recall' + | 'udi' + | 'covid19serology' + | 'label' + | 'ndc' + | 'drugsfda' + | 'drugshortages' + | 'historicaldocument' + | 'nsde' + | 'substance' + | 'unii' + | 'problem' + | 'crl' + | 'completeresponseletters'; + +export type endpointBoxProps = { + noun_name: NounName, + endpoint_name: EndpointName +}; + +export type EndpointStatusData = { + last_updated: string; + status: string; + documents: number; +} | Record | null; + +export type endpointStatusProps = { + data: EndpointStatusData | null; + fullPath: string; +}; + +export type endpointStatusContainerProps = { + endpoint: string; + path: string; + status: string; + fullPath: string; + data: Object | null; + className?: string; + style?: Object; + [key: string]: any; +}; + +export type endpointStatusContainerState = { + data: Object | null; +}; diff --git a/src/types/index.ts b/src/types/index.ts index fa49a56cb..ccf407e8d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,3 +1,5 @@ export * from './query.types'; +export * from './endpoint.types'; + export * from './sidebar.types'; export * from './content.types'; From 4cbe515682928b26079a9c5732a8c78153aeba27 Mon Sep 17 00:00:00 2001 From: Ayer <59009@icf.com> Date: Thu, 12 Feb 2026 09:46:15 -0600 Subject: [PATCH 2/2] modernize downloads component --- src/components/Downloads.tsx | 14 +--- src/components/FieldDownload.tsx | 94 +----------------------- src/components/SideBar/DownloadsMenu.tsx | 8 +- src/constants/file_download.ts | 81 ++++++++++++++++++++ src/constants/index.ts | 3 +- src/containers/DownloadsContainer.tsx | 24 +++--- src/types/download.types.ts | 65 ++++++++++++++++ src/types/index.ts | 2 +- 8 files changed, 165 insertions(+), 126 deletions(-) create mode 100644 src/constants/file_download.ts create mode 100644 src/types/download.types.ts diff --git a/src/components/Downloads.tsx b/src/components/Downloads.tsx index f21efa5d1..ade44bf64 100644 --- a/src/components/Downloads.tsx +++ b/src/components/Downloads.tsx @@ -4,6 +4,7 @@ import React from 'react' import Link from 'gatsby-link' import cx from 'classnames' import DownloadsContainer from '../containers/DownloadsContainer' +import type { DownloadProps } from '../types/download.types' const liCx: string = 'marg-b-1 row col grow-none t-2 d-2' const mbCx: string = 'clr-gray inline-block' @@ -71,18 +72,7 @@ const _renderByYear = (results: any, years: any) => { }) } -type tPROPS = { - allPartitions: Array; - k: number; - api_path: string; - title: string; - results: Object; - showAllResults: boolean; - toggle: Function; - updated: string; -}; - -const Downloads = (props: tPROPS) => { +const Downloads = (props: DownloadProps) => { const { allPartitions, k, diff --git a/src/components/FieldDownload.tsx b/src/components/FieldDownload.tsx index 6019276a6..5fb1e6131 100644 --- a/src/components/FieldDownload.tsx +++ b/src/components/FieldDownload.tsx @@ -1,97 +1,9 @@ import React from 'react' import '../css/components/FieldDownload.scss' +import type { DownloadProps } from '../types/download.types' +import { pdfDownloadMap, xlsxDownloadMap, yamlDownloadMap } from '../constants/file_download' -const pdfDownloadMap: Readonly> = Object.freeze({ - 'animalandveterinarydrugevent': '/fields/animalandveterinaryevent_reference.pdf', - 'foodevent': '/fields/foodevent_reference.pdf', - 'foodenforcement': '/fields/foodenforcement_reference.pdf', - 'cosmeticevent': '/fields/cosmeticevent_reference.pdf', - 'drugevent': '/fields/drugevent_reference.pdf', - 'druglabel': '/fields/druglabel_reference.pdf', - 'drugndc': '/fields/drugndc_reference.pdf', - 'drugenforcement': '/fields/drugenforcement_reference.pdf', - 'drugsfda': '/fields/drugsfda_reference.pdf', - 'drugshortages': '/fields/drugshortages_reference.pdf', - 'deviceevent': '/fields/deviceevent_reference.pdf', - 'devicerecall': '/fields/devicerecall_reference.pdf', - 'deviceclass': '/fields/deviceclass_reference.pdf', - 'devicereglist': '/fields/devicereglist_reference.pdf', - 'deviceclearance': '/fields/deviceclearance_reference.pdf', - 'devicepma': '/fields/devicepma_reference.pdf', - 'deviceudi': '/fields/deviceudi_reference.pdf', - 'deviceenforcement': '/fields/deviceenforcement_reference.pdf', - 'covid19serology': '/fields/devicecovid19serology_reference.pdf', - 'otherhistoricaldocument': '/fields/otherhistoricaldocument_reference.pdf', - 'othernsde': '/fields/othernsde_reference.pdf', - 'othersubstance': '/fields/othersubstance_reference.pdf', - 'tobaccoproblem': '/fields/tobaccoproblem_reference.pdf', - 'transparencycrl': '/fields/transparencycrl_reference.pdf' -}); - -const xlsxDownloadMap: Readonly> = Object.freeze({ - 'animalandveterinarydrugevent': '/fields/animalandveterinaryevent_reference.xlsx', - 'foodevent': '/fields/foodevent_reference.xlsx', - 'foodenforcement': '/fields/foodenforcement_reference.xlsx', - 'cosmeticevent': '/fields/cosmeticevent_reference.xlsx', - 'drugevent': '/fields/drugevent_reference.xlsx', - 'druglabel': '/fields/druglabel_reference.xlsx', - 'drugndc': '/fields/drugndc_reference.xlsx', - 'drugenforcement': '/fields/drugenforcement_reference.xlsx', - 'drugsfda': '/fields/drugsfda_reference.xlsx', - 'drugshortages': '/fields/drugshortages_reference.xlsx', - 'deviceevent': '/fields/deviceevent_reference.xlsx', - 'devicerecall': '/fields/devicerecall_reference.xlsx', - 'deviceclass': '/fields/deviceclass_reference.xlsx', - 'devicereglist': '/fields/devicereglist_reference.xlsx', - 'deviceclearance': '/fields/deviceclearance_reference.xlsx', - 'devicepma': '/fields/devicepma_reference.xlsx', - 'deviceudi': '/fields/deviceudi_reference.xlsx', - 'deviceenforcement': '/fields/deviceenforcement_reference.xlsx', - 'covid19serology': '/fields/devicecovid19serology_reference.xlsx', - 'otherhistoricaldocument': '/fields/otherhistoricaldocument_reference.xlsx', - 'othernsde': '/fields/othernsde_reference.xlsx', - 'othersubstance': '/fields/othersubstance_reference.xlsx', - 'tobaccoproblem': '/fields/tobaccoproblem_reference.xlsx', - 'transparencycrl': '/fields/transparencycrl_reference.xlsx' -}); - -const yamlDownloadMap: Readonly> = Object.freeze({ - 'animalandveterinarydrugevent': '/fields/animalandveterinaryevent.yaml', - 'foodevent': '/fields/foodevent.yaml', - 'foodenforcement': '/fields/foodenforcement.yaml', - 'cosmeticevent': '/fields/cosmeticevent.yaml', - 'drugevent': '/fields/drugevent.yaml', - 'druglabel': '/fields/druglabel.yaml', - 'drugndc': '/fields/drugndc.yaml', - 'drugenforcement': '/fields/drugenforcement.yaml', - 'drugsfda': '/fields/drugsfda.yaml', - 'drugshortages': '/fields/drugshortages.yaml', - 'deviceevent': '/fields/deviceevent.yaml', - 'devicerecall': '/fields/devicerecall.yaml', - 'deviceclass': '/fields/deviceclass.yaml', - 'devicereglist': '/fields/devicereglist.yaml', - 'deviceclearance': '/fields/deviceclearance.yaml', - 'devicepma': '/fields/devicepma.yaml', - 'deviceudi': '/fields/deviceudi.yaml', - 'deviceenforcement': '/fields/deviceenforcement.yaml', - 'covid19serology': '/fields/devicecovid19serology.yaml', - 'otherhistoricaldocument': '/fields/otherhistoricaldocument.yaml', - 'othernsde': '/fields/othernsde.yaml', - 'othersubstance': '/fields/othersubstance.yaml', - 'tobaccoproblem': '/fields/tobaccoproblem.yaml', - 'transparencycrl': '/fields/transparencycrl.yaml' -}); - - -type tPROPS = { - k: string | number; - meta: { - status: string; - [key: string]: any; - }; -}; - -const FieldDownload = (props: tPROPS) => { +const FieldDownload = (props: DownloadProps) => { const { // key basically. can't pass key as prop k, diff --git a/src/components/SideBar/DownloadsMenu.tsx b/src/components/SideBar/DownloadsMenu.tsx index 18c7ee3a0..79ed59e83 100644 --- a/src/components/SideBar/DownloadsMenu.tsx +++ b/src/components/SideBar/DownloadsMenu.tsx @@ -6,6 +6,7 @@ import cx from 'classnames' import ARIA from '../../constants/aria' import RenderContentObject from '../RenderContentObject' +import type { DownloadsMenuProps } from '../../types/download.types' /** * @description [semantic menu means no links. we don't leave the page] @@ -26,13 +27,6 @@ const _scrollIntoView = (e: React.MouseEvent) => { }) } -interface DownloadsMenuProps { - bottomPos: number; - content: (string | Object)[]; - isBottom: boolean; - isFixed?: boolean; -} - const DownloadsMenu = (props: DownloadsMenuProps) => { const { bottomPos, diff --git a/src/constants/file_download.ts b/src/constants/file_download.ts new file mode 100644 index 000000000..4c6ca2328 --- /dev/null +++ b/src/constants/file_download.ts @@ -0,0 +1,81 @@ + +export const pdfDownloadMap: Readonly> = Object.freeze({ + 'animalandveterinarydrugevent': '/fields/animalandveterinaryevent_reference.pdf', + 'foodevent': '/fields/foodevent_reference.pdf', + 'foodenforcement': '/fields/foodenforcement_reference.pdf', + 'cosmeticevent': '/fields/cosmeticevent_reference.pdf', + 'drugevent': '/fields/drugevent_reference.pdf', + 'druglabel': '/fields/druglabel_reference.pdf', + 'drugndc': '/fields/drugndc_reference.pdf', + 'drugenforcement': '/fields/drugenforcement_reference.pdf', + 'drugsfda': '/fields/drugsfda_reference.pdf', + 'drugshortages': '/fields/drugshortages_reference.pdf', + 'deviceevent': '/fields/deviceevent_reference.pdf', + 'devicerecall': '/fields/devicerecall_reference.pdf', + 'deviceclass': '/fields/deviceclass_reference.pdf', + 'devicereglist': '/fields/devicereglist_reference.pdf', + 'deviceclearance': '/fields/deviceclearance_reference.pdf', + 'devicepma': '/fields/devicepma_reference.pdf', + 'deviceudi': '/fields/deviceudi_reference.pdf', + 'deviceenforcement': '/fields/deviceenforcement_reference.pdf', + 'covid19serology': '/fields/devicecovid19serology_reference.pdf', + 'otherhistoricaldocument': '/fields/otherhistoricaldocument_reference.pdf', + 'othernsde': '/fields/othernsde_reference.pdf', + 'othersubstance': '/fields/othersubstance_reference.pdf', + 'tobaccoproblem': '/fields/tobaccoproblem_reference.pdf', + 'transparencycrl': '/fields/transparencycrl_reference.pdf' +}); + +export const xlsxDownloadMap: Readonly> = Object.freeze({ + 'animalandveterinarydrugevent': '/fields/animalandveterinaryevent_reference.xlsx', + 'foodevent': '/fields/foodevent_reference.xlsx', + 'foodenforcement': '/fields/foodenforcement_reference.xlsx', + 'cosmeticevent': '/fields/cosmeticevent_reference.xlsx', + 'drugevent': '/fields/drugevent_reference.xlsx', + 'druglabel': '/fields/druglabel_reference.xlsx', + 'drugndc': '/fields/drugndc_reference.xlsx', + 'drugenforcement': '/fields/drugenforcement_reference.xlsx', + 'drugsfda': '/fields/drugsfda_reference.xlsx', + 'drugshortages': '/fields/drugshortages_reference.xlsx', + 'deviceevent': '/fields/deviceevent_reference.xlsx', + 'devicerecall': '/fields/devicerecall_reference.xlsx', + 'deviceclass': '/fields/deviceclass_reference.xlsx', + 'devicereglist': '/fields/devicereglist_reference.xlsx', + 'deviceclearance': '/fields/deviceclearance_reference.xlsx', + 'devicepma': '/fields/devicepma_reference.xlsx', + 'deviceudi': '/fields/deviceudi_reference.xlsx', + 'deviceenforcement': '/fields/deviceenforcement_reference.xlsx', + 'covid19serology': '/fields/devicecovid19serology_reference.xlsx', + 'otherhistoricaldocument': '/fields/otherhistoricaldocument_reference.xlsx', + 'othernsde': '/fields/othernsde_reference.xlsx', + 'othersubstance': '/fields/othersubstance_reference.xlsx', + 'tobaccoproblem': '/fields/tobaccoproblem_reference.xlsx', + 'transparencycrl': '/fields/transparencycrl_reference.xlsx' +}); + +export const yamlDownloadMap: Readonly> = Object.freeze({ + 'animalandveterinarydrugevent': '/fields/animalandveterinaryevent.yaml', + 'foodevent': '/fields/foodevent.yaml', + 'foodenforcement': '/fields/foodenforcement.yaml', + 'cosmeticevent': '/fields/cosmeticevent.yaml', + 'drugevent': '/fields/drugevent.yaml', + 'druglabel': '/fields/druglabel.yaml', + 'drugndc': '/fields/drugndc.yaml', + 'drugenforcement': '/fields/drugenforcement.yaml', + 'drugsfda': '/fields/drugsfda.yaml', + 'drugshortages': '/fields/drugshortages.yaml', + 'deviceevent': '/fields/deviceevent.yaml', + 'devicerecall': '/fields/devicerecall.yaml', + 'deviceclass': '/fields/deviceclass.yaml', + 'devicereglist': '/fields/devicereglist.yaml', + 'deviceclearance': '/fields/deviceclearance.yaml', + 'devicepma': '/fields/devicepma.yaml', + 'deviceudi': '/fields/deviceudi.yaml', + 'deviceenforcement': '/fields/deviceenforcement.yaml', + 'covid19serology': '/fields/devicecovid19serology.yaml', + 'otherhistoricaldocument': '/fields/otherhistoricaldocument.yaml', + 'othernsde': '/fields/othernsde.yaml', + 'othersubstance': '/fields/othersubstance.yaml', + 'tobaccoproblem': '/fields/tobaccoproblem.yaml', + 'transparencycrl': '/fields/transparencycrl.yaml' +}); \ No newline at end of file diff --git a/src/constants/index.ts b/src/constants/index.ts index 27ef618a7..9bb9ba22a 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1 +1,2 @@ -export * from './endpoint_box'; \ No newline at end of file +export * from './endpoint_box'; +export * from './file_download'; \ No newline at end of file diff --git a/src/containers/DownloadsContainer.tsx b/src/containers/DownloadsContainer.tsx index b36876cae..dc4005988 100644 --- a/src/containers/DownloadsContainer.tsx +++ b/src/containers/DownloadsContainer.tsx @@ -4,15 +4,11 @@ import React from 'react' import get from 'lodash/get' import xhrGET from '../utils/xhr' import { API_LINK } from '../constants/api' +import type { DownloadsContainerState } from '../types/download.types' -type tSTATE = { - data: Object | null | undefined; - showAllResults: boolean; -}; - -const DownloadsContainer = function (ComposedDownloads: ReactClass): ReactClass { +const DownloadsContainer = function (ComposedDownloads: React.ComponentType): React.ComponentType { class HOC extends React.Component { - state: tSTATE = { + state: DownloadsContainerState = { data: null, showAllResults: false, }; @@ -22,7 +18,7 @@ const DownloadsContainer = function (ComposedDownloads: ReactClass): ReactClass } _fetchDownloads () { - const _handleResponse = data => { + const _handleResponse = (data: any) => { this.setState({ data, @@ -46,12 +42,12 @@ const DownloadsContainer = function (ComposedDownloads: ReactClass): ReactClass * @param {Array} results [original results array] * @returns {Object} [map, where each year is an array] */ - _getResultsByCategory (results: Array): Object { + _getResultsByCategory (results: Array): Object { // handle data sorted by years // or data sorted by set // or data that is just all lumped together for some reason const yearRe: RegExp = /(\d{4} )|(All other data)|^(\w|\/)+/ - const resultsByYear: Object = {} + const resultsByYear: { [key: string]: any } = {} for (const result of results) { if (result.size_mb < 0.01) { @@ -76,7 +72,7 @@ const DownloadsContainer = function (ComposedDownloads: ReactClass): ReactClass // drug/event => results.drug.event const key: string = `results${api_path.split('/').join('.')}` // data = { results: { drug: { event: relevantData } } } - const results: Object = get(this.state.data, key) + const results: any = get(this.state.data, key) // some endpoint won't have download data if (typeof results !== 'object') return @@ -85,13 +81,13 @@ const DownloadsContainer = function (ComposedDownloads: ReactClass): ReactClass const resultsByCat: Object = this._getResultsByCategory(results.partitions) // type so flow knows meta can't be undefined // NOT the same as this.props.meta - const meta: Object = get(this.state.data, 'meta') + const meta: any = get(this.state.data, 'meta') || {} return ( ; + k: number; + api_path: string; + title: string; + results: Object; + showAllResults: boolean; + toggle: Function; + updated: string; + meta?: any +}; + +export interface DownloadsMenuProps { + bottomPos: number; + content: (string | Object)[]; + isBottom: boolean; + isFixed?: boolean; +} + +export type DownloadsContainerState = { + data: Object | null | undefined; + showAllResults: boolean; +}; + + +export interface DownloadResult { + size_mb: number; + display_name: string; + [key: string]: any; +} + +export interface DownloadResults { + partitions: Array; + [key: string]: any; +} + +export interface WithMetaProps { + meta: { + api_path: string; + title: string; + [key: string]: any; + }; + k?: any; + api_path?: string; + title?: string; + allPartitions?: Array; + results?: Record; + showAllResults?: boolean; + toggle?: () => void; + updated?: string; +} + +export interface MetaData { + last_updated: string; + [key: string]: any; +} + +export type FileDownloadProps = { + k: string | number; + meta: { + status: string; + [key: string]: any; + }; +}; diff --git a/src/types/index.ts b/src/types/index.ts index ccf407e8d..02714d91c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,5 +1,5 @@ export * from './query.types'; export * from './endpoint.types'; - export * from './sidebar.types'; export * from './content.types'; +export * from './download.types';