Skip to content

Commit 9f006af

Browse files
authored
Merge pull request #30 from howtographql/bookmark-upvote-tutorials
Bookmark upvote tutorials
2 parents 5f839ac + fccc484 commit 9f006af

File tree

13 files changed

+939
-798
lines changed

13 files changed

+939
-798
lines changed

oss

Submodule oss updated 58 files
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import * as React from 'react';
2+
import gql from 'graphql-tag';
3+
import { Mutation } from 'react-apollo';
4+
import { loginUser } from '../utils/auth';
5+
import { BookmarkButton } from './buttons';
6+
import { handleMutationResponse, ApiErrors } from '../utils/errorHandling';
7+
8+
const BookmarkMutation = ({ tutorial }) => (
9+
<Mutation
10+
mutation={gql`
11+
mutation BookmarkTutorial($id: ID!) {
12+
bookmarkTutorial(tutorialId: $id) {
13+
code
14+
success
15+
userTutorial {
16+
id
17+
bookmarked
18+
}
19+
}
20+
}
21+
`}
22+
variables={{
23+
id: tutorial.id,
24+
}}
25+
>
26+
{bookmark => {
27+
let bookmarked = tutorial.viewerUserTutorial.bookmarked;
28+
return (
29+
<BookmarkButton
30+
active={bookmarked}
31+
onClick={async () => {
32+
const mutationRes = await handleMutationResponse(bookmark());
33+
if (mutationRes.error) {
34+
if (mutationRes.error === ApiErrors.AUTHORIZATION) {
35+
loginUser();
36+
} else {
37+
console.log(mutationRes.error);
38+
}
39+
}
40+
}}
41+
/>
42+
);
43+
}}
44+
</Mutation>
45+
);
46+
47+
export default BookmarkMutation;

packages/gatsby-theme/src/components/TutorialListing.tsx

Lines changed: 17 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import * as React from 'react';
2-
import { Heading, Text, Card, Flex, Box, Button } from './shared/base';
2+
import { Heading, Text, Card, Flex, Box } from './shared/base';
33
import { getTutorialOverviewSlug } from '../utils/getTutorialSlug';
4-
import Upvote from './Upvote';
54
import { Link } from 'gatsby';
6-
import { Query, Mutation } from 'react-apollo';
5+
import { Query } from 'react-apollo';
76
import gql from 'graphql-tag';
8-
import { optionalChaining } from '../utils/helpers';
9-
import { loginUser } from '../utils/auth';
10-
import { handleMutationResponse, ApiErrors } from '../utils/errorHandling';
7+
import UpvoteMutation from './UpvoteMutation';
8+
import BookmarkMutation from './BookmarkMutation';
119

