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 ( - + @@ -156,189 +161,185 @@ export function TaskModal({ isOpen, onClose, onAddTask }: TaskModalProps) { -
- {/* Basic Information */} -
-
- - updateFormData('name', e.target.value)} - className={errors.name ? 'border-destructive' : ''} - /> - {errors.name && ( -

{errors.name}

- )} -
- -
- -