Skip to content

Commit bbdc43a

Browse files
committed
Attempt to sync up code with tutorial
1 parent f7e837a commit bbdc43a

File tree

13 files changed

+153
-148
lines changed

13 files changed

+153
-148
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_size = 2
6+
end_of_line = lf
7+
indent_style = space
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"private": true,
55
"dependencies": {
66
"@urql/exchange-graphcache": "^1.0.0-beta.3",
7-
"@urql/exchange-suspense": "^0.1.0",
87
"graphql": "14.5.3",
98
"graphql-tag": "^2.10.1",
109
"react": "16.9.0",

src/components/App.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
import React from 'react';
22
import { Switch, Route, Redirect } from 'react-router-dom';
3+
34
import LinkList from './LinkList';
45
import CreateLink from './CreateLink';
56
import Header from './Header';
67
import Login from './Login';
78
import Search from './Search';
89

9-
const Fetching = () => <p>Fetcing</p>;
1010
const App = () => (
1111
<div className="center w85">
1212
<Header />
1313
<div className="ph3 pv1 background-gray">
14-
<React.Suspense fallback={<Fetching />}>
15-
<Switch>
16-
<Route exact path="/" render={() => <Redirect to="/new/1" />} />
17-
<Route exact path="/create" component={CreateLink} />
18-
<Route exact path="/login" component={Login} />
19-
<Route exact path="/search" component={Search} />
20-
<Route exact path="/top" component={LinkList} />
21-
<Route exact path="/new/:page" component={LinkList} />
22-
</Switch>
23-
</React.Suspense>
14+
<Switch>
15+
<Route exact path="/" render={() => <Redirect to="/new/1" />} />
16+
<Route exact path="/top" component={LinkList} />
17+
<Route exact path="/new/:page" component={LinkList} />
18+
<Route exact path="/create" component={CreateLink} />
19+
<Route exact path="/login" component={Login} />
20+
<Route exact path="/search" component={Search} />
21+
</Switch>
2422
</div>
2523
</div>
2624
);

src/components/CreateLink.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@ const POST_MUTATION = gql`
1111
description
1212
}
1313
}
14-
`
14+
`;
1515

16-
const CreateLink = ({ history }) => {
16+
const CreateLink = props => {
1717
const [description, setDescription] = React.useState('');
1818
const [url, setUrl] = React.useState('');
19-
const [{ fetching }, executeMutation] = useMutation(POST_MUTATION);
19+
20+
const [state, executeMutation] = useMutation(POST_MUTATION);
2021

2122
const postMutation = React.useCallback(() => {
2223
executeMutation({ url, description }).then(() => {
23-
history.push('/new/1');
24+
props.history.push('/new/1');
2425
});
25-
}, [url, description, executeMutation, history]);
26+
}, [executeMutation, url, description, executeMutation, props.history]);
2627

2728
return (
2829
<div>
@@ -42,11 +43,14 @@ const CreateLink = ({ history }) => {
4243
placeholder="The URL for the link"
4344
/>
4445
</div>
45-
<button type="button" disabled={fetching} onClick={postMutation}>
46+
<button
47+
disabled={state.fetching}
48+
onClick={postMutation}
49+
>
4650
Submit
4751
</button>
4852
</div>
4953
);
50-
}
54+
};
5155

5256
export default CreateLink;

src/components/Header.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import React from 'react';
22
import { Link } from 'react-router-dom';
33
import { withRouter } from 'react-router';
4-
import { getToken, deleteToken } from '../utils';
4+
5+
import { getToken, deleteToken } from '../token';
56

67
const Header = ({ history }) => {
7-
const authToken = getToken();
8-
const logout = React.useCallback(() => {
9-
deleteToken();
10-
history.push('/');
11-
}, [history])
8+
const isLoggedIn = !!getToken();
9+
1210
return (
1311
<div className="flex pa1 justify-between nowrap orange">
1412
<div className="flex flex-fixed black">
@@ -24,7 +22,7 @@ const Header = ({ history }) => {
2422
<Link to="/search" className="ml1 no-underline black">
2523
search
2624
</Link>
27-
{authToken && (
25+
{isLoggedIn && (
2826
<div className="flex">
2927
<div className="ml1">|</div>
3028
<Link to="/create" className="ml1 no-underline black">
@@ -34,10 +32,13 @@ const Header = ({ history }) => {
3432
)}
3533
</div>
3634
<div className="flex flex-fixed">
37-
{authToken ? (
35+
{isLoggedn ? (
3836
<div
3937
className="ml1 pointer black"
40-
onClick={logout}
38+
onClick={() => {
39+
deleteToken()
40+
props.history.push('/')
41+
}}
4142
>
4243
logout
4344
</div>
@@ -51,4 +52,4 @@ const Header = ({ history }) => {
5152
);
5253
}
5354

54-
export default withRouter(Header);
55+
export default withRouter(Header);

src/components/Link.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,43 @@
11
import React from 'react';
22
import { useMutation } from 'urql';
33
import gql from 'graphql-tag';
4-
import { timeDifferenceForDate, getToken } from '../utils';
4+
5+
import { timeDifferenceForDate } from '../dates';
6+
import { getToken } from '../token';
57

68
const VOTE_MUTATION = gql`
79
mutation VoteMutation($linkId: ID!) {
810
vote(linkId: $linkId) {
9-
id
1011
link {
12+
id
1113
votes {
1214
id
1315
user {
1416
id
1517
}
1618
}
1719
}
18-
user {
19-
id
20-
}
2120
}
2221
}
2322
`;
2423

2524
const Link = ({ link, index }) => {
26-
const authToken = getToken();
27-
const [{ fetching }, executeMutation] = useMutation(VOTE_MUTATION);
25+
const isLoggedIn = getToken();
26+
27+
const [state, executeMutation] = useMutation(VOTE_MUTATION);
2828

29-
const voteMutation = React.useCallback(() => {
30-
if (!fetching) {
29+
const upvote = React.useCallback(() => {
30+
if (!state.fetching) {
3131
executeMutation({ linkId: link.id });
3232
}
33-
}, [fetching, link, executeMutation]);
33+
}, [state.fetching, link, executeMutation]);
3434

3535
return (
3636
<div className="flex mt2 items-start">
3737
<div className="flex items-center">
3838
<span className="gray">{index + 1}.</span>
39-
{authToken && (
40-
<div className="ml1 gray f11" onClick={voteMutation} disabled={fetching}>
39+
{isLoggedIn && (
40+
<div className="ml1 gray f11" onClick={upvote}>
4141
4242
</div>
4343
)}
@@ -58,4 +58,4 @@ const Link = ({ link, index }) => {
5858
);
5959
}
6060

61-
export default Link;
61+
export default Link;

src/components/LinkList.js

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import React, { Fragment } from 'react';
1+
import React from 'react';
22
import { useQuery, useSubscription } from 'urql';
33
import gql from 'graphql-tag';
4-
import { LINKS_PER_PAGE } from '../constants';
4+
55
import Link from './Link';
66

77
export const FEED_QUERY = gql`
@@ -76,59 +76,54 @@ const NEW_VOTES_SUBSCRIPTION = gql`
7676
}
7777
`;
7878

79-
const LinkList = ({ location, match, history }) => {
80-
const isNewPage = location.pathname.includes('new');
81-
82-
const variables = React.useMemo(() => {
83-
const page = parseInt(match.params.page, 10);
79+
const LinkList = props => {
80+
const isNewPage = props.location.pathname.includes('new')
81+
const page = parseInt(props.match.params.page, 10)
8482

85-
const skip = isNewPage ? (page - 1) * LINKS_PER_PAGE : 0;
86-
const first = isNewPage ? LINKS_PER_PAGE : 100;
87-
const orderBy = isNewPage ? 'createdAt_DESC' : null;
88-
return { first, skip, orderBy };
89-
}, [match, isNewPage]);
83+
const variables = React.useMemo(() => ({
84+
skip: isNewPage ? (page - 1) * 10 : 0,
85+
first: isNewPage ? 10 : 100,
86+
orderBy: isNewPage ? 'createdAt_DESC' : null
87+
}), [isNewPage, page])
9088

91-
const [{ data, error, fetching }] = useQuery({
92-
query: FEED_QUERY,
93-
variables,
94-
});
89+
const [result] = useQuery({ query: FEED_QUERY, variables });
90+
const { data, fetching, error } = result;
9591

9692
useSubscription({ query: NEW_VOTES_SUBSCRIPTION });
9793
useSubscription({ query: NEW_LINKS_SUBSCRIPTION });
9894

9995
const linksToRender = React.useMemo(() => {
100-
if (fetching) return [];
101-
if (isNewPage) return data.feed.links;
102-
const rankedLinks = data.feed.links.slice();
103-
rankedLinks.sort((l1, l2) => l2.votes.length - l1.votes.length);
104-
return rankedLinks;
105-
}, [data, fetching, isNewPage]);
96+
if (!data) {
97+
return [];
98+
} else if (isNewPage) {
99+
return data.feed.links;
100+
} else {
101+
const rankedLinks = data.feed.links
102+
.slice()
103+
.sort((l1, l2) => l2.votes.length - l1.votes.length);
104+
return rankedLinks;
105+
}
106+
}, [data, isNewPage]);
106107

107108
const nextPage = React.useCallback(() => {
108-
const page = parseInt(match.params.page, 10);
109-
if (page <= data.feed.count / LINKS_PER_PAGE) {
110-
const nextPage = page + 1;
111-
history.push(`/new/${nextPage}`);
109+
if (page <= data.feed.count / 10) {
110+
props.history.push(`/new/${page + 1}`);
112111
}
113-
}, [data, history, match.params]);
112+
}, [props.history, data.feed.count, page]);
114113

