Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Edition membres projets #57

Merged
merged 3 commits into from
May 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 170 additions & 15 deletions components/projects/UserTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
<DataTable
:value="modelValue"
removable-sort
resizable-columns
table-style="min-width: 50rem"
:rows="5"
paginator
>
<template #header>
<div class="flex justify-content-between align-items-center pr-5">
Expand All @@ -13,12 +16,12 @@
class="my-2"
severity="info"
size="large"
@click="setDialogVisible(true)"
@click="setAddDialogVisible(true)"
></Button>
</div>
</template>

<Column field="user" sortable header="Nom">
<Column field="user" sortable header="Nom" style="min-width: 16rem">
<template #body="slotProps">
<div class="flex align-items-center gap-4">
<img
Expand All @@ -29,18 +32,40 @@
</div>
</template>
</Column>
<Column field="role" sortable header="Role">

<Column field="role" sortable header="Role" style="min-width: 12rem">
<template #body="slotProps">
<span>{{
roles.find(({ role }) => role === slotProps.data.role)?.name
}}</span>
</template>
</Column>

<Column style="min-width: 8rem; width: 10rem">
<template #body="slotProps">
<Button
v-if="slotProps.data.role != 'OWNER'"
icon="pi pi-pencil"
rounded
class="mr-2"
severity="info"
@click="(event) => askUpdateMember(event, slotProps.data)"
></Button>
<Button
v-if="slotProps.data.role != 'OWNER'"
icon="pi pi-trash"
rounded
severity="danger"
@click="(event) => askDeleteMember(event, slotProps.data)"
></Button>
</template>
</Column>
</DataTable>
</div>

<!-- Dialog displayed when adding a member -->
<Dialog
v-model:visible="isDialogVisible"
v-model:visible="isAddDialogVisible"
modal
header="Ajouter un membre au projet"
class="w-5"
Expand Down Expand Up @@ -82,16 +107,74 @@
label="Annuler"
severity="danger"
class="w-4"
@click="setDialogVisible(false)"
@click="setAddDialogVisible(false)"
></Button>
</div>
</div>
</Dialog>

<!-- Overlay displayed when updating a member's role -->
<OverlayPanel ref="updateOverlay">
<div>
<div class="field text-center w-100">
<SelectButton
v-model="selectedRole"
:options="roles.slice(1)"
option-label="name"
class="w-full m-auto"
unselectable
>
</SelectButton>
</div>

<div class="flex justify-content-center align-items-center">
<Button
icon="pi pi-check"
severity="success"
class="mr-4"
rounded
@click="updateMember()"
></Button>
<Button
icon="pi pi-times"
severity="danger"
rounded
@click="updateOverlay.hide()"
></Button>
</div>
</div>
</OverlayPanel>

<!-- Overlay displayed when deleting a member -->
<OverlayPanel ref="deleteOverlay">
<div>
<div class="text-center w-100">
<p class="strong">Veuillez-confirmer pour supprimer.</p>
</div>

<div class="flex justify-content-center align-items-center">
<Button
icon="pi pi-check"
severity="success"
class="mr-4"
rounded
@click="deleteMember()"
></Button>
<Button
icon="pi pi-times"
severity="danger"
rounded
@click="deleteOverlay.hide()"
></Button>
</div>
</div>
</OverlayPanel>
</template>

<script lang="ts" setup>
const auth = useAuth();

