From 4a1d64e470f7f8fae90e5014f3e6e64c5ffea2c8 Mon Sep 17 00:00:00 2001
From: zaultavangar <zaul_tavangar@brown.edu>
Date: Sat, 16 Dec 2023 17:26:32 -0500
Subject: more functionality for calendar feature

---
 src/client/util/CalendarManager.tsx | 153 ++++++++++++++++++++++++++++++------
 1 file changed, 130 insertions(+), 23 deletions(-)

(limited to 'src/client/util/CalendarManager.tsx')

diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx
index 39ba41652..e471db7c6 100644
--- a/src/client/util/CalendarManager.tsx
+++ b/src/client/util/CalendarManager.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
 import './CalendarManager.scss';
 import { observer } from "mobx-react";
 import { action, computed, observable, runInAction } from 'mobx';
-import { Doc } from '../../fields/Doc';
+import { Doc, DocListCast } from '../../fields/Doc';
 import { DocumentView } from '../views/nodes/DocumentView';
 import { DictationOverlay } from '../views/DictationOverlay';
 import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
@@ -10,19 +10,38 @@ import { MainViewModal } from '../views/MainViewModal';
 import { TextField } from '@material-ui/core';
 import Select from 'react-select';
 import { SettingsManager } from './SettingsManager';
-import { StrCast } from '../../fields/Types';
+import { DocCast, StrCast } from '../../fields/Types';
 import { SelectionManager } from './SelectionManager';
 import { DocumentManager } from './DocumentManager';
 import { DocData } from '../../fields/DocSymbols';
-import { DateRange, Range, RangeKeyDict } from 'react-date-range';
+// import { DateRange, Range, RangeKeyDict } from 'react-date-range';
 import { Button } from 'browndash-components';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import {DateRangePicker} from '@adobe/react-spectrum';
 import { IconLookup, faPlus } from '@fortawesome/free-solid-svg-icons';
-import 'react-date-range/dist/styles.css';
-import 'react-date-range/dist/theme/default.css';
+import { Docs } from '../documents/Documents';
+// import 'react-date-range/dist/styles.css';
+// import 'react-date-range/dist/theme/default.css';
 
 type CreationType = 'new-calendar' | 'existing-calendar' | 'manage-calendars';
 
