view client/src/login/Login.vue @ 1217:ba8cd80d68b6

made more use of bootstrap classes instead of custom css
author Markus Kottlaender <markus@intevation.de>
date Mon, 19 Nov 2018 15:20:22 +0100
parents b23622905a3f
children
line wrap: on
line source

(<template>
    <div class="d-flex flex-column login bg-white shadow">
        <div class="m-5">
            <!-- logo section -->
            <div class="d-flex flex-row justify-content-center mb-3">
                <div class="logo mr-3"><img src="../application/assets/logo.png"></div>
                <div class="title">
                    <h1>{{ appTitle }}</h1>
                </div>
            </div>
            <!-- end logo section -->
            <form class="loginform mx-auto" @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 mx-auto mb-auto"><img :src="secondaryLogo"></div>
        </div>
    </div>
</template>)

<style lang="sass" scoped>
.login
  min-width: 375px
  min-height: 500px
  @extend %fully-centered

.loginform
  max-width: 375px

.alert
  padding: 0.5rem

.secondary-logo
  max-width: 375px

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

<script>
import { mapState } 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;
    },
    ...mapState("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>