// Setup props and events
const props = defineProps<{
modelValue: Exclude<
Awaited<ReturnType<typeof getProject>>,
Expand All @@ -102,12 +185,12 @@ const props = defineProps<{

const emit = defineEmits<{
(event: "update:modelValue", payload: typeof props.modelValue): void;
(event: "memberAdded", payload: typeof props.modelValue[number]): void;
(event: "memberAdded", payload: (typeof props.modelValue)[number]): void;
(event: "memberEdited", payload: (typeof props.modelValue)[number]): void;
(event: "memberDeleted", payload: (typeof props.modelValue)[number]): void;
}>();

// Add user dialog
const selectedUser: Ref<any | undefined> = ref();

// Init variables
const roles: Array<{
name: string;
role: (typeof props.modelValue)[number]["role"];
Expand All @@ -116,32 +199,52 @@ const roles: Array<{
{ name: "Développeur", role: "DEVELOPER" },
{ name: "Gestionnaire", role: "MANAGER" },
];

const selectedUser: Ref<
Exclude<Awaited<ReturnType<typeof getUsers>>, undefined>[number] | undefined
> = ref();
const selectedMember: Ref<
| Exclude<
Awaited<ReturnType<typeof getProject>>,
undefined
>["members"][number]
| undefined
> = ref();
const selectedRole = ref(roles[1]);
const isDialogVisible = ref(false);

const updateOverlay = ref();
const deleteOverlay = ref();
const isAddDialogVisible = ref(false);

// Set the user to add
const setSelectedUser = (user: any) => {
if (typeof user !== "string" && user !== null) {
selectedUser.value = user;
}
};

const setDialogVisible = (value: boolean) => {
isDialogVisible.value = value;
// Control the add member dialog
const setAddDialogVisible = (value: boolean) => {
isAddDialogVisible.value = value;
if (!value) {
selectedRole.value = roles[1];
}
};

// Add a new member to the project
const addMember = async () => {
if (!selectedRole.value || !selectedUser.value) return;

// Check if the member already exists
if (
props.modelValue?.find(
(member) => member.user.name === selectedUser.value?.name
)
)
) {
return;
}

// Create and push the new member
const newMember = {
id: "",
role: selectedRole.value.role,
Expand All @@ -150,12 +253,64 @@ const addMember = async () => {
name: selectedUser.value.name,
image: selectedUser.value.image,
},
}
};

props.modelValue?.push(newMember);
emit("memberAdded", newMember);
setAddDialogVisible(false);
};

// Toggle the updateOverlay (and set the selected member and its current role)
const askUpdateMember = (
event: any,
member: Exclude<
Awaited<ReturnType<typeof getProject>>,
undefined
>["members"][number]
) => {
selectedMember.value = member;

updateOverlay.value.toggle(event);
if (selectedMember.value !== undefined) {
selectedRole.value =
roles.find(({ role }) => role === selectedMember.value?.role) ?? roles[1];
}
};

// Update the role of the selected member
const updateMember = async () => {
if (!selectedRole.value || !selectedMember.value) return;

const currentMemberIndex = props.modelValue.indexOf(selectedMember.value);
if (currentMemberIndex === -1) return;

props.modelValue[currentMemberIndex].role = selectedRole.value.role;
emit("memberEdited", selectedMember.value);
updateOverlay.value.hide();
};

// Toggle the deleteOverlay (asks if the user really wants to delete the selectedMember)
const askDeleteMember = (
event: any,
member: Exclude<
Awaited<ReturnType<typeof getProject>>,
undefined
>["members"][number]
) => {
selectedMember.value = member;
deleteOverlay.value.toggle(event);
};

// Delete the selected member
const deleteMember = async () => {
if (!selectedMember.value) return;

const currentMemberIndex = props.modelValue.indexOf(selectedMember.value);
if (currentMemberIndex === -1) return;

setDialogVisible(false);
props.modelValue.splice(currentMemberIndex, 1);
emit("memberDeleted", selectedMember.value);
deleteOverlay.value.hide();
};
</script>

Expand Down
22 changes: 22 additions & 0 deletions pages/projects/update/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
:model-value="members ?? []"
:users-available="userList"
@member-added="addMember"
@member-edited="updateMember"
@member-deleted="deleteMember"
></ProjectsUserTable>
</div>

Expand Down Expand Up @@ -112,6 +114,8 @@ const members: Ref<
| undefined
> = ref();
const newMembers: typeof members = ref([]);
const updatedMembers: typeof members = ref([]);
const deletedMembers: typeof members = ref([]);

// Fetch data
const loaded = ref(false);
Expand Down Expand Up @@ -153,6 +157,22 @@ const addMember = (
newMembers.value?.push(member);
};

// Tracl members to update
const updateMember = (
member: Exclude<(typeof members)["value"], undefined>[number]
) => {
updatedMembers.value?.push(member);
};

// Track members to delete
const deleteMember = (
member: Exclude<(typeof members)["value"], undefined>[number]
) => {
deletedMembers.value?.push(member);
};

// Track members to delete

// Form validation
const nameErrorMessage = ref("");
const membersErrorMessage = ref("");
Expand Down Expand Up @@ -196,6 +216,8 @@ const updateThisProject = async () => {
userId: member.user.id,
role: member.role,
})) ?? [],
updateMembers: updatedMembers.value,
deleteMembers: deletedMembers.value,
});
};

Expand Down
2 changes: 2 additions & 0 deletions plugins/primevue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import DataTable from "primevue/datatable";
import Column from "primevue/column";
import Dialog from "primevue/dialog";
import Listbox from "primevue/listbox";
import OverlayPanel from "primevue/overlaypanel";

import ToastService from "primevue/toastservice";
import Toast from "primevue/toast";
Expand All @@ -35,4 +36,5 @@ export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component("Column", Column);
nuxtApp.vueApp.component("Dialog", Dialog);
nuxtApp.vueApp.component("Listbox", Listbox);
nuxtApp.vueApp.component("OverlayPanel", OverlayPanel);
});
Loading