+interface CalendarSelectOptions {
+    label: string,
+    value: string
+}
+
+const formatDateToString = (date: Date) => {
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0'); 
+    const day = String(date.getDate()).padStart(2, '0');
+
+    return `${year}-${month}-${day}`;
+}
+
+// TODO: If doc is already part of a calendar, display that
+// TODO: For a doc already in a calendar: give option to edit date range, delete from calendar
+
+
 @observer
 export class CalendarManager extends React.Component<{}> {
     public static Instance: CalendarManager;
@@ -36,11 +55,28 @@ export class CalendarManager extends React.Component<{}> {
 
     @observable private creationType: CreationType = 'new-calendar';
 
+    @observable private existingCalendars: Doc[] = DocListCast(Doc.MyCalendars.data);
+
+    @computed get selectOptions() {
+        return this.existingCalendars.map(calendar => ({ label: StrCast(calendar.title), value: StrCast(calendar.title) }));
+    }
+
+    @observable 
+    selectedExistingCalendarOption: CalendarSelectOptions | null = null;
+
     @observable 
     calendarName: string = "";
 
+    @observable 
+    calendarDescription: string = "";
+
+    @observable
+    errorMessage: string = "";
+
     @action
     setInterationType = (type: CreationType) => {
+        this.errorMessage = "";
+        this.calendarName = "";
         this.creationType = type;
     }
 
@@ -76,6 +112,60 @@ export class CalendarManager extends React.Component<{}> {
         
     }
 
+    @action
+    handleSelectChange = (option: any) => {
+        let selectOpt = option as CalendarSelectOptions;
+        this.selectedExistingCalendarOption = selectOpt;
+        this.calendarName = selectOpt.value; // or label
+    }
+
+    @action
+    handleTextFieldChange = (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
+        this.calendarName = event.target.value;
+    }
+
+    // TODO: Make undoable
+    private addToCalendar = () => {
+        let docs = SelectionManager.Views().length < 2 ? [this.targetDoc] : SelectionManager.Views().map(docView => docView.rootDoc);
+        const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData]; // doc to add to calendar
+
+        if (targetDoc) {
+            let calendar: Doc;
+            if (this.creationType === 'new-calendar'){
+                if (!this.existingCalendars.find(doc => StrCast(doc.title) === this.calendarName)){ 
+                    calendar = Docs.Create.CalendarDocument({
+                        title: this.calendarName,
+                        description: this.calendarDescription
+                    }, []);
+                } else {
+                    this.errorMessage = "Calendar with this name already exists"
+                    return;
+                }
+            } else {
+                // find existing calendar based on selected name (should technically always find one)
+                const existingCalendar = this.existingCalendars.find(calendar => StrCast(calendar.title) === this.calendarName);
+                if (existingCalendar) calendar = existingCalendar;
+                else {
+                    this.errorMessage = "Must select an existing calendar";
+                    return;
+                }
+            }
+            // Get start and end date strings
+            const startDateStr = formatDateToString(this.selectedDateRange.start);
+            const endDateStr = formatDateToString(this.selectedDateRange.end);
+
+            const subDocEmbedding = Doc.MakeEmbedding(targetDoc); // embedding 
+            subDocEmbedding.embedContainer = calendar; // set embed container
+            subDocEmbedding.date_range = `${startDateStr}-${endDateStr}`; // set subDoc date range
+
+            Doc.AddDocToList(calendar, 'data', subDocEmbedding); // add embedded subDoc to calendar
+            
+            Doc.AddDocToList(Doc.MyCalendars, 'data', calendar); // add to dashboard calendars
+            
+        }
+
+    }
+
     private focusOn = (contents: string) => {
         const title = this.targetDoc ? StrCast(this.targetDoc.title) : '';
         const docs = SelectionManager.Views().length > 1 ? SelectionManager.Views().map(docView => docView.props.Document) : [this.targetDoc];
@@ -108,20 +198,19 @@ export class CalendarManager extends React.Component<{}> {
     };
 
     @observable
-    selectedDateRange: Range[] = [{
-        startDate: new Date(),
-        endDate: undefined,
-        key: 'selection'
+    selectedDateRange: any = [{
+        start: new Date(),
+        end: new Date(),
     }]
 
     @action
-    setSelectedDateRange = (range: Range[]) => {
+    setSelectedDateRange = (range: any) => {
         this.selectedDateRange = range;
     }
 
     @computed
     get createButtonActive() {
-        if (this.calendarName.length === 0) return false // disabled if no calendar name
+        if (this.calendarName.length === 0 || this.errorMessage.length > 0) return false // disabled if no calendar name
         let startDate: Date | undefined;
         let endDate: Date | undefined;
         try {
@@ -170,6 +259,7 @@ export class CalendarManager extends React.Component<{}> {
                     {this.creationType === 'new-calendar' ? 
                         <TextField
                             fullWidth
+                            onChange={this.handleTextFieldChange}
                             placeholder='Enter calendar name...'
                             variant='filled'
                             style={{
@@ -178,38 +268,55 @@ export class CalendarManager extends React.Component<{}> {
                                 borderRadius: '5px'
 
                             }}
-                            
                         />
                     :
                         <Select
                             className='existing-calendar-search'
                             placeholder='Search for existing calendar...'
-                            isMulti
+                            isClearable
                             isSearchable
+                            options={this.selectOptions}
+                            value={this.selectedExistingCalendarOption}
+                            onChange={this.handleSelectChange}
+                            styles={{
+                                control: () => ({
+                                    display: 'inline-flex',
+                                    width: '100%',
+                                }),
+                                indicatorSeparator: () => ({
+                                    display: 'inline-flex',
+                                    visibility: 'hidden',
+                                }),
+                                indicatorsContainer: () => ({
+                                    display: 'inline-flex',
+                                    textDecorationColor: 'black',
+                                }),
+                                valueContainer: () => ({
+                                    display: 'inline-flex',
+                                    fontStyle: StrCast(Doc.UserDoc().userColor),
+                                    color: StrCast(Doc.UserDoc().userColor),
+                                    width: '100%',
+                                }),
+                            }}
                         >
-                            
                         </Select>
                     }
                 </div>
                 <div className='date-range-picker-container'>
-                    <DateRange
-                        className='react-date-range'
-                        editableDateInputs={true}
-                        // ranges={[selectionRange]}
-                        onChange={item => this.setSelectedDateRange([item.selection])}
-                        ranges={this.selectedDateRange}
-                    // onChange={this.handleSelect}
-                    />
+                    <DateRangePicker 
+                        value={this.selectedDateRange}
+                        onChange={(v => this.setSelectedDateRange(v))}
+                        label="Date range" />
                 </div>
                 <div className='create-button-container'>
                     <Button
                         active={this.createButtonActive}
+                        onClick={() => {}}
                         text="Add to Calendar"
                         iconPlacement='right'
                         icon={<FontAwesomeIcon icon={faPlus as IconLookup}/>}
                     />
                 </div>
-                
             </div>
         )
     }
-- 
cgit v1.2.3-70-g09d2

