kabisa/kudos-frontend

View on GitHub
src/modules/login/LoginPage.tsx

Summary

Maintainability
B
6 hrs
Test Coverage
A
96%
import { Component, FormEvent } from "react";
import { withRouter } from "react-router-dom";
import { History } from "history";
import { Mutation } from "@apollo/client/react/components";
import { ApolloError, gql } from "@apollo/client";

import {
  PATH_CHOOSE_TEAM,
  PATH_FORGOT_PASSWORD,
  PATH_REGISTER,
} from "../../routes";
import {
  Auth,
  ERROR_EMAIL_INVALID,
  ERROR_INCOMPLETE,
  getGraphqlError,
  validateEmail,
} from "../../support";
import { FormWrapper } from "../../components";
import { loginSuccess } from "./helper";

import s from "./LoginPage.module.css";
import { Button, Input, Label } from "@kabisa/ui-components";
import Segment from "../../components/atoms/Segment";
import BasePage from "./BasePage";
import MessageBox from "../../ui/MessageBox";
import { Link } from "../../components/Link";

export const MUTATION_LOGIN = gql`
  mutation SignInUser($email: EmailAddress!, $password: String!) {
    signInUser(credentials: { email: $email, password: $password }) {
      authenticateData {
        token
        user {
          id
        }
      }
    }
  }
`;

export interface LoginResult {
  signInUser: {
    authenticateData: {
      token: string;
      user: {
        id: string;
      };
    };
    errors: ApolloError[];
  };
}

export interface LoginParameters {
  email: string;
  password: string;
}

export interface Props {
  history: History;
}

export interface State {
  email: string;
  password: string;
  error: string;
}

class LoginPage extends Component<Props, State> {
  constructor(props: Props) {
    super(props);

    if (Auth.isLoggedIn()) {
      this.props.history.push(PATH_CHOOSE_TEAM);
    }

    this.state = {
      email: "",
      password: "",
      error: "",
    };

    this.confirm = this.confirm.bind(this);
    this.formSubmit = this.formSubmit.bind(this);
  }

  confirm(data: LoginResult) {
    if (data.signInUser.authenticateData) {
      loginSuccess(data.signInUser.authenticateData);

      this.props.history.push(PATH_CHOOSE_TEAM);
    } else {
      this.setState({ error: "Something went wrong." });
    }
  }

  formSubmit(e: FormEvent, signInUser: any) {
    e.preventDefault();
    this.setState({ error: "" });
    let { email } = this.state;
    const { password } = this.state;

    email = email.trim();

    if (!email || !password) {
      this.setState({ error: ERROR_INCOMPLETE });
      return;
    }

    if (!validateEmail(email)) {
      this.setState({ error: ERROR_EMAIL_INVALID });
      return;
    }

    signInUser({
      variables: { email, password },
    });
  }

  render() {
    return (
      <Mutation<LoginResult, LoginParameters>
        mutation={MUTATION_LOGIN}
        onError={(error) => {
          this.setState({ error: getGraphqlError(error) });
        }}
        onCompleted={(data) => this.confirm(data)}
      >
        {(signInUser, { loading }) => {
          let displayError;
          if (this.state.error) {
            displayError = this.state.error;
          }
          return (
            <BasePage>
              <FormWrapper header="Login">
                <Segment>
                  <form
                    className="form-container"
                    onSubmit={(e) => this.formSubmit(e, signInUser)}
                  >
                    <Label>
                      Email
                      <Input
                        data-testid="email-input"
                        name="email"
                        type="email"
                        placeholder="E-mail address"
                        value={this.state.email}
                        onChange={(e) =>
                          this.setState({ email: e.target.value })
                        }
                      />
                    </Label>

                    <Label>
                      Password
                      <Input
                        data-testid="password-input"
                        name="password"
                        placeholder="Password"
                        type="password"
                        value={this.state.password}
                        onChange={(e) =>
                          this.setState({ password: e.target.value })
                        }
                      />
                    </Label>

                    <Button
                      data-testid="submit-button"
                      type="submit"
                      variant="primary"
                      disabled={loading}
                      className={s.button}
                    >
                      Login
                    </Button>

                    {displayError && (
                      <MessageBox
                        variant="error"
                        title="Unable to login"
                        message={displayError}
                      />
                    )}
                  </form>
                  <div className={s.footer}>
                    <Link
                      data-testid="sign-up-button"
                      to={PATH_REGISTER}
                      className={s.left}
                      theme="dark"
                    >
                      Sign Up
                    </Link>
                    <Link
                      data-testid="forgot-button"
                      to={PATH_FORGOT_PASSWORD}
                      theme="dark"
                      className={s.right}
                    >
                      Forgot password?
                    </Link>
                  </div>
                </Segment>
              </FormWrapper>
            </BasePage>
          );
        }}
      </Mutation>
    );
  }
}

// @ts-ignore
export default withRouter(LoginPage);