From 6ebaf5599a6d9adc14a869ceebf9be6869348ef2 Mon Sep 17 00:00:00 2001
From: Tdee <101107770+datakanezukochan@users.noreply.github.com>
Date: Thu, 19 Jun 2025 14:19:39 +0700
Subject: [PATCH 1/3] optimize algo for scheduling
---
.../scheduler/components/ScheduleDisplay.tsx | 21 +-
.../(root)/scheduler/components/TaskList.tsx | 25 ++
.../(root)/scheduler/components/TaskModal.tsx | 321 ++++++++--------
.../app/[locale]/(root)/scheduler/page.tsx | 199 +++++++++-
packages/ai/src/scheduling/algorithm.test.ts | 63 +++-
packages/ai/src/scheduling/algorithm.ts | 355 ++++++++++--------
packages/ai/src/scheduling/default.ts | 1 +
packages/ai/src/scheduling/templates.ts | 6 +
packages/ai/src/scheduling/types.ts | 2 +
9 files changed, 675 insertions(+), 318 deletions(-)
diff --git a/apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx b/apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx
index b678398e2..d0a041764 100644
--- a/apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx
+++ b/apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx
@@ -13,6 +13,7 @@ import {
AlertTriangleIcon,
CalendarIcon,
ClockIcon,
+ LockIcon,
SparklesIcon,
TrendingUpIcon,
} from '@tuturuuu/ui/icons';
@@ -225,15 +226,29 @@ export function ScheduleDisplay({ events }: ScheduleDisplayProps) {
{/* Event Card */}
{/* Event Header */}
+ {event.locked && (
+
+
+
+
+
+
+ Locked event: this time is blocked
+
+
+
+ )}
{event.isPastDeadline && (
diff --git a/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx b/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
index 4429ae772..0aae7d0d5 100644
--- a/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
+++ b/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
@@ -18,6 +18,7 @@ import {
Trash2Icon,
ZapIcon,
} from '@tuturuuu/ui/icons';
+import { SplitIcon } from '@tuturuuu/ui/icons';
import { Input } from '@tuturuuu/ui/input';
import { Label } from '@tuturuuu/ui/label';
import { Progress } from '@tuturuuu/ui/progress';
@@ -28,6 +29,7 @@ import {
SelectTrigger,
SelectValue,
} from '@tuturuuu/ui/select';
+import { Switch } from '@tuturuuu/ui/switch';
import { Tooltip, TooltipContent, TooltipTrigger } from '@tuturuuu/ui/tooltip';
import dayjs from 'dayjs';
import { useMemo } from 'react';
@@ -245,6 +247,29 @@ export function TaskList({
: ''
}`}
/>
+ {/* Split Toggle Button */}
+
+
+
+
+
+
+ onUpdateTask(task.id, {
+ allowSplit: checked,
+ })
+ }
+ className="scale-90"
+ />
+
+
+
+ Allow this task to be split into sessions
+
+
+
{isCompleted && (
)}
diff --git a/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx b/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx
index 2c1287040..d43a2bbab 100644
--- a/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx
+++ b/apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx
@@ -21,9 +21,11 @@ import {
SelectValue,
} from '@tuturuuu/ui/select';
import { Separator } from '@tuturuuu/ui/separator';
+import { Switch } from '@tuturuuu/ui/switch';
import { Textarea } from '@tuturuuu/ui/textarea';
import dayjs from 'dayjs';
import { useState } from 'react';
+import { SplitIcon } from '@tuturuuu/ui/icons';
interface TaskModalProps {
isOpen: boolean;
@@ -62,6 +64,7 @@ export function TaskModal({ isOpen, onClose, onAddTask }: TaskModalProps) {
category: 'work' as 'work' | 'personal' | 'meeting',
deadline: '',
priority: 'medium' as 'low' | 'medium' | 'high',
+ allowSplit: true,
});
const [errors, setErrors] = useState>({});
@@ -115,6 +118,7 @@ export function TaskModal({ isOpen, onClose, onAddTask }: TaskModalProps) {
maxDuration: formData.maxDuration,
category: formData.category,
deadline: formData.deadline ? dayjs(formData.deadline) : undefined,
+ allowSplit: formData.allowSplit,
};
onAddTask(newTask);
@@ -131,12 +135,13 @@ export function TaskModal({ isOpen, onClose, onAddTask }: TaskModalProps) {
category: 'work',
deadline: '',
priority: 'medium',
+ allowSplit: true,
});
setErrors({});
onClose();
};
- const updateFormData = (field: string, value: string | number) => {
+ const updateFormData = (field: string, value: string | number | boolean) => {
setFormData((prev) => ({ ...prev, [field]: value }));
if (errors[field]) {
setErrors((prev) => ({ ...prev, [field]: '' }));
@@ -145,7 +150,7 @@ export function TaskModal({ isOpen, onClose, onAddTask }: TaskModalProps) {
return (