Skip to content

Commit 690f9e2

Browse files
authored
Merge branch 'master' into 2188-update-the-dropdownmenu-to-set-the-selected-item
2 parents 35520f9 + 7335130 commit 690f9e2

File tree

9 files changed

+173
-13
lines changed

9 files changed

+173
-13
lines changed

__tests__/pages/__snapshots__/forgotpassword.test.js.snap

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,12 @@ exports[`ForgotPassword Page Should render invalid user/email form on error 1`]
182182
<p
183183
class="card-text"
184184
/>
185-
<a
185+
<button
186186
class="btn btn-primary btn-lg btn-block mb-3"
187-
href="/forgotpassword"
188-
role="button"
187+
data-testid="back"
189188
>
190189
Go Back
191-
</a>
190+
</button>
192191
</div>
193192
</div>
194193
</div>

__tests__/pages/forgotpassword.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,11 @@ describe('ForgotPassword Page', () => {
112112

113113
// wait for mutation updates after submitButton is clicked
114114
await waitFor(() => expect(container).toMatchSnapshot())
115+
116+
const backButton = getByTestId('back')
117+
118+
await waitFor(() => fireEvent.click(backButton))
119+
120+
await waitFor(() => getByRole('heading', { name: /reset your password/i }))
115121
})
116122
})

graphql/index.tsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ export type Mutation = {
137137
reqPwReset: SuccessResponse
138138
setStar: SuccessResponse
139139
signup?: Maybe<AuthResponse>
140+
unlinkDiscord?: Maybe<User>
140141
updateChallenge?: Maybe<Array<Maybe<Lesson>>>
141142
updateExercise: Exercise
142143
updateLesson: Array<Lesson>
@@ -1059,6 +1060,13 @@ export type SignupMutation = {
10591060
} | null
10601061
}
10611062