115114
const previousPage = React.useCallback(() => {
116-
const page = parseInt(match.params.page, 10);
117115
if (page > 1) {
118-
const previousPage = page - 1;
119-
history.push(`/new/${previousPage}`);
116+
props.history.push(`/new/${page - 1}`);
120117
}
121-
}, [match, history]);
118+
}, [props.history, page]);
122119

123120
if (fetching) return <div>Fetching</div>;
124121
if (error) return <div>Error</div>;
125122

126-
const pageIndex =match.params.page
127-
? (match.params.page - 1) * LINKS_PER_PAGE
128-
: 0;
123+
const pageIndex = isNewPage ? (page - 1) * 10 : 0
129124

130125
return (
131-
<Fragment>
126+
<React.Fragment>
132127
{linksToRender.map((link, index) => (
133128
<Link
134129
key={link.id}
@@ -146,7 +141,7 @@ const LinkList = ({ location, match, history }) => {
146141
</div>
147142
</div>
148143
)}
149-
</Fragment>
144+
</React.Fragment>
150145
);
151146
}
152147

src/components/Login.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React from 'react';
22
import { useMutation } from 'urql';
33
import gql from 'graphql-tag';
4-
import { setToken } from '../utils';
4+
5+
import { setToken } from '../token';
56

67
const SIGNUP_MUTATION = gql`
78
mutation SignupMutation($email: String!, $password: String!, $name: String!) {
@@ -19,21 +20,26 @@ const LOGIN_MUTATION = gql`
1920
}
2021
`;
2122

22-
const Login = ({ history }) => {
23+
const Login = props => {
2324
const [login, setLogin] = React.useState(true);
2425
const [email, setEmail] = React.useState('');
2526
const [password, setPassword] = React.useState('');
2627
const [name, setName] = React.useState('');
2728

28-
const [{ fetching }, executeMutation] = useMutation(login ? LOGIN_MUTATION : SIGNUP_MUTATION);
29+
const [state, executeMutation] = useMutation(
30+
isLogin ? LOGIN_MUTATION : SIGNUP_MUTATION
31+
);
2932

3033
const mutate = React.useCallback(() => {
31-
executeMutation({ email, password, name }).then(({ data }) => {
32-
const { token } = login ? data.login : data.signup;
33-
setToken(token);
34-
history.push(`/`);
35-
});
36-
}, [email, password, name, executeMutation, history, login]);
34+
executeMutation({ email, password, name })
35+
.then(({ data }) => {
36+
const token = data && data[isLogin ? 'login' : 'signup'].token
37+
if (token) {
38+
setToken(token)
39+
props.history.push('/')
40+
}
41+
});
42+
}, [executeMutation, props.history, setToken, email, password, name]);
3743

3844
return (
3945
<div>

src/components/Search.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import { useQuery } from 'urql';
33
import gql from 'graphql-tag';
4+
45
import Link from './Link';
56

67
const FEED_SEARCH_QUERY = gql`
@@ -28,13 +29,19 @@ const FEED_SEARCH_QUERY = gql`
2829

2930
const Search = () => {
3031
const [filter, setFilter] = React.useState('');
31-
const [result, executeQuery] = useQuery({ query: FEED_SEARCH_QUERY, variables: { filter}, pause: true });
3232

33-
const links = result.data ? result.data.feed.links : [];
33+
const [result, executeQuery] = useQuery({
34+
query: FEED_SEARCH_QUERY,
35+
variables: { filter },
36+
pause: true,
37+
});
38+
3439
const search = React.useCallback(() => {
3540
executeQuery();
3641
}, [executeQuery]);
3742

43+
const links = result.data ? result.data.feed.links : [];
44+
3845
return (
3946
<div>
4047
<div>

src/constants.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)