1210
type TutorialListingProps = {
1311
tutorial: Tutorial;
@@ -20,20 +18,22 @@ type Tutorial = {
2018
};
2119

2220
type FrontMatter = {
21+
id: string;
2322
tutorialTitle: string;
2423
description: string;
2524
};
2625

2726
const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
2827
tutorial,
2928
}) => {
30-
const tutorialId = 'cjwi9iv2klfsb0b14sqc9wpuj';
29+
const gatsbyID = tutorial.frontmatter.id;
3130
return (
3231
<Query
3332
query={gql`
34-
query TutorialListing($id: ID!) {
35-
tutorial(id: $id) {
33+
query getTutorialbyGatsbyID($gatsbyID: String!) {
34+
getTutorialbyGatsbyID(gatsbyID: $gatsbyID) {
3635
id
36+
name
3737
upvotes
3838
numberOfStudents
3939
viewerUserTutorial {
@@ -44,96 +44,21 @@ const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
4444
}
4545
}
4646
`}
47-
variables={{ id: tutorialId }}
47+
variables={{ gatsbyID: gatsbyID }}
4848
>
4949
{({ data }) => {
5050
return (
5151
<Card width={[1]} p={4} my={4} borderRadius={8} boxShadow="small">
5252
<Flex alignItems="center" justifyContent="center">
5353
<Box width={1 / 12}>
54-
<Mutation
55-
mutation={gql`
56-
mutation UpvoteTutorial($id: ID!) {
57-
upvoteTutorial(tutorialId: $id) {
58-
code
59-
success
60-
userTutorial {
61-
id
62-
upvoted
63-
tutorial {
64-
id
65-
upvotes
66-
}
67-
}
68-
}
69-
}
70-
`}
71-
variables={{
72-
id: tutorialId,
73-
}}
74-
>
75-
{upvote => {
76-
return (
77-
<Upvote
78-
onClick={async () => {
79-
const mutationRes = await handleMutationResponse(
80-
upvote(),
81-
);
82-
if (mutationRes.error) {
83-
if (mutationRes.error === ApiErrors.AUTHORIZATION) {
84-
loginUser();
85-
} else {
86-
console.log(mutationRes.error);
87-
}
88-
}
89-
}}
90-
active={optionalChaining(
91-
() => data.tutorial.viewerUserTutorial.upvoted,
92-
)}
93-
count={optionalChaining(() => data.tutorial.upvotes)}
94-
/>
95-
);
96-
}}
97-
</Mutation>
98-
<Mutation
99-
mutation={gql`
100-
mutation BookmarkTutorial($id: ID!) {
101-
bookmarkTutorial(tutorialId: $id) {
102-
code
103-
success
104-
userTutorial {
105-
id
106-
bookmarked
107-
}
108-
}
109-
}
110-
`}
111-
variables={{
112-
id: tutorialId,
113-
}}
114-
>
115-
{bookmark => {
116-
return (
117-
<Button
118-
onClick={async () => {
119-
const mutationRes = await handleMutationResponse(
120-
bookmark(),
121-
);
122-
if (mutationRes.error) {
123-
if (mutationRes.error === ApiErrors.AUTHORIZATION) {
124-
loginUser();
125-
} else {
126-
console.log(mutationRes.error);
127-
}
128-
}
129-
}}
130-
>
131-
Bookmark
132-
</Button>
133-
);
134-
}}
135-
</Mutation>
54+
{data.getTutorialbyGatsbyID && (
55+
<UpvoteMutation tutorial={data.getTutorialbyGatsbyID} />
56+
)}
57+
{data.getTutorialbyGatsbyID && (
58+
<BookmarkMutation tutorial={data.getTutorialbyGatsbyID} />
59+
)}
13660
</Box>
61+
13762
<Box width={11 / 12}>
13863
<Link to={getTutorialOverviewSlug(tutorial.fileAbsolutePath)}>
13964
<Heading>{tutorial.frontmatter.tutorialTitle}</Heading>

packages/gatsby-theme/src/components/Upvote.tsx

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import * as React from 'react';
2+
import gql from 'graphql-tag';
3+
import { Mutation } from 'react-apollo';
4+
import { loginUser } from '../utils/auth';
5+
import { handleMutationResponse, ApiErrors } from '../utils/errorHandling';
6+
import { VoteButton } from './buttons';
7+
import { Heading, Flex } from './shared/base';
8+
9+
const UpvoteMutation = ({ tutorial }) => (
10+
<Mutation
11+
mutation={gql`
12+
mutation UpvoteTutorial($id: ID!) {
13+
upvoteTutorial(tutorialId: $id) {
14+
code
15+
success
16+
userTutorial {
17+
id
18+
upvoted
19+
tutorial {
20+
id
21+
upvotes
22+
}
23+
}
24+
}
25+
}
26+
`}
27+
variables={{
28+
id: tutorial.id,
29+
}}
30+
>
31+
{upvote => {
32+
let active = tutorial.viewerUserTutorial.upvoted;
33+
let upvotes = tutorial.upvotes;
34+
return (
35+
<Flex
36+
flexDirection="column"
37+
alignItems="center"
38+
justifyContent="center"
39+
>
40+
<VoteButton
41+
onClick={async () => {
42+
const mutationRes = await handleMutationResponse(upvote());
43+
if (mutationRes.error) {
44+
if (mutationRes.error === ApiErrors.AUTHORIZATION) {
45+
loginUser();
46+
} else {
47+
console.log(mutationRes.error);
48+
}
49+
}
50+
}}
51+
active={active}
52+
/>
53+
<Heading>{upvotes}</Heading>
54+
</Flex>
55+
);
56+
}}
57+
</Mutation>
58+
);
59+
60+
export default UpvoteMutation;

packages/gatsby-theme/src/components/buttons.tsx

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,27 @@ import React from 'react';
22
import { ButtonProps } from './shared/base';
33
import { Flex, Image, Button } from './shared/base';
44

5-
export const VoteButton: React.FunctionComponent<ButtonProps> = props => (
6-
<CustomButton {...props} type="vote" />
7-
);
5+
export const VoteButton: React.FunctionComponent<
6+
ButtonProps & {
7+
active?: Boolean;
8+
}
9+
> = props =>
10+
props.active ? (
11+
<CustomButton {...props} type="voteActive" />
12+
) : (
13+
<CustomButton {...props} type="vote" />
14+
);
15+
16+
export const BookmarkButton: React.FunctionComponent<
17+
ButtonProps & {
18+
active?: Boolean;
19+
}
20+
> = props =>
21+
props.active ? (
22+
<CustomButton {...props} type="bookmarkActive" />
23+
) : (
24+
<CustomButton {...props} type="bookmark" />
25+
);
826

927
export const GithubButton: React.FunctionComponent<ButtonProps> = props => (
1028
<CustomButton {...props} type="github" />
@@ -20,7 +38,15 @@ export const SpectrumButton: React.FunctionComponent<ButtonProps> = props => (
2038

2139
export const CustomButton: React.FunctionComponent<
2240
ButtonProps & {
23-
type?: 'github' | 'tutorial' | 'spectrum' | 'vote' | 'default';
41+
type?:
42+
| 'github'
43+
| 'tutorial'
44+
| 'spectrum'
45+
| 'vote'
46+
| 'voteActive'
47+
| 'bookmark'
48+
| 'bookmarkActive'
49+
| 'default';
2450
}
2551
> = ({ type = 'default', children, ...buttonProps }) => {
2652
const { icon, bg } = customButtonTypes[type];
@@ -49,6 +75,9 @@ interface CustomButtonType {
4975
github: ButtonType;
5076
spectrum: ButtonType;
5177
vote: ButtonType;
78+
voteActive: ButtonType;
79+
bookmark: ButtonType;
80+
bookmarkActive: ButtonType;
5281
default: ButtonType;
5382
}
5483

@@ -69,6 +98,20 @@ const customButtonTypes: CustomButtonType = {
6998
icon: 'https://i.ibb.co/b3FGXbD/Vote.png',
7099
bg: 'white',
71100
},
101+
voteActive: {
102+
icon: 'https://i.ibb.co/b3FGXbD/Vote.png',
103+
bg: 'blue',
104+
},
105+
bookmark: {
106+
icon:
107+
'http://endlessicons.com/wp-content/uploads/2014/03/bookmark-icon-1-614x460.png',
108+
bg: 'white',
109+
},
110+
bookmarkActive: {
111+
icon:
112+
'http://endlessicons.com/wp-content/uploads/2014/03/bookmark-icon-1-614x460.png',
113+
bg: 'blue',
114+
},
72115
default: {
73116
icon: '',
74117
bg: 'primary',

packages/gatsby-theme/src/pages/community.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export const query = graphql`
3636
id
3737
fileAbsolutePath
3838
frontmatter {
39+
id
3940
tutorialTitle
4041
description
4142
}

packages/gatsby-theme/src/utils/errorHandling.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export async function handleMutationResponse(
1515
};
1616
}
1717
return {
18-
error: ApiErrors.INVALID,
18+
err: ApiErrors.INVALID,
1919
};
2020
}
2121
}

0 commit comments

Comments
 (0)