view client/src/components/Userdetail.vue @ 397:b5555bf6d45c

fix: Clear errors on user switch When user switched selection of which accounts to edit, validation errors werent cleared.
author Thomas Junk <thomas.junk@intevation.de>
date Tue, 14 Aug 2018 09:59:55 +0200
parents c57b952c60be
children cb233a5a2ecd
line wrap: on
line source

<template>
  <div class="userdetails shadow">
    <div class="card">
      <div class="card-header text-white bg-info mb-3">
          {{ currentUser.user }}
        <span @click="closeDetailview" class="pull-right"><i class="fa fa-close"></i></span>
      </div>
      <div class="card-body">
        <form @submit.prevent="save">
          <div class="formfields">
            <div v-if="currentUser.isNew" class="form-group row">
              <label for="user">Username</label>
              <input type="user" class="form-control form-control-sm" id="user" aria-describedby="userHelp" v-model="currentUser.user">
              <div v-show="errors.user" class="text-danger"><small><i class="fa fa-warning"></i> {{ errors.user }}</small></div>
            </div>
            <div class="form-group row">
              <label for="country">Country</label>
              <select class="form-control form-control-sm" v-on:change="validateCountry" v-model="currentUser.country">
                <option disabled value="">Please select one</option>
                <option>AT</option>
                <option>RO</option>
                <option>BG</option>
              </select>
              <div v-show="errors.country" class="text-danger"><small><i class="fa fa-warning"></i> {{ errors.country }}</small></div>
            </div>
            <div class="form-group row">
              <label for="email">Email address</label>
              <input type="email" v-on:change="validateEmailaddress" class="form-control form-control-sm" id="email" aria-describedby="emailHelp" v-model="currentUser.email">
              <div v-show="errors.email" class="text-danger"><small><i class="fa fa-warning"></i> {{ errors.email }}</small></div>
            </div>
            <div class="form-group row">
              <label for="role">Role</label>
              <select class="form-control form-control-sm" v-on:change="validateRole" v-model="currentUser.role">
                <option disabled value="">Please select one</option>
                <option value="sys_admin">Sysadmin</option>
                <option value="waterway_admin">Waterway Admin</option>
                <option value="waterway_user">Waterway User</option>
              </select>
              <div v-show="errors.role" class="text-danger"><small><i class="fa fa-warning"></i> {{ errors.role }}</small></div>
            </div>
            <div class="form-group row">
              <label for="password">Password</label>
              <input type="password" v-on:change="validatePassword" class="form-control form-control-sm" id="password" aria-describedby="passwordHelp" v-model="password">
              <div v-show="errors.password" class="text-danger"><small><i class="fa fa-warning"></i> {{ errors.password }}</small></div>
            </div>
            <div class="form-group row">
              <label for="passwordre">Retype Password</label>
              <input type="password" v-on:change="validatePassword" class="form-control form-control-sm" id="passwordre" aria-describedby="passwordreHelp" v-model="passwordre">
              <div v-show="errors.passwordre" class="text-danger"><small><i class="fa fa-warning"></i> {{ errors.passwordre }}</small></div>
            </div>
          </div>
          <div>
            <button type="submit" :disabled="submitted" class="btn btn-info pull-right">Submit</button>
          </div>
        </form>
    </div>
    </div>
  </div>
</template>

<style lang="scss">
@import "../assets/application.scss";

.formfields {
  width: 10vw;
}

.userdetails {
  margin-top: $large-offset;
  width: 53vw;
  margin-right: auto;
  height: 100%;
}

form {
  margin-left: $offset;
  font-size: 0.9rem;
}

.shadow {
  box-shadow: $basic-shadow-light !important;
}
</style>
<script>
import app from "../main";

const clearedErrors = () => {
  return {
    email: "",
    country: "",
    role: "",
    password: "",
    passwordre: ""
  };
};

const isEmailValid = email => {
  /* cf. types.go */
  // eslint-disable-next-line
  return /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(
    email
  );
};

const violatedPasswordRules = password => {
  return (
    // rules according to issue 70
    password.length < 7 ||
    /\W/.test(password) == false ||
    /\d/.test(password) == false
  );
};

export default {
  name: "userdetail",
  data() {
    return {
      password: "",
      passwordre: "",
      currentUser: {},
      path: null,
      submitted: false,
      errors: {
        email: "",
        country: "",
        role: "",
        password: "",
        passwordre: ""
      }
    };
  },
  mounted() {
    this.currentUser = { ...this.user };
    this.path = this.user.name;
  },
  watch: {
    user() {
      this.currentUser = { ...this.user };
      this.path = this.user.name;
      this.errors = clearedErrors();
    }
  },
  computed: {
    user() {
      return this.$store.getters["usermanagement/currentUser"];
    },
    isFormValid() {
      this.validateCountry();
      this.validateRole();
      this.validatePassword();
      this.validateEmailaddress();
      const valid =
        isEmailValid(this.currentUser.email) &&
        !this.currentUser.country &&
        this.password === this.passwordre &&
        (this.password === "" || violatedPasswordRules(this.password));
      return valid;
    }
  },
  methods: {
    closeDetailview() {
      this.$store.commit("usermanagement/clearCurrentUser");
      this.$store.commit("usermanagement/setUserDetailsInvisible");
    },
    validateCountry() {
      if (this.currentUser.country) {
        this.errors.country = "";
      } else {
        this.errors.country = "Please choose a country";
      }
    },
    validateRole() {
      if (this.currentUser.role) {
        this.errors.role = "";
      } else {
        this.errors.role = "Please choose a role";
      }
    },
    validatePassword() {
      if (this.password !== this.passwordre) {
        this.errors.passwordre = "Passwords do not match!";
      } else {
        this.errors.passwordre = "";
      }
      if (this.password !== "" && violatedPasswordRules(this.password)) {
        this.errors.password =
          "Password should at least be 8 char long including 1 digit and 1 special char like $";
      } else {
        this.errors.password = "";
      }
    },
    validateEmailaddress() {
      if (isEmailValid(this.currentUser.email)) {
        this.errors.email = "";
      } else {
        this.errors.email = "invalid email";
      }
    },
    save() {
      if (!this.isFormValid) return;
      if (this.password) this.currentUser.password = this.password;
      this.submitted = true;
      this.$store
        .dispatch("usermanagement/saveCurrentUser", {
          path: this.user.user,
          user: this.currentUser
        })
        .then(() => {
          this.submitted = false;
          this.$store.dispatch("usermanagement/loadUsers").catch(error => {
            const { status, data } = error.response;
            app.$toast.error({
              title: "Backend Error",
              message: `${status}: ${data}`
            });
          });
        })
        .catch(error => {
          this.submitted = false;
          const { status, data } = error.response;
          app.$toast.error({
            title: "Error while saving user",
            message: `${status}: ${data}`
          });
        });
    }
  }
};
</script>