aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/calendarBox/CalendarBox.tsx
blob: 748c3322e95b0e886fe9cb0a645a3815ac660367 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import multiMonthPlugin from '@fullcalendar/multimonth';
import { makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { dateRangeStrToDates } from '../../../../Utils';
import { Doc } from '../../../../fields/Doc';
import { StrCast } from '../../../../fields/Types';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { FieldView, FieldViewProps } from '../FieldView';

type CalendarView = 'month' | 'multi-month' | 'week';

@observer
export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>() {
    public static LayoutString(fieldKey: string = 'calendar') {
        return FieldView.LayoutString(CalendarBox, fieldKey);
    }

    constructor(props: FieldViewProps) {
        super(props);
        makeObservable(this);
    }

    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,
        });
    }

    render() {
        return (
            <div className="calendar-box-conatiner">
                <div id="calendar-box-v1"></div>
            </div>
        );
    }
}