import { Calendar, EventSourceInput } from '@fullcalendar/core'; import dayGridPlugin from '@fullcalendar/daygrid'; import multiMonthPlugin from '@fullcalendar/multimonth'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { dateRangeStrToDates } from '../../../../ClientUtils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../FieldView'; import './CalendarBox.scss'; import { CollectionSubView, SubCollectionViewProps } from '../../collections/CollectionSubView'; type CalendarView = 'month' | 'multi-month' | 'week'; @observer export class CalendarBox extends CollectionSubView() { _calendarRef: HTMLDivElement | null = null; _calendar: Calendar | undefined; _oldWheel: HTMLElement | null = null; _observer: ResizeObserver | undefined; constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @observable _multiMonth = 0; componentDidMount(): void { reaction( () => this.calendarEvents, events => { this._calendar?.setOption('events', events); }, { fireImmediately: true } ); } @computed get calendarEvents(): EventSourceInput | undefined { return this.childDocs.map(doc => { const { startDate: start, endDate: end } = dateRangeStrToDates(StrCast(doc.date_range)); return { title: StrCast(doc.title), start, end, startEditable: true, endEditable: true, allDay: false, classNames: ['mother'], // will determine the style editable: true, // subject to change in the future backgroundColor: this.eventToColor(doc), color: 'white', extendedProps: { description: StrCast(doc.description), }, }; }); } @computed get dateRangeStrDates() { return dateRangeStrToDates(StrCast(this.Document.date_range)); } // Choose a calendar view based on the date range @computed get calendarViewType(): CalendarView { const { startDate, endDate } = this.dateRangeStrDates; if (startDate.getFullYear() !== endDate.getFullYear() || startDate.getMonth() !== endDate.getMonth()) return 'multi-month'; if (Math.abs(startDate.getDay() - endDate.getDay()) > 7) return 'month'; return 'week'; } eventToColor(event: Doc): string { // TODO: Return a different color based on the event type console.log(event.title); return 'blue'; } handleEventClick = (/* arg: EventClickArg */) => { // TODO: open popover with event description, option to open CalendarManager and change event date, delete event, etc. }; // https://fullcalendar.io renderCalendar = () => { const cal = !this._calendarRef ? null : (this._calendar = new Calendar(this._calendarRef, { plugins: [multiMonthPlugin, dayGridPlugin], headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth multiMonth', // timeGridWeek timeGridDay listWeek', }, initialDate: this.dateRangeStrDates.startDate, navLinks: true, editable: false, displayEventTime: false, displayEventEnd: false, aspectRatio: NumCast(this.Document.width) / NumCast(this.Document.height), events: this.calendarEvents, eventClick: this.handleEventClick, })); cal?.render(); }; onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); render() { this._multiMonth; return (