-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from zarathustra323/messing-with-sasquatch
Overhaul of web components
- Loading branch information
Showing
49 changed files
with
1,731 additions
and
1,298 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"verbose": true, | ||
"ignore": ["node_modules", ".next"], | ||
"watch": ["server/**/*", "server.js"], | ||
"watch": ["src/server/**/*", "server.js"], | ||
"ext": "js json" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,89 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import Head from 'next/head'; | ||
import { ApolloProvider, getDataFromTree } from 'react-apollo'; | ||
import { getDataFromTree } from 'react-apollo'; | ||
import PropTypes from 'prop-types'; | ||
import initApollo from './init'; | ||
import apolloConfig from './config'; | ||
|
||
const getDisplayName = Component => Component.displayName || Component.name || 'Unknown'; | ||
|
||
export default function withApollo(apolloConfig) { | ||
return (ComposedComponent) => { | ||
class WithData extends React.Component { | ||
static async getInitialProps(context) { | ||
let serverState = { apollo: {} }; | ||
const { | ||
req, | ||
query, | ||
pathname, | ||
asPath, | ||
} = context; | ||
export default (App) => { | ||
class WithApollo extends React.Component { | ||
/** | ||
* | ||
* @param {*} props | ||
*/ | ||
constructor(props) { | ||
super(props); | ||
const { apolloState } = this.props; | ||
this.apollo = initApollo(apolloConfig, apolloState); | ||
} | ||
|
||
// Await the composed components initial props. | ||
let composedProps = {}; | ||
if (ComposedComponent.getInitialProps) { | ||
composedProps = await ComposedComponent.getInitialProps(context); | ||
} | ||
/** | ||
* | ||
* @param {*} ctx | ||
*/ | ||
static async getInitialProps({ | ||
Component, | ||
router, | ||
ctx, | ||
rest, | ||
}) { | ||
const { req } = ctx; | ||
|
||
// Run all GraphQL queries in tree and extract their data. | ||
if (!process.browser) { | ||
const apollo = initApollo(apolloConfig, null, req); | ||
const url = { query, pathname }; | ||
// Await the App's initial props. | ||
let appProps = {}; | ||
if (App.getInitialProps) { | ||
appProps = await App.getInitialProps({ | ||
Component, | ||
router, | ||
ctx, | ||
...rest, | ||
}); | ||
} | ||
|
||
try { | ||
// Run queries in the tree. | ||
await getDataFromTree( | ||
<ApolloProvider client={apollo}> | ||
<ComposedComponent | ||
url={url} | ||
context={context} | ||
{...composedProps} | ||
/> | ||
</ApolloProvider>, | ||
{ router: { asPath, pathname, query } }, | ||
); | ||
} catch (e) { | ||
// Prevent errors from crashing SSR. | ||
// Handle the error in components via data.error prop. | ||
// eslint-disable-next-line no-console | ||
console.error('SERVER ERROR', e); | ||
} | ||
// Clear the head state so duplicate head data is prevented. | ||
Head.rewind(); | ||
serverState = { | ||
apollo: { data: apollo.cache.extract() }, | ||
}; | ||
const apollo = initApollo(apolloConfig, {}, req); | ||
// Run all GraphQL queries in tree and extract the data. | ||
if (!process.browser) { | ||
try { | ||
// Run queries in the tree. | ||
await getDataFromTree(<App | ||
{...appProps} | ||
Component={Component} | ||
router={router} | ||
apollo={apollo} | ||
/>); | ||
} catch (e) { | ||
// Prevent errors from crashing SSR. | ||
// Handle the error in components via data.error prop. | ||
// @see http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error | ||
// eslint-disable-next-line no-console | ||
console.error('SERVER ERROR in getDataFromTree', e); | ||
} | ||
return { serverState, ...composedProps }; | ||
// Clear the head state so duplicate head data is prevented. | ||
Head.rewind(); | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
const { serverState } = this.props; | ||
this.apollo = initApollo(apolloConfig, serverState.apollo.data); | ||
} | ||
// Extract the Apollo query data. | ||
const apolloState = apollo.cache.extract(); | ||
|
||
render() { | ||
return ( | ||
<ApolloProvider client={this.apollo}> | ||
<ComposedComponent {...this.props} /> | ||
</ApolloProvider> | ||
); | ||
} | ||
return { | ||
...appProps, | ||
apolloState, | ||
}; | ||
} | ||
|
||
WithData.displayName = `WithData(${getDisplayName(ComposedComponent)})`; | ||
/** | ||
* | ||
*/ | ||
render() { | ||
return <App {...this.props} apollo={this.apollo} />; | ||
} | ||
} | ||
|
||
WithData.propTypes = { | ||
// eslint-disable-next-line react/forbid-prop-types | ||
serverState: PropTypes.object.isRequired, | ||
}; | ||
return WithData; | ||
WithApollo.displayName = 'WithApollo(App)'; | ||
WithApollo.propTypes = { | ||
// eslint-disable-next-line react/forbid-prop-types | ||
apolloState: PropTypes.object.isRequired, | ||
}; | ||
} | ||
return WithApollo; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { Alert } from 'reactstrap'; | ||
|
||
const ErrorAlert = ({ message }) => ( | ||
<Alert className="mb-0" color="warning"> | ||
<h5 className="alert-heading"> | ||
Oh Snap! | ||
</h5> | ||
<hr /> | ||
<p className="mb-0"> | ||
{message} | ||
</p> | ||
</Alert> | ||
); | ||
|
||
ErrorAlert.defaultProps = { | ||
message: 'An unknown, fatal error occurred.', | ||
}; | ||
|
||
ErrorAlert.propTypes = { | ||
message: PropTypes.string, | ||
}; | ||
|
||
export default ErrorAlert; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import React, { Fragment } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
/** | ||
* Renders the global site script tag for gtag.js with Google Analytics. | ||
* | ||
* If no tracking ID is present, no script will be inserted. | ||
* Also sets the accountKey globally. | ||
* | ||
* @see https://github.com/zeit/next.js/blob/master/examples/with-google-analytics | ||
*/ | ||
const GoogleAnalytics = ({ trackingId, accountKey }) => { | ||
if (!trackingId) return null; | ||
/** | ||
* Global Site Tag (gtag.js) - Google Analytics | ||
* | ||
*/ | ||
return ( | ||
<Fragment> | ||
<script async src={`https://www.googletagmanager.com/gtag/js?id=${trackingId}`} /> | ||
<script | ||
dangerouslySetInnerHTML={{ // eslint-disable-line react/no-danger | ||
__html: ` | ||
window.dataLayer = window.dataLayer || []; | ||
function gtag(){dataLayer.push(arguments);} | ||
gtag('js', new Date()); | ||
window.gtag('config', '${trackingId}', { | ||
send_page_view: false, | ||
custom_map: { | ||
dimension1: 'account_key', | ||
dimension2: 'story_id' | ||
}, | ||
account_key: '${accountKey}' | ||
}); | ||
`, | ||
}} | ||
/> | ||
</Fragment> | ||
); | ||
}; | ||
|
||
GoogleAnalytics.defaultProps = { | ||
trackingId: '', | ||
}; | ||
|
||
GoogleAnalytics.propTypes = { | ||
trackingId: PropTypes.string, | ||
accountKey: PropTypes.string.isRequired, | ||
}; | ||
|
||
export default GoogleAnalytics; |
Oops, something went wrong.