Skip to content
Snippets Groups Projects
Project_members.vue 8.48 KiB
Newer Older
<template>
  <div class="fourteen wide column">
    <h1 class="ui header">Gérer les membres</h1>

    <h4>Ajouter un membre</h4>

    <form id="form-feature-edit" class="ui form" name="add-member">
      <div class="two fields">
        <div class="field">
          <!-- <label :for="">{{ form.title.label }}</label> -->
          <!-- <input type="text" v-model="newMember.name" /> -->
          <Dropdown
            :options="userOptions"
            :selected="newMember.user.name"
            :selection.sync="newMember.user"
            :search="true"
            :clearable="true"
          />
Timothee P's avatar
Timothee P committed
          <ul id="errorlist" class="errorlist">
            <li v-for="error in newMember.errors" :key="error">
              {{ error }}
            </li>
          </ul>
        </div>
        <div class="field">
          <!-- <label for="add-member"></label> -->
          <Dropdown
            :options="levelOptions"
            :selected="newMember.role.name"
            :selection.sync="newMember.role"
          />
        </div>
      </div>
      <button @click="addMember" type="button" class="ui teal icon button">
        <i class="white save icon"></i>
        <span class="padding-1">Ajouter</span>
      </button>
    </form>

    <!-- <input type="text" v-model="newMember.name" /> -->

    <h4>Modifier le rôle d'un membre</h4>
    <form
      id="form-members"
      action="."
      method="post"
      enctype="multipart/form-data"
      class="ui form"
    >
      <table class="ui red table">
        <thead>
          <tr>
            <th>
              Membre
              <i
                :class="{
                  down: isSortedAsc('member'),
                  up: isSortedDesc('member'),
                }"
                class="icon sort"
                @click="changeSort('member')"
              />
            </th>
            <th>
              Niveau d'autorisation
              <i
                :class="{
                  down: isSortedAsc('role'),
                  up: isSortedDesc('role'),
                }"
                class="icon sort"
                @click="changeSort('role')"
              />
            </th>
          <tr v-for="member in projectMembers" :key="member.username">
            <td>
              {{ member.user.last_name }} {{ member.user.first_name }}<br /><i
                >{{ member.user.username }}</i
              >
            </td>
            <td>
              <div class="required field">
                <Dropdown
                  :options="levelOptions"
                  :selected="member.userLevel.name"
                  :selection.sync="member.userLevel"
                  :search="true"
                />
              </div>
            </td>
          </tr>
Timothee P's avatar
Timothee P committed
      <button @click="saveMembers" type="button" class="ui teal icon button">
        <i class="white save icon"></i> Enregistrer les changements
      </button>
    </form>
  </div>
</template>

<script>
import axios from "axios";
import frag from "vue-frag";
import { mapGetters } from "vuex";
import Dropdown from "@/components/Dropdown.vue";

export default {
  name: "Project_members",

  directives: {
    frag,
  },
  components: {
    Dropdown,
  },

  data() {
    return {
      projectUsers: [],
        { name: "Utilisateur connecté", value: "logged_user" },
        { name: "Contributeur", value: "contributor" },
        { name: "Modérateur", value: "moderator" },
        { name: "Administrateur projet", value: "admin" },
Timothee P's avatar
Timothee P committed
        errors: [],
        user: {
          name: "",
          value: "",
        },
          name: "Contributeur",
          value: "contributor",
        },
      },

  computed: {
    ...mapGetters(["project"]),

    userOptions: function () {
      return this.projectUsers
        .filter((el) => el.userLevel.value === "logged_user")
        .map((el) => {
          return {
            name: el.user.username,
            value: el.user.id,
          };
        });
    },

    levelOptions: function () {
      return this.options.filter((el) =>
        this.project.moderation ? el : el.value !== "moderator"
      );
    },
Timothee P's avatar
Timothee P committed
      return this.projectUsers
        .filter((el) => el.userLevel.value !== "logged_user")
        .sort((a, b) => {
          if (this.sort.column !== "") {
            if (this.sort.column === "member") {
              const textA = a.user.username.toUpperCase();
              const textB = b.user.username.toUpperCase();
              if (this.sort.ascending) {
                return textA < textB ? -1 : textA > textB ? 1 : 0;
              } else {
                return textA > textB ? -1 : textA < textB ? 1 : 0;
              }
            } else if (this.sort.column === "role") {
              const textA = a.userLevel.name.toUpperCase();
              const textB = b.userLevel.name.toUpperCase();
              if (this.sort.ascending) {
                return textA < textB ? -1 : textA > textB ? 1 : 0;
              } else {
                return textA > textB ? -1 : textA < textB ? 1 : 0;
              }
            }
Timothee P's avatar
Timothee P committed
          } else {
            return 0;
          }
        });
Timothee P's avatar
Timothee P committed
    validateNewMember() {
      this.newMember.errors = [];
      if (!this.newMember.user.value) {
        this.newMember.errors.push("Veuillez compléter ce champ.");
        return false;
      }
      return true;
    },

Timothee P's avatar
Timothee P committed
      if (this.validateNewMember()) {
        //* find user
        const indexOfUser = this.projectUsers.findIndex(
          (el) => el.user.id === this.newMember.user.value
        );
        //* modify its userLever
        this.projectUsers[indexOfUser].userLevel = this.newMember.role;
        //* empty add form
        this.newMember.user = { value: "", name: "" };
      }
    },

    isSortedAsc(column) {
      return this.sort.column === column && this.sort.ascending;
    },
    isSortedDesc(column) {
      return this.sort.column === column && !this.sort.ascending;
    },

    changeSort(column) {
      if (this.sort.column === column) {
        //changer order
        this.sort.ascending = !this.sort.ascending;
      } else {
        this.sort.column = column;
        this.sort.ascending = true;
      }
Timothee P's avatar
Timothee P committed
    saveMembers() {
      const data = this.projectUsers.map((member) => {
        return {
          user: member.user,
          level: {
            display: member.userLevel.name,
            codename: member.userLevel.value,
          },
        };
      });
      axios
        .put(
          `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.project.slug}/utilisateurs/`,
          data
        )
          if (response.status === 200) {
            this.$store.dispatch("GET_USER_LEVEL_PROJECTS"); //* update user status in top right menu
Timothee P's avatar
Timothee P committed
            this.$store.commit("DISPLAY_MESSAGE", "Permissions mises à jour");
          } else {
            this.$store.commit(
              "DISPLAY_MESSAGE",
              "Une erreur s'est produite pendant la mises à jour des permissions"
            );
        .catch((error) => {
          throw error;
        });
Timothee P's avatar
Timothee P committed
    fetchMembers() {
      // todo: move function to a service
      return axios
        .get(
          `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.$route.params.slug}/utilisateurs`
        )
        .then((response) => response.data)
    populateMembers() {
      this.$store.commit(
        "DISPLAY_LOADER",
        "Récupération des membres en cours..."
      );
      this.fetchMembers().then((members) => {
        this.$store.commit("DISCARD_LOADER");
        this.projectUsers = members.map((el) => {
            userLevel: { name: el.level.display, value: el.level.codename },
            ...el,
          };
        });
      });
    },
  },

  created() {
    if (!this.project) {
      this.$store.dispatch("GET_PROJECT_INFO", this.$route.params.slug);
    }
    this.populateMembers();
  },

  destroyed() {
    //* allow user to change page if ever stuck on loader
    this.$store.commit("DISCARD_LOADER");
  },
</script>

<style>
.padding-1 {
  padding: 0 1em;
}

i.icon.sort:not(.down):not(.up) {
  color: rgb(220, 220, 220);
}