From 9af2a205b323a997428f98869f90fa5be1e0b870 Mon Sep 17 00:00:00 2001 From: Creighton Date: Sat, 21 Sep 2024 19:34:33 -0500 Subject: [PATCH 1/9] feat: allow editing completion date Signed-off-by: Creighton --- src/models/task.js | 26 +++++++++++++++++++----- src/store/tasks.js | 34 +++++++++++++++++++++++++++++++ src/views/AppSidebar.vue | 44 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/models/task.js b/src/models/task.js index bc5a20da9..f0945ff1c 100644 --- a/src/models/task.js +++ b/src/models/task.js @@ -306,12 +306,14 @@ export default class Task { } } - setCompleted(completed) { + setCompleted(completed, completedDate = null) { if (completed) { - const now = ICAL.Time.fromJSDate(new Date(), true) - this.vtodo.updatePropertyWithValue('completed', now) - this._completedDate = now - this._completedDateMoment = moment(now, 'YYYYMMDDTHHmmssZ') + if (completedDate === null) { + completedDate = ICAL.Time.fromJSDate(new Date(), true) + } + this.vtodo.updatePropertyWithValue('completed', completedDate) + this._completedDate = completedDate + this._completedDateMoment = moment(completedDate, 'YYYYMMDDTHHmmssZ') } else { this.vtodo.removeProperty('completed') this._completedDate = null @@ -325,6 +327,20 @@ export default class Task { return this._completedDate } + set completedDate(completedDate) { + if (completedDate) { + this.setCompleted(true, completedDate) + this.setComplete(100) + this.setStatus('COMPLETED') + } else { + this.setCompleted(false) + if (this.complete === 100) { + this.setComplete(99) + this.setStatus('IN-PROCESS') + } + } + } + get completedDateMoment() { return this._completedDateMoment.clone() } diff --git a/src/store/tasks.js b/src/store/tasks.js index 15603a632..daf673954 100644 --- a/src/store/tasks.js +++ b/src/store/tasks.js @@ -605,6 +605,29 @@ const mutations = { } }, + /** + * Sets the completed date of a task + * + * @param {object} state The store data + * @param {object} data Destructuring object + * @param {Task} data.task The task + * @param {moment|null} data.completedDate The completed date moment + */ + setCompletedDate(state, { task, completedDate }) { + if (completedDate !== null) { + // Check that the completed date is in the past. + let now = moment(ICAL.Time.fromJSDate(new Date(), true), 'YYYYMMDDTHHmmssZ') + if (completedDate.isAfter(now)) { + showError(t('tasks', 'Completion date must be in the past.')) + return + } + // Convert completed date to ICALTime first + completedDate = momentToICALTime(completedDate, false) + } + // Set the completed date + task.completedDate = completedDate + }, + /** * Toggles if the start and due dates of a task are all day * @@ -1318,6 +1341,17 @@ const actions = { context.dispatch('updateTask', task) }, + /** + * Sets the completed date of a task + * + * @param {object} context The store context + * @param {Task} task The task to update + */ + async setCompletedDate(context, { task, completedDate }) { + context.commit('setCompletedDate', { task, completedDate }) + context.dispatch('updateTask', task) + }, + /** * Sets the start or due date to the given day * diff --git a/src/views/AppSidebar.vue b/src/views/AppSidebar.vue index 5fe9bc0b7..cd8d4bcbf 100644 --- a/src/views/AppSidebar.vue +++ b/src/views/AppSidebar.vue @@ -60,6 +60,18 @@ License along with this library. If not, see . + + + Date: Sun, 22 Sep 2024 12:19:30 -0500 Subject: [PATCH 2/9] lint fixes Signed-off-by: Creighton --- src/store/tasks.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/store/tasks.js b/src/store/tasks.js index daf673954..379041bdf 100644 --- a/src/store/tasks.js +++ b/src/store/tasks.js @@ -616,7 +616,7 @@ const mutations = { setCompletedDate(state, { task, completedDate }) { if (completedDate !== null) { // Check that the completed date is in the past. - let now = moment(ICAL.Time.fromJSDate(new Date(), true), 'YYYYMMDDTHHmmssZ') + const now = moment(ICAL.Time.fromJSDate(new Date(), true), 'YYYYMMDDTHHmmssZ') if (completedDate.isAfter(now)) { showError(t('tasks', 'Completion date must be in the past.')) return @@ -1375,7 +1375,7 @@ const actions = { context.commit('setStart', { task, start: newStart }) context.dispatch('updateTask', task) } - // Adjust due date + // Adjust due date } else if (due.isValid()) { diff = due.diff(moment().startOf('day'), 'days') diff = diff < 0 ? 0 : diff @@ -1384,7 +1384,7 @@ const actions = { context.commit('setDue', { task, due: newDue }) context.dispatch('updateTask', task) } - // Set the due date to appropriate value + // Set the due date to appropriate value } else { context.commit('setDue', { task, due: day }) context.dispatch('updateTask', task) From 07db14e6c89e06f70c26613871a3cecab81d0ce2 Mon Sep 17 00:00:00 2001 From: Creighton Date: Sun, 22 Sep 2024 19:36:33 -0500 Subject: [PATCH 3/9] move completion date input to task details section Signed-off-by: Creighton --- src/views/AppSidebar.vue | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/views/AppSidebar.vue b/src/views/AppSidebar.vue index cd8d4bcbf..50fd422ba 100644 --- a/src/views/AppSidebar.vue +++ b/src/views/AppSidebar.vue @@ -60,18 +60,6 @@ License along with this library. If not, see . - - - . :placeholder="t('tasks', 'Select a status')" icon="IconPulse" @change-value="changeStatus" /> + + + Date: Sun, 22 Sep 2024 19:38:42 -0500 Subject: [PATCH 4/9] control whether a DateTimePickerItem can be overdue Signed-off-by: Creighton --- src/components/AppSidebar/DateTimePickerItem.vue | 9 ++++++++- src/views/AppSidebar.vue | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/AppSidebar/DateTimePickerItem.vue b/src/components/AppSidebar/DateTimePickerItem.vue index 54066724e..139749873 100644 --- a/src/components/AppSidebar/DateTimePickerItem.vue +++ b/src/components/AppSidebar/DateTimePickerItem.vue @@ -115,6 +115,13 @@ export default { type: Boolean, default: false, }, + /** + * Whether the date can be considered 'overdue' + */ + checkOverdue: { + type: Boolean, + default: false, + } }, data() { return { @@ -139,7 +146,7 @@ export default { return this.date.isValid() }, isOverdue() { - return overdue(this.date) + return this.checkOverdue && overdue(this.date) }, }, methods: { diff --git a/src/views/AppSidebar.vue b/src/views/AppSidebar.vue index 50fd422ba..d40b4fa18 100644 --- a/src/views/AppSidebar.vue +++ b/src/views/AppSidebar.vue @@ -41,6 +41,7 @@ License along with this library. If not, see . :property-string="startDateString" :read-only="readOnly" :task="task" + :check-overdue=true @editing="(editing) => editingStart = editing" @set-value="setStartDate">