From 82118777bac99f71a352a80d78936cde474cffad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loren=20=F0=9F=A4=93?= Date: Tue, 28 Aug 2018 22:17:06 -0400 Subject: [PATCH] withAuth -> withUser, fixes #33 --- src/components/App.js | 21 +------ src/components/CurrentUser.js | 24 ++++---- src/components/Profile.js | 13 ++-- src/index.js | 54 +---------------- src/lib/apollo.js | 51 ++++++++++++++++ src/lib/auth.js | 48 +++++++++++++++ src/lib/withAuth.js | 111 ---------------------------------- src/lib/withUser.js | 22 +++++++ 8 files changed, 145 insertions(+), 199 deletions(-) create mode 100644 src/lib/apollo.js create mode 100644 src/lib/auth.js delete mode 100644 src/lib/withAuth.js create mode 100644 src/lib/withUser.js diff --git a/src/components/App.js b/src/components/App.js index 895f813..c1b6151 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,7 +1,6 @@ import React, { Component } from 'react' import { Switch, Route, Redirect } from 'react-router' import { Link } from 'react-router-dom' -import PropTypes from 'prop-types' import logo from '../logo.svg' import StarCount from './StarCount' @@ -9,7 +8,6 @@ import TableOfContents from './TableOfContents' import Section from './Section' import CurrentUser from './CurrentUser' import Profile from './Profile' -import withAuth from '../lib/withAuth' import Reviews from './Reviews' const Book = () => ( @@ -24,8 +22,6 @@ const Book = () => ( class App extends Component { render() { - const { logout, ...authProps } = this.props - return (
@@ -34,15 +30,11 @@ class App extends Component { logo

The GraphQL Guide

- +
} /> - } - /> +
@@ -50,11 +42,4 @@ class App extends Component { } } -App.propTypes = { - user: PropTypes.object, - login: PropTypes.func.isRequired, - logout: PropTypes.func.isRequired, - loading: PropTypes.bool.isRequired -} - -export default withAuth(App) +export default App diff --git a/src/components/CurrentUser.js b/src/components/CurrentUser.js index 94ebfdf..dfb69f0 100644 --- a/src/components/CurrentUser.js +++ b/src/components/CurrentUser.js @@ -2,19 +2,20 @@ import React from 'react' import PropTypes from 'prop-types' import { Link } from 'react-router-dom' -const CurrentUser = ({ user, login, loading }) => { - const User = () => ( - - {user.firstName} - {user.firstName} - - ) +import { withUser } from '../lib/withUser' +import { login } from '../lib/auth' +const CurrentUser = ({ user, loggingIn }) => { let content if (user) { - content = - } else if (loading) { + content = ( + + {user.firstName} + {user.firstName} + + ) + } else if (loggingIn) { content =
} else { content = @@ -28,8 +29,7 @@ CurrentUser.propTypes = { firstName: PropTypes.string.isRequired, photo: PropTypes.string.isRequired }), - login: PropTypes.func.isRequired, - loading: PropTypes.bool.isRequired + loggingIn: PropTypes.bool.isRequired } -export default CurrentUser +export default withUser(CurrentUser) diff --git a/src/components/Profile.js b/src/components/Profile.js index 4cbe616..8db29d8 100644 --- a/src/components/Profile.js +++ b/src/components/Profile.js @@ -1,8 +1,11 @@ import React from 'react' import PropTypes from 'prop-types' -const Profile = ({ user, login, logout, loading }) => { - if (loading) { +import { withUser } from '../lib/withUser' +import { login, logout } from '../lib/auth' + +const Profile = ({ user, loggingIn }) => { + if (loggingIn) { return (
@@ -63,9 +66,7 @@ Profile.propTypes = { email: PropTypes.string.isRequired, hasPurchased: PropTypes.string }), - login: PropTypes.func.isRequired, - logout: PropTypes.func.isRequired, - loading: PropTypes.bool.isRequired + loggingIn: PropTypes.bool.isRequired } -export default Profile +export default withUser(Profile) diff --git a/src/index.js b/src/index.js index da035a0..ad25a6b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,66 +1,16 @@ import React from 'react' import ReactDOM from 'react-dom' -import { ApolloClient } from 'apollo-client' import { ApolloProvider } from 'react-apollo' -import { InMemoryCache } from 'apollo-cache-inmemory' -import { split } from 'apollo-link' -import { WebSocketLink } from 'apollo-link-ws' -import { createHttpLink } from 'apollo-link-http' -import { getMainDefinition } from 'apollo-utilities' import { BrowserRouter } from 'react-router-dom' -import { setContext } from 'apollo-link-context' -import { getAuthToken } from 'auth0-helpers' import './index.css' import registerServiceWorker from './registerServiceWorker' import App from './components/App' - -const httpLink = createHttpLink({ - uri: 'https://api.graphql.guide/graphql' -}) - -const authLink = setContext(async (_, { headers }) => { - const token = await getAuthToken({ - doLoginIfTokenExpired: true - }) - - if (token) { - return { - headers: { - ...headers, - authorization: `Bearer ${token}` - } - } - } else { - return { headers } - } -}) - -const authedHttpLink = authLink.concat(httpLink) - -const wsLink = new WebSocketLink({ - uri: `wss://api.graphql.guide/subscriptions`, - options: { - reconnect: true - } -}) - -const link = split( - ({ query }) => { - const { kind, operation } = getMainDefinition(query) - return kind === 'OperationDefinition' && operation === 'subscription' - }, - wsLink, - authedHttpLink -) - -const cache = new InMemoryCache() - -const client = new ApolloClient({ link, cache }) +import { apollo } from './lib/apollo' ReactDOM.render( - + , diff --git a/src/lib/apollo.js b/src/lib/apollo.js new file mode 100644 index 0000000..5b73c55 --- /dev/null +++ b/src/lib/apollo.js @@ -0,0 +1,51 @@ +import { ApolloClient } from 'apollo-client' +import { InMemoryCache } from 'apollo-cache-inmemory' +import { split } from 'apollo-link' +import { WebSocketLink } from 'apollo-link-ws' +import { createHttpLink } from 'apollo-link-http' +import { getMainDefinition } from 'apollo-utilities' +import { setContext } from 'apollo-link-context' +import { getAuthToken } from 'auth0-helpers' + +const httpLink = createHttpLink({ + uri: 'https://api.graphql.guide/graphql' +}) + +const authLink = setContext(async (_, { headers }) => { + const token = await getAuthToken({ + doLoginIfTokenExpired: true + }) + + if (token) { + return { + headers: { + ...headers, + authorization: `Bearer ${token}` + } + } + } else { + return { headers } + } +}) + +const authedHttpLink = authLink.concat(httpLink) + +const wsLink = new WebSocketLink({ + uri: `wss://api.graphql.guide/subscriptions`, + options: { + reconnect: true + } +}) + +const link = split( + ({ query }) => { + const { kind, operation } = getMainDefinition(query) + return kind === 'OperationDefinition' && operation === 'subscription' + }, + wsLink, + authedHttpLink +) + +const cache = new InMemoryCache() + +export const apollo = new ApolloClient({ link, cache }) diff --git a/src/lib/auth.js b/src/lib/auth.js new file mode 100644 index 0000000..2ac23f4 --- /dev/null +++ b/src/lib/auth.js @@ -0,0 +1,48 @@ +import auth0 from 'auth0-js' +import { + initAuthHelpers, + login as auth0Login, + logout as auth0Logout +} from 'auth0-helpers' + +import { apollo } from './apollo' + +const client = new auth0.WebAuth({ + domain: 'graphql.auth0.com', + clientID: '8fErnZoF3hbzQ2AbMYu5xcS0aVNzQ0PC', + responseType: 'token', + audience: 'https://api.graphql.guide', + scope: 'openid profile guide' +}) + +initAuthHelpers({ + client, + usePopup: true, + authOptions: { + connection: 'github', + owp: true, + popupOptions: { height: 623 } // make tall enough for content + }, + checkSessionOptions: { + redirect_uri: window.location.origin + }, + onError: e => console.error(e) +}) + +export const login = () => { + auth0Login({ + onCompleted: e => { + if (e) { + console.error(e) + return + } + + apollo.reFetchObservableQueries() + } + }) +} + +export const logout = () => { + auth0Logout() + apollo.resetStore() +} diff --git a/src/lib/withAuth.js b/src/lib/withAuth.js deleted file mode 100644 index 5fec7d8..0000000 --- a/src/lib/withAuth.js +++ /dev/null @@ -1,111 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import wrapDisplayName from 'recompose/wrapDisplayName' -import { graphql, withApollo } from 'react-apollo' -import { ApolloClient } from 'apollo-client' -import gql from 'graphql-tag' -import auth0 from 'auth0-js' -import { initAuthHelpers, login, logout } from 'auth0-helpers' - -const client = new auth0.WebAuth({ - domain: 'graphql.auth0.com', - clientID: '8fErnZoF3hbzQ2AbMYu5xcS0aVNzQ0PC', - responseType: 'token', - audience: 'https://api.graphql.guide', - scope: 'openid profile guide' -}) - -initAuthHelpers({ - client, - usePopup: true, - authOptions: { - connection: 'github', - owp: true, - popupOptions: { height: 623 } // make tall enough for content - }, - checkSessionOptions: { - redirect_uri: window.location.origin - }, - onError: e => console.error(e) -}) - -const USER_QUERY = gql` - query UserQuery { - currentUser { - firstName - name - username - email - photo - hasPurchased - } - } -` - -const withUser = graphql(USER_QUERY, { - props: ({ ownProps, data: { currentUser, loading } }) => ({ - currentUser, - loading, - ownProps - }) -}) - -function withAuth(BaseComponent) { - class WithAuthWrapper extends React.Component { - constructor(props) { - super(props) - - this.state = { - loggingIn: false - } - } - - login = () => { - this.setState({ loggingIn: true }) - login({ - onCompleted: (e, t) => { - e && console.log(e) - this.props.client.reFetchObservableQueries() - this.setState({ loggingIn: false }) - } - }) - } - - logout = () => { - logout() - this.props.client.resetStore() - } - - render() { - const { currentUser, loading, ownProps } = this.props - - return ( - - ) - } - } - - WithAuthWrapper.propTypes = { - currentUser: PropTypes.shape({ - firstName: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - username: PropTypes.string.isRequired, - email: PropTypes.string.isRequired, - photo: PropTypes.string.isRequired, - hasPurchased: PropTypes.string - }), - loading: PropTypes.bool.isRequired, - client: PropTypes.instanceOf(ApolloClient).isRequired - } - - WithAuthWrapper.displayName = wrapDisplayName(BaseComponent, 'withAuth') - return withApollo(withUser(WithAuthWrapper)) -} - -export default withAuth diff --git a/src/lib/withUser.js b/src/lib/withUser.js new file mode 100644 index 0000000..46827d5 --- /dev/null +++ b/src/lib/withUser.js @@ -0,0 +1,22 @@ +import { graphql } from 'react-apollo' +import gql from 'graphql-tag' + +export const USER_QUERY = gql` + query UserQuery { + currentUser { + firstName + name + username + email + photo + hasPurchased + } + } +` + +export const withUser = graphql(USER_QUERY, { + props: ({ data: { currentUser, loading } }) => ({ + user: currentUser, + loggingIn: loading + }) +})