Skip to content
Snippets Groups Projects
Commit 2fe9d939 authored by Tamlyn Rhodes's avatar Tamlyn Rhodes
Browse files

feat(client): add Apollo Client

Add ApolloProvider.
Add mutation load state tracking HoC.
Support multipart uploads over GraphQL.
parent b6792273
No related branches found
No related tags found
No related merge requests found
...@@ -14,15 +14,22 @@ ...@@ -14,15 +14,22 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@pubsweet/ui": "^3.3.0", "@pubsweet/ui": "^3.3.0",
"apollo-client-preset": "^1.0.8",
"apollo-link": "^1.2.1",
"apollo-link-context": "^1.0.5",
"apollo-upload-client": "^8.0.0",
"authsome": "0.0.9", "authsome": "0.0.9",
"config": "^1.21.0", "config": "^1.21.0",
"event-source-polyfill": "^0.0.10", "event-source-polyfill": "^0.0.10",
"global": "^4.3.1", "global": "^4.3.1",
"graphql": "^0.13.0",
"graphql-tag": "^2.7.3",
"isomorphic-fetch": "^2.1.1", "isomorphic-fetch": "^2.1.1",
"lint-staged": "^6.0.0", "lint-staged": "^6.0.0",
"lodash": "^4.0.0", "lodash": "^4.0.0",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
"react": "^16.2.0", "react": "^16.2.0",
"react-apollo": "^2.1.0",
"react-redux": "^5.0.2", "react-redux": "^5.0.2",
"react-router-dom": "^4.2.2", "react-router-dom": "^4.2.2",
"react-router-redux": "next", "react-router-redux": "next",
...@@ -50,7 +57,7 @@ ...@@ -50,7 +57,7 @@
"redux-mock-store": "^1.3.0" "redux-mock-store": "^1.3.0"
}, },
"peerDependencies": { "peerDependencies": {
"pubsweet-server": ">=1.0.0" "pubsweet-server": ">=1.1.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
......
...@@ -3,18 +3,42 @@ import { ConnectedRouter } from 'react-router-redux' ...@@ -3,18 +3,42 @@ import { ConnectedRouter } from 'react-router-redux'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { ThemeProvider } from 'styled-components' import { ThemeProvider } from 'styled-components'
import { ApolloProvider } from 'react-apollo'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { createUploadLink } from 'apollo-upload-client'
import StyleRoot, { injectGlobalStyles } from '../helpers/StyleRoot' import StyleRoot, { injectGlobalStyles } from '../helpers/StyleRoot'
injectGlobalStyles() injectGlobalStyles()
const uploadLink = createUploadLink()
const httpLink = createHttpLink()
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('token')
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
}
})
const client = new ApolloClient({
link: authLink.concat(uploadLink, httpLink),
cache: new InMemoryCache(),
})
const Root = ({ store, history, routes, theme }) => ( const Root = ({ store, history, routes, theme }) => (
<Provider store={store}> <ApolloProvider client={client}>
<ConnectedRouter history={history}> <Provider store={store}>
<ThemeProvider theme={theme}> <ConnectedRouter history={history}>
<StyleRoot>{routes}</StyleRoot> <ThemeProvider theme={theme}>
</ThemeProvider> <StyleRoot>{routes}</StyleRoot>
</ConnectedRouter> </ThemeProvider>
</Provider> </ConnectedRouter>
</Provider>
</ApolloProvider>
) )
Root.propTypes = { Root.propTypes = {
......
import React from 'react'
import PropTypes from 'prop-types'
export default () => WrappedComponent => {
const Wrapper = ({
data: { loading, error, ...apolloProps },
...parentProps
}) => {
if (loading) return <div>Loading...</div>
if (error) return <div>{error.message}</div>
return <WrappedComponent {...parentProps} {...apolloProps} />
}
Wrapper.propTypes = {
data: PropTypes.object,
}
return Wrapper
}
import React from 'react'
export default ({ name = 'mutate' } = {}) => WrappedComponent =>
class extends React.Component {
state = { loading: false, error: null, result: null }
loadingProperty = `${name}Loading`
errorProperty = `${name}Error`
resultProperty = `${name}Result`
executeMutation(options) {
this.setState({
loading: true,
error: null,
result: null,
})
return this.props[name](options)
.then(result => {
this.setState({
loading: false,
error: null,
result,
})
})
.catch(error => {
this.setState({
loading: false,
error,
result: null,
})
})
}
render() {
const props = {
...this.props,
[name]: this.executeMutation.bind(this),
[this.loadingProperty]: this.state.loading,
[this.errorProperty]: this.state.error,
[this.resultProperty]: this.state.result,
}
return <WrappedComponent {...props} />
}
}
...@@ -6,3 +6,6 @@ export { ...@@ -6,3 +6,6 @@ export {
export { default as actions } from './actions' export { default as actions } from './actions'
export { default as reducers } from './reducers' export { default as reducers } from './reducers'
export { default as validations } from './validations' export { default as validations } from './validations'
export { default as withLoader } from './helpers/withLoader'
export { default as withAuthsome } from './helpers/withAuthsome'
export { default as withMutationState } from './helpers/withMutationState'
...@@ -4,6 +4,7 @@ import createHistory from 'history/createBrowserHistory' ...@@ -4,6 +4,7 @@ import createHistory from 'history/createBrowserHistory'
import styled from 'styled-components' import styled from 'styled-components'
global.PUBSWEET_COMPONENTS = [] global.PUBSWEET_COMPONENTS = []
global.fetch = () => {}
const Root = require('../../src/components/Root').default const Root = require('../../src/components/Root').default
const configureStore = require('../../src/store/configureStore') const configureStore = require('../../src/store/configureStore')
......
...@@ -56,7 +56,8 @@ ...@@ -56,7 +56,8 @@
"config/" "config/"
], ],
"globals": { "globals": {
"PUBSWEET_COMPONENTS": [] "PUBSWEET_COMPONENTS": [],
"fetch": true
}, },
"setupTestFrameworkScriptFile": "<rootDir>/test/jest-setup.js" "setupTestFrameworkScriptFile": "<rootDir>/test/jest-setup.js"
} }
......
This diff is collapsed.
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment