Skip to content

Add schedule timeline updates and V2 roadmap preview#32

Merged
macintoshwan merged 13 commits into
mainfrom
feature/schedule
Apr 22, 2026
Merged

Add schedule timeline updates and V2 roadmap preview#32
macintoshwan merged 13 commits into
mainfrom
feature/schedule

Conversation

@macintoshwan

Copy link
Copy Markdown
Owner

Summary

This PR finalizes the current schedule phase and prepares the repository for a stable V1 period.

Included changes

  • Complete schedule timeline refactor baseline for multi-day usage on the current branch
  • Fix build-blocking TypeScript issues found in deployment logs
  • Add README updates:
    • mark V1 as stable for daily use
    • announce planned V2 direction (AI-first + unified model exploration)

Why

The goal is to close this phase cleanly, merge to main, and keep a stable version available for at least the next month while V2 planning proceeds in isolation.

Notes

Copilot AI review requested due to automatic review settings April 22, 2026 18:36
@macintoshwan macintoshwan merged commit 4e3f719 into main Apr 22, 2026
4 checks passed
@macintoshwan macintoshwan deleted the feature/schedule branch April 22, 2026 18:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a “fixed schedule events” capability (DB + UI) and updates project status messaging to mark V1 as stable while previewing V2 direction.

Changes:

  • Adds is_fixed_event, schedule_start_at, schedule_end_at to tasks (with an index for fixed events).
  • Introduces schedule timeline UI + modal for creating fixed-time blocks, and allows clicking a todo to open task details.
  • Updates base styles for new schedule components and refreshes README status/roadmap.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
supabase/migrations/005_add_task_schedule_columns.sql Adds schedule-related columns + partial index for fixed events.
src/types/index.ts Extends Task type with schedule-related fields.
src/styles/base.css Adds styling for date/time inputs, schedule timeline, and modal sizing.
src/components/TodoListContainer.tsx Plumbs through onSelectTodoTask callback.
src/components/TodoList.tsx Makes todo items keyboard/click selectable and adjusts layout for project tag.
src/components/ScheduleTimeline.tsx New schedule timeline component that renders free/occupied segments.
src/components/App.tsx Wires schedule section/modal, derives schedule events, and opens task detail modal from todo list.
README.md Updates project status to “V1 stable” and adds V2 preview section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/App.tsx
Comment on lines +299 to +301
const taskDayKey = rawStart.toISOString().slice(0, 10);
const dayStartForTask = new Date(`${taskDayKey}T00:00:00`);
const dayEndForTask = new Date(`${taskDayKey}T23:59:59.999`);

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

taskDayKey 通过 rawStart.toISOString().slice(0, 10) 取的是 UTC 日期;而 todayKey/scheduleDate 是本地日期字符串。两者混用会导致在非 UTC 时区下把事件归到错误的日期列(例如本地凌晨/深夜的事件)。建议用本地时间生成 dateKey(基于 rawStart.getFullYear()/getMonth()/getDate()),并确保后续 dayStartForTask 也基于同一套本地日历日。

Copilot uses AI. Check for mistakes.
Comment thread src/components/App.tsx
Comment on lines +659 to +661
const [scheduleDate, setScheduleDate] = useState(defaultDate ?? new Date().toISOString().slice(0, 10));
const [startTime, setStartTime] = useState('08:00');
const [endTime, setEndTime] = useState('09:00');

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scheduleDate 默认值使用 new Date().toISOString().slice(0, 10) 取的是 UTC 日期,用户本地时区可能会默认到“昨天/明天”。建议改用与全局一致的本地日期生成方式(例如复用 getLocalDateKey()),保证日期输入的默认值符合用户本地日期。

