Something went wrong on our end
-
Timothee P authoredTimothee P authored
ProjectMembers.vue 10.61 KiB
<template>
<div id="project-members">
<h1 class="ui header">
Gérer les membres
</h1>
<h4>Ajouter un membre</h4>
<div
id="form-feature-edit"
class="ui form"
name="add-member"
>
<div class="two fields">
<div class="field">
<Dropdown
:options="userOptions"
:selected="newMember.user.name"
:selection.sync="newMember.user"
:search="true"
:clearable="true"
/>
<ul
id="errorlist"
class="errorlist"
>
<li
v-for="error in newMember.errors"
:key="error"
>
{{ error }}
</li>
</ul>
</div>
<div class="field">
<Dropdown
:options="levelOptions"
:selected="newMember.role.name"
:selection.sync="newMember.role"
/>
</div>
</div>
<button
type="button"
class="ui green icon button"
:disabled="!newMember.user.name"
@click="addMember"
>
<i
class="white add icon"
aria-hidden="true"
/>
<span class="padding-1">Ajouter</span>
</button>
</div>
<h4>Modifier le rôle d'un membre</h4>
<div
id="form-members"
class="ui form"
>
<table
class="ui red table"
aria-describedby="Table des membres du projet"
>
<thead>
<tr>
<th scope="col">
Membre
<i
:class="{
down: isSortedAsc('member'),
up: isSortedDesc('member'),
}"
class="icon sort"
aria-hidden="true"
@click="changeSort('member')"
/>
</th>
<th scope="col">
Niveau d'autorisation
<i
:class="{
down: isSortedAsc('role'),
up: isSortedDesc('role'),
}"
class="icon sort"
aria-hidden="true"
@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><em>{{ member.user.username }}</em>
</td>
<td>
<div class="required field online">
<Dropdown
:options="levelOptions"
:selected="member.userLevel.name"
:selection.sync="member.userLevel"
:search="true"
/>
<button
type="button"
class="ui icon button button-hover-red"
data-tooltip="Retirer ce membre"
@click="removeMember(member)"
>
<i
class="times icon"
aria-hidden="true"
/>
</button>
</div>
</td>
</tr>
</tbody>
</table>
<div class="ui divider" />
<button
type="button"
class="ui teal icon button"
@click="saveMembers"
>
<i
class="white save icon"
aria-hidden="true"
/> Enregistrer les changements
</button>
</div>
</div>
</template>
<script>
import axios from '@/axios-client.js';
import { mapMutations, mapState } from 'vuex';
import Dropdown from '@/components/Dropdown.vue';
import { formatUserOption } from '@/utils';
export default {
name: 'ProjectMembers',
components: {
Dropdown,
},
data() {
return {
projectUsers: [],
options: [
{ name: 'Utilisateur connecté', value: 'logged_user' },
{ name: 'Contributeur', value: 'contributor' },
{ name: 'Super Contributeur', value: 'super_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: {
...mapState('projects', ['project']),
userOptions: function () {
return this.projectUsers
.filter((el) => el.userLevel.value === 'logged_user')
.map((el) => formatUserOption(el.user)); // Format user data to fit dropdown option structure
},
levelOptions: function () {
return this.options.filter(
(el) =>
(this.project && this.project.moderation ? el : el.value !== 'moderator') &&
el.value !== 'logged_user'
);
},
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;
}
});
},
},
created() {
if (!this.project) {
this.$store.dispatch('projects/GET_PROJECT', this.$route.params.slug);
this.$store.dispatch('projects/GET_PROJECT_INFO', this.$route.params.slug);
}
this.populateMembers();
},
destroyed() {
//* allow user to change page if ever stuck on loader
this.DISCARD_LOADER();
},
methods: {
...mapMutations([
'DISPLAY_MESSAGE',
'DISPLAY_LOADER',
'DISCARD_LOADER'
]),
validateNewMember() {
this.newMember.errors = [];
if (!this.newMember.user.value) {
this.newMember.errors.push('Veuillez compléter ce champ.');
return false;
}
return true;
},
changeUserRole(id, role) {
const indexOfUser = this.projectUsers.findIndex(
(el) => el.user.id === id
);
//* modify its userLever
this.projectUsers[indexOfUser].userLevel = role;
},
addMember() {
if (this.validateNewMember()) {
this.changeUserRole(this.newMember.user.value, 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;
}
},
removeMember(member) {
this.changeUserRole(member.user.id, {
name: 'Utilisateur connecté',
value: 'logged_user',
});
},
/**
* Saves the updated members and their roles for a project.
* Displays a loader while the update is in progress and provides feedback upon completion or error.
*/
saveMembers() {
// Display a loader to indicate that the update process is ongoing
this.DISPLAY_LOADER('Mise à jour des membres du projet en cours ...');
// Prepare the data to be sent in the API request
const data = this.projectUsers.map((member) => {
return {
user: member.user,
level: {
display: member.userLevel.name, // Display name of the user level
codename: member.userLevel.value, // Codename of the user level
},
};
});
// Make an API request to update the project members
axios
.put(
`${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.project.slug}/utilisateurs/`,
data
)
.then((response) => {
// Check if the response status is 200 (OK)
if (response.status === 200) {
// Dispatch an action to update the user status in the top right menu
this.$store.dispatch('GET_USER_LEVEL_PROJECTS');
// Display a positive message indicating success
this.DISPLAY_MESSAGE({ comment: 'Permissions mises à jour avec succès', level: 'positive' });
} else {
// Display a generic error message if the response status is not 200
this.DISPLAY_MESSAGE({
comment: "Une erreur s'est produite pendant la mises à jour des permissions",
level: 'negative'
});
}
// Hide the loader regardless of the request result
this.DISCARD_LOADER();
})
.catch((error) => {
// Hide the loader if an error occurs
this.DISCARD_LOADER();
// Determine the error message to display
const errorMessage = error.response && error.response.data && error.response.data.error
? error.response.data.error
: "Une erreur s'est produite pendant la mises à jour des permissions";
// Display the error message
this.DISPLAY_MESSAGE({
comment: errorMessage,
level: 'negative'
});
// Log the error to the console for debugging
console.error(error);
});
},
populateMembers() {
this.DISPLAY_LOADER('Récupération des membres en cours...');
this.$store.dispatch('projects/GET_PROJECT_USERS', this.$route.params.slug).then((members) => {
this.DISCARD_LOADER();
this.projectUsers = members.map((el) => {
return {
userLevel: { name: el.level.display, value: el.level.codename },
...el,
};
});
});
},
},
};
</script>
<style>
.padding-1 {
padding: 0 1em;
}
i.icon.sort:not(.down):not(.up) {
color: rgb(220, 220, 220);
}
.online {
display: flex;
}
</style>