view client/src/login/Login.vue @ 1097:874d19f32015

added fontawesome5 and implemented one example icon on login screen
author Markus Kottlaender <markus@intevation.de>
date Thu, 01 Nov 2018 10:19:28 +0100
parents 3418f3e2c822
children d9e6a1f6f394
line wrap: on
line source

(<template>
    <div class="d-flex flex-column login shadow-lg">
        <div class="loginmask">
            <!-- logo section -->
            <div class="d-flex flex-row justify-content-center mb-3">
                <div class="logo"><img src="../application/assets/logo.png"></div>
                <div class="title">
                    <h1>{{ appTitle }}</h1>
                </div>
            </div>
            <!-- end logo section -->
            <form class="loginform" @submit.prevent="login">
                <div id="alert" :style="errorMessageStyle" :class="errorMessageClass" role="alert">
                    <span>{{ errorMessage }}</span>
                </div>
                <div class="input-group mb-3">
                    <input type="text" v-model="user" id="inputUsername" class="form-control shadow-sm" :placeholder="usernameLabel" required autofocus>
                </div>
                <div class="input-group mb-3">
                    <input :type="isPasswordVisible" v-model="password" id="inputPassword" class="form-control shadow-sm" :placeholder='passwordLabel' :required='!showPasswordReset' :disabled='showPasswordReset'>
                    <div class="input-group-append">
                        <span class="input-group-text disabled" id="basic-addon2" @click="showPassword">
                            <font-awesome-icon icon="eye" v-if="!readablePassword" />
                            <font-awesome-icon icon="eye-slash" v-if="readablePassword" />
                        </span>
                    </div>
                </div>
                <button v-if="showPasswordReset==false" class="btn btn-primary btn-block shadow-sm" :disabled="submitted || showPasswordReset" type="submit">
                    <translate>Login</translate>
                </button>
                <div v-if="showPasswordReset" class="passwordreset">
                    <button class="btn btn-block btn-info" type="button" @click="resetPassword">
                        <translate>Request password reset!</translate>
                    </button>
                    <div class="pull-right">
                        <a href="#" @click.prevent="togglePasswordReset">
                            <translate>back to login</translate>
                        </a>
                    </div>
                </div>
                <div v-else class="pull-right">
                    <a href="#" @click.prevent="togglePasswordReset">
                        <translate>Forgot password</translate>
                    </a>
                </div>
            </form>

            <!-- bottom logo section -->
            <div class="mb-3 secondary-logo"><img :src="secondaryLogo"></div>
        </div>
    </div>
</template>)

<style lang="scss">
.login {
  background-color: white;
  min-width: 375px;
  min-height: 500px;
  @extend %fully-centered;
}

.loginform {
  max-width: 375px;
  margin-left: auto;
  margin-right: auto;
}

.loginmask {
  position: relative;
  margin-left: $large-offset;
  margin-right: $large-offset;
  margin-top: $large-offset;
}

.logo {
  margin-right: $offset;
}

.alert {
  padding: 0.5rem;
}

.secondary-logo {
  max-width: 375px;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: auto;
}

/* avoid IE and Edge show a password reveal as we do our own */
input[type="password"]::-ms-reveal {
  display: none;
}
</style>

<script>
import { mapGetters } from "vuex";
import { HTTP } from "../application/lib/http.js";
import { displayError } from "../application/lib/errors.js";

const UNAUTHORIZED = 401;

export default {
  name: "login",
  data() {
    return {
      user: "",
      password: "",
      submitted: false,
      loginFailed: false,
      passwordJustResetted: false,
      readablePassword: false,
      showPasswordReset: false,
      usernameToReset: ""
    };
  },
  computed: {
    errorMessage() {
      if (this.loginFailed) return this.$gettext("Login failed");
      if (this.passwordJustResetted)
        return this.$gettext("Password reset requested!");
      return "&npsp;";
    },
    passwordLabel() {
      return this.$gettext("Enter passphrase");
    },
    usernameLabel() {
      return this.$gettext("Enter username");
    },
    isPasswordVisible() {
      return this.readablePassword ? "text" : "password";
    },
    errorMessageStyle() {
      if (this.loginFailed || this.passwordJustResetted) {
        return "visibility:visible";
      }
      return "visibility:hidden";
    },
    errorMessageClass() {
      let result = {
        "mb-3": true,
        errormessage: true,
        alert: true
      };
      if (this.loginFailed) {
        result["alert-danger"] = true;
      }
      if (this.passwordJustResetted) {
        result["alert-info"] = true;
      }
      return result;
    },
    ...mapGetters("application", ["appTitle", "secondaryLogo"])
  },
  methods: {
    login() {
      this.submitted = true;
      this.passwordJustResetted = false;
      const { user, password } = this;
      this.$store
        .dispatch("user/login", { user, password })
        .then(() => {
          this.loginFailed = false;
          this.$router.push("/");
        })
        .catch(error => {
          this.loginFailed = true;
          this.submitted = false;
          const { status, data } = error.response;
          if (status !== UNAUTHORIZED) {
            //Unauthorized is handled in alert-div
            displayError({
              title: "Backend Error",
              message: `${status}: ${data.message || data}`
            });
          }
        });
    },
    showPassword() {
      // disallowing toggle when in reset mode
      if (this.showPasswordReset) return;
      this.readablePassword = !this.readablePassword;
    },
    togglePasswordReset() {
      this.passwordJustResetted = false;
      this.showPasswordReset = !this.showPasswordReset;
      this.loginFailed = false;
    },
    resetPassword() {
      if (this.user) {
        HTTP.post("/users/passwordreset", { user: this.user }).catch(error => {
          const { status, data } = error.response;
          displayError({
            title: "Backend Error",
            message: `${status}: ${data.message || data}`
          });
        });
        this.togglePasswordReset();
        this.passwordJustResetted = true;
      }
    }
  }
};
</script>