diff --git a/src/main/resources/static/js/planningdinamico.js b/src/main/resources/static/js/planningdinamico.js new file mode 100644 index 0000000..afa721e --- /dev/null +++ b/src/main/resources/static/js/planningdinamico.js @@ -0,0 +1,275 @@ + class PlanningCalendar { + constructor() { + this.currentDate = new Date(); + this.tasks = this.loadTasks(); + this.draggedTask = null; + this.init(); + } + + init() { + this.setupEventListeners(); + this.render(); + } + + setupEventListeners() { + document.getElementById('prevMonth').addEventListener('click', () => this.previousMonth()); + document.getElementById('nextMonth').addEventListener('click', () => this.nextMonth()); + document.getElementById('addTaskForm').addEventListener('submit', (e) => this.addTask(e)); + document.getElementById('resetBtn').addEventListener('click', () => this.resetAll()); + } + + previousMonth() { + this.currentDate.setMonth(this.currentDate.getMonth() - 1); + this.render(); + } + + nextMonth() { + this.currentDate.setMonth(this.currentDate.getMonth() + 1); + this.render(); + } + + render() { + this.renderMonthTitle(); + this.renderCalendar(); + } + + renderMonthTitle() { + const options = { month: 'long', year: 'numeric' }; + const title = this.currentDate.toLocaleDateString('es-ES', options); + document.getElementById('monthTitle').textContent = title.charAt(0).toUpperCase() + title.slice(1); + } + + renderCalendar() { + const grid = document.getElementById('calendarGrid'); + grid.innerHTML = ''; + + // Encabezados de días + const dayNames = ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom']; + dayNames.forEach(day => { + const header = document.createElement('div'); + header.className = 'day-header'; + header.textContent = day; + grid.appendChild(header); + }); + + // Obtener primer y último día del mes + const year = this.currentDate.getFullYear(); + const month = this.currentDate.getMonth(); + const firstDay = new Date(year, month, 1); + const lastDay = new Date(year, month + 1, 0); + + // Ajustar para que lunes sea 0 + let dayOfWeek = firstDay.getDay() - 1; + if (dayOfWeek === -1) dayOfWeek = 6; + + // Días del mes anterior + const prevMonthLastDay = new Date(year, month, 0).getDate(); + for (let i = dayOfWeek - 1; i >= 0; i--) { + const cell = this.createDayCell(prevMonthLastDay - i, 'other-month'); + grid.appendChild(cell); + } + + // Días del mes actual + for (let day = 1; day <= lastDay.getDate(); day++) { + const date = new Date(year, month, day); + const cell = this.createDayCell(day, '', date); + grid.appendChild(cell); + } + + // Días del próximo mes + const remainingCells = grid.children.length - 7; // 7 headers + const totalCells = Math.ceil(remainingCells / 7) * 7; + for (let day = 1; day <= totalCells - remainingCells; day++) { + const cell = this.createDayCell(day, 'other-month'); + grid.appendChild(cell); + } + } + + createDayCell(day, extraClass, date = null) { + const cell = document.createElement('div'); + cell.className = `day-cell ${extraClass}`; + + if (extraClass === 'other-month') { + cell.classList.add('empty'); + } else { + // Es día del mes actual + const isToday = date && this.isToday(date); + const isWeekend = date && (date.getDay() === 0 || date.getDay() === 6); + + if (isToday) cell.classList.add('today'); + if (isWeekend) cell.classList.add('weekend'); + + const dayNumber = document.createElement('div'); + dayNumber.className = 'day-number' + (isWeekend ? ' weekend' : ''); + dayNumber.textContent = day; + cell.appendChild(dayNumber); + + const dateKey = this.getDateKey(date); + const dayTasks = this.tasks[dateKey] || []; + + const tasksList = document.createElement('div'); + tasksList.className = 'tasks-list'; + + dayTasks.forEach(task => { + const taskEl = this.createTaskElement(task, dateKey); + tasksList.appendChild(taskEl); + }); + + cell.appendChild(tasksList); + + // Agregar zona de drop + const dropZone = document.createElement('div'); + dropZone.className = 'drop-zone'; + cell.appendChild(dropZone); + + // Event listeners para drag & drop + cell.addEventListener('dragover', (e) => this.handleDragOver(e)); + cell.addEventListener('drop', (e) => this.handleDrop(e, dateKey)); + cell.addEventListener('dragleave', (e) => this.handleDragLeave(e)); + } + + return cell; + } + + createTaskElement(task, dateKey) { + const taskEl = document.createElement('div'); + taskEl.className = 'task-item'; + taskEl.draggable = true; + taskEl.textContent = task.text; + + const deleteBtn = document.createElement('button'); + deleteBtn.type = 'button'; + deleteBtn.className = 'task-delete-btn'; + deleteBtn.textContent = '✕'; + deleteBtn.addEventListener('click', (e) => { + e.stopPropagation(); + this.deleteTask(task.id, dateKey); + }); + + taskEl.appendChild(deleteBtn); + + taskEl.addEventListener('dragstart', (e) => this.handleDragStart(e, task.id, dateKey)); + taskEl.addEventListener('dragend', (e) => this.handleDragEnd(e)); + + return taskEl; + } + + handleDragStart(e, taskId, fromDateKey) { + this.draggedTask = { taskId, fromDateKey }; + e.target.classList.add('dragging'); + e.dataTransfer.effectAllowed = 'move'; + } + + handleDragEnd(e) { + e.target.classList.remove('dragging'); + } + + handleDragOver(e) { + e.preventDefault(); + e.dataTransfer.dropEffect = 'move'; + e.target.closest('.day-cell').classList.add('drag-over'); + } + + handleDragLeave(e) { + e.target.closest('.day-cell').classList.remove('drag-over'); + } + + handleDrop(e, toDateKey) { + e.preventDefault(); + e.target.closest('.day-cell').classList.remove('drag-over'); + + if (!this.draggedTask) return; + + const { taskId, fromDateKey } = this.draggedTask; + this.moveTask(taskId, fromDateKey, toDateKey); + this.draggedTask = null; + } + + addTask(e) { + e.preventDefault(); + const input = document.getElementById('taskInput'); + const text = input.value.trim(); + + if (!text) return; + + const today = this.getDateKey(new Date()); + const task = { + id: Date.now(), + text: text, + date: today + }; + + if (!this.tasks[today]) { + this.tasks[today] = []; + } + + this.tasks[today].push(task); + this.saveTasks(); + input.value = ''; + this.render(); + } + + deleteTask(taskId, dateKey) { + if (this.tasks[dateKey]) { + this.tasks[dateKey] = this.tasks[dateKey].filter(t => t.id !== taskId); + if (this.tasks[dateKey].length === 0) { + delete this.tasks[dateKey]; + } + this.saveTasks(); + this.render(); + } + } + + moveTask(taskId, fromDateKey, toDateKey) { + if (!this.tasks[fromDateKey]) return; + + const taskIndex = this.tasks[fromDateKey].findIndex(t => t.id === taskId); + if (taskIndex === -1) return; + + const task = this.tasks[fromDateKey][taskIndex]; + this.tasks[fromDateKey].splice(taskIndex, 1); + + if (this.tasks[fromDateKey].length === 0) { + delete this.tasks[fromDateKey]; + } + + if (!this.tasks[toDateKey]) { + this.tasks[toDateKey] = []; + } + + this.tasks[toDateKey].push(task); + this.saveTasks(); + this.render(); + } + + getDateKey(date) { + return date.toISOString().split('T')[0]; + } + + isToday(date) { + const today = new Date(); + return date.toDateString() === today.toDateString(); + } + + saveTasks() { + localStorage.setItem('planningTasks', JSON.stringify(this.tasks)); + } + + loadTasks() { + const stored = localStorage.getItem('planningTasks'); + return stored ? JSON.parse(stored) : {}; + } + + resetAll() { + if (confirm('¿Estás seguro de que deseas limpiar todas las tareas?')) { + this.tasks = {}; + this.saveTasks(); + this.render(); + } + } + } + + // Inicializar cuando el DOM esté listo + document.addEventListener('DOMContentLoaded', () => { + new PlanningCalendar(); + }); \ No newline at end of file diff --git a/src/main/resources/templates/planning.html b/src/main/resources/templates/planning.html index 86a481f..fdf8888 100644 --- a/src/main/resources/templates/planning.html +++ b/src/main/resources/templates/planning.html @@ -5,6 +5,7 @@ Planning TAI — Agenda + @@ -60,286 +61,6 @@
- + \ No newline at end of file