Creating a Reddit Clone Using React and GraphQL - 11
Tags: react, graphql, typescript, redditclone
Published: 2021-03-11 17:50:53

### This blog post originally posted on my blog site and you can find it [here](https://www.rasikag.com/posts/learning-react-with-ben-awad-11). 


From the last post, we stop at finishing `forgotPassword` mutation. Now we come to `GraphQL` playground and execute the forget-password mutation.

```javascript

mutation {
  forgotPassword(email:"rasika@rasikag.com")
}

```

Then in the `console` you will see the forget password URL and click it. It will show the test email. Click on the link and it will navigate to our web app. At this point, we don’t have forgot password page. Let’s go and create it. But in the link, you will see the token that we created.

Create a folder called `change-password` as the top level and the file will be `[token].tsx` . This is the `Next.js` convention that we can access a variable in the URL.

Here is our page initial code block.

```javascript
import { NextPage } from "next";
import React from "react";

const ChangePassword: NextPage<{ token: string }> = ({ token }) => {
  return <div></div>;
};
```

We are using `Next.js` ‘s `NextPage` type that leverage the functionalities that get the query parameters. To do that we are adding `getInitialProps` method. Add below code block after the `ChangePassword` . This method will catch the query parameter and pass it as `token`

```javascript

ChangePassword.getInitialProps = ({query}) => {
  return {
    token: query.token as string
  }
}

```

Now let’s create the forget password form. We can grab that from the login page.

```javascript
return (
  <Wrapper variant="small">
    <Formik
      initialValues={{ newPassword: "" }}
      onSubmit={async (values, { setErrors }) => {}}
    >
      {({ isSubmitting }) => (
        <Form>
          <Box mt={4}>
            <InputField
              name="newPassword"
              placeholder="new password"
              label="New Password"
              type="password"
            />
          </Box>
          <Button
            isLoading={isSubmitting}
            mt={4}
            type="submit"
            colorScheme="teal"
          >
            Change Password
          </Button>
        </Form>
      )}
    </Formik>
  </Wrapper>
);
```

You will see that our onSubmit function doesn’t have any code. Before that in here, we are receiving the token and we need to send the new password to the server to reset it. Let’s add that mutation `UserResolver`.

```javascript

@Mutation(() => UserResponse)
  async changePassword(
    @Arg("token") token: string,
    @Arg("newPassword") newPassword: string,
    @Ctx() { em, redis, req }: RedditDbContext
  ): Promise<UserResponse> {
    // first validate the password
    if (newPassword.length <= 2) {
      return {
        errors: [
          {
            field: "newPassword",
            message: "length must be greater than 2",
          },
        ],
      };
    }
    // check user id exist
    const userId = await redis.get(FORGET_PASSWORD_PREFIX + token);
    if (!userId) {
      return {
        errors: [
          {
            field: "token",
            message: "token expired",
          },
        ],
      };
    }

    const user = await em.findOne(User, { id: parseInt(userId) });
    if (!user) {
      return {
        errors: [
          {
            field: "token",
            message: "user no longer exist",
          },
        ],
      };
    }

    user.password = await argon2.hash(newPassword);
    await em.persistAndFlush(user);
    req.session.userId = user.id;
    return { user };
  }

```

We are validating the password first. Then validate the `userid` by checking the token. If all validation pass, then update the user. We need to hash this password first. Then update the user. Also here we are setting the session for that user.

We complete the back-end. Let’s go and add the front-end code for this change. We are starting by adding new `graphql` mutation. Create a file `changePassword.graphql` and add the below code.

```javascript

mutation ChangePassword($token: String!, $newPassword: String!) {
  changePassword(token: $token, newPassword: $newPassword) {
    errors {
      ...RegularError
    }
    user {
      ...RegularUser
    }
  }
}

```

To manage errors we can create we created `RegularError` fragment and we can replace all the `errors` with RegularError fragment.

```javascript

fragment RegularError on FieldError {
  id
  username
}

```

At this point, if we check our `login`, `register` and `changePassword` mutations we can see that body is the same. So let’s make another fragment and replace it. Create a fragment called `RegularUserResponse` and replace others with it.

```javascript

fragment RegularUserResponse on UserResponse {
  errors {
    ...RegularError
  }
  user {
    ...RegularUser
  }
}

```

> Main thing need to observe that fragments are base on back-end `ObjectType` . If you check that `UserResponse` is match with back-end `UserResponse` `ObjectType` and those names should be match.

Now let’s replace those `graphql` queries with this fragment.

> Make sure to run `yarn gen` from web app after doing all the things to generate the types.

Now we are going to file the `onSublit` method in `ChangePassword` component.

```javascript

// add below code lines above from return method
const router = useRouter();
const [, changePassword] = useChangePasswordMutation();
// ...
onSubmit={async (values, { setErrors }) => {
  const response = await changePassword({
    newPassword: values.newPassword,
    token,
  });
  if (response.data?.changePassword.errors) {
    // the graphql errors like this
    // [{filed: "username", message: "value empty"}]
    setErrors(toErrorMap(response.data.changePassword.errors));
  } else if (response.data?.changePassword.user) {
    // TODO: try to move this else if block
    // user log in successfully
    router.push("/");
  }
}}

```

But there are few things that need to handle. One thing is we can get the response that saying the error field is token and in the form we don't have any field called the token. From the next post, we are going to handle that.

---

Thanks for reading this. If you have anything to ask regarding this please leave a comment here. Also, I wrote this according to my understanding. So if any point is wrong, don’t hesitate to correct me. I really appreciate you.
That’s for today friends. See you soon. Thank you.

**References:**

This article series based on the [Ben Award - Fullstack React GraphQL TypeScript Tutorial](https://www.youtube.com/watch?v=I6ypD7qv3Z8). This is amazing tutorial and I highly recommend you to check that out.

Main image [credit](https://www.pexels.com/photo/landscape-photography-of-mountains-covered-in-snow-691668/)