252 lines
9.3 KiB
Vue
252 lines
9.3 KiB
Vue
<script setup>
|
|
import { computed, ref } from 'vue';
|
|
import { Link, router } from '@inertiajs/vue3';
|
|
import { Modal } from 'bootstrap';
|
|
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
|
|
|
|
const props = defineProps({ projects: Array });
|
|
|
|
const projectStats = computed(() => props.projects.map((project) => {
|
|
const tasks = Array.isArray(project.tasks) ? project.tasks : [];
|
|
const totalTasks = tasks.length;
|
|
const completedTasks = tasks.filter(task => task.status === 'done').length;
|
|
|
|
return {
|
|
project,
|
|
totalTasks,
|
|
completedTasks,
|
|
progress: totalTasks ? Math.round((completedTasks / totalTasks) * 100) : 0,
|
|
};
|
|
}));
|
|
|
|
// Referencia al elemento del DOM para manejar el modal de Bootstrap
|
|
const modalElement = ref(null);
|
|
let modalInstance = null;
|
|
const deleteModalElement = ref(null);
|
|
let deleteModalInstance = null;
|
|
|
|
const name = ref('');
|
|
const description = ref('');
|
|
const isEditMode = ref(false);
|
|
const descripcion = ref('');
|
|
const id = ref(null);
|
|
const projectToDelete = ref(null);
|
|
|
|
const abrirCrear = () => {
|
|
isEditMode.value = false;
|
|
id.value = null;
|
|
name.value = ''; // Limpiar formulario
|
|
descripcion.value = ''; // Limpiar formulario
|
|
mostrarModal();
|
|
};
|
|
|
|
const abrirEditar = (item) => {
|
|
isEditMode.value = true;
|
|
id.value = item.id;
|
|
name.value = item.name;
|
|
descripcion.value = item.description;
|
|
mostrarModal();
|
|
};
|
|
|
|
const eliminarProyecto = (item) => {
|
|
projectToDelete.value = item;
|
|
|
|
if (!deleteModalElement.value) {
|
|
return;
|
|
}
|
|
|
|
if (!deleteModalInstance) {
|
|
deleteModalInstance = new Modal(deleteModalElement.value);
|
|
}
|
|
|
|
deleteModalInstance.show();
|
|
};
|
|
|
|
const confirmarEliminacion = () => {
|
|
if (!projectToDelete.value) {
|
|
return;
|
|
}
|
|
|
|
const projectId = projectToDelete.value.id;
|
|
|
|
deleteModalInstance?.hide();
|
|
router.delete(`/projects/${projectId}`, {
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
projectToDelete.value = null;
|
|
},
|
|
});
|
|
};
|
|
|
|
const mostrarModal = () => {
|
|
if (!modalElement.value) {
|
|
return;
|
|
}
|
|
|
|
if (!modalInstance) {
|
|
modalInstance = new Modal(modalElement.value);
|
|
}
|
|
|
|
modalInstance.show();
|
|
};
|
|
|
|
const ocultarModal = () => {
|
|
modalInstance?.hide();
|
|
};
|
|
|
|
|
|
const guardarRegistro = async () => {
|
|
try {
|
|
if (isEditMode.value) {
|
|
router.put(`/projects/${id.value}`, { name: name.value, description: descripcion.value }, {
|
|
onSuccess: () => {
|
|
name.value = '';
|
|
descripcion.value = '';
|
|
ocultarModal();
|
|
},
|
|
});
|
|
return;
|
|
}
|
|
router.post('/projects', { name: name.value, description: descripcion.value }, {
|
|
onSuccess: () => {
|
|
name.value = '';
|
|
descripcion.value = '';
|
|
ocultarModal();
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error('Error al guardar:', error);
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<AuthenticatedLayout>
|
|
<template #header>
|
|
<h2 class="h4 mb-0">Mis proyectos</h2>
|
|
</template>
|
|
|
|
<div class="container py-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<!-- Button trigger modal -->
|
|
<button type="button" class="btn btn-primary" @click="abrirCrear">
|
|
Crear proyecto
|
|
</button>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
<div v-for="item in projectStats" :key="item.project.id" class="col-sm-6 col-lg-4">
|
|
<div class="project-card card h-100 rounded-4 shadow-sm border-0 overflow-hidden">
|
|
<div class="project-card-top"></div>
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-start gap-2 mb-3">
|
|
<Link :href="`/projects/${item.project.id}`" class="text-decoration-none text-dark flex-grow-1">
|
|
<div class="d-flex align-items-center gap-2 mb-2">
|
|
<span class="project-icon-badge">
|
|
<i class="bi bi-kanban"></i>
|
|
</span>
|
|
<h5 class="card-title mb-0">{{ item.project.name }}</h5>
|
|
</div>
|
|
</Link>
|
|
|
|
<div class="d-flex align-items-center gap-2">
|
|
<button
|
|
type="button"
|
|
class="btn btn-link text-dark text-decoration-none p-0"
|
|
@click.stop="abrirEditar(item.project)"
|
|
aria-label="Editar proyecto"
|
|
>
|
|
<i class="bi bi-pencil-square fs-5"></i>
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
class="btn btn-link text-danger text-decoration-none p-0"
|
|
@click.stop="eliminarProyecto(item.project)"
|
|
aria-label="Eliminar proyecto"
|
|
>
|
|
<i class="bi bi-trash fs-5"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<p class="card-text text-muted mb-3">
|
|
{{ item.project.description || 'Sin descripción' }}
|
|
</p>
|
|
|
|
<div class="d-flex justify-content-between align-items-center small text-muted mb-2">
|
|
<span>{{ item.totalTasks }} tareas</span>
|
|
<span>{{ item.completedTasks }} completas</span>
|
|
</div>
|
|
|
|
<div class="progress" role="progressbar" aria-label="Progreso del proyecto" aria-valuemin="0" aria-valuemax="100">
|
|
<div class="progress-bar" :style="{ width: `${item.progress}%` }"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal para crear y editar proyectos -->
|
|
<div class="modal fade" id="proyectoModal" tabindex="-1" aria-hidden="true" ref="modalElement">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h1 class="modal-title fs-5" id="exampleModalLabel">
|
|
{{ isEditMode ? 'EDITAR PROYECTO' : 'NUEVO PROYECTO' }}
|
|
</h1>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<form @submit.prevent="guardarRegistro">
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label for="name" class="form-label">Nombre</label>
|
|
<input type="text" class="form-control" id="name" v-model="name" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="description" class="form-label">Descripción</label>
|
|
<input type="text" class="form-control" id="description" v-model="description">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="submit" class="btn btn-primary">{{ isEditMode ? 'Actualizar proyecto' : 'Crear proyecto' }}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal para eliminar proyecto -->
|
|
<div
|
|
class="modal fade"
|
|
id="confirmDeleteModal"
|
|
tabindex="-1"
|
|
aria-labelledby="confirmDeleteModalLabel"
|
|
aria-hidden="true"
|
|
ref="deleteModalElement"
|
|
>
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h1 id="confirmDeleteModalLabel" class="modal-title fs-5">Eliminar proyecto</h1>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
¿Seguro que quieres eliminar el proyecto
|
|
<strong>{{ projectToDelete?.name }}</strong>?
|
|
Esta accion eliminara todas las tareas asociadas al proyecto y no se podra deshacer.
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
|
<button type="button" class="btn btn-danger" @click="confirmarEliminacion">
|
|
<i class="bi bi-trash me-1"></i>
|
|
Eliminar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</AuthenticatedLayout>
|
|
</template> |