feat(UserManagement): añadida funcionalidad activar/desactivar usuario con modal…

feat(UserManagement): añadida funcionalidad activar/desactivar usuario con modal y mejora en paginación
parent 86fd9473
Showing with 90 additions and 20 deletions
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<div> <div>
<label> <label>
Mostrar Mostrar
<select v-model="itemsPerPage" class="form-select form-select-sm d-inline-block w-auto mx-1"> <select v-model.number="userStore.pageSize" class="form-select form-select-sm d-inline-block w-auto mx-1">
<option value="5">5</option> <option value="5">5</option>
<option value="10">10</option> <option value="10">10</option>
<option value="15">15</option> <option value="15">15</option>
...@@ -71,12 +71,18 @@ ...@@ -71,12 +71,18 @@
<td>{{ user.deletedAt ? user.deletedAt : '-' }}</td> <td>{{ user.deletedAt ? user.deletedAt : '-' }}</td>
<td> <td>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<button v-if="!user.deletedAt" @click="deactivateUser(user.id)" class="btn btn-outline-danger btn-sm" title="Desactivar"> <button id="activator-button" v-if="!user.deletedAt" @click="showDeactivateModal(user.id)" class="btn btn-outline-danger btn-sm" title="Desactivar">
<i class="bi bi-person-slash"></i> <i class="bi bi-person-slash"></i>
</button> </button>
<button v-else @click="reactivateUser(user.id)" class="btn btn-outline-success btn-sm" title="Reactivar"> <button v-else @click="showReactivateModal(user.id)" class="btn btn-outline-success btn-sm" title="Reactivar">
<i class="bi bi-person-plus"></i> <i class="bi bi-person-plus"></i>
</button> </button>
<button v-if="user.role != 'ADMIN' && !user.deletedAt" @click="changeUserRole(user.id, 'ADMIN')" class="btn btn-outline-primary btn-sm" title="Hacer admin">
<i class="bi bi-person-fill-gear"></i>
</button>
<button v-if="user.role == 'ADMIN'" @click="changeUserRole(user.id, 'USER')" class="btn btn-outline-info btn-sm" title="Quitar admin">
<i class="bi bi-person-fill"></i>
</button>
</div> </div>
</td> </td>
</tr> </tr>
...@@ -85,7 +91,9 @@ ...@@ -85,7 +91,9 @@
</div> </div>
<div class="d-flex justify-content-between align-items-center mt-3"> <div class="d-flex justify-content-between align-items-center mt-3">
<div class="small text-muted">Mostrando {{ startIndex }} a {{ endIndex }} de {{ userStore.totalElements }} usuarios</div> <div class="small text-muted">
{{ displayedRange }}
</div>
<nav aria-label="Page navigation"> <nav aria-label="Page navigation">
<ul class="pagination pagination-sm mb-0 pagination-custom"> <ul class="pagination pagination-sm mb-0 pagination-custom">
<li class="page-item" :class="{ disabled: userStore.currentPage === 0 }"> <li class="page-item" :class="{ disabled: userStore.currentPage === 0 }">
...@@ -105,20 +113,27 @@ ...@@ -105,20 +113,27 @@
</div> </div>
</div> </div>
</div> </div>
<ConfirmModal
:modalId="'userActionModal'"
:message="modalMessage"
@confirmed="handleConfirmation"
/>
</template> </template>
<script setup> <script setup>
import { useUserStore } from '@/stores/userStore'; import { useUserStore } from '@/stores/userStore';
import { ref, onMounted, watch, computed } from 'vue'; import { ref, onMounted, watch, computed } from 'vue';
import ConfirmModal from '@/components/ConfirmModal.vue';
import * as bootstrap from 'bootstrap';
const userStore = useUserStore(); const userStore = useUserStore();
const errorMsg = ref(null); const errorMsg = ref(null);
const itemsPerPage = ref(userStore.pageSize);
onMounted(async () => { onMounted(async () => {
errorMsg.value = null; errorMsg.value = null;
try { try {
await userStore.readAll(); await userStore.readAll(userStore.currentPage, userStore.pageSize, userStore.sortBy, userStore.sortDirection);
} catch (error) { } catch (error) {
errorMsg.value = 'No se pudieron cargar los usuarios. Inténtalo de nuevo más tarde.'; errorMsg.value = 'No se pudieron cargar los usuarios. Inténtalo de nuevo más tarde.';
} }
...@@ -126,33 +141,88 @@ onMounted(async () => { ...@@ -126,33 +141,88 @@ onMounted(async () => {
// Cambip de página // Cambip de página
const goToPage = (page) => { const goToPage = (page) => {
userStore.readAll(page, itemsPerPage.value, userStore.sortBy, userStore.sortDirection); userStore.readAll(page, userStore.pageSize, userStore.sortBy, userStore.sortDirection);
}; };
// Cambio de ordenación // Cambio de ordenación
const sortByColumn = (column) => { const sortByColumn = (column) => {
// Si es la misma columna, invierte la dirección
const newSortDirection = userStore.sortBy === column && userStore.sortDirection === 'asc' ? 'desc' : 'asc'; const newSortDirection = userStore.sortBy === column && userStore.sortDirection === 'asc' ? 'desc' : 'asc';
userStore.readAll(0, itemsPerPage.value, column, newSortDirection) userStore.readAll(0, userStore.pageSize, column, newSortDirection)
}; };
// Cambios en itemsPerPage // Cambios en itemsPerPage
watch(itemsPerPage, (newSize) => { watch(() => userStore.pageSize, (newSize) => {
userStore.fetchUsers(0, newSize, userStore.sortBy, userStore.sortDirection); userStore.readAll(0, newSize, userStore.sortBy, userStore.sortDirection);
}); });
// Propiedad computada para el índice de inicio // Propiedad computada para mostrar el rango de usuarios
const startIndex = computed(() => { const displayedRange = computed(() => {
if (userStore.totalElements === 0) return 0; const totalUsers = userStore.totalElements;
return (userStore.currentPage * userStore.pageSize) + 1; const usersOnPage = userStore.users.length;
});
if (totalUsers === 0 || usersOnPage === 0) {
return 'No hay usuarios para mostrar.';
}
// Propiedad computada para el índice de fin const currentPage = userStore.currentPage;
const endIndex = computed(() => { const pageSize = userStore.pageSize;
const end = (userStore.currentPage + 1) * userStore.pageSize; // Aseguramos que los valores son números antes de la operación
return Math.min(end, userStore.totalElements); const start = Number(currentPage) * Number(pageSize) + 1;
const end = Math.min(start + usersOnPage - 1, totalUsers);
return `Mostrando ${start} a ${end} de ${totalUsers} usuarios`;
}); });
// Variables para el modal
const userToChangeId = ref(null);
const isDeactivating = ref(false);
const modalMessage = ref('');
let modalInstance = null;
// Funciones para los botones de la tabla
const showDeactivateModal = (userId) => {
userToChangeId.value = userId;
isDeactivating.value = true;
modalMessage.value = '¿Estás seguro de que quieres desactivar este usuario?';
if (!modalInstance) {
modalInstance = new bootstrap.Modal(document.getElementById('userActionModal'));
}
modalInstance.show();
};
const showReactivateModal = (userId) => {
userToChangeId.value = userId;
isDeactivating.value = false;
modalMessage.value = '¿Estás seguro de que quieres reactivar este usuario?';
if (!modalInstance) {
modalInstance = new bootstrap.Modal(document.getElementById('userActionModal'));
}
modalInstance.show();
};
// Función que se ejecuta al recibir la confirmación del modal
const handleConfirmation = async () => {
if (modalInstance) {
modalInstance.hide();
}
errorMsg.value = null;
try {
if (isDeactivating.value) {
await userStore.deactivate(userToChangeId.value);
} else {
await userStore.activate(userToChangeId.value);
}
// Recarga los datos para que la tabla refleje el cambio
await userStore.readAll(userStore.currentPage, userStore.pageSize, userStore.sortBy, userStore.sortDirection);
} catch (error) {
errorMsg.value = `Error al ${isDeactivating.value ? 'desactivar' : 'activar'} el usuario.`;
}
};
</script> </script>
<style scoped> <style scoped>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment