From c53ab98d37e68653057f12ff02e00fbe131ae930 Mon Sep 17 00:00:00 2001 From: aaravkumar Date: Mon, 28 Apr 2025 23:48:41 -0400 Subject: added task nodes calendar intergation, and ability to complete tasks directly via calendar view --- src/client/views/nodes/TaskManagerTask.tsx | 138 +++++++++++++++++++++++++---- 1 file changed, 121 insertions(+), 17 deletions(-) (limited to 'src/client/views/nodes/TaskManagerTask.tsx') diff --git a/src/client/views/nodes/TaskManagerTask.tsx b/src/client/views/nodes/TaskManagerTask.tsx index 1a9205ada..2d2444275 100644 --- a/src/client/views/nodes/TaskManagerTask.tsx +++ b/src/client/views/nodes/TaskManagerTask.tsx @@ -37,24 +37,87 @@ export class TaskManagerTask extends React.Component { delete this.props.Document.startTime; delete this.props.Document.endTime; } + + this.setTaskDateRange(); }; @action updateStart = (e: React.ChangeEvent) => { - this.props.Document.startTime = new DateField(new Date(e.target.value)); + const newStart = new Date(e.target.value); + + this.props.Document.startTime = new DateField(newStart); + + const endDate = this.props.Document.endTime instanceof DateField ? this.props.Document.endTime.date : undefined; + if (endDate && newStart > endDate) { + // Alert user + alert('Start time cannot be after end time. End time has been adjusted.'); + + // Fix end time + const adjustedEnd = new Date(newStart.getTime() + 60 * 60 * 1000); + this.props.Document.endTime = new DateField(adjustedEnd); + } + + this.setTaskDateRange(); }; + + @action updateEnd = (e: React.ChangeEvent) => { - this.props.Document.endTime = new DateField(new Date(e.target.value)); + const newEnd = new Date(e.target.value); + + this.props.Document.endTime = new DateField(newEnd); + + const startDate = this.props.Document.startTime instanceof DateField ? this.props.Document.startTime.date : undefined; + if (startDate && newEnd < startDate) { + // Alert user + alert('End time cannot be before start time. Start time has been adjusted.'); + + // Fix start time + const adjustedStart = new Date(newEnd.getTime() - 60 * 60 * 1000); + this.props.Document.startTime = new DateField(adjustedStart); + } + + this.setTaskDateRange(); }; - @observable - completed = false; + + + + @action + setTaskDateRange() { + const doc = this.props.Document; + + if (doc.allDay) { + // All-day task → use date only + if (!doc.title) return; + + const parsedDate = new Date(doc.title as string); + if (!isNaN(parsedDate.getTime())) { + const localStart = new Date(parsedDate.getFullYear(), parsedDate.getMonth(), parsedDate.getDate()); + const localEnd = new Date(localStart); + doc.date_range = `${localStart.toISOString()}|${localEnd.toISOString()}`; + doc.allDay = true; + } + } else { + // Timed task → use full startTime and endTime + const startField = doc.startTime; + const endField = doc.endTime; + const startDate = startField instanceof DateField ? startField.date : null; + const endDate = endField instanceof DateField ? endField.date : null; + + if (startDate && endDate && !isNaN(startDate.getTime()) && !isNaN(endDate.getTime())) { + doc.date_range = `${startDate.toISOString()}|${endDate.toISOString()}`; + doc.allDay = false; + } else { + console.warn('startTime or endTime is invalid'); + } + } + } @action toggleComplete = (e: React.ChangeEvent) => { - this.completed = e.target.checked; + this.props.Document.completed = e.target.checked; }; constructor(props: TaskManagerProps) { @@ -62,15 +125,44 @@ export class TaskManagerTask extends React.Component { makeObservable(this); } + componentDidMount() { + this.setTaskDateRange(); + } + + render() { + + function toLocalDateTimeString(date: Date): string { + const pad = (n: number) => n.toString().padStart(2, '0'); + return ( + date.getFullYear() + + '-' + + pad(date.getMonth() + 1) + + '-' + + pad(date.getDate()) + + 'T' + + pad(date.getHours()) + + ':' + + pad(date.getMinutes()) + ); + } + const doc = this.props.Document; const taskDesc = typeof doc.text === 'string' ? doc.text : ''; const taskTitle = typeof doc.title === 'string' ? doc.title : ''; const allDay = !!doc.allDay; + const isCompleted = !!this.props.Document.completed; + + const startTime = doc.startTime instanceof DateField && doc.startTime.date instanceof Date + ? toLocalDateTimeString(doc.startTime.date) + : ''; + + const endTime = doc.endTime instanceof DateField && doc.endTime.date instanceof Date + ? toLocalDateTimeString(doc.endTime.date) + : ''; + - const startTime = doc.startTime instanceof DateField ? doc.startTime.date.toISOString().slice(0, 16) : ''; - const endTime = doc.endTime instanceof DateField ? doc.endTime.date.toISOString().slice(0, 16) : ''; return (
@@ -80,8 +172,8 @@ export class TaskManagerTask extends React.Component { placeholder="Task Title" value={taskTitle} onChange={this.updateTitle} - disabled={this.completed} - style={{opacity: this.completed ? 0.7 : 1,}} + disabled={isCompleted} + style={{opacity: isCompleted ? 0.7 : 1,}} />