From 0b4659e2d85c5311835651d3f1aa54c48f3849de Mon Sep 17 00:00:00 2001
From: Skitty1238 <157652284+Skitty1238@users.noreply.github.com>
Date: Tue, 3 Jun 2025 11:09:32 -0400
Subject: fix for task resizing not working after merge, and fix for all-day
 view for initial task-nodes (i.e. if you just created task node and checked
 all-day, cal view was previously showing task 1 day early)

---
 src/client/views/nodes/calendarBox/CalendarBox.tsx | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

(limited to 'src/client/views/nodes/calendarBox/CalendarBox.tsx')

diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 26aed72c3..92b3224e9 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -22,6 +22,7 @@ import './CalendarBox.scss';
 import { DateField } from '../../../../fields/DateField';
 import { undoable } from '../../../util/UndoManager';
 import { DocumentType } from '../../../documents/DocumentTypes';
+import { truncate } from 'fs/promises';
 
 type CalendarView = 'multiMonth' | 'dayGridMonth' | 'timeGridWeek' | 'timeGridDay';
 
@@ -74,8 +75,20 @@ export class CalendarBox extends CollectionSubView() {
 
     @computed get calendarEvents(): EventSourceInput | undefined {
         return this.childDocs.map(doc => {
-            const { start, end } = dateRangeStrToDates(StrCast(doc.$task_dateRange));
-            const isCompleted = BoolCast(doc.$task_completed); // AARAV ADD
+            // const { start, end } = dateRangeStrToDates(StrCast(doc.$task_dateRange));
+            const isCompleted = BoolCast(doc.$task_completed);
+
+            const rangeStr = StrCast(doc.$task_dateRange);
+            const [startStr, endStr] = rangeStr.split('|');
+            let start: string | Date, end: string | Date;
+
+            if (BoolCast(doc.$task_allDay)) {
+                start = startStr;
+                end = endStr;
+            } else {
+                ({ start, end } = dateRangeStrToDates(rangeStr));
+            }
+
             return {
                 title: StrCast(doc.title),
                 start,
@@ -157,7 +170,7 @@ export class CalendarBox extends CollectionSubView() {
             delete doc.$task_endTime;
         } else {
             doc.$task_startTime = new DateField(startDate);
-            doc.task_endTime = new DateField(endDate);
+            doc.$task_endTime = new DateField(endDate);
         }
     }, 'change event date');
 
@@ -220,7 +233,7 @@ export class CalendarBox extends CollectionSubView() {
                 }}
                 initialDate={untracked(() => this.dateSelect.start)}
                 navLinks={true}
-                editable={false}
+                editable={true}
                 // expandRows={true}
                 // handleWindowResize={true}
                 displayEventTime={false}
@@ -231,6 +244,7 @@ export class CalendarBox extends CollectionSubView() {
                 events={this.calendarEvents}
                 eventClick={this.handleEventClick}
                 eventDrop={this.handleEventDrop}
+                eventResize={this.handleEventDrop}
                 unselectAuto={false}
                 // unselect={() => {}}
                 select={(info: DateSelectArg) => {
-- 
cgit v1.2.3-70-g09d2


From 6e7a29470e2c9e2fad287b4851b9eb561821ea9e Mon Sep 17 00:00:00 2001
From: Skitty1238 <157652284+Skitty1238@users.noreply.github.com>
Date: Tue, 3 Jun 2025 13:10:05 -0400
Subject: fixed drag and drop of calendar events not following cursor properly

---
 .../views/nodes/calendarBox/CalendarBox.scss       |  9 +++
 src/client/views/nodes/calendarBox/CalendarBox.tsx | 77 +++++++++++++++++++---
 src/server/apis/google/GoogleTasksHandler.ts       | 54 +++++++++++++++
 3 files changed, 131 insertions(+), 9 deletions(-)
 create mode 100644 src/server/apis/google/GoogleTasksHandler.ts

(limited to 'src/client/views/nodes/calendarBox/CalendarBox.tsx')

diff --git a/src/client/views/nodes/calendarBox/CalendarBox.scss b/src/client/views/nodes/calendarBox/CalendarBox.scss
index 891db9d90..89dc294a5 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.scss
+++ b/src/client/views/nodes/calendarBox/CalendarBox.scss
@@ -50,3 +50,12 @@
         pointer-events: unset;
     }
 }
+
+.custom-drag-mirror {
+    transition: none !important;
+    transform: none !important;
+}
+
+.fc-event-dragging {
+    opacity: 0 !important;
+}
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 92b3224e9..a4183a11a 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -298,15 +298,74 @@ export class CalendarBox extends CollectionSubView() {
                         ev.preventDefault();
                     });
                 }}