1063+
export type UnlinkDiscordMutationVariables = Exact<{ [key: string]: never }>
1064+
1065+
export type UnlinkDiscordMutation = {
1066+
__typename?: 'Mutation'
1067+
unlinkDiscord?: { __typename?: 'User'; id: number } | null
1068+
}
1069+
10621070
export type UpdateChallengeMutationVariables = Exact<{
10631071
lessonId: Scalars['Int']
10641072
order: Scalars['Int']
@@ -1654,6 +1662,11 @@ export type MutationResolvers<
16541662
'email' | 'firstName' | 'lastName' | 'password' | 'username'
16551663
>
16561664
>
1665+
unlinkDiscord?: Resolver<
1666+
Maybe<ResolversTypes['User']>,
1667+
ParentType,
1668+
ContextType
1669+
>
16571670
updateChallenge?: Resolver<
16581671
Maybe<Array<Maybe<ResolversTypes['Lesson']>>>,
16591672
ParentType,
@@ -4588,6 +4601,86 @@ export type SignupMutationOptions = Apollo.BaseMutationOptions<
45884601
SignupMutation,
45894602
SignupMutationVariables
45904603
>
4604+
export const UnlinkDiscordDocument = gql`
4605+
mutation unlinkDiscord {
4606+
unlinkDiscord {
4607+
id
4608+
}
4609+
}
4610+
`
4611+
export type UnlinkDiscordMutationFn = Apollo.MutationFunction<
4612+
UnlinkDiscordMutation,
4613+
UnlinkDiscordMutationVariables
4614+
>
4615+
export type UnlinkDiscordProps<
4616+
TChildProps = {},
4617+
TDataName extends string = 'mutate'
4618+
> = {
4619+
[key in TDataName]: Apollo.MutationFunction<
4620+
UnlinkDiscordMutation,
4621+
UnlinkDiscordMutationVariables
4622+
>
4623+
} & TChildProps
4624+
export function withUnlinkDiscord<
4625+
TProps,
4626+
TChildProps = {},
4627+
TDataName extends string = 'mutate'
4628+
>(
4629+
operationOptions?: ApolloReactHoc.OperationOption<
4630+
TProps,
4631+
UnlinkDiscordMutation,
4632+
UnlinkDiscordMutationVariables,
4633+
UnlinkDiscordProps<TChildProps, TDataName>
4634+
>
4635+
) {
4636+
return ApolloReactHoc.withMutation<
4637+
TProps,
4638+
UnlinkDiscordMutation,
4639+
UnlinkDiscordMutationVariables,
4640+
UnlinkDiscordProps<TChildProps, TDataName>
4641+
>(UnlinkDiscordDocument, {
4642+
alias: 'unlinkDiscord',
4643+
...operationOptions
4644+
})
4645+
}
4646+
4647+
/**
4648+
* __useUnlinkDiscordMutation__
4649+
*
4650+
* To run a mutation, you first call `useUnlinkDiscordMutation` within a React component and pass it any options that fit your needs.
4651+
* When your component renders, `useUnlinkDiscordMutation` returns a tuple that includes:
4652+
* - A mutate function that you can call at any time to execute the mutation
4653+
* - An object with fields that represent the current status of the mutation's execution
4654+
*
4655+
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
4656+
*
4657+
* @example
4658+
* const [unlinkDiscordMutation, { data, loading, error }] = useUnlinkDiscordMutation({
4659+
* variables: {
4660+
* },
4661+
* });
4662+
*/
4663+
export function useUnlinkDiscordMutation(
4664+
baseOptions?: Apollo.MutationHookOptions<
4665+
UnlinkDiscordMutation,
4666+
UnlinkDiscordMutationVariables
4667+
>
4668+
) {
4669+
const options = { ...defaultOptions, ...baseOptions }
4670+
return Apollo.useMutation<
4671+
UnlinkDiscordMutation,
4672+
UnlinkDiscordMutationVariables
4673+
>(UnlinkDiscordDocument, options)
4674+
}
4675+
export type UnlinkDiscordMutationHookResult = ReturnType<
4676+
typeof useUnlinkDiscordMutation
4677+
>
4678+
export type UnlinkDiscordMutationResult =
4679+
Apollo.MutationResult<UnlinkDiscordMutation>
4680+
export type UnlinkDiscordMutationOptions = Apollo.BaseMutationOptions<
4681+
UnlinkDiscordMutation,
4682+
UnlinkDiscordMutationVariables
4683+
>
45914684
export const UpdateChallengeDocument = gql`
45924685
mutation updateChallenge(
45934686
$lessonId: Int!
@@ -5281,6 +5374,7 @@ export type MutationKeySpecifier = (
52815374
| 'reqPwReset'
52825375
| 'setStar'
52835376
| 'signup'
5377+
| 'unlinkDiscord'
52845378
| 'updateChallenge'
52855379
| 'updateExercise'
52865380
| 'updateLesson'
@@ -5310,6 +5404,7 @@ export type MutationFieldPolicy = {
53105404
reqPwReset?: FieldPolicy<any> | FieldReadFunction<any>
53115405
setStar?: FieldPolicy<any> | FieldReadFunction<any>
53125406
signup?: FieldPolicy<any> | FieldReadFunction<any>
5407+
unlinkDiscord?: FieldPolicy<any> | FieldReadFunction<any>
53135408
updateChallenge?: FieldPolicy<any> | FieldReadFunction<any>
53145409
updateExercise?: FieldPolicy<any> | FieldReadFunction<any>
53155410
updateLesson?: FieldPolicy<any> | FieldReadFunction<any>

graphql/queries/unlinkDiscord.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { gql } from '@apollo/client'
2+
3+
export const UNLINK_DISCORD = gql`
4+
mutation unlinkDiscord {
5+
unlinkDiscord {
6+
id
7+
}
8+
}
9+
`

graphql/resolvers.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { changeAdminRights } from './resolvers/adminController'
2323
import { createLesson, updateLesson } from './resolvers/lessonsController'
2424
import { getPreviousSubmissions } from './resolvers/getPreviousSubmissions'
2525
import { deleteComment } from './resolvers/deleteComment'
26+
import { unlinkDiscord } from './resolvers/unlinkDiscord'
2627
import {
2728
addModule,
2829
modules,
@@ -78,6 +79,7 @@ export default {
7879
addComment,
7980
deleteComment,
8081
flagExercise,
81-
removeExerciseFlag
82+
removeExerciseFlag,
83+
unlinkDiscord
8284
}
8385
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import prismaMock from '../../__tests__/utils/prismaMock'
2+
import { unlinkDiscord } from './unlinkDiscord'
3+
4+
const mockUser = {
5+
username: 'noob',
6+
id: 1
7+
}
8+
9+
const ctx = { req: { user: { id: 1 } } }
10+
const ctxWithError = { req: { user: { id: null } } }
11+
12+
describe('unlinkDiscord resolver', () => {
13+
it('should unlink discord successfully', async () => {
14+
prismaMock.user.update.mockResolvedValue(mockUser)
15+
16+
expect(unlinkDiscord(null, null, ctx)).resolves.toStrictEqual(mockUser)
17+
})
18+
19+
it('should throw error', async () => {
20+
prismaMock.user.update.mockResolvedValue(mockUser)
21+
22+
expect(unlinkDiscord(null, null, ctxWithError)).rejects.toThrow(
23+
'Invalid user'
24+
)
25+
})
26+
})

graphql/resolvers/unlinkDiscord.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import prisma from '../../prisma'
2+
import { Context } from '../../@types/helpers'
3+
4+
export const unlinkDiscord = async (_parent: void, _: any, ctx: Context) => {
5+
const userId = ctx.req.user?.id
6+
7+
if (!userId) throw new Error('Invalid user')
8+
9+
return await prisma.user.update({
10+
where: {
11+
id: userId
12+
},
13+
data: {
14+
discordAccessToken: '',
15+
discordAccessTokenExpires: null,
16+
discordId: '',
17+
discordRefreshToken: ''
18+
}
19+
})
20+
}

graphql/typeDefs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export default gql`
122122
title: String!
123123
id: Int!
124124
): [Lesson]
125+
unlinkDiscord: User
125126
}
126127
127128
type AuthResponse {

pages/forgotpassword.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { useMutation } from '@apollo/client'
2-
import React from 'react'
1+
import { ApolloError, useMutation } from '@apollo/client'
2+
import React, { useState } from 'react'
33
import { Formik, Form, Field } from 'formik'
44
import RESET_PASSWORD from '../graphql/queries/resetPassword'
55
import { resetPasswordValidation } from '../helpers/formValidation'
@@ -12,7 +12,10 @@ const initialValues = {
1212
}
1313

1414
export const ResetPassword: React.FC = () => {
15-
const [reqPwReset, { data, error }] = useMutation(RESET_PASSWORD)
15+
const [error, setError] = useState<null | ApolloError>(null)
16+
const [reqPwReset, { data }] = useMutation(RESET_PASSWORD, {
17+
onError: setError
18+
})
1619
const handleSubmit = async ({ userOrEmail }: { userOrEmail: string }) => {
1720
try {
1821
await reqPwReset({ variables: { userOrEmail } })
@@ -27,17 +30,16 @@ export const ResetPassword: React.FC = () => {
2730
</Card>
2831
)
2932
}
30-
// Can't use NavLink since page needs to reload.
3133
if (error) {
3234
return (
3335
<Card title="Username or Email does not exist">
34-
<a
35-
href="/forgotpassword"
36+
<button
3637
className="btn btn-primary btn-lg btn-block mb-3"
37-
role="button"
38+
onClick={() => setError(null)}
39+
data-testid="back"
3840
>
3941
Go Back
40-
</a>
42+
</button>
4143
</Card>
4244
)
4345
}

0 commit comments

Comments
 (0)