Newer
Older
Sébastien DA ROCHA
committed
<template>

Timothee P
committed
<div id="project-members">
<h1 class="ui header">
Gérer les membres
</h1>
Sébastien DA ROCHA
committed
<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"
>
</div>
<div class="field">
<Dropdown
:options="levelOptions"
:selected="newMember.role.name"
:selection.sync="newMember.role"
<span class="padding-1">Ajouter</span>
</button>
<h4>Modifier le rôle d'un membre</h4>
<div
id="form-members"
class="ui form"
>
<table
class="ui red table"
>
Sébastien DA ROCHA
committed
<thead>
<tr>
Membre
:class="{
down: isSortedAsc('member'),
up: isSortedDesc('member'),
}"
class="icon sort"
@click="changeSort('member')"
/>
</th>
Niveau d'autorisation
:class="{
down: isSortedAsc('role'),
up: isSortedDesc('role'),
}"
class="icon sort"
@click="changeSort('role')"
/>
</th>
Sébastien DA ROCHA
committed
</tr>
</thead>
<tbody>
<tr
v-for="member in projectMembers"
:key="member.username"
>
{{ member.user.last_name }} {{ member.user.first_name }}<br><em>{{ member.user.username }}</em>
<div class="required field online">
<Dropdown
:options="levelOptions"
:selected="member.userLevel.name"
:selection.sync="member.userLevel"
:search="true"
/>
<button
type="button"

Timothee P
committed
class="ui icon button button-hover-red"
data-tooltip="Retirer ce membre"
</button>
</div>
</td>
</tr>
Sébastien DA ROCHA
committed
</tbody>
</table>
Sébastien DA ROCHA
committed
<button
type="button"
class="ui teal icon button"
@click="saveMembers"
>
<i
class="white save icon"
aria-hidden="true"
/> Enregistrer les changements
Sébastien DA ROCHA
committed
</button>
Sébastien DA ROCHA
committed
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex';
import Dropdown from '@/components/Dropdown.vue';
Sébastien DA ROCHA
committed
export default {
Sébastien DA ROCHA
committed
components: {
Dropdown,
},
data() {
return {
{ 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' },
Sébastien DA ROCHA
committed
],
role: {
name: 'Contributeur',
value: 'contributor',
sort: {
ascending: true,
},
Sébastien DA ROCHA
committed
};
},
...mapState('projects', ['project']),
userOptions: function () {
return this.projectUsers
.filter((el) => el.userLevel.value === 'logged_user')
if (el.user.last_name) {
name: [name, el.user.username],
value: el.user.id,
};
});
},
levelOptions: function () {
return this.options.filter(
(el) =>
(this.project && this.project.moderation ? el : el.value !== 'moderator') &&
.filter((el) => el.userLevel.value !== 'logged_user')
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;
}
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;
}
}
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();
Sébastien DA ROCHA
committed
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.');
changeUserRole(id, role) {
const indexOfUser = this.projectUsers.findIndex(
(el) => el.user.id === id
);
//* modify its userLever
this.projectUsers[indexOfUser].userLevel = role;
},
this.changeUserRole(this.newMember.user.value, this.newMember.role);
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.
*/
// Display a loader to indicate that the update process is ongoing
this.DISPLAY_LOADER('Updating project members...');
// 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
)
Sébastien DA ROCHA
committed
.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 updated successfully', level: 'positive' });
// Display a generic error message if the response status is not 200
this.DISPLAY_MESSAGE({
comment: "An error occurred while updating permissions",
level: 'negative'
});
// Hide the loader regardless of the request result
this.DISCARD_LOADER();
Sébastien DA ROCHA
committed
})
.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
: "An error occurred while updating permissions";
// Display the error message
this.DISPLAY_MESSAGE({
comment: errorMessage,
level: 'negative'
});
// Log the error to the console for debugging
console.error(error);
Sébastien DA ROCHA
committed
},
fetchMembers() {
// todo: move function to a service
Sébastien DA ROCHA
committed
return axios
.get(
`${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.$route.params.slug}/utilisateurs/`
Sébastien DA ROCHA
committed
)
.then((response) => response.data)
Sébastien DA ROCHA
committed
.catch((error) => {
throw error;
});
},
this.DISPLAY_LOADER('Récupération des membres en cours...');
this.fetchMembers().then((members) => {
this.DISCARD_LOADER();
this.projectUsers = members.map((el) => {
Sébastien DA ROCHA
committed
return {
userLevel: { name: el.level.display, value: el.level.codename },
Sébastien DA ROCHA
committed
...el,
};
});
});
},
},
};
</script>
<style>
.padding-1 {
padding: 0 1em;
}
i.icon.sort:not(.down):not(.up) {
color: rgb(220, 220, 220);
}
.online {
display: flex;
}