diff --git a/frontend/static/js/todos.js b/frontend/static/js/todos.js index fb8fc5f..2f8b7c7 100644 --- a/frontend/static/js/todos.js +++ b/frontend/static/js/todos.js @@ -231,12 +231,37 @@ function todosApp() { if (!this.currentTodo || !this.scheduleForm.start_date) return; try { + // 선택한 날짜의 총 시간 체크 + const selectedDate = this.scheduleForm.start_date; + const newMinutes = parseInt(this.scheduleForm.estimated_minutes); + + // 해당 날짜의 기존 할일들 시간 합계 + const existingMinutes = this.todos + .filter(todo => { + if (!todo.start_date || todo.id === this.currentTodo.id) return false; + const todoDate = new Date(todo.start_date).toISOString().slice(0, 10); + return todoDate === selectedDate && (todo.status === 'scheduled' || todo.status === 'active'); + }) + .reduce((sum, todo) => sum + (todo.estimated_minutes || 0), 0); + + const totalMinutes = existingMinutes + newMinutes; + const totalHours = Math.round(totalMinutes / 60 * 10) / 10; + + // 8시간 초과 시 경고 + if (totalMinutes > 480) { // 8시간 = 480분 + const confirm = window.confirm( + `⚠️ 경고: ${selectedDate}의 총 작업시간이 ${totalHours}시간이 됩니다.\n` + + `8시간을 초과했습니다. 계속 진행하시겠습니까?` + ); + if (!confirm) return; + } + // 날짜만 사용하여 해당 날짜의 시작 시간으로 설정 const startDate = new Date(this.scheduleForm.start_date + 'T00:00:00'); const response = await window.api.post(`/todos/${this.currentTodo.id}/schedule`, { start_date: startDate.toISOString(), - estimated_minutes: parseInt(this.scheduleForm.estimated_minutes) + estimated_minutes: newMinutes }); // 할일 업데이트 @@ -280,46 +305,16 @@ function todosApp() { } }, - // 지연 모달 열기 + // 지연 모달 열기 (일정 설정 모달 재사용) openDelayModal(todo) { this.currentTodo = todo; - this.delayForm = { - delayed_until: this.formatDateTimeLocal(new Date(Date.now() + 24 * 60 * 60 * 1000)) // 내일 + this.scheduleForm = { + start_date: this.formatDateLocal(new Date(Date.now() + 24 * 60 * 60 * 1000)), // 내일 + estimated_minutes: todo.estimated_minutes || 30 }; - this.showDelayModal = true; + this.showScheduleModal = true; // 일정 설정 모달 사용 }, - // 지연 모달 닫기 - closeDelayModal() { - this.showDelayModal = false; - this.currentTodo = null; - }, - - // 할일 지연 - async delayTodo() { - if (!this.currentTodo || !this.delayForm.delayed_until) return; - - try { - const response = await window.api.put(`/todos/${this.currentTodo.id}/delay`, { - delayed_until: new Date(this.delayForm.delayed_until).toISOString() - }); - - // 할일 업데이트 - const index = this.todos.findIndex(t => t.id === this.currentTodo.id); - if (index !== -1) { - this.todos[index] = response; - } - - await this.loadStats(); - this.closeDelayModal(); - - console.log('✅ 할일 지연 설정 완료'); - - } catch (error) { - console.error('❌ 할일 지연 실패:', error); - alert('할일 지연 설정 중 오류가 발생했습니다.'); - } - }, // 댓글 모달 열기 async openCommentModal(todo) { @@ -620,105 +615,5 @@ document.addEventListener('DOMContentLoaded', () => { } }); -// 캘린더 컴포넌트 (메인 컴포넌트에 통합) -function calendarComponent() { - return { - currentDate: new Date(), - - init() { - // 부모 컴포넌트 참조 설정 - this.parentApp = this.$el.closest('[x-data*="todosApp"]').__x.$data; - }, - - get calendarDays() { - if (!this.parentApp) return []; - - 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); - const startDate = new Date(firstDay); - startDate.setDate(startDate.getDate() - firstDay.getDay()); - - const days = []; - const today = new Date(); - const todayString = today.toISOString().slice(0, 10); - - for (let i = 0; i < 42; i++) { - const currentDay = new Date(startDate); - currentDay.setDate(startDate.getDate() + i); - - const dateString = currentDay.toISOString().slice(0, 10); - const isCurrentMonth = currentDay.getMonth() === month; - const isToday = dateString === todayString; - - // 해당 날짜의 할일들 찾기 - const dayTodos = this.parentApp.todos.filter(todo => { - if (!todo.start_date) return false; - const todoDate = new Date(todo.start_date).toISOString().slice(0, 10); - return todoDate === dateString && (todo.status === 'scheduled' || todo.status === 'active'); - }); - - days.push({ - day: currentDay.getDate(), - dateString: dateString, - isCurrentMonth: isCurrentMonth, - isToday: isToday, - todos: dayTodos - }); - } - - return days; - }, - - formatMonthYear(date) { - return date.toLocaleDateString('ko-KR', { year: 'numeric', month: 'long' }); - }, - - formatSelectedDate(dateString) { - if (!dateString) return ''; - const date = new Date(dateString); - return date.toLocaleDateString('ko-KR', { month: 'long', day: 'numeric', weekday: 'short' }); - }, - - previousMonth() { - this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, 1); - }, - - nextMonth() { - this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, 1); - }, - - selectDate(dateString) { - if (this.parentApp) { - this.parentApp.scheduleForm.start_date = dateString; - } - }, - - selectDelayDate(dateString) { - if (this.parentApp) { - this.parentApp.delayForm.delayed_until = dateString; - } - }, - - getSelectedDateTodos() { - if (!this.parentApp || !this.parentApp.scheduleForm.start_date) return []; - return this.parentApp.todos.filter(todo => { - if (!todo.start_date) return false; - const todoDate = new Date(todo.start_date).toISOString().slice(0, 10); - return todoDate === this.parentApp.scheduleForm.start_date && (todo.status === 'scheduled' || todo.status === 'active'); - }); - }, - - getDelayDateTodos() { - if (!this.parentApp || !this.parentApp.delayForm.delayed_until) return []; - return this.parentApp.todos.filter(todo => { - if (!todo.start_date) return false; - const todoDate = new Date(todo.start_date).toISOString().slice(0, 10); - return todoDate === this.parentApp.delayForm.delayed_until && (todo.status === 'scheduled' || todo.status === 'active'); - }); - } - }; -} console.log('📋 할일관리 컴포넌트 등록 완료'); diff --git a/frontend/todos.html b/frontend/todos.html index ae3a5a3..b210bc0 100644 --- a/frontend/todos.html +++ b/frontend/todos.html @@ -217,107 +217,6 @@ animation: haptic-pulse 0.1s ease-in-out; } - /* 캘린더 스타일 */ - .calendar-container { - background: white; - border-radius: 12px; - box-shadow: 0 4px 12px rgba(0,0,0,0.1); - } - - .calendar-header { - padding: 16px; - border-bottom: 1px solid #e5e7eb; - display: flex; - justify-content: between; - align-items: center; - } - - .calendar-grid { - display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 1px; - background: #f3f4f6; - padding: 1px; - } - - .calendar-day { - background: white; - min-height: 60px; - padding: 8px 4px; - display: flex; - flex-direction: column; - font-size: 12px; - position: relative; - cursor: pointer; - transition: all 0.2s ease; - } - - .calendar-day:hover { - background: #f9fafb; - } - - .calendar-day.selected { - background: #6366f1; - color: white; - } - - .calendar-day.today { - background: #fef3c7; - font-weight: 600; - } - - .calendar-day.other-month { - color: #9ca3af; - background: #f9fafb; - } - - .calendar-day-number { - font-weight: 500; - margin-bottom: 2px; - } - - .calendar-todos { - flex: 1; - display: flex; - flex-direction: column; - gap: 1px; - } - - .calendar-todo-item { - background: #dbeafe; - color: #1e40af; - padding: 1px 4px; - border-radius: 4px; - font-size: 10px; - font-weight: 500; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .calendar-todo-item.active { - background: #fef3c7; - color: #d97706; - } - - .calendar-todo-item.scheduled { - background: #dbeafe; - color: #1e40af; - } - - .calendar-weekdays { - display: grid; - grid-template-columns: repeat(7, 1fr); - background: #f3f4f6; - font-weight: 600; - font-size: 12px; - color: #6b7280; - } - - .calendar-weekday { - padding: 8px; - text-align: center; - }
@@ -475,10 +374,10 @@ 완료