Copilot uses AI. Check for mistakes.
const dates = useMemo(() => {
const result: string[] = [];
for (let i = 0; i < viewDays; i++) {
const d = new Date(todayKey);

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里同样使用 new Date(todayKey) 解析 YYYY-MM-DD,会按 UTC 解析并可能造成日期偏移,进而导致 timeline 的列标题/列数与 todayKey(本地日)不一致。建议用 new Date(${todayKey}T00:00:00) 或拆分年月日构造本地日期。

Suggested change
const d = new Date(todayKey);
const d = new Date(`${todayKey}T00:00:00`);

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +50
segments.push({
kind: 'occupied',
startMinute: event.startMinute,
endMinute: event.endMinute,
id: event.id,
name: event.name,
});

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当存在重叠或乱序数据时(例如后端写入或未来功能引入),这里会在 cursor 已经过了某个时间段的情况下仍然 push 一个从 event.startMinute 开始的 occupied 段,导致总时长被重复计算、渲染高度超过 24h。建议在生成 occupied 段时将开始时间裁剪为 max(cursor, event.startMinute),或在 normalized 阶段合并/裁剪重叠区间。

Suggested change
segments.push({
kind: 'occupied',
startMinute: event.startMinute,
endMinute: event.endMinute,
id: event.id,
name: event.name,
});
const occupiedStart = Math.max(cursor, event.startMinute);
if (occupiedStart < event.endMinute) {
segments.push({
kind: 'occupied',
startMinute: occupiedStart,
endMinute: event.endMinute,
id: event.id,
name: event.name,
});
}

Copilot uses AI. Check for mistakes.
ADD COLUMN IF NOT EXISTS is_fixed_event boolean NOT NULL DEFAULT false,
ADD COLUMN IF NOT EXISTS schedule_start_at timestamp with time zone,
ADD COLUMN IF NOT EXISTS schedule_end_at timestamp with time zone;

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前 schema 允许 is_fixed_event = trueschedule_start_at/schedule_end_at 为空或结束早于开始(前端校验可绕过/未来接口可能写入)。建议在 DB 层增加约束(例如 CHECK:(NOT is_fixed_event) OR (schedule_start_at IS NOT NULL AND schedule_end_at IS NOT NULL AND schedule_end_at > schedule_start_at)),以保证数据一致性并减少后续代码中的防御性判断。

Suggested change
-- Enforce valid fixed-event schedule ranges at the database layer
ALTER TABLE public.tasks
ADD CONSTRAINT tasks_fixed_event_schedule_check
CHECK (
(NOT is_fixed_event)
OR (
schedule_start_at IS NOT NULL
AND schedule_end_at IS NOT NULL
AND schedule_end_at > schedule_start_at
)
);

Copilot uses AI. Check for mistakes.
Comment thread src/types/index.ts
Comment on lines +44 to +46
is_fixed_event?: boolean;
schedule_start_at?: string | null;
schedule_end_at?: string | null;

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Task 接口顶部注释写的是“严格对齐 Supabase schema”,但这里把 is_fixed_event(DB 中 NOT NULL + DEFAULT false)以及新时间字段都声明成可选属性,会让类型系统允许缺字段的 task 并掩盖数据一致性问题。建议把 is_fixed_event 设为必填 boolean,并将 schedule_start_at/schedule_end_at 设为必填但可空(string | null),与 schema 对齐。

Suggested change
is_fixed_event?: boolean;
schedule_start_at?: string | null;
schedule_end_at?: string | null;
is_fixed_event: boolean;
schedule_start_at: string | null;
schedule_end_at: string | null;

Copilot uses AI. Check for mistakes.
Comment thread src/components/App.tsx
Comment on lines +279 to +284
const d = new Date(todayKey);
d.setDate(d.getDate() + i);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
dates.push(`${y}-${m}-${dd}`);

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里用 new Date(todayKey) 解析 YYYY-MM-DD 的日期字符串在 JS 中会按 UTC 解析(且不同时区可能出现日期偏移),随后再用 setDate 叠加天数,容易导致生成的 dates 列表和本地 todayKey 不一致。建议用 new Date(${todayKey}T00:00:00)(本地 0 点)或手动拆分 year/month/day 构造,避免时区偏移。

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants