From 1d41eee268b3b626bf553e251baace1ff9069fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loren=20=F0=9F=A4=93?= Date: Tue, 28 Aug 2018 22:27:27 -0400 Subject: [PATCH] withAuth -> withUser, fixes #33 --- src/components/App.js | 23 +++----------- src/components/CurrentUser.js | 24 +++++++-------- src/components/Profile.js | 13 ++++---- src/components/Reviews.js | 3 +- src/index.js | 57 ++--------------------------------- src/lib/apollo.js | 55 +++++++++++++++++++++++++++++++++ src/lib/auth.js | 48 +++++++++++++++++++++++++++++ src/lib/withUser.js | 25 +++++++++++++++ 8 files changed, 155 insertions(+), 93 deletions(-) create mode 100644 src/lib/apollo.js create mode 100644 src/lib/auth.js create mode 100644 src/lib/withUser.js diff --git a/src/components/App.js b/src/components/App.js index f330c41..4fa2b31 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 = ({ user }) => ( @@ -24,8 +22,6 @@ const Book = ({ user }) => ( class App extends Component { render() { - const { logout, ...authProps } = this.props - return (
@@ -34,27 +30,16 @@ class App extends Component { logo

The GraphQL Guide

- +
} /> - } - /> - } /> + +
) } } -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/components/Reviews.js b/src/components/Reviews.js index 5878ff3..5791817 100644 --- a/src/components/Reviews.js +++ b/src/components/Reviews.js @@ -10,6 +10,7 @@ import { FormControl } from 'material-ui/Form' import Select from 'material-ui/Select' import ReviewList from './ReviewList' +import { withUser } from '../lib/withUser' import ReviewForm from './ReviewForm' class Reviews extends Component { @@ -96,4 +97,4 @@ Reviews.propTypes = { }) } -export default Reviews +export default withUser(Reviews) diff --git a/src/index.js b/src/index.js index 6b48562..5e89560 100644 --- a/src/index.js +++ b/src/index.js @@ -1,66 +1,13 @@ 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 { MuiThemeProvider, createMuiTheme } from 'material-ui/styles' import './index.css' import registerServiceWorker from './registerServiceWorker' import App from './components/App' -import { errorLink } from './lib/errorLink' - -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 networkLink = split( - ({ query }) => { - const { kind, operation } = getMainDefinition(query) - return kind === 'OperationDefinition' && operation === 'subscription' - }, - wsLink, - authedHttpLink -) - -const link = errorLink.concat(networkLink) - -const cache = new InMemoryCache() - -const client = new ApolloClient({ link, cache }) +import { apollo } from './lib/apollo' const GRAPHQL_PINK = '#e10098' @@ -70,7 +17,7 @@ const theme = createMuiTheme({ ReactDOM.render( - + diff --git a/src/lib/apollo.js b/src/lib/apollo.js new file mode 100644 index 0000000..5ed57e3 --- /dev/null +++ b/src/lib/apollo.js @@ -0,0 +1,55 @@ +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' + +import { errorLink } from './errorLink' + +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 networkLink = split( + ({ query }) => { + const { kind, operation } = getMainDefinition(query) + return kind === 'OperationDefinition' && operation === 'subscription' + }, + wsLink, + authedHttpLink +) + +const link = errorLink.concat(networkLink) + +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/withUser.js b/src/lib/withUser.js new file mode 100644 index 0000000..0bf5587 --- /dev/null +++ b/src/lib/withUser.js @@ -0,0 +1,25 @@ +import { graphql } from 'react-apollo' +import gql from 'graphql-tag' + +export const USER_QUERY = gql` + query UserQuery { + currentUser { + firstName + name + username + email + photo + hasPurchased + favoriteReviews { + id + } + } + } +` + +export const withUser = graphql(USER_QUERY, { + props: ({ data: { currentUser, loading } }) => ({ + user: currentUser, + loggingIn: loading + }) +})