Skip to content

Commit 5a7619c

Browse files
authored
Merge pull request #31 from howtographql/tutorial-progress-mutation
Tutorial progress mutation
2 parents 9f006af + 74e6dbb commit 5a7619c

File tree

10 files changed

+257
-41
lines changed

10 files changed

+257
-41
lines changed

oss

Submodule oss updated from d629d35 to a977db4
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 { Button } from './shared/base';
7+
8+
type ChapterMutationProps = {
9+
gatsbyID: any;
10+
currentChapter: any;
11+
};
12+
13+
const ChapterMutation: React.FunctionComponent<ChapterMutationProps> = ({
14+
gatsbyID,
15+
currentChapter,
16+
}) => (
17+
<Mutation
18+
mutation={gql`
19+
mutation upsertCurrentChapter($gatsbyID: String!, $chapter: Int!) {
20+
upsertCurrentChapter(gatsbyID: $gatsbyID, chapter: $chapter) {
21+
code
22+
success
23+
userTutorial {
24+
id
25+
currentChapter
26+
}
27+
}
28+
}
29+
`}
30+
variables={{
31+
gatsbyID: gatsbyID,
32+
chapter: currentChapter,
33+
}}
34+
>
35+
{currentChapter => {
36+
return (
37+
<Button
38+
onClick={async () => {
39+
const mutationRes = await handleMutationResponse(currentChapter());
40+
if (mutationRes.error) {
41+
if (mutationRes.error === ApiErrors.AUTHORIZATION) {
42+
loginUser();
43+
} else {
44+
console.log(mutationRes.error);
45+
}
46+
}
47+
}}
48+
>
49+
Next Chapter
50+
</Button>
51+
);
52+
}}
53+
</Mutation>
54+
);
55+
56+
export default ChapterMutation;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as React from 'react';
2+
import { Text } from './shared/base';
3+
4+
const Percentage = ({ tutorial }) => {
5+
let progress = tutorial.viewerUserTutorial.currentChapter;
6+
let percentage = progress
7+
? Math.floor((progress / tutorial.numberofChapters) * 100)
8+
: 0;
9+
return (
10+
<div>
11+
{percentage ? <Text>{percentage}%</Text> : <Text> No Progress </Text>}
12+
</div>
13+
);
14+
};
15+
16+
export default Percentage;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ interface FillerProps {
4141
percentage: number;
4242
}
4343

44-
const Filler = styled('div')<FillerProps>`
44+
const Filler = styled.div<FillerProps>`
4545
background: ${props => props.theme.colors.primary};
4646
height: 100%;
4747
border-radius: inherit;

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Query } from 'react-apollo';
66
import gql from 'graphql-tag';
77
import UpvoteMutation from './UpvoteMutation';
88
import BookmarkMutation from './BookmarkMutation';
9+
import Percentage from './Percentage';
910

