Skip to content

Commit 1c6082a

Browse files
committed
site will ask user to login if they upvote
1 parent 23f84cb commit 1c6082a

File tree

3 files changed

+118
-64
lines changed

3 files changed

+118
-64
lines changed

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { Link } from 'gatsby';
66
import { Query, Mutation } from 'react-apollo';
77
import gql from 'graphql-tag';
88
import { optionalChaining } from '../utils/helpers';
9+
import { loginUser } from '../utils/auth';
10+
import { handleMutationResponse, ApiErrors } from '../utils/errorHandling';
911

1012
type TutorialListingProps = {
1113
tutorial: Tutorial;
@@ -25,7 +27,7 @@ type FrontMatter = {
2527
const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
2628
tutorial,
2729
}) => {
28-
const tutorialId = "cjwb6f2hy7e4f0b14bxh1mar2";
30+
const tutorialId = 'cjwb6f2hy7e4f0b14bxh1mar2';
2931
return (
3032
<Query
3133
query={gql`
@@ -67,17 +69,30 @@ const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
6769
}
6870
`}
6971
variables={{
70-
id: tutorialId
72+
id: tutorialId,
7173
}}
7274
>
73-
{(upvote) => {
75+
{upvote => {
7476
return (
7577
<Upvote
76-
onClick={() => upvote()}
77-
active={optionalChaining(() => data.tutorial.viewerUserTutorial.upvoted)}
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+
)}
7893
count={optionalChaining(() => data.tutorial.upvotes)}
7994
/>
80-
)
95+
);
8196
}}
8297
</Mutation>
8398
</Box>
@@ -89,7 +104,7 @@ const TutorialListing: React.FunctionComponent<TutorialListingProps> = ({
89104
</Box>
90105
</Flex>
91106
</Card>
92-
)
107+
);
93108
}}
94109
</Query>
95110
);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export enum ApiErrors {
2+
AUTHORIZATION = 'AUTHORIZATION',
3+
INVALID = 'INVALID',
4+
}
5+
6+
export async function handleMutationResponse(
7+
mutationReq: Promise<any>,
8+
): Promise<any> {
9+
try {
10+
return await mutationReq;
11+
} catch (err) {
12+
if (err.message === 'GraphQL error: Not authorized') {
13+
return {
14+
error: ApiErrors.AUTHORIZATION,
15+
};
16+
}
17+
return {
18+
error: ApiErrors.INVALID,
19+
};
20+
}
21+
}

packages/server/src/graphql/UserTutorial.ts

Lines changed: 75 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { prismaObjectType, objectType, mutationField, idArg } from 'yoga'
2-
import { PayloadInterface } from './PayloadInterface';
3-
import { authorizeUser } from './auth';
4-
import { Context } from '../context';
5-
import { UserTutorial as UserTutorialType, UserTutorialCreateInput } from '../../.yoga/prisma-client';
2+
import { PayloadInterface } from './PayloadInterface'
3+
import { authorizeUser } from './auth'
4+
import { Context } from '../context'
5+
import {
6+
UserTutorial as UserTutorialType,
7+
UserTutorialCreateInput,
8+
} from '../../.yoga/prisma-client'
69

