Skip to content
This repository was archived by the owner on Oct 9, 2024. It is now read-only.

Commit 4c9c42e

Browse files
Adding Auth0 integration
- Added NavBar and Profile components - Added Private route and react-auth0-spa.js - Updated GraphQLData and configuration template
1 parent 948e9a8 commit 4c9c42e

File tree

14 files changed

+362
-8
lines changed

14 files changed

+362
-8
lines changed

todo-app-react/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"private": true,
55
"dependencies": {
66
"@apollo/react-hooks": "^3.1.5",
7+
"@auth0/auth0-spa-js": "^1.8.1",
78
"@testing-library/jest-dom": "^4.2.4",
89
"@testing-library/react": "^9.3.2",
910
"@testing-library/user-event": "^7.1.2",

todo-app-react/src/App.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.navheader {
2+
margin: auto 0px;
3+
padding: 15px;
4+
background: #f5f5f5;
5+
}

todo-app-react/src/App.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ import ApolloClient from "apollo-client";
55
import { InMemoryCache } from "apollo-cache-inmemory";
66
import { ApolloProvider } from "@apollo/react-hooks";
77
import { createHttpLink } from "apollo-link-http";
8+
import { useAuth0 } from "./react-auth0-spa";
89

9-
import TodoApp from "./TodoApp";
10+
import TodoApp from './TodoApp';
11+
import NavBar from "./NavBar";
12+
import Profile from "./Profile";
13+
import history from "./history";
14+
import PrivateRoute from "./PrivateRoute";
1015
import config from "./config.json";
1116
import './App.css';
1217

@@ -25,12 +30,24 @@ const createApolloClient = () => {
2530
}
2631

2732
const App = () => {
33+
const { loading } = useAuth0();
34+
if (loading) {
35+
return <div>Loading...</div>;
36+
}
2837
const client = createApolloClient();
2938
return (
3039
<ApolloProvider client={client}>
3140
<div>
32-
<h1>todos</h1>
33-
<TodoApp />
41+
<Router history={history}>
42+
<h1>todos</h1>
43+
<header className="navheader">
44+
<NavBar />
45+
</header>
46+
<Switch>
47+
<PrivateRoute path="/" component={TodoApp} exact />
48+
<PrivateRoute path="/profile" component={Profile} />
49+
</Switch>
50+
</Router>
3451
</div>
3552
</ApolloProvider>
3653
);

todo-app-react/src/GraphQLData.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
import gql from "graphql-tag";
22

3+
export const GET_USER = gql`
4+
query getUser($username: String!){
5+
getUser(username: $username) {
6+
username
7+
name
8+
tasks {
9+
id
10+
title
11+
completed
12+
}
13+
}
14+
}
15+
`;
16+
17+
export const ADD_USER = gql`
18+
mutation addUser($user: AddUserInput!) {
19+
addUser(input: [$user]) {
20+
user {
21+
username
22+
}
23+
}
24+
}
25+
`;
26+
327
export const GET_TODOS = gql`
428
query {
529
queryTask {

todo-app-react/src/NavBar.css

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
.navbar ul {
2+
list-style-type: none;
3+
margin: 0;
4+
padding: 0;
5+
height: 47px;
6+
}
7+
.navbar li {
8+
display: inline;
9+
float: left;
10+
}
11+
.navbar li:first-child {
12+
margin-right: 10px;
13+
}
14+
.navbar li a {
15+
display: block;
16+
color: white;
17+
background-color: #b83f45;
18+
text-align: center;
19+
padding: 14px 16px;
20+
font-size: large;
21+
font-weight: bold;
22+
text-decoration: none;
23+
}
24+
/* Change the link color to #111 (black) on hover */
25+
.navbar li a:hover {
26+
background-color: silver;
27+
color: white;
28+
}

todo-app-react/src/NavBar.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from "react";
2+
import { useAuth0 } from "./react-auth0-spa";
3+
import { Link } from "react-router-dom";
4+
5+
import './NavBar.css';
6+
7+
const NavBar = () => {
8+
const { loading, isAuthenticated, logout } = useAuth0();
9+
10+
if (loading) {
11+
return <div>Loading...</div>
12+
}
13+
14+
return (
15+
<div className="navbar">
16+
<ul>
17+
{isAuthenticated && (
18+
<span>
19+
<li>
20+
<Link to="/">Home</Link>
21+
</li>
22+
<li>
23+
<Link to="/profile">Profile</Link>
24+
</li>
25+
<li style={{ float: "right"}}>
26+
<Link onClick={() => logout()}>
27+
Log out
28+
</Link>
29+
</li>
30+
</span>
31+
)}
32+
</ul>
33+
</div>
34+
);
35+
};
36+
37+
export default NavBar;

todo-app-react/src/PrivateRoute.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { useEffect } from "react";
2+
import { Route } from "react-router-dom";
3+
import { useAuth0 } from "./react-auth0-spa";
4+
5+
const PrivateRoute = ({ component: Component, path, ...rest }) => {
6+
const { loading, isAuthenticated, loginWithRedirect } = useAuth0();
7+
8+
useEffect(() => {
9+
if (loading || isAuthenticated) {
10+
return;
11+
}
12+
const fn = async () => {
13+
await loginWithRedirect({
14+
appState: {targetUrl: window.location.pathname}
15+
});
16+
};
17+
fn();
18+
}, [loading, isAuthenticated, loginWithRedirect, path]);
19+
20+
const render = props =>
21+
isAuthenticated === true ? <Component {...props} /> : null;
22+
23+
return <Route path={path} render={render} {...rest} />;
24+
};
25+
26+
export default PrivateRoute;

todo-app-react/src/Profile.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.profile {
2+
padding: 15px;
3+
}
4+
.profile-img {
5+
display: block;
6+
margin: 0 auto;
7+
border-radius: 50%;
8+
}

todo-app-react/src/Profile.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { useAuth0 } from "./react-auth0-spa";
3+
import './Profile.css';
4+
5+
const Profile = () => {
6+
const { loading, user } = useAuth0();
7+
8+
if (loading || !user) {
9+
return <div>Loading...</div>;
10+
}
11+
12+
return (
13+
<div className="profile">
14+
<img className="profile-img" src={user.picture} alt="Profile" />
15+
<p>Name: <strong>{user.nickname}</strong></p>
16+
<p>Email: <strong>{user.email}</strong></p>
17+
</div>
18+
);
19+
};
20+
21+
export default Profile;

todo-app-react/src/TodoApp.js

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,54 @@ import defs from './defs'
55
import history from './history';
66
import TodoFooter from './TodoFooter'
77
import TodoItem from './TodoItem'
8-
import { GET_TODOS, ADD_TODO, DELETE_TODO, TOGGLE_TODO, UPDATE_TODO, CLEAR_COMPLETED_TODO, TOGGLE_ALL_TODO } from "./GraphQLData";
8+
import { GET_USER, GET_TODOS, ADD_USER, ADD_TODO, DELETE_TODO, TOGGLE_TODO, UPDATE_TODO, CLEAR_COMPLETED_TODO, TOGGLE_ALL_TODO } from "./GraphQLData";
9+
import { useAuth0 } from "./react-auth0-spa";
910

1011
const ENTER_KEY = 13
1112

13+
const useImperativeQuery = (query) => {
14+
const { refetch } = useQuery(query, { skip: true });
15+
const imperativelyCallQuery = (variables) => {
16+
return refetch(variables);
17+
};
18+
return imperativelyCallQuery;
19+
};
1220
const TodoApp = () => {
1321
const [nowShowing, setNowShowing] = useState(defs.ALL_TODOS);
1422
const [getEditing, setEditing] = useState(null);
1523
const [newTodo, setNewTodo] = useState("");
1624
const [shownTodos, setShownTodos] = useState([]);
1725

26+
const [addUser] = useMutation(ADD_USER);
1827
const [addTodo] = useMutation(ADD_TODO);
1928
const [toggleTodo] = useMutation(TOGGLE_TODO);
2029
const [toggleAllTodo] = useMutation(TOGGLE_ALL_TODO);
2130
const [deleteTodo] = useMutation(DELETE_TODO);
2231
const [updateTodo] = useMutation(UPDATE_TODO);
2332
const [clearCompletedTodo] = useMutation(CLEAR_COMPLETED_TODO);
33+
const getUsers = useImperativeQuery(GET_USER)
34+
35+
const { user } = useAuth0();
36+
37+
const createUser = () => {
38+
if (user === undefined) {
39+
return null;
40+
}
41+
const { data: getUser } = getUsers({
42+
username: user.email
43+
});
44+
if (getUser && getUser.getUser === null) {
45+
const newUser = {
46+
username: user.email,
47+
name: user.nickname,
48+
};
49+
addUser({
50+
variables: {
51+
user: newUser
52+
}
53+
})
54+
}
55+
}
2456

2557
const { loading, error, data } = useQuery(GET_TODOS);
2658
const getData = () => {
@@ -54,8 +86,9 @@ const TodoApp = () => {
5486
history.listen((location, action) =>
5587
processLocationHash(location.hash)
5688
)
89+
createUser()
5790
getData()
58-
}, [data]) // eslint-disable-line react-hooks/exhaustive-deps
91+
}, [user, data]) // eslint-disable-line react-hooks/exhaustive-deps
5992

6093
const handleChange = event => {
6194
setNewTodo(event.target.value)
@@ -76,7 +109,7 @@ const TodoApp = () => {
76109
const add = (title) =>
77110
addTodo({
78111
variables: { task: [
79-
{ title: title, completed: false, user: { username: "email@example.com" } }
112+
{ title: title, completed: false, user: { username: user.email } }
80113
]},
81114
refetchQueries: [{
82115
query: GET_TODOS

0 commit comments

Comments
 (0)