1011
type TutorialListingProps = {
1112
tutorial: Tutorial;
@@ -27,6 +28,7 @@ const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
2728
tutorial,
2829
}) => {
2930
const gatsbyID = tutorial.frontmatter.id;
31+
let tutorialPath = getTutorialOverviewSlug(tutorial.fileAbsolutePath);
3032
return (
3133
<Query
3234
query={gql`
@@ -35,11 +37,13 @@ const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
3537
id
3638
name
3739
upvotes
40+
numberofChapters
3841
numberOfStudents
3942
viewerUserTutorial {
4043
id
4144
upvoted
4245
bookmarked
46+
currentChapter
4347
}
4448
}
4549
}
@@ -52,15 +56,16 @@ const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
5256
<Flex alignItems="center" justifyContent="center">
5357
<Box width={1 / 12}>
5458
{data.getTutorialbyGatsbyID && (
55-
<UpvoteMutation tutorial={data.getTutorialbyGatsbyID} />
56-
)}
57-
{data.getTutorialbyGatsbyID && (
58-
<BookmarkMutation tutorial={data.getTutorialbyGatsbyID} />
59+
<div>
60+
<UpvoteMutation tutorial={data.getTutorialbyGatsbyID} />
61+
<BookmarkMutation tutorial={data.getTutorialbyGatsbyID} />
62+
<Percentage tutorial={data.getTutorialbyGatsbyID} />
63+
</div>
5964
)}
6065
</Box>
6166

6267
<Box width={11 / 12}>
63-
<Link to={getTutorialOverviewSlug(tutorial.fileAbsolutePath)}>
68+
<Link to={tutorialPath}>
6469
<Heading>{tutorial.frontmatter.tutorialTitle}</Heading>
6570
</Link>
6671
<Text>{tutorial.frontmatter.description}</Text>

packages/gatsby-theme/src/components/templates/Tutorial.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { TutorialMdxQuery } from '../../graphqlTypes';
88
import { HideOnTablet, ShowOnTablet } from '../../utils/responsive';
99
import { Flex, Box } from '../shared/base';
1010
import { optionalChaining } from '../../utils/helpers';
11+
import ChapterMutation from '../ChapterMutation';
1112

1213
type TutorialLayoutProps = { data: TutorialMdxQuery } & RouterProps;
1314

@@ -19,6 +20,10 @@ const TutorialLayout: React.FunctionComponent<TutorialLayoutProps> = ({
1920
return null;
2021
}
2122
const { pageTitle } = data!.mdx!.frontmatter!;
23+
const gatsbyID = optionalChaining(
24+
() => data!.tutorialTitle!.frontmatter!.id!,
25+
);
26+
2227
const tutorialTitle = optionalChaining(
2328
() => data!.tutorialTitle!.frontmatter!.tutorialTitle!,
2429
);
@@ -27,6 +32,7 @@ const TutorialLayout: React.FunctionComponent<TutorialLayoutProps> = ({
2732
data!.pageTitles!.edges!.map(a => a.node!.frontmatter!.pageTitle!),
2833
) || [];
2934
const { location } = props;
35+
const currentChapter = chapters.indexOf(pageTitle) + 1;
3036

3137
return (
3238
<Layout location={location}>
@@ -54,6 +60,7 @@ const TutorialLayout: React.FunctionComponent<TutorialLayoutProps> = ({
5460
<ShowOnTablet>
5561
<MDXRenderer>{data!.mdx!.code!.body}</MDXRenderer>
5662
</ShowOnTablet>
63+
<ChapterMutation gatsbyID={gatsbyID} currentChapter={currentChapter} />
5764
</Layout>
5865
);
5966
};
@@ -93,6 +100,7 @@ export const pageQuery = graphql`
93100
fileAbsolutePath: { regex: $folderRegex }
94101
) {
95102
frontmatter {
103+
id
96104
tutorialTitle
97105
}
98106
}

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ type Tutorial = {
4949
};
5050

5151
const ProfilePage: React.FunctionComponent<ProfileProps> = ({ user }) => {
52-
console.log(user);
5352
return (
5453
<Layout>
5554
<Flex flexDirection="column">
@@ -89,6 +88,17 @@ const ProfilePage: React.FunctionComponent<ProfileProps> = ({ user }) => {
8988
),
9089
)}
9190
</ul>
91+
<Heading> In Progress Tutorials </Heading>
92+
<ul>
93+
{user.progress.map(
94+
a =>
95+
a.tutorial && (
96+
<li key={a.tutorial.id}>
97+
<span>{a.tutorial.name}</span>
98+
</li>
99+
),
100+
)}
101+
</ul>
92102
</Layout>
93103
);
94104
};
@@ -115,6 +125,12 @@ const PROFILE_QUERY = gql`
115125
name
116126
}
117127
}
128+
progress: userTutorials(where: { currentChapter_not: 0 }) {
129+
tutorial {
130+
id
131+
name
132+
}
133+
}
118134
}
119135
}
120136
}

packages/server/.yoga/nexus.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ export interface NexusGenFieldTypes {
344344
Mutation: { // field return type
345345
authenticate: NexusGenRootTypes['AuthenticateUserPayload'] | null; // AuthenticateUserPayload
346346
bookmarkTutorial: NexusGenRootTypes['UserTutorialPayload']; // UserTutorialPayload!
347+
upsertCurrentChapter: NexusGenRootTypes['UserTutorialPayload']; // UserTutorialPayload!
347348
upsertTutorial: NexusGenRootTypes['Tutorial']; // Tutorial!
348349
upvoteTutorial: NexusGenRootTypes['UserTutorialPayload']; // UserTutorialPayload!
349350
}
@@ -415,6 +416,10 @@ export interface NexusGenArgTypes {
415416
bookmarkTutorial: { // args
416417
tutorialId: string; // ID!
417418
}
419+
upsertCurrentChapter: { // args
420+
chapter: number; // Int!
421+
gatsbyID: string; // String!
422+
}
418423
upsertTutorial: { // args
419424
gatsbyID: string; // String!
420425
name: string; // String!

0 commit comments

Comments
 (0)