710
export const UserTutorial = prismaObjectType({
811
name: 'UserTutorial',
@@ -14,93 +17,108 @@ export const UserTutorial = prismaObjectType({
1417
})
1518

1619
export const UserTutorialPayload = objectType({
17-
name: "UserTutorialPayload",
18-
definition: (type) => {
19-
type.implements(PayloadInterface);
20-
type.field("userTutorial", {
20+
name: 'UserTutorialPayload',
21+
definition: type => {
22+
type.implements(PayloadInterface)
23+
type.field('userTutorial', {
2124
type: UserTutorial,
22-
nullable: true
23-
});
24-
}
25+
nullable: true,
26+
})
27+
},
2528
})
2629

27-
export const upvoteTutorial = mutationField("upvoteTutorial", {
30+
export const upvoteTutorial = mutationField('upvoteTutorial', {
2831
type: UserTutorialPayload,
29-
description: "An authenticated user can upvote a tutorial.",
32+
description: 'An authenticated user can upvote a tutorial.',
3033
args: {
3134
tutorialId: idArg({
32-
required: true
33-
})
35+
required: true,
36+
}),
3437
},
3538
authorize: authorizeUser(),
3639
resolve: async (_, { tutorialId }, ctx) => {
37-
const userId = ctx.currentUserId;
38-
const existingUserTutorial = await getUserTutorial({
39-
userId,
40-
tutorialId
41-
}, ctx);
42-
let upsertedUserTutorial = await upsertUserTutorial({
43-
userId,
44-
tutorialId,
45-
userTutorialId: existingUserTutorial && existingUserTutorial.id,
46-
updates: {
47-
upvoted: !existingUserTutorial.upvoted,
40+
const userId = ctx.currentUserId
41+
const existingUserTutorial = await getUserTutorial(
42+
{
43+
userId,
44+
tutorialId,
45+
},
46+
ctx,
47+
)
48+
let upsertedUserTutorial = await upsertUserTutorial(
49+
{
50+
userId,
51+
tutorialId,
52+
userTutorialId: existingUserTutorial && existingUserTutorial.id,
53+
updates: {
54+
upvoted: existingUserTutorial ? !existingUserTutorial.upvoted : true,
55+
},
4856
},
49-
}, ctx);
50-
return ({
51-
code: "200",
57+
ctx,
58+
)
59+
return {
60+
code: '200',
5261
success: true,
5362
message: null,
54-
userTutorial: upsertedUserTutorial
55-
})
56-
}
63+
userTutorial: upsertedUserTutorial,
64+
}
65+
},
5766
})
5867

59-
async function upsertUserTutorial(args: { userTutorialId?: string, updates: UserTutorialCreateInput, userId: string, tutorialId: any }, ctx: Context): Promise<UserTutorialType> {
60-
const { userTutorialId, updates, userId, tutorialId } = args;
61-
let upsertedUserTutorial;
68+
async function upsertUserTutorial(
69+
args: {
70+
userTutorialId?: string
71+
updates: UserTutorialCreateInput
72+
userId: string
73+
tutorialId: any
74+
},
75+
ctx: Context,
76+
): Promise<UserTutorialType> {
77+
const { userTutorialId, updates, userId, tutorialId } = args
78+
let upsertedUserTutorial
6279
if (userTutorialId) {
6380
upsertedUserTutorial = await ctx.prisma.updateUserTutorial({
6481
where: {
65-
id: userTutorialId
82+
id: userTutorialId,
6683
},
67-
data: updates
68-
});
69-
}
70-
else {
84+
data: updates,
85+
})
86+
} else {
7187
upsertedUserTutorial = await ctx.prisma.createUserTutorial({
7288
...updates,
7389
user: {
7490
connect: {
75-
id: userId
76-
}
91+
id: userId,
92+
},
7793
},
7894
tutorial: {
7995
connect: {
80-
id: tutorialId
81-
}
82-
}
83-
});
96+
id: tutorialId,
97+
},
98+
},
99+
})
84100
}
85-
return upsertedUserTutorial;
101+
return upsertedUserTutorial
86102
}
87103

88-
export async function getUserTutorial(args: { userId: string, tutorialId: any }, ctx: Context): Promise<null | UserTutorialType> {
89-
const { userId, tutorialId } = args;
104+
export async function getUserTutorial(
105+
args: { userId: string; tutorialId: any },
106+
ctx: Context,
107+
): Promise<null | UserTutorialType> {
108+
const { userId, tutorialId } = args
90109
const existingUserTutorials = await ctx.prisma.userTutorials({
91110
first: 1,
92111
where: {
93112
user: {
94-
id: userId
113+
id: userId,
95114
},
96115
tutorial: {
97-
id: tutorialId
98-
}
99-
}
100-
});
116+
id: tutorialId,
117+
},
118+
},
119+
})
101120
if (existingUserTutorials.length > 0) {
102-
return existingUserTutorials[0];
121+
return existingUserTutorials[0]
103122
}
104-
return null;
123+
return null
105124
}
106-

0 commit comments

Comments
 (0)