diff options
author | bobzel <zzzman@gmail.com> | 2025-06-05 14:58:31 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2025-06-05 14:58:31 -0400 |
commit | 11cdfbcf26714351b5fd43ac2f95d30a7ae6de4b (patch) | |
tree | 485c67cf81993e4a2d4a1a23d7d424453fc23e6d /src | |
parent | 353fcddb918ee9ccaedd69032f9212fc66c04a7f (diff) |
updated taskBox to use Cast methods and mobx instead of react state. Made TaskBox extend ViewBoxBaseComponent to access this.Document/this.fieldKey, etc
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 24 | ||||
-rw-r--r-- | src/client/views/nodes/TaskBox.tsx | 164 |
2 files changed, 75 insertions, 113 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 120ad0688..27cb95144 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -591,30 +591,6 @@ export namespace Docs { options: { acl: '' }, }, ], - - // AARAV ADD // - [ - DocumentType.JOURNAL, - { - layout: { view: EmptyBox, dataField: 'text' }, - options: { - title: 'Daily Journal', - acl_Guest: SharingPermissions.View, - }, - }, - ], - - [ - DocumentType.TASK, - { - layout: { view: EmptyBox, dataField: 'text' }, - options: { - title: 'Task', - acl_Guest: SharingPermissions.View, - }, - }, - ], - // AARAV ADD // ]); const suffix = 'Proto'; diff --git a/src/client/views/nodes/TaskBox.tsx b/src/client/views/nodes/TaskBox.tsx index 82c22057e..168e1455e 100644 --- a/src/client/views/nodes/TaskBox.tsx +++ b/src/client/views/nodes/TaskBox.tsx @@ -1,30 +1,30 @@ -import { action, makeObservable, IReactionDisposer, reaction } from 'mobx'; +import { action, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { DateField } from '../../../fields/DateField'; +import { BoolCast, DateCast, NumCast, StrCast } from '../../../fields/Types'; +import { GoogleAuthenticationManager } from '../../apis/GoogleAuthenticationManager'; import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; -import { FieldView } from './FieldView'; -import { DateField } from '../../../fields/DateField'; -import { Doc } from '../../../fields/Doc'; - +import { ViewBoxBaseComponent } from '../DocComponent'; +import { FieldView, FieldViewProps } from './FieldView'; import './TaskBox.scss'; -import { GoogleAuthenticationManager } from '../../apis/GoogleAuthenticationManager'; - -/** - * Props (reference to document) for Task Box - */ - -interface TaskBoxProps { - Document: Doc; -} /** * TaskBox class for adding task information + completing tasks */ @observer -export class TaskBox extends React.Component<TaskBoxProps> { +export class TaskBox extends ViewBoxBaseComponent<FieldViewProps>() { + /** + * Return the JSX string that will create this component + * @param fieldStr the Doc field that contains the primary data for this component + * @returns + */ + public static LayoutString(fieldStr: string) { + return FieldView.LayoutString(TaskBox, fieldStr); + } // contains the last synced task information - lastSyncedTask: { + private _lastSyncedTask: { title: string; text: string; due?: string; @@ -36,18 +36,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { completed: false, }; - state = { - needsSync: false, - }; - - /** - * Method to reuturn the - * @param fieldStr - * @returns - */ - public static LayoutString(fieldStr: string) { - return FieldView.LayoutString(TaskBox, fieldStr); - } + @observable _needsSync = false; /** * Method to update the task description @@ -56,7 +45,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { @action updateText = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { - this.props.Document.text = e.target.value; + this.Document[this.fieldKey] = e.target.value; }; /** @@ -65,7 +54,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { */ @action updateTitle = (e: React.ChangeEvent<HTMLInputElement>) => { - this.props.Document.title = e.target.value; + this.Document.title = e.target.value; }; /** @@ -74,11 +63,11 @@ export class TaskBox extends React.Component<TaskBoxProps> { */ @action updateAllDay = (e: React.ChangeEvent<HTMLInputElement>) => { - this.props.Document.$task_allDay = e.target.checked; + this.Document.$task_allDay = e.target.checked; if (e.target.checked) { - delete this.props.Document.$task_startTime; - delete this.props.Document.$task_endTime; + delete this.Document.$task_startTime; + delete this.Document.$task_endTime; } this.setTaskDateRange(); @@ -92,16 +81,16 @@ export class TaskBox extends React.Component<TaskBoxProps> { updateStart = (e: React.ChangeEvent<HTMLInputElement>) => { const newStart = new Date(e.target.value); - this.props.Document.$task_startTime = new DateField(newStart); + this.Document.$task_startTime = new DateField(newStart); - const endDate = this.props.Document.$task_endTime instanceof DateField ? this.props.Document.$task_endTime.date : undefined; + const endDate = this.Document.$task_endTime instanceof DateField ? this.Document.$task_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.$task_endTime = new DateField(adjustedEnd); + this.Document.$task_endTime = new DateField(adjustedEnd); } this.setTaskDateRange(); @@ -115,16 +104,16 @@ export class TaskBox extends React.Component<TaskBoxProps> { updateEnd = (e: React.ChangeEvent<HTMLInputElement>) => { const newEnd = new Date(e.target.value); - this.props.Document.$task_endTime = new DateField(newEnd); + this.Document.$task_endTime = new DateField(newEnd); - const startDate = this.props.Document.$task_startTime instanceof DateField ? this.props.Document.$task_startTime.date : undefined; + const startDate = this.Document.$task_startTime instanceof DateField ? this.Document.$task_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.$task_startTime = new DateField(adjustedStart); + this.Document.$task_startTime = new DateField(adjustedStart); } this.setTaskDateRange(); @@ -135,10 +124,10 @@ export class TaskBox extends React.Component<TaskBoxProps> { */ @action setTaskDateRange() { - const doc = this.props.Document; + const doc = this.Document; if (doc.$task_allDay) { - const range = typeof doc.$task_dateRange === 'string' ? doc.$task_dateRange.split('|') : []; + const range = StrCast(doc.$task_dateRange).split('|'); const dateStr = range[0] ?? new Date().toISOString().split('T')[0]; // default to today doc.$task_dateRange = `${dateStr}|${dateStr}`; @@ -163,7 +152,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { @action toggleComplete = (e: React.ChangeEvent<HTMLInputElement>) => { - this.props.Document.$task_completed = e.target.checked; + this.Document.$task_completed = e.target.checked; }; /** @@ -182,7 +171,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { componentDidMount() { this.setTaskDateRange(); - const doc = this.props.Document; + const doc = this.Document; // adding task on creation to google @@ -192,15 +181,15 @@ export class TaskBox extends React.Component<TaskBoxProps> { const token = await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(); if (!token) return; - const body: any = { - title: doc.title || 'Untitled Task', - notes: doc.text || '', + const body: { title: string; notes: string; status: string; completed?: string; due?: string } = { + title: StrCast(doc.title, 'Untitled Task'), + notes: StrCast(doc[this.fieldKey]), status: doc.$task_completed ? 'completed' : 'needsAction', completed: doc.$task_completed ? new Date().toISOString() : undefined, }; - if (doc.$task_allDay && typeof doc.$task_dateRange === 'string') { - const datePart = doc.$task_dateRange.split('|')[0]; + const datePart = StrCast(doc.$task_dateRange).split('|')[0]; + if (doc.$task_allDay && datePart) { if (datePart && !isNaN(new Date(datePart).getTime())) { const baseDate = datePart.includes('T') ? datePart : datePart + 'T00:00:00Z'; body.due = new Date(baseDate).toISOString(); @@ -233,20 +222,20 @@ export class TaskBox extends React.Component<TaskBoxProps> { })(); this._heightDisposer = reaction( - () => Number(doc._height), + () => NumCast(doc._height), height => { - const minHeight = Number(doc.height_min ?? 0); - if (!isNaN(height) && height < minHeight) { + const minHeight = NumCast(doc.height_min); + if (height < minHeight) { doc._height = minHeight; } } ); this._widthDisposer = reaction( - () => Number(doc._width), + () => NumCast(doc._width), width => { - const minWidth = Number(doc.width_min ?? 0); - if (!isNaN(width) && width < minWidth) { + const minWidth = NumCast(doc.width_min); + if (width < minWidth) { doc._width = minWidth; } } @@ -254,35 +243,34 @@ export class TaskBox extends React.Component<TaskBoxProps> { this._googleTaskCreateDisposer = reaction( () => { - const { title, text, $task_completed, $task_dateRange, $task_startTime, $task_endTime, $task_allDay } = doc; - - const completed = !!$task_completed; - let due: string | undefined; - - if ($task_allDay && typeof $task_dateRange === 'string') { - const datePart = $task_dateRange.split('|')[0]; - if (datePart && !isNaN(new Date(datePart).getTime())) { - due = new Date(datePart + 'T00:00:00Z').toISOString(); - } - } else if ($task_endTime && $task_endTime instanceof DateField && $task_endTime.date) { - due = $task_endTime.date.toISOString(); - } else if ($task_startTime && $task_startTime instanceof DateField && $task_startTime.date) { - due = $task_startTime.date.toISOString(); - } - - return { title, text, completed, due }; + const completed = BoolCast(doc.$task_completed); + const $task_allDay = BoolCast(doc.$task_allDay); + const endTime = DateCast(doc.$task_endTime); + const startTime = DateCast(doc.$task_startTime); + const datePart = StrCast(doc.$task_dateRange)?.split('|')[0]; + + const due = (() => { + if ($task_allDay && datePart) { + if (!isNaN(new Date(datePart).getTime())) return new Date(datePart).toISOString(); + } else if (endTime && !isNaN(+endTime.date)) return endTime.date.toISOString(); + else if (startTime && !isNaN(+startTime.date)) return startTime.date.toISOString(); + })(); + + return { title: StrCast(doc.title), text: StrCast(doc[this.fieldKey]), completed, due }; }, - current => { - const hasChanged = current.title !== this.lastSyncedTask.title || current.text !== this.lastSyncedTask.text || current.due !== this.lastSyncedTask.due || current.completed !== this.lastSyncedTask.completed; - - this.setState({ needsSync: hasChanged }); + ({ title, text, completed, due }) => { + this._needsSync = + title !== this._lastSyncedTask.title || // + text !== this._lastSyncedTask.text || + due !== this._lastSyncedTask.due || + completed !== this._lastSyncedTask.completed; }, { fireImmediately: true } ); } componentWillUnmount() { - const doc = this.props.Document; + const doc = this.Document; this._googleTaskCreateDisposer?.(); this._heightDisposer?.(); this._widthDisposer?.(); @@ -321,15 +309,15 @@ export class TaskBox extends React.Component<TaskBoxProps> { return date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate()) + 'T' + pad(date.getHours()) + ':' + pad(date.getMinutes()); } - const doc = this.props.Document; + const doc = this.Document; - const taskDesc = typeof doc.text === 'string' ? doc.text : ''; - const taskTitle = typeof doc.title === 'string' ? doc.title : ''; + const taskDesc = StrCast(doc[this.fieldKey]); + const taskTitle = StrCast(doc.title); const allDay = !!doc.$task_allDay; - const isCompleted = !!this.props.Document.$task_completed; + const isCompleted = !!this.Document.$task_completed; - const startTime = doc.$task_startTime instanceof DateField && doc.$task_startTime.date instanceof Date ? toLocalDateTimeString(doc.$task_startTime.date) : ''; - const endTime = doc.$task_endTime instanceof DateField && doc.$task_endTime.date instanceof Date ? toLocalDateTimeString(doc.$task_endTime.date) : ''; + const startTime = DateCast(doc.$task_startTime) ? toLocalDateTimeString(DateCast(doc.$task_startTime)!.date) : ''; + const endTime = DateCast(doc.$task_endTime) ? toLocalDateTimeString(DateCast(doc.$task_endTime)!.date) : ''; const handleGoogleTaskSync = async () => { console.log('GT button clicked'); @@ -352,7 +340,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { let due: string | undefined; if (allDay) { - const rawRange = typeof doc.$task_dateRange === 'string' ? doc.$task_dateRange : ''; + const rawRange = StrCast(doc.$task_dateRange); const datePart = rawRange.split('|')[0]; if (datePart && !isNaN(new Date(datePart).getTime())) { @@ -396,13 +384,13 @@ export class TaskBox extends React.Component<TaskBoxProps> { if (result?.id) { alert('✅ Task synced with Google Tasks!'); if (result?.id) { - this.lastSyncedTask = { + this._lastSyncedTask = { title: taskTitle, text: taskDesc, due, completed: isCompleted, }; - this.setState({ needsSync: false }); + runInAction(() => (this._needsSync = false)); } } else { alert(`❌ Failed: ${result?.error?.message || 'Unknown error'}`); @@ -427,9 +415,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { <input type="date" value={(() => { - const rawRange = doc.$task_dateRange; - if (typeof rawRange !== 'string') return ''; - const datePart = rawRange.split('|')[0]; + const datePart = StrCast(doc.$task_dateRange).split('|')[0]; if (!datePart) return ''; const d = new Date(datePart); return !isNaN(d.getTime()) ? d.toISOString().split('T')[0] : ''; @@ -456,7 +442,7 @@ export class TaskBox extends React.Component<TaskBoxProps> { <button className="task-manager-google" - disabled={!this.state.needsSync} + disabled={!this._needsSync} onClick={event => { event.preventDefault(); handleGoogleTaskSync(); |