<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" :twoParts="true" /> <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> </thead> <tbody> <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> </tbody> </table> <div class="ui divider"></div> <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: [], options: [ { name: "Utilisateur connecté", value: "logged_user" }, { name: "Contributeur", value: "contributor" }, { name: "Modérateur", value: "moderator" }, { name: "Administrateur projet", value: "admin" }, ], newMember: { errors: [], user: { name: "", value: "", }, role: { name: "Contributeur", value: "contributor", }, }, sort: { column: "", ascending: true, }, }; }, computed: { ...mapGetters(["project"]), userOptions: function () { return this.projectUsers .filter((el) => el.userLevel.value === "logged_user") .map((el) => { let name = el.user.first_name || ""; if (el.user.last_name) { name = name + " " + el.user.last_name; } return { name: [name, el.user.username], value: el.user.id, }; }); }, levelOptions: function () { return this.options.filter((el) => this.project.moderation ? el : el.value !== "moderator" ); }, projectMembers() { 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; } } } else { return 0; } }); }, }, methods: { validateNewMember() { this.newMember.errors = []; if (!this.newMember.user.value) { this.newMember.errors.push("Veuillez compléter ce champ."); return false; } return true; }, addMember() { 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; } }, 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 ) .then((response) => { if (response.status === 200) { this.$store.dispatch("GET_USER_LEVEL_PROJECTS"); //* update user status in top right menu 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; }); }, 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) .catch((error) => { throw error; }); }, 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) => { return { 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); } </style>