+
+                // for dragging and dropping (mirror)
+
+                eventDragStart={(arg) => {
+                    const mirror = arg.el.cloneNode(true) as HTMLElement;
+                    const rect = arg.el.getBoundingClientRect();
+
+                    mirror.style.position = 'fixed';
+                    mirror.style.pointerEvents = 'none';
+                    mirror.style.opacity = '0.8';
+                    mirror.style.zIndex = '10000';
+                    mirror.classList.add('custom-drag-mirror');
+                    mirror.style.width = `${rect.width}px`;
+                    mirror.style.height = `${rect.height}px`;
+                  
+                    document.body.appendChild(mirror);
+                  
+                    const moveListener = (ev: MouseEvent) => {
+                      mirror.style.left = `${ev.clientX}px`;
+                      mirror.style.top = `${ev.clientY}px`;
+                    };
+                  
+                    window.addEventListener('mousemove', moveListener);
+
+                    // hide the actual box
+                    arg.el.style.visibility = 'hidden';
+                    arg.el.style.opacity = '0';
+                  
+                    (arg.el as any)._mirrorElement = mirror;
+                    (arg.el as any)._moveListener = moveListener;
+                }}
+                
+                eventDragStop={(arg) => {
+                    const el = arg.el as any;
+                    const mirror = el._mirrorElement;
+                    const moveListener = el._moveListener;
+
+                    // show the actual box
+                    el.style.visibility = 'visible';
+                    el.style.opacity = '1';
+                    
+                    if (mirror) document.body.removeChild(mirror);
+                    if (moveListener) window.removeEventListener('mousemove', moveListener);
+                }}
+                  
             />
         );
     }
 
     render() {
+        const scale = this._props.ScreenToLocalTransform().Scale;
+        const scaledWidth = this._props.PanelWidth();
+        const scaledHeight = this._props.PanelHeight();
+
         return (
             <div
                 key={this.calendarViewType}
                 className={`calendarBox${this._props.isContentActive() ? '-interactive' : ''}`}
+                style={{
+                    width: scaledWidth,
+                    height: scaledHeight,
+                    overflow: 'hidden',
+                    position: 'relative',
+                  }}
+                ref={r => {
+                    this.createDashEventsTarget(r);
+                    this.fixWheelEvents(r, this._props.isContentActive);
+                }}
                 onPointerDown={e => {
                     setTimeout(
                         action(() => {
@@ -317,17 +376,17 @@ export class CalendarBox extends CollectionSubView() {
                             if (cname.includes('timeGridDay')) this.dataDoc[this.calTypeFieldKey] = 'timeGridDay';
                         })
                     );
-                }}
-                style={{
-                    width: this._props.PanelWidth() / this._props.ScreenToLocalTransform().Scale,
-                    height: this._props.PanelHeight() / this._props.ScreenToLocalTransform().Scale,
-                    transform: `scale(${this._props.ScreenToLocalTransform().Scale})`,
-                }}
-                ref={r => {
-                    this.createDashEventsTarget(r);
-                    this.fixWheelEvents(r, this._props.isContentActive);
                 }}>
+                <div
+                    style={{
+                        transform: `scale(${scale})`,
+                        transformOrigin: 'top left',
+                        width: scaledWidth / scale,
+                        height: scaledHeight / scale,
+                    }}
+                >
                 {this.renderCalendar}
+                </div>
             </div>
         );
     }
diff --git a/src/server/apis/google/GoogleTasksHandler.ts b/src/server/apis/google/GoogleTasksHandler.ts
new file mode 100644
index 000000000..a8af86fe2
--- /dev/null
+++ b/src/server/apis/google/GoogleTasksHandler.ts
@@ -0,0 +1,54 @@
+import express from 'express';
+import { google } from 'googleapis';
+import { GoogleCredentialsLoader } from './CredentialsLoader';
+import User from '../../authentication/DashUserModel';
+import { DashUserModel } from '../../authentication/DashUserModel';
+
+
+const router = express.Router();
+
+router.post('/tasks/create', async (req, res) => {
+  try {
+    const { title, notes, due } = req.body;
+
+    // Make sure user is authenticated
+    if (!req.user) {
+      return res.status(401).json({ error: 'User not authenticated' });
+    }
+
+    // Assuming access token is stored in user model
+    const user = req.user as typeof User; // replace with your actual User type if needed
+    const accessToken = user.googleAccessToken; // <-- change this based on where you store it
+
+    if (!accessToken) {
+      return res.status(400).json({ error: 'Google access token not found for user' });
+    }
+
+    const credentials = GoogleCredentialsLoader.ProjectCredentials;
+    const auth = new google.auth.OAuth2(
+      credentials.client_id,
+      credentials.client_secret,
+      credentials.redirect_uris[0]
+    );
+
+    auth.setCredentials({ access_token: accessToken });
+
+    const tasks = google.tasks({ version: 'v1', auth });
+
+    const result = await tasks.tasks.insert({
+      tasklist: '@default',
+      requestBody: {
+        title,
+        notes,
+        due,
+      },
+    });
+
+    res.status(200).json(result.data);
+  } catch (err) {
+    console.error('Error creating Google Task:', err);
+    res.status(500).json({ error: 'Failed to create task' });
+  }
+});
+
+export default router;
-- 
cgit v1.2.3-70-g09d2

