-
Notifications
You must be signed in to change notification settings - Fork 19
COVE ‐ Wrapper Middleware
David Cummo edited this page Aug 28, 2024
·
1 revision
import React, { useEffect, useState, useCallback, Suspense } from 'react'
import 'whatwg-fetch'
import './styles.scss'
import cdcLogo from './cdc-hhs.svg'
const CdcMap = React.lazy(() => import('@cdc/map'));
const CdcChart = React.lazy(() => import('@cdc/chart'));
const CdcEditor = React.lazy(() => import('@cdc/editor'));
const CdcDashboard = React.lazy(() => import('@cdc/dashboard'));
const CdcDataBite = React.lazy(() => import('@cdc/data-bite'));
const CdcWaffleChart = React.lazy(() => import('@cdc/waffle-chart'));
const CdcMarkupInclude = React.lazy(() => import('@cdc/markup-include'));
const Loading = ({viewport = "lg"}) => {
return (
<section className="loading">
<div className={`la-ball-beat la-dark ${viewport}`}>
<div />
<div />
<div />
</div>
</section>
)
}
const Wrapper = ({configURL, language, config: configObj, isEditor, hostname, sharePath}) => {
const [ config, setConfig ] = useState(configObj)
const [ type, setType ] = useState(null)
const metricsCall = useCallback((type, url) => {
const s = window.s || {}
if(true === s.hasOwnProperty('tl')) {
let newObj = {...s}
newObj.pageURL = window.location.href
newObj.linkTrackVars = "pageURL";
newObj.linkURL = url // URL We are navigating to
s.tl( true, type, null, newObj )
}
})
const iframeCheck = () => {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
const navigationHandler = useCallback((urlString = '') => {
// Abort if value is blank
if(0 === urlString.length) {
throw Error("Blank string passed as URL. Navigation aborted.");
}
// Make sure this isn't loading through an iFrame.
const inIframe = iframeCheck();
// Determine if link is a relative hash link
const isHashLink = urlString.startsWith('#');
// Smooth scrolling for hash links on the same page as the map
if(true === isHashLink && false === inIframe) {
let hashName = urlString.substr(1);
let scrollSection = window.document.querySelector(`*[id="${hashName}"]`) || window.document.querySelector(`*[name="${hashName}"]`)
if(scrollSection) {
scrollSection.scrollIntoView({
behavior: 'smooth'
})
return true;
} else {
throw Error("Internal hash link detected but unable to find element on page. Navigation aborted.");
}
}
// Metrics Call
const extension = urlString.substring( urlString.lastIndexOf( '.' ) + 1 )
const s = window.s || {}
let metricsParam = 'e';
if ( s.hasOwnProperty('linkDownloadFileTypes') && s.linkDownloadFileTypes.includes(extension) ) {
metricsParam = 'd'; // Different parameter for downloads
}
let urlObj;
// If we're not loading through iframe (ex: widget loader)
if(false === inIframe) {
// Insert proper base for relative URLs
const parentUrlObj = new URL(window.location.href);
// Only insert a dynamic base if this is on a CDC.gov page, regardless of environment.
// This prevents security concerns where a party could embed a CDC visualization on their own site and have the relative URLs go to their own content making it look like its endorsed by the CDC.
let urlBase = parentUrlObj.host.endsWith('cdc.gov') ? parentUrlObj.origin : 'https://www.cdc.gov/';
urlObj = new URL(urlString, urlBase);
} else {
urlObj = new URL(urlString);
}
// Set the string to the newly constructed string.
urlString = urlObj.toString();
// Don't make a metrics call if it's a link to cdc.gov and does not have a download extension (ex. pdf) or if we're inside the editor.
if( false === ( 'e' === metricsParam && urlString.includes('cdc.gov') ) && false === isEditor ) {
metricsCall(metricsParam, urlString);
}
// Open constructed link in new tab/window
window.open(urlString, '_blank');
})
useEffect(() => {
if(null === configURL) {
console.warn('No configuration URL detected.');
return;
}
const grabConfigObj = async () => {
try {
const response = await fetch(configURL);
const data = await response.json();
let tempConfigObj = {language, ...data}
setConfig(tempConfigObj);
setLoading(false);
} catch (err) {
new Error(err)
}
};
grabConfigObj();
}, [configURL]);
useEffect(() => {
if(config && config.hasOwnProperty('type')) {
setType(config.type)
}
}, [config])
// WCMS Admin
if(isEditor && config) {
// This either passes an existing config or starts with a blank editor
return (
<Suspense fallback={<Loading />}>
<CdcEditor config={config} hostname={hostname} sharepath={sharePath} />
</Suspense>)
}
// Standalone mode when you run `npm run start` just so it isn't blank
if(!config && !configURL) {
return (<Suspense fallback={<Loading />}>
<CdcEditor hostname={hostname} sharepath={sharePath} />
</Suspense>)
}
switch (type) {
case 'map':
return (
<Suspense fallback={<Loading />}>
<CdcMap config={config} hostname={hostname} navigationHandler={navigationHandler} logo={cdcLogo} />
</Suspense>
)
case 'chart':
return (
<Suspense fallback={<Loading />}>
<CdcChart config={config} hostname={hostname} />
</Suspense>
)
case 'dashboard':
return (
<Suspense fallback={<Loading />}>
<CdcDashboard config={config} hostname={hostname} />
</Suspense>
)
case 'data-bite':
return (
<Suspense fallback={<Loading />}>
<CdcDataBite config={config} hostname={hostname} />
</Suspense>
)
case 'waffle-chart':
return (
<Suspense fallback={<Loading />}>
<CdcWaffleChart config={config} hostname={hostname} />
</Suspense>
)
case 'markup-include':
return (
<Suspense fallback={<Loading />}>
<CdcMarkupInclude config={config} hostname={hostname} />
</Suspense>
)
default:
return <Loading />
}
}
export default Wrapper