diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Utils.ts | 21 | ||||
-rw-r--r-- | src/client/util/CalendarManager.tsx | 3 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCalendarView.tsx | 103 | ||||
-rw-r--r-- | src/client/views/nodes/calendarBox/CalendarBox.tsx | 110 |
4 files changed, 231 insertions, 6 deletions
diff --git a/src/Utils.ts b/src/Utils.ts index 5f9475f23..a060e4a2c 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -895,3 +895,24 @@ export function setupMoveUpEvents( document.addEventListener('pointerup', _upEvent, true); document.addEventListener('click', _clickEvent, true); } + +export function dateRangeStrToDates (dateStr: string) { + // dateStr in yyyy-mm-dd format + const dateRangeParts = dateStr.split("|"); // splits into from and to date + const fromParts = dateRangeParts[0].split("-"); + const toParts = dateRangeParts[1].split("-"); + + const fromYear = parseInt(fromParts[0]); + const fromMonth = parseInt(fromParts[1])-1; + const fromDay = parseInt(fromParts[2]); + + const toYear = parseInt(toParts[0]); + const toMonth = parseInt(toParts[1])-1; + const toDay = parseInt(toParts[2]); + + + return [ + new Date(fromYear, fromMonth, fromDay), + new Date(toYear, toMonth, toDay) + ]; +}
\ No newline at end of file diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx index d5d4203b1..c3e54ebd3 100644 --- a/src/client/util/CalendarManager.tsx +++ b/src/client/util/CalendarManager.tsx @@ -125,6 +125,7 @@ export class CalendarManager extends ObservableReactComponent<{}> { @action handleCalendarTitleChange = (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => { + console.log("Existing calendars: ", this.existingCalendars); this.calendarName = event.target.value; }; @@ -175,7 +176,7 @@ export class CalendarManager extends ObservableReactComponent<{}> { const subDocEmbedding = Doc.MakeEmbedding(targetDoc); // embedding console.log("subdoc embedding", subDocEmbedding); subDocEmbedding.embedContainer = calendar; // set embed container - subDocEmbedding.date_range = `${startDateStr}-${endDateStr}`; // set subDoc date range + subDocEmbedding.date_range = `${startDateStr}|${endDateStr}`; // set subDoc date range Doc.AddDocToList(calendar, 'data', subDocEmbedding); // add embedded subDoc to calendar diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx index 99dc09732..f94d05c61 100644 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -1,8 +1,18 @@ import * as React from 'react'; import { CollectionSubView } from "./CollectionSubView"; import { observer } from 'mobx-react'; -import { makeObservable, observable } from 'mobx'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { computed, makeObservable, observable } from 'mobx'; +import { Doc, DocListCast, Opt } from '../../../fields/Doc'; +import { CollectionStackingView } from './CollectionStackingView'; +import { CollectionViewType } from '../../documents/DocumentTypes'; +import { dateRangeStrToDates, emptyFunction, returnAll, returnEmptyDoclist, returnNone, returnOne, returnTrue } from '../../../Utils'; +import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { TbRuler } from 'react-icons/tb'; +import { Transform } from '../../util/Transform'; +import { DocData } from '../../../fields/DocSymbols'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { StyleProp } from '../StyleProvider'; +import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; @observer export class CollectionCalendarView extends CollectionSubView(){ @@ -20,13 +30,98 @@ export class CollectionCalendarView extends CollectionSubView(){ } - @observable private existingCalendars: Doc[] = DocListCast(Doc.MyCalendars?.data); + @computed get allCalendars(){ + return this.childDocs; // returns a list of docs (i.e. calendars) + } + + removeCalendar = () => { + + } + + addCalendar = (doc: Doc | Doc[], annotationKey?: string | undefined): boolean => { + // bring up calendar modal with option to create a calendar + return true; + } + + _stackRef = React.createRef<CollectionStackingView>(); + + panelHeight = () => { + return 0; // a standard height for all calendars; TODO: change + } + + panelWidth = () => { + return 0; //a standard width for all calendars; TODO: change + } + + // most recent calendar should come first + sortByMostRecentDate = (calendarA: Doc, calendarB: Doc) => { + const aDateRangeStr = StrCast(calendarA.date_range); + const bDateRangeStr = StrCast(calendarB.date_range); + + const [aFromDate, aToDate] = dateRangeStrToDates(aDateRangeStr); + const [bFromDate, bToDate] = dateRangeStrToDates(bDateRangeStr); + + if (aFromDate > bFromDate) { + return -1; // a comes first + } else if (aFromDate < bFromDate) { + return 1; // b comes first + } else { // start dates are the same + if (aToDate > bToDate) { + return -1; // a comes first + } else if (aToDate < bToDate) { + return 1; // b comes first + } else { + return 0; // same start and end dates + } + } + + + } + + + + screenToLocalTransform = () => + this._props + .ScreenToLocalTransform() + .translate(Doc.NativeWidth(this._props.Document), 0) + .scale(this._props.NativeDimScaling?.() || 1); + + get calendarsKey() { + return this._props.fieldKey + '_calendars'; + } render(){ return ( <div> - Hello + <CollectionStackingView + {...this._props} + setContentView={emptyFunction} + // NativeWidth={} + // NativeHeight={returnZero} + ref={this._stackRef} + PanelHeight={this.panelHeight} + PanelWidth={this.panelWidth} + // childFilters={this.childFilters} DO I NEED THIS? + sortFunc={this.sortByMostRecentDate} + setHeight={this.setHeightCallback} + isAnnotationOverlay={false} + // select={emptyFunction} What does this mean? + NativeDimScaling={returnOne} + isAnyChildContentActive={returnTrue} // ?? + // childDocumentsActive={} + // whenChildContentsActiveChanged={} + childHideDecorationTitle={false} + removeDocument={this.removeDocument} // will calendar automatically be removed from myCalendars + moveDocument={this.moveDocument} + addDocument={this.addCalendar} + ScreenToLocalTransform={this.screenToLocalTransform} + renderDepth={this._props.renderDepth + 1} + type_collection={CollectionViewType.Stacking} + fieldKey={this.calendarsKey} + pointerEvents={returnAll} + /> </div> + ) } }
\ No newline at end of file diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx index 0aa3b4ccc..989feb774 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.tsx +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -5,6 +5,13 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps, ViewBoxBaseCompon import { FieldView, FieldViewProps } from '../FieldView'; import { StrCast } from '../../../../fields/Types'; import { makeObservable } from 'mobx'; +import { dateRangeStrToDates } from '../../../../Utils'; +import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core' +import dayGridPlugin from '@fullcalendar/daygrid' +import multiMonthPlugin from '@fullcalendar/multimonth' +import { faListNumeric } from '@fortawesome/free-solid-svg-icons'; + +type CalendarView = 'month' | 'multi-month' | 'week'; @observer export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>(){ @@ -12,6 +19,103 @@ export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>(){ return FieldView.LayoutString(CalendarBox, fieldKey); } + componentDidMount(): void { + + } + + componentWillUnmount(): void { + + } + + _calendarRef = React.createRef<HTMLElement>() + + get dateRangeStr (){ + return StrCast(this.Document.date_range); + } + + // Choose a calendar view based on the date range + get calendarViewType (): CalendarView { + const [fromDate, toDate] = dateRangeStrToDates(this.dateRangeStr); + + if (fromDate.getFullYear() !== toDate.getFullYear() || fromDate.getMonth() !== toDate.getMonth()) return 'multi-month'; + + if (Math.abs(fromDate.getDay() - toDate.getDay()) > 7) return 'month'; + return 'week'; + } + + get calendarStartDate () { + return this.dateRangeStr.split("|")[0]; + } + + get calendarToDate () { + return this.dateRangeStr.split("|")[1]; + } + + get childDocs (): Doc[] { + return this.childDocs; // get all sub docs for a calendar + } + + docBackgroundColor (type: string): string { + // TODO: Return a different color based on the event type + return 'blue'; + } + + get calendarEvents (): EventSourceInput | undefined { + if (this.childDocs.length === 0) return undefined; + return this.childDocs.map((doc, idx) => { + const docTitle = StrCast(doc.title); + const docDateRange = StrCast(doc.date_range); + const [startDate, endDate] = dateRangeStrToDates(docDateRange); + const docType = doc.type; + const docDescription = doc.description ? StrCast(doc.description): ""; + + return { + title: docTitle, + start: startDate, + end: endDate, + allDay: false, + classNames:[StrCast(docType)], // will determine the style + editable: false, // subject to change in the future + backgroundColor: this.docBackgroundColor(StrCast(doc.type)), + color: 'white', + extendedProps: { + description: docDescription + }, + + } + + }) + } + + handleEventClick = (arg: EventClickArg) => { + // TODO: open popover with event description, option to open CalendarManager and change event date, delete event, etc. + } + + calendarEl: HTMLElement = document.getElementById('calendar-box-v1')!; + + // https://fullcalendar.io + get calendar() { + return new Calendar(this.calendarEl, + { + plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin], + headerToolbar: { + left: 'prev,next today', + center: 'title', + right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' + }, + initialDate: this.calendarStartDate, + navLinks: true, + editable: false, + displayEventTime: false, + displayEventEnd: false, + events: this.calendarEvents, + eventClick: this.handleEventClick + } + ) + + } + + constructor(props: any){ super(props); makeObservable(this); @@ -19,7 +123,11 @@ export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>(){ render(){ return ( - <div></div> + <div className='calendar-box-conatiner'> + <div id='calendar-box-v1'> + + </div> + </div> ); } |