Commit 63d0cc84 by qiuzhi99

18_setContext

1 parent 723d4202
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
"@apollo/react-hooks": "^3.1.3", "@apollo/react-hooks": "^3.1.3",
"apollo-boost": "^0.4.4", "apollo-boost": "^0.4.4",
"apollo-cache-inmemory": "^1.6.3", "apollo-cache-inmemory": "^1.6.3",
"apollo-link-context": "^1.0.19",
"apollo-link-http": "^1.5.16", "apollo-link-http": "^1.5.16",
"graphql": "^14.5.8", "graphql": "^14.5.8",
"graphql-tag": "^2.10.1", "graphql-tag": "^2.10.1",
"jwt-decode": "^2.2.0",
"moment": "^2.24.0", "moment": "^2.24.0",
"react": "^16.10.2", "react": "^16.10.2",
"react-dom": "^16.10.2", "react-dom": "^16.10.2",
......
...@@ -4,11 +4,21 @@ import ApolloClient from "apollo-client"; ...@@ -4,11 +4,21 @@ import ApolloClient from "apollo-client";
import { ApolloProvider } from "@apollo/react-hooks"; import { ApolloProvider } from "@apollo/react-hooks";
import { createHttpLink } from "apollo-link-http"; import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory"; import { InMemoryCache } from "apollo-cache-inmemory";
import { setContext } from "apollo-link-context";
const httpLink = createHttpLink({ uri: "http://localhost:5001" }); const httpLink = createHttpLink({ uri: "http://localhost:5001" });
const authLink = setContext(() => {
const token = localStorage.getItem("jwtToken");
return {
headers: {
Authorization: token ? `Bearer ${token}` : ""
}
};
});
const client = new ApolloClient({ const client = new ApolloClient({
link: httpLink, link: authLink.concat(httpLink),
cache: new InMemoryCache() cache: new InMemoryCache()
}); });
......
...@@ -11,6 +11,7 @@ import MenuBar from "./components/MenuBar"; ...@@ -11,6 +11,7 @@ import MenuBar from "./components/MenuBar";
import "./App.css"; import "./App.css";
import { AuthProvider } from "./context/auth"; import { AuthProvider } from "./context/auth";
import AuthRoute from "./utils/AuthRoute";
function App() { function App() {
return ( return (
...@@ -19,8 +20,8 @@ function App() { ...@@ -19,8 +20,8 @@ function App() {
<Container> <Container>
<MenuBar /> <MenuBar />
<Route exact path="/" component={Home} /> <Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} /> <AuthRoute exact path="/login" component={Login} />
<Route exact path="/register" component={Register} /> <AuthRoute exact path="/register" component={Register} />
</Container> </Container>
</Router> </Router>
</AuthProvider> </AuthProvider>
......
import React, { useState } from "react"; import React, { useState, useContext } from "react";
import { Menu } from "semantic-ui-react"; import { Menu } from "semantic-ui-react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { AuthContext } from "../context/auth";
const MenuBar = () => { const MenuBar = () => {
const { user, logout } = useContext(AuthContext);
const pathname = window.location.pathname; const pathname = window.location.pathname;
const path = pathname === "/" ? "home" : pathname.substr(1); const path = pathname === "/" ? "home" : pathname.substr(1);
const [activeItem, setActiveItem] = useState(path); const [activeItem, setActiveItem] = useState(path);
const handleItemClick = (e, { name }) => setActiveItem(name); const handleItemClick = (e, { name }) => setActiveItem(name);
return ( const menuBar = user ? (
<div> <Menu size="massive" color="teal" pointing secondary>
<Menu size="massive" color="teal" pointing secondary> <Menu.Item name={user.username} active as={Link} to="/" />
<Menu.Menu position="right">
<Menu.Item name="logout" onClick={logout} />
</Menu.Menu>
</Menu>
) : (
<Menu size="massive" color="teal" pointing secondary>
<Menu.Item
name="home"
active={activeItem === "home"}
onClick={handleItemClick}
as={Link}
to="/"
/>
<Menu.Menu position="right">
<Menu.Item <Menu.Item
name="home" name="login"
active={activeItem === "home"} active={activeItem === "login"}
onClick={handleItemClick} onClick={handleItemClick}
as={Link} as={Link}
to="/" to="/login"
/> />
<Menu.Menu position="right"> <Menu.Item
<Menu.Item name="register"
name="login" active={activeItem === "register"}
active={activeItem === "login"} onClick={handleItemClick}
onClick={handleItemClick} as={Link}
as={Link} to="/register"
to="/login" />
/> </Menu.Menu>
<Menu.Item </Menu>
name="register"
active={activeItem === "register"}
onClick={handleItemClick}
as={Link}
to="/register"
/>
</Menu.Menu>
</Menu>
</div>
); );
return menuBar;
}; };
export default MenuBar; export default MenuBar;
import React from "react";
import { Form, Button } from "semantic-ui-react";
import { useForm } from "../utils/hook";
import { useMutation } from "@apollo/react-hooks";
import gql from "graphql-tag";
function PostForm() {
const { onChange, onSubmit, values } = useForm(createPostCallback, {
body: ""
});
const [createPost, { error }] = useMutation(CREATE_POST_MUTATION, {
update(_, result) {
values.body = "";
},
variables: values
});
console.dir(error);
function createPostCallback() {
createPost();
}
return (
<>
<Form onSubmit={onSubmit}>
<h2>Create a post:</h2>
<Form.Field>
<Form.Input
placeholder="Hi World!"
value={values.body}
name="body"
error={error ? true : false}
onChange={onChange}
/>
<Button type="submit" color="teal">
Submit
</Button>
</Form.Field>
</Form>
{error && (
<div className="ui error message" style={{ marginBottom: 20 }}>
<ul className="list">{error.graphQLErrors[0].message}</ul>
</div>
)}
</>
);
}
const CREATE_POST_MUTATION = gql`
mutation createPost($body: String!) {
createPost(body: $body) {
id
body
createdAt
username
likes {
id
username
createdAt
}
likeCount
comments {
id
body
username
createdAt
}
commentCount
}
}
`;
export default PostForm;
import React, { createContext, useReducer } from "react"; import React, { createContext, useReducer } from "react";
import jwtDecode from "jwt-decode";
const initialState = {
user: null
};
if (localStorage.getItem("jwtToken")) {
const decodedToken = jwtDecode(localStorage.getItem("jwtToken"));
if (decodedToken.exp * 1000 < Date.now()) {
localStorage.removeItem("jwtToken");
} else {
initialState.user = decodedToken;
}
}
const AuthContext = createContext({ const AuthContext = createContext({
user: null, user: null,
...@@ -25,9 +40,10 @@ function authReducer(state, action) { ...@@ -25,9 +40,10 @@ function authReducer(state, action) {
} }
function AuthProvider(props) { function AuthProvider(props) {
const [state, dispatch] = useReducer(authReducer, { user: null }); const [state, dispatch] = useReducer(authReducer, initialState);
function login(userData) { function login(userData) {
localStorage.setItem("jwtToken", userData.token);
dispatch({ dispatch({
type: "LOGIN", type: "LOGIN",
payload: userData payload: userData
...@@ -35,6 +51,7 @@ function AuthProvider(props) { ...@@ -35,6 +51,7 @@ function AuthProvider(props) {
} }
function logout() { function logout() {
localStorage.removeItem("jwtToken");
dispatch({ dispatch({
type: "LOGOUT" type: "LOGOUT"
}); });
......
import React from "react"; import React, { useContext } from "react";
import gql from "graphql-tag"; import gql from "graphql-tag";
import { useQuery } from "@apollo/react-hooks"; import { useQuery } from "@apollo/react-hooks";
import { Grid } from "semantic-ui-react"; import { Grid } from "semantic-ui-react";
import PostCard from "../components/PostCard"; import PostCard from "../components/PostCard";
import { AuthContext } from "../context/auth";
import PostForm from "../components/PostForm";
const FETCH_POSTS_QUERY = gql` const FETCH_POSTS_QUERY = gql`
{ {
...@@ -27,6 +29,7 @@ const FETCH_POSTS_QUERY = gql` ...@@ -27,6 +29,7 @@ const FETCH_POSTS_QUERY = gql`
`; `;
const Home = () => { const Home = () => {
const { user } = useContext(AuthContext);
const { loading, data } = useQuery(FETCH_POSTS_QUERY); const { loading, data } = useQuery(FETCH_POSTS_QUERY);
return ( return (
...@@ -35,6 +38,11 @@ const Home = () => { ...@@ -35,6 +38,11 @@ const Home = () => {
<h1>Recent Posts</h1> <h1>Recent Posts</h1>
</Grid.Row> </Grid.Row>
<Grid.Row> <Grid.Row>
{user && (
<Grid.Column>
<PostForm />
</Grid.Column>
)}
{loading ? ( {loading ? (
<h1>Loading posts...</h1> <h1>Loading posts...</h1>
) : ( ) : (
......
...@@ -21,6 +21,7 @@ const Login = props => { ...@@ -21,6 +21,7 @@ const Login = props => {
data: { login: userData } data: { login: userData }
} }
) { ) {
console.log(userData);
context.login(userData); context.login(userData);
props.history.push("/"); props.history.push("/");
}, },
......
import React, { useContext } from "react";
import { AuthContext } from "../context/auth";
import { Route, Redirect } from "react-router-dom";
function AuthRoute({ component: Compoment, ...rest }) {
const { user } = useContext(AuthContext);
return (
<Route
{...rest}
render={props => (user ? <Redirect to="/" /> : <Compoment {...props} />)}
/>
);
}
export default AuthRoute;
...@@ -1758,6 +1758,14 @@ apollo-client@^2.6.4: ...@@ -1758,6 +1758,14 @@ apollo-client@^2.6.4:
tslib "^1.9.3" tslib "^1.9.3"
zen-observable "^0.8.0" zen-observable "^0.8.0"
apollo-link-context@^1.0.19:
version "1.0.19"
resolved "https://registry.npm.taobao.org/apollo-link-context/download/apollo-link-context-1.0.19.tgz#3c9ba5bf75ed5428567ce057b8837ef874a58987"
integrity sha1-PJulv3XtVChWfOBXuIN++HSliYc=
dependencies:
apollo-link "^1.2.13"
tslib "^1.9.3"
apollo-link-error@^1.0.3: apollo-link-error@^1.0.3:
version "1.1.12" version "1.1.12"
resolved "https://registry.npm.taobao.org/apollo-link-error/download/apollo-link-error-1.1.12.tgz#e24487bb3c30af0654047611cda87038afbacbf9" resolved "https://registry.npm.taobao.org/apollo-link-error/download/apollo-link-error-1.1.12.tgz#e24487bb3c30af0654047611cda87038afbacbf9"
...@@ -6011,6 +6019,11 @@ jsx-ast-utils@^2.1.0, jsx-ast-utils@^2.2.1: ...@@ -6011,6 +6019,11 @@ jsx-ast-utils@^2.1.0, jsx-ast-utils@^2.2.1:
array-includes "^3.0.3" array-includes "^3.0.3"
object.assign "^4.1.0" object.assign "^4.1.0"
jwt-decode@^2.2.0:
version "2.2.0"
resolved "https://registry.npm.taobao.org/jwt-decode/download/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79"
integrity sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=
keyboard-key@^1.0.4: keyboard-key@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.npm.taobao.org/keyboard-key/download/keyboard-key-1.0.4.tgz#52d8fa07b7e17757072aa22a67fb4ae85e4c46b0" resolved "https://registry.npm.taobao.org/keyboard-key/download/keyboard-key-1.0.4.tgz#52d8fa07b7e17757072aa22a67fb4ae85e4c46b0"
......
...@@ -30,6 +30,10 @@ module.exports = { ...@@ -30,6 +30,10 @@ module.exports = {
async createPost(_, { body }, context) { async createPost(_, { body }, context) {
const user = checkAuth(context); const user = checkAuth(context);
if (body.trim() === "") {
throw new Error("Post body must not be empty");
}
const newPost = new Post({ const newPost = new Post({
body, body,
username: user.username, username: